test: zk dispute game factory and registry#19872
test: zk dispute game factory and registry#198720xChin wants to merge 20 commits intoethereum-optimism:developfrom
Conversation
| function setUp() public virtual override { | ||
| super.setUp(); | ||
|
|
||
| skipIfDevFeatureDisabled(DevFeatures.ZK_DISPUTE_GAME); |
There was a problem hiding this comment.
Every this is testes when zk dispute game is enabled. Maybe create one to check that reverts if the flag is disabled.
There was a problem hiding this comment.
With the flag disabled, the ZK game implementation wouldn't be deployed or registered in the factory so there's no zkGameProxy to test against. The ASR and factory are game-type agnostic; they don't check the feature flag themselves. The flag only gates deployment at the OPCM level, which is already covered by test_upgrade_enableZKGameWithoutDevFeature_reverts in the OPCM tests. At the ASR/factory level, "flag disabled" just means "no ZK game exists," which isn't a ZK-specific scenario worth testing here.
|
|
||
| bytes memory args = abi.encodePacked( | ||
| keccak256("absolutePrestate"), // absolutePrestate 32 bytes | ||
| zkVerifier, // verifier 20 bytes |
There was a problem hiding this comment.
could we just create some vars instead of having the numer
There was a problem hiding this comment.
| // Verify CWIA getters — confirms gameArgs were forwarded correctly without re-encoding. | ||
| assertEq(GameType.unwrap(_proxy.gameType()), GameType.unwrap(GameTypes.ZK_DISPUTE_GAME)); | ||
| assertEq(_proxy.gameCreator(), _proposer); | ||
| assertTrue(_proxy.l1Head().raw() != bytes32(0)); |
There was a problem hiding this comment.
you only check that is not 0 , there is any way to check with the proper value
There was a problem hiding this comment.
| assertTrue(_proxy.l1Head().raw() != bytes32(0)); | ||
| assertEq(_proxy.parentIndex(), type(uint32).max); | ||
| assertEq(_proxy.absolutePrestate(), keccak256("absolutePrestate")); | ||
| assertTrue(address(_proxy.verifier()) != address(0)); |
There was a problem hiding this comment.
| function test_create_zeroBond_reverts() public { | ||
| skipIfDevFeatureDisabled(DevFeatures.ZK_DISPUTE_GAME); | ||
|
|
||
| setupZKDisputeGame( |
There was a problem hiding this comment.
Could we crearte a func to create this? we have something similar in test_create_wrongBond_reverts
There was a problem hiding this comment.
| vm.prank(proposer); | ||
| vm.expectRevert(IncorrectBondAmount.selector); | ||
| // Sending 0.5 ether instead of the required 1 ether. | ||
| disputeGameFactory.create{ value: 0.5 ether }(GameTypes.ZK_DISPUTE_GAME, rootClaim_, extraData_); |
There was a problem hiding this comment.
Could we create something like: testFuzz_create_overpayment_revert we are not testing the overpay only the under.
There was a problem hiding this comment.
There is no harm in adding more tests, but the generic testFuzz_create_overpayment_reverts in DisputeGameFactory_Create_Test already covers game type 10 (ZK).
The bond check (msg.value != initBonds[_gameType]) happens in the factory before initialize()is called, so the game implementation is irrelevant FakeClone and ZKDisputeGame hit the exact same code path. Adding a ZK-specific version wouldn't improve coverage
| address zkImpl = address(new ZKDisputeGame()); | ||
| IZKVerifier zkVerifier = IZKVerifier(address(new ZKMockVerifier())); | ||
|
|
||
| bytes memory args = abi.encodePacked( |
There was a problem hiding this comment.
Also could we use the same helper func that use the contract to encode
There was a problem hiding this comment.
not quite following what helper function for encoding you are talking about
|
|
||
| // Find the 2 most recent ZK games. | ||
| IDisputeGameFactory.GameSearchResult[] memory results = | ||
| disputeGameFactory.findLatestGames(GameTypes.ZK_DISPUTE_GAME, latestIdx, 2); |
There was a problem hiding this comment.
Do we have another tests with n > gameCount
There was a problem hiding this comment.
we don't. good catch test: check findLatestGames works if n > gameCount
| contract AnchorStateRegistry_IsGameProper_ZkDisputeGame_Test is AnchorStateRegistry_ZkDisputeGame_TestInit { | ||
| /// @notice Tests that a ZK game meeting all conditions is proper. | ||
| function test_isGameProper_meetsAllConditions_succeeds() public view { | ||
| assertTrue(anchorStateRegistry.isGameProper(zkGameProxy)); |
There was a problem hiding this comment.
Should we add another one for farse, with a random address or something likes this
There was a problem hiding this comment.
There was a problem hiding this comment.
Added test_isGameProper_notRegistered_succeeds which mocks the factory to report the ZK game as unregistered and asserts isGameProper returns false. Note that the generic tests (test_isGameProper_isNotFactoryRegistered_succeeds, testFuzz_isGameClaimValid_notRegistered_succeeds) already cover this code path since the registration check is game-type agnostic, but having the explicit ZK
variant keeps the test structure consistent so good catch ser
| disputeGameFactory.setInitBond(lgt, 1 ether); | ||
| } | ||
|
|
||
| vm.deal(address(this), 2 ether); |
There was a problem hiding this comment.
| for (uint8 i; i < maxGameType + 1; i++) { | ||
| GameType lgt = GameType.wrap(i); | ||
| disputeGameFactory.setImplementation(lgt, IDisputeGame(address(fakeClone))); | ||
| disputeGameFactory.setInitBond(lgt, 1 ether); | ||
| } |
There was a problem hiding this comment.
is this loop needed? whats the purpose of going through all game types?
There was a problem hiding this comment.
this test was removed in test: add fuzz testing given testFuzz_create_wrongBond_reverts covers all bond mismatch scenarios (underpayment, overpayment, zero) with fuzzing.
but regarding the loop logic, it would set the implementation to all game types like it's done in the previously existing testFuzz_create_incorrectBondAmount_reverts to avoid the NoImplementation() error
| (, uint256 anchorL2SeqNum) = anchorStateRegistry.getAnchorRoot(); | ||
|
|
||
| // extraData: l2SequenceNumber (32 bytes) || parentIndex (4 bytes). | ||
| // parentIndex = uint32.max indicates this is the first game in the chain. | ||
| bytes memory extraData_ = abi.encodePacked(anchorL2SeqNum + 1000, type(uint32).max); | ||
|
|
||
| Claim rootClaim_ = changeClaimStatus(Claim.wrap(keccak256("zkRootClaim")), VMStatuses.INVALID); |
There was a problem hiding this comment.
couldnt you use _zkCreateParams ?
There was a problem hiding this comment.
|
|
||
| /// @title DisputeGameFactory_Create_ZkDisputeGame_Test | ||
| /// @notice Tests the `create` function of the `DisputeGameFactory` contract with ZKDisputeGame. | ||
| contract DisputeGameFactory_Create_ZkDisputeGame_Test is DisputeGameFactory_ZkDisputeGame_TestInit { |
There was a problem hiding this comment.
missing fuzzing - same for the rest of the test contracts
There was a problem hiding this comment.
done in test: add fuzz testing and test: add more fuzz tests
| ZKDisputeGameParams({ | ||
| maxChallengeDuration: Duration.wrap(3.5 days), | ||
| maxProveDuration: Duration.wrap(12 hours), | ||
| absolutePrestate: keccak256("absolutePrestate"), | ||
| challengerBond: 1 ether | ||
| }) |
There was a problem hiding this comment.
I think that if we are gonna hardcode these values for everything then there is no point in setupZKDisputeGame to have a ZKDisputeGameParams input for this and repeat the same hardcoded values we could just define a default set of params, unless we want to have different params or fuzz any of these.
This is especially important since in _assertZKGameCWIA the expected values are always hardcoded for the specific vars.
There was a problem hiding this comment.
Yes, I've defined a defaultZKParams var. Also modified the _assertZKGameCWIA allowing it to receive the game params as arg for all the fuzz testing implemented
| vm.warp(block.timestamp + 1000); | ||
| vm.prank(proposer); | ||
| vm.expectRevert(IncorrectBondAmount.selector); | ||
| disputeGameFactory.create{ value: 0.5 ether }(GameTypes.ZK_DISPUTE_GAME, rootClaim_, extraData_); |
There was a problem hiding this comment.
we could fuzz the amount here
There was a problem hiding this comment.
if you fuzz the testFuzz_create_overpayment_reverts then probably this becomes a repeated test
| contract DisputeGameFactory_Create_ZkDisputeGame_Test is DisputeGameFactory_ZkDisputeGame_TestInit { | ||
| /// @notice Tests that the factory creates a ZKDisputeGame CWIA clone correctly. | ||
| function test_create_succeeds() public { | ||
| skipIfDevFeatureDisabled(DevFeatures.ZK_DISPUTE_GAME); |
There was a problem hiding this comment.
The best practice in cases like this where we skip all tests since all are related to the ZK dispute game dev flag is to define this in a setUp function probably best would be in DisputeGameFactory_ZkDisputeGame_TestInit
There was a problem hiding this comment.
| /// @title DisputeGameFactory_ZkDisputeGame_TestInit | ||
| /// @notice Reusable test initialization for ZKDisputeGame factory tests. | ||
| abstract contract DisputeGameFactory_ZkDisputeGame_TestInit is DisputeGameFactory_TestInit { | ||
| IZKVerifier zkVerifier; |
There was a problem hiding this comment.
It's declared as a state var in TestInit because both _createZKGameWithParams (which sets it) and _assertZKGameCWIA (which reads it) live there. The alternative would be returning it from _createZKGameWithParams and passing it as an extra param to _assertZKGameCWIA, but I'd rather keep it this way
| address zkImpl = address(new ZKDisputeGame()); | ||
| bytes memory args = abi.encodePacked(keccak256("absolutePrestate")); | ||
|
|
||
| vm.prank(address(0)); |
There was a problem hiding this comment.
| import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; | ||
| import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol"; | ||
| import { IProxyAdminOwnedBase } from "interfaces/universal/IProxyAdminOwnedBase.sol"; | ||
| import { ZKDisputeGame } from "src/dispute/zk/ZKDisputeGame.sol"; |
There was a problem hiding this comment.
Can't we use the interface instead?
There was a problem hiding this comment.
yes refactor: use IDisputeGame interface, actually given that the ASR should be game-agnostic, I've directly used the IDisputeGame interface. which works
0xOneTony
left a comment
There was a problem hiding this comment.
requesting changes above^
|
/ci authorize a651fe6 |
|
/ci authorize c41aa6f |
|
/ci authorize e8910df |
Summary
Adds ZK dispute game test coverage for
DisputeGameFactoryandAnchorStateRegistry, proving both contracts work correctly with the newZK_DISPUTE_GAMEtype (game type 10).Changes
DisputeGameFactory.t.solRestructuring:
_ZkDisputeGame_contractstest_create_implArgs_succeedsintoDisputeGameFactory_Create_FaultDisputeGame_Testfor explicit game-type separationDisputeGameFactory_ZkDisputeGame_TestInitabstract base with shared helpers (_createZKGame,_assertZKGameFactoryStorage,_assertZKGameCWIA)New test contracts:
DisputeGameFactory_Create_ZkDisputeGame_Test— create happy path, zero bond, wrong bond, no impl, duplicate UUIDDisputeGameFactory_SetImplementation_ZkDisputeGame_Test— impl+args storage, non-owner revertDisputeGameFactory_SetInitBond_ZkDisputeGame_Test— bond set/update, non-owner revertDisputeGameFactory_FindLatestGames_ZkDisputeGame_Test— multi-game orderingNew generic test:
testFuzz_create_overpayment_reverts— verifies factory rejects overpayment (sends more ETH than required bond)AnchorStateRegistry.t.solNew abstract base:
AnchorStateRegistry_ZkDisputeGame_TestInit— creates a real ZK game via factory, provides_mockZkGameAsValid()helperNew test contracts:
AnchorStateRegistry_SetAnchorState_ZkDisputeGame_Test— valid newer state, older game claim rejected, blacklisted, retired, challenger wins, not finalized (6 tests)AnchorStateRegistry_IsGameClaimValid_ZkDisputeGame_Test— valid claim, blacklisted, retired, not respected (4 tests)AnchorStateRegistry_IsGameProper_ZkDisputeGame_Test— all conditions met, blacklisted (2 tests)AnchorStateRegistry_BlacklistDisputeGame_ZkDisputeGame_Test— blacklist succeeds (1 test)Test plan
DEV_FEATURE__ZK_DISPUTE_GAME=true forge test --match-path test/dispute/DisputeGameFactory.t.solDEV_FEATURE__ZK_DISPUTE_GAME=true forge test --match-path test/dispute/AnchorStateRegistry.t.soljust pre-prpasses