Skip to content

Commit 3b64ec2

Browse files
expanded test coverage
1 parent c5b8c57 commit 3b64ec2

File tree

3 files changed

+242
-1
lines changed

3 files changed

+242
-1
lines changed

op-e2e/faultproofs/output_alphabet_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ func TestOutputAlphabetGame_ReclaimBond(t *testing.T) {
129129

130130
// Advance the time past the finalization delay
131131
// Finalization delay is the same as the credit unlock delay
132-
sys.TimeTravelClock.AdvanceTime(game.CreditUnlockDuration(ctx))
132+
// But just warp way into the future to be safe
133+
sys.TimeTravelClock.AdvanceTime(game.CreditUnlockDuration(ctx) * 2)
133134
require.NoError(t, wait.ForNextBlock(ctx, l1Client))
134135

135136
// Wait for alice to have no available credit

packages/contracts-bedrock/test/dispute/AnchorStateRegistry.t.sol

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ contract AnchorStateRegistry_IsGameProper_Test is AnchorStateRegistry_Init {
257257
}
258258

259259
/// @notice Tests that isGameProper will return false if the game is not the respected game type.
260+
/// @param _gameType The game type to use for the test.
260261
function testFuzz_isGameProper_isNotRespected_succeeds(GameType _gameType) public {
261262
if (_gameType.raw() == gameProxy.gameType().raw()) {
262263
_gameType = GameType.wrap(_gameType.raw() + 1);
@@ -283,6 +284,7 @@ contract AnchorStateRegistry_IsGameProper_Test is AnchorStateRegistry_Init {
283284
}
284285

285286
/// @notice Tests that isGameProper will return false if the game is retired.
287+
/// @param _retirementTimestamp The retirement timestamp to use for the test.
286288
function testFuzz_isGameProper_isRetired_succeeds(uint64 _retirementTimestamp) public {
287289
// Make sure retirement timestamp is later than the game's creation time.
288290
_retirementTimestamp = uint64(bound(_retirementTimestamp, gameProxy.createdAt().raw() + 1, type(uint64).max));
@@ -298,6 +300,206 @@ contract AnchorStateRegistry_IsGameProper_Test is AnchorStateRegistry_Init {
298300
}
299301
}
300302

303+
contract AnchorStateRegistry_IsGameResolved_Test is AnchorStateRegistry_Init {
304+
/// @notice Tests that isGameResolved will return true if the game is resolved.
305+
/// @param _resolvedAtTimestamp The resolvedAt timestamp to use for the test.
306+
function testFuzz_isGameResolved_challengerWins_succeeds(uint256 _resolvedAtTimestamp) public {
307+
// Bound resolvedAt to be less than or equal to current timestamp.
308+
_resolvedAtTimestamp = bound(_resolvedAtTimestamp, 0, block.timestamp);
309+
310+
// Mock the resolvedAt timestamp.
311+
vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.resolvedAt, ()), abi.encode(_resolvedAtTimestamp));
312+
313+
// Mock the status to be CHALLENGER_WINS.
314+
vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.status, ()), abi.encode(GameStatus.CHALLENGER_WINS));
315+
316+
// Game should be resolved.
317+
assertTrue(anchorStateRegistry.isGameResolved(gameProxy));
318+
}
319+
320+
/// @notice Tests that isGameResolved will return true if the game is resolved.
321+
/// @param _resolvedAtTimestamp The resolvedAt timestamp to use for the test.
322+
function testFuzz_isGameResolved_defenderWins_succeeds(uint256 _resolvedAtTimestamp) public {
323+
// Bound resolvedAt to be less than or equal to current timestamp.
324+
_resolvedAtTimestamp = bound(_resolvedAtTimestamp, 0, block.timestamp);
325+
326+
// Mock the resolvedAt timestamp.
327+
vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.resolvedAt, ()), abi.encode(_resolvedAtTimestamp));
328+
329+
// Mock the status to be DEFENDER_WINS.
330+
vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.status, ()), abi.encode(GameStatus.DEFENDER_WINS));
331+
332+
// Game should be resolved.
333+
assertTrue(anchorStateRegistry.isGameResolved(gameProxy));
334+
}
335+
336+
/// @notice Tests that isGameResolved will return false if the game is in progress and not resolved.
337+
/// @param _resolvedAtTimestamp The resolvedAt timestamp to use for the test.
338+
function testFuzz_isGameResolved_inProgressNotResolved_succeeds(uint256 _resolvedAtTimestamp) public {
339+
// Bound resolvedAt to be less than or equal to current timestamp.
340+
_resolvedAtTimestamp = bound(_resolvedAtTimestamp, 0, block.timestamp);
341+
342+
// Mock the resolvedAt timestamp.
343+
vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.resolvedAt, ()), abi.encode(_resolvedAtTimestamp));
344+
345+
// Mock the status to be IN_PROGRESS.
346+
vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.status, ()), abi.encode(GameStatus.IN_PROGRESS));
347+
348+
// Game should not be resolved.
349+
assertFalse(anchorStateRegistry.isGameResolved(gameProxy));
350+
}
351+
}
352+
353+
contract AnchorStateRegistry_IsGameAirgapped_TestFail is AnchorStateRegistry_Init {
354+
/// @notice Tests that isGameAirgapped will return true if the game is airgapped.
355+
/// @param _resolvedAtTimestamp The resolvedAt timestamp to use for the test.
356+
function testFuzz_isGameAirgapped_isAirgapped_succeeds(uint256 _resolvedAtTimestamp) public {
357+
// Warp forward by disputeGameFinalityDelaySeconds.
358+
vm.warp(block.timestamp + optimismPortal2.disputeGameFinalityDelaySeconds());
359+
360+
// Bound resolvedAt to be at least disputeGameFinalityDelaySeconds in the past.
361+
_resolvedAtTimestamp =
362+
bound(_resolvedAtTimestamp, 0, block.timestamp - optimismPortal2.disputeGameFinalityDelaySeconds() - 1);
363+
364+
// Mock the resolvedAt timestamp.
365+
vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.resolvedAt, ()), abi.encode(_resolvedAtTimestamp));
366+
367+
// Game should be airgapped.
368+
assertTrue(anchorStateRegistry.isGameAirgapped(gameProxy));
369+
}
370+
371+
/// @notice Tests that isGameAirgapped will return false if the game is not airgapped.
372+
/// @param _resolvedAtTimestamp The resolvedAt timestamp to use for the test.
373+
function testFuzz_isGameAirgapped_isNotAirgapped_succeeds(uint256 _resolvedAtTimestamp) public {
374+
// Warp forward by disputeGameFinalityDelaySeconds.
375+
vm.warp(block.timestamp + optimismPortal2.disputeGameFinalityDelaySeconds());
376+
377+
// Bound resolvedAt to be less than disputeGameFinalityDelaySeconds in the past.
378+
_resolvedAtTimestamp = bound(
379+
_resolvedAtTimestamp, block.timestamp - optimismPortal2.disputeGameFinalityDelaySeconds(), block.timestamp
380+
);
381+
382+
// Mock the resolvedAt timestamp.
383+
vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.resolvedAt, ()), abi.encode(_resolvedAtTimestamp));
384+
385+
// Game should not be airgapped.
386+
assertFalse(anchorStateRegistry.isGameAirgapped(gameProxy));
387+
}
388+
}
389+
390+
contract AnchorStateRegistry_IsGameClaimValid_Test is AnchorStateRegistry_Init {
391+
/// @notice Tests that isGameClaimValid will return true if the game claim is valid.
392+
/// @param _resolvedAtTimestamp The resolvedAt timestamp to use for the test.
393+
function testFuzz_isGameClaimValid_claimIsValid_succeeds(uint256 _resolvedAtTimestamp) public {
394+
// Warp forward by disputeGameFinalityDelaySeconds.
395+
vm.warp(block.timestamp + optimismPortal2.disputeGameFinalityDelaySeconds());
396+
397+
// Bound resolvedAt to be at least disputeGameFinalityDelaySeconds in the past.
398+
_resolvedAtTimestamp =
399+
bound(_resolvedAtTimestamp, 0, block.timestamp - optimismPortal2.disputeGameFinalityDelaySeconds() - 1);
400+
401+
// Mock that the game was respected.
402+
vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.wasRespectedGameTypeWhenCreated, ()), abi.encode(true));
403+
404+
// Mock the resolvedAt timestamp.
405+
vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.resolvedAt, ()), abi.encode(_resolvedAtTimestamp));
406+
407+
// Mock the status to be DEFENDER_WINS.
408+
vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.status, ()), abi.encode(GameStatus.DEFENDER_WINS));
409+
410+
// Claim should be valid.
411+
assertTrue(anchorStateRegistry.isGameClaimValid(gameProxy));
412+
}
413+
414+
/// @notice Tests that isGameClaimValid will return false if the game is not registered.
415+
function testFuzz_isGameClaimValid_notRegistered_succeeds() public {
416+
// Mock the DisputeGameFactory to make it seem that the game was not registered.
417+
vm.mockCall(
418+
address(disputeGameFactory),
419+
abi.encodeCall(
420+
disputeGameFactory.games, (gameProxy.gameType(), gameProxy.rootClaim(), gameProxy.extraData())
421+
),
422+
abi.encode(address(0), 0)
423+
);
424+
425+
// Claim should not be valid.
426+
assertFalse(anchorStateRegistry.isGameClaimValid(gameProxy));
427+
}
428+
429+
/// @notice Tests that isGameClaimValid will return false if the game is not respected.
430+
/// @param _gameType The game type to use for the test.
431+
function testFuzz_isGameClaimValid_isNotRespected_succeeds(GameType _gameType) public {
432+
if (_gameType.raw() == gameProxy.gameType().raw()) {
433+
_gameType = GameType.wrap(_gameType.raw() + 1);
434+
}
435+
436+
// Mock that the game was not respected.
437+
vm.mockCall(
438+
address(gameProxy), abi.encodeCall(gameProxy.wasRespectedGameTypeWhenCreated, ()), abi.encode(false)
439+
);
440+
441+
// Claim should not be valid.
442+
assertFalse(anchorStateRegistry.isGameClaimValid(gameProxy));
443+
}
444+
445+
/// @notice Tests that isGameClaimValid will return false if the game is blacklisted.
446+
function testFuzz_isGameClaimValid_isBlacklisted_succeeds() public {
447+
// Mock the disputeGameBlacklist call to return true.
448+
vm.mockCall(
449+
address(optimismPortal2),
450+
abi.encodeCall(optimismPortal2.disputeGameBlacklist, (gameProxy)),
451+
abi.encode(true)
452+
);
453+
454+
// Claim should not be valid.
455+
assertFalse(anchorStateRegistry.isGameClaimValid(gameProxy));
456+
}
457+
458+
/// @notice Tests that isGameClaimValid will return false if the game is retired.
459+
/// @param _resolvedAtTimestamp The resolvedAt timestamp to use for the test.
460+
function testFuzz_isGameClaimValid_isRetired_succeeds(uint256 _resolvedAtTimestamp) public {
461+
// Make sure retirement timestamp is later than the game's creation time.
462+
_resolvedAtTimestamp = uint64(bound(_resolvedAtTimestamp, gameProxy.createdAt().raw() + 1, type(uint64).max));
463+
464+
// Mock the respectedGameTypeUpdatedAt call to be later than the game's creation time.
465+
vm.mockCall(
466+
address(optimismPortal2),
467+
abi.encodeCall(optimismPortal2.respectedGameTypeUpdatedAt, ()),
468+
abi.encode(_resolvedAtTimestamp)
469+
);
470+
471+
// Claim should not be valid.
472+
assertFalse(anchorStateRegistry.isGameClaimValid(gameProxy));
473+
}
474+
475+
/// @notice Tests that isGameClaimValid will return false if the game is not resolved.
476+
function testFuzz_isGameClaimValid_notResolved_succeeds() public {
477+
// Mock the status to be IN_PROGRESS.
478+
vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.status, ()), abi.encode(GameStatus.IN_PROGRESS));
479+
480+
// Claim should not be valid.
481+
assertFalse(anchorStateRegistry.isGameClaimValid(gameProxy));
482+
}
483+
484+
/// @notice Tests that isGameClaimValid will return false if the game is not airgapped.
485+
/// @param _resolvedAtTimestamp The resolvedAt timestamp to use for the test.
486+
function testFuzz_isGameClaimValid_notAirgapped_succeeds(uint256 _resolvedAtTimestamp) public {
487+
// Warp forward by disputeGameFinalityDelaySeconds.
488+
vm.warp(block.timestamp + optimismPortal2.disputeGameFinalityDelaySeconds());
489+
490+
// Bound resolvedAt to be less than disputeGameFinalityDelaySeconds in the past.
491+
_resolvedAtTimestamp = bound(
492+
_resolvedAtTimestamp, block.timestamp - optimismPortal2.disputeGameFinalityDelaySeconds(), block.timestamp
493+
);
494+
495+
// Mock the resolvedAt timestamp.
496+
vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.resolvedAt, ()), abi.encode(_resolvedAtTimestamp));
497+
498+
// Claim should not be valid.
499+
assertFalse(anchorStateRegistry.isGameClaimValid(gameProxy));
500+
}
501+
}
502+
301503
contract AnchorStateRegistry_SetAnchorState_Test is AnchorStateRegistry_Init {
302504
/// @notice Tests that setAnchorState will succeed if the game is valid, the game block
303505
/// number is greater than the current anchor root block number, and the game is the

packages/contracts-bedrock/test/dispute/FaultDisputeGame.t.sol

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,44 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
351351
});
352352
}
353353

354+
/// @dev Tests that the constructor of the `FaultDisputeGame` reverts when the `_gameType`
355+
/// parameter is set to the reserved `type(uint32).max` game type.
356+
function test_constructor_reservedGameType_reverts() public {
357+
AlphabetVM alphabetVM = new AlphabetVM(
358+
absolutePrestate,
359+
IPreimageOracle(
360+
DeployUtils.create1({
361+
_name: "PreimageOracle",
362+
_args: DeployUtils.encodeConstructor(abi.encodeCall(IPreimageOracle.__constructor__, (0, 0)))
363+
})
364+
)
365+
);
366+
367+
vm.expectRevert(ReservedGameType.selector);
368+
DeployUtils.create1({
369+
_name: "FaultDisputeGame",
370+
_args: DeployUtils.encodeConstructor(
371+
abi.encodeCall(
372+
IFaultDisputeGame.__constructor__,
373+
(
374+
IFaultDisputeGame.GameConstructorParams({
375+
gameType: GameType.wrap(type(uint32).max),
376+
absolutePrestate: absolutePrestate,
377+
maxGameDepth: 16,
378+
splitDepth: 8,
379+
clockExtension: Duration.wrap(3 hours),
380+
maxClockDuration: Duration.wrap(3.5 days),
381+
vm: alphabetVM,
382+
weth: IDelayedWETH(payable(address(0))),
383+
anchorStateRegistry: IAnchorStateRegistry(address(0)),
384+
l2ChainId: 10
385+
})
386+
)
387+
)
388+
)
389+
});
390+
}
391+
354392
/// @dev Tests that the game's root claim is set correctly.
355393
function test_rootClaim_succeeds() public view {
356394
assertEq(gameProxy.rootClaim().raw(), ROOT_CLAIM.raw());

0 commit comments

Comments
 (0)