diff --git a/deploy-config/local.json b/deploy-config/local.json index 4d80f4919..e3409f209 100644 --- a/deploy-config/local.json +++ b/deploy-config/local.json @@ -17,13 +17,11 @@ "l2GenesisBlockGasLimit": "0x17D7840", "l2OutputOracleStartingBlockNumber": 1, "l2OutputOracleStartingTimestamp": 1, - "multiproofSlowBlockInterval": 100, + "multiproofBlockInterval": 100, "multiproofConfigHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "multiproofFastBlockInterval": 1000, - "multiproofFastIntermediateBlockInterval": 100, "multiproofGameType": 621, "multiproofGenesisBlockNumber": 0, - "multiproofSlowIntermediateBlockInterval": 10, + "multiproofIntermediateBlockInterval": 10, "multiproofGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000001", "nitroValidator": "0x0000000000000000000000000000000000000000", "operatorFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", diff --git a/interfaces/L1/proofs/IAggregateVerifier.sol b/interfaces/L1/proofs/IAggregateVerifier.sol index 1bb74be3a..9e3039953 100644 --- a/interfaces/L1/proofs/IAggregateVerifier.sol +++ b/interfaces/L1/proofs/IAggregateVerifier.sol @@ -29,11 +29,8 @@ interface IAggregateVerifier is IDisputeGame { function L2_GENESIS_BLOCK_NUMBER() external view returns (uint256); function L2_GENESIS_TIMESTAMP() external view returns (uint64); function L2_BLOCK_TIME() external view returns (uint64); - function SLOW_BLOCK_INTERVAL() external view returns (uint256); - function SLOW_INTERMEDIATE_BLOCK_INTERVAL() external view returns (uint256); - function FAST_BLOCK_INTERVAL() external view returns (uint256); - function FAST_INTERMEDIATE_BLOCK_INTERVAL() external view returns (uint256); - function intervalsForStartingBlock(uint256 startingBlock) external view returns (uint256, uint256); + function BLOCK_INTERVAL() external view returns (uint256); + function INTERMEDIATE_BLOCK_INTERVAL() external view returns (uint256); function startingOutputRoot() external view returns (Proposal memory); function bondRecipient() external view returns (address); diff --git a/scripts/deploy/DeployConfig.s.sol b/scripts/deploy/DeployConfig.s.sol index 6097a0e94..a315df72b 100644 --- a/scripts/deploy/DeployConfig.s.sol +++ b/scripts/deploy/DeployConfig.s.sol @@ -51,12 +51,10 @@ contract DeployConfig is Script { uint256 public l2GenesisTimestamp; uint256 public l2OutputOracleStartingBlockNumber; uint256 public l2OutputOracleStartingTimestamp; - uint256 public multiproofSlowBlockInterval; - uint256 public multiproofFastBlockInterval; - uint256 public multiproofFastIntermediateBlockInterval; + uint256 public multiproofBlockInterval; uint256 public multiproofGameType; uint256 public multiproofGenesisBlockNumber; - uint256 public multiproofSlowIntermediateBlockInterval; + uint256 public multiproofIntermediateBlockInterval; uint256 public operatorFeeVaultMinimumWithdrawalAmount; uint256 public operatorFeeVaultWithdrawalNetwork; uint256 public proofMaturityDelaySeconds; @@ -117,12 +115,10 @@ contract DeployConfig is Script { l2OutputOracleStartingTimestamp = _json.readUint("$.l2OutputOracleStartingTimestamp"); l2GenesisBlockNumber = _json.readUintOr("$.l2GenesisBlockNumber", 0); l2GenesisTimestamp = _json.readUintOr("$.l2GenesisTimestamp", 0); - multiproofSlowBlockInterval = _json.readUintOr("$.multiproofSlowBlockInterval", 100); - multiproofFastBlockInterval = _json.readUintOr("$.multiproofFastBlockInterval", 1000); - multiproofFastIntermediateBlockInterval = _json.readUintOr("$.multiproofFastIntermediateBlockInterval", 100); + multiproofBlockInterval = _json.readUintOr("$.multiproofBlockInterval", 100); multiproofGameType = _json.readUintOr("$.multiproofGameType", 621); multiproofGenesisBlockNumber = _json.readUintOr("$.multiproofGenesisBlockNumber", 0); - multiproofSlowIntermediateBlockInterval = _json.readUintOr("$.multiproofSlowIntermediateBlockInterval", 10); + multiproofIntermediateBlockInterval = _json.readUintOr("$.multiproofIntermediateBlockInterval", 10); operatorFeeVaultMinimumWithdrawalAmount = _json.readUint("$.operatorFeeVaultMinimumWithdrawalAmount"); operatorFeeVaultWithdrawalNetwork = _json.readUint("$.operatorFeeVaultWithdrawalNetwork"); proofMaturityDelaySeconds = _json.readUintOr("$.proofMaturityDelaySeconds", 0); diff --git a/scripts/deploy/SystemDeploy.s.sol b/scripts/deploy/SystemDeploy.s.sol index 0923c411c..b196fc42f 100644 --- a/scripts/deploy/SystemDeploy.s.sol +++ b/scripts/deploy/SystemDeploy.s.sol @@ -79,10 +79,8 @@ contract SystemDeploy is Script { uint256 multiproofGameType; address nitroValidator; AggregateVerifier.ScheduleConfig scheduleConfig; - uint256 multiproofSlowBlockInterval; - uint256 multiproofSlowIntermediateBlockInterval; - uint256 multiproofFastBlockInterval; - uint256 multiproofFastIntermediateBlockInterval; + uint256 multiproofBlockInterval; + uint256 multiproofIntermediateBlockInterval; ISP1Verifier sp1Verifier; address teeProposer; address teeChallenger; @@ -130,10 +128,8 @@ contract SystemDeploy is Script { bytes32 multiproofConfigHash; uint256 l2ChainId; AggregateVerifier.ScheduleConfig scheduleConfig; - uint256 multiproofSlowBlockInterval; - uint256 multiproofSlowIntermediateBlockInterval; - uint256 multiproofFastBlockInterval; - uint256 multiproofFastIntermediateBlockInterval; + uint256 multiproofBlockInterval; + uint256 multiproofIntermediateBlockInterval; } struct MultiproofOutput { @@ -271,10 +267,8 @@ contract SystemDeploy is Script { multiproofGameType: cfg.multiproofGameType(), nitroValidator: cfg.nitroValidator(), scheduleConfig: _configuredScheduleConfig(), - multiproofSlowBlockInterval: cfg.multiproofSlowBlockInterval(), - multiproofSlowIntermediateBlockInterval: cfg.multiproofSlowIntermediateBlockInterval(), - multiproofFastBlockInterval: cfg.multiproofFastBlockInterval(), - multiproofFastIntermediateBlockInterval: cfg.multiproofFastIntermediateBlockInterval(), + multiproofBlockInterval: cfg.multiproofBlockInterval(), + multiproofIntermediateBlockInterval: cfg.multiproofIntermediateBlockInterval(), sp1Verifier: ISP1Verifier(cfg.sp1Verifier()), teeProposer: cfg.teeProposer(), teeChallenger: cfg.teeChallenger(), @@ -1061,10 +1055,8 @@ contract SystemDeploy is Script { multiproofConfigHash: _input.multiproofConfigHash, l2ChainId: _opChainInput.l2ChainId, scheduleConfig: scheduleConfig, - multiproofSlowBlockInterval: _input.multiproofSlowBlockInterval, - multiproofSlowIntermediateBlockInterval: _input.multiproofSlowIntermediateBlockInterval, - multiproofFastBlockInterval: _input.multiproofFastBlockInterval, - multiproofFastIntermediateBlockInterval: _input.multiproofFastIntermediateBlockInterval + multiproofBlockInterval: _input.multiproofBlockInterval, + multiproofIntermediateBlockInterval: _input.multiproofIntermediateBlockInterval }) ); @@ -1092,12 +1084,8 @@ contract SystemDeploy is Script { AggregateVerifier.ZkHashes(_input.zkRangeHash, _input.zkAggregationHash), _input.multiproofConfigHash, _input.l2ChainId, - AggregateVerifier.IntervalConfig({ - slowBlockInterval: _input.multiproofSlowBlockInterval, - slowIntermediateBlockInterval: _input.multiproofSlowIntermediateBlockInterval, - fastBlockInterval: _input.multiproofFastBlockInterval, - fastIntermediateBlockInterval: _input.multiproofFastIntermediateBlockInterval - }), + _input.multiproofBlockInterval, + _input.multiproofIntermediateBlockInterval, _input.scheduleConfig ) ) @@ -1140,13 +1128,12 @@ contract SystemDeploy is Script { require(address(_input.sp1Verifier) != address(0), "SystemDeploy: sp1Verifier not set"); DeployUtils.assertValidContractAddress(_input.nitroValidator); DeployUtils.assertValidContractAddress(address(_input.sp1Verifier)); - require(_input.multiproofSlowBlockInterval != 0, "SystemDeploy: multiproof block interval not set"); + require(_input.multiproofBlockInterval != 0, "SystemDeploy: multiproof block interval not set"); require( - _input.multiproofSlowIntermediateBlockInterval != 0, - "SystemDeploy: multiproof intermediate interval not set" + _input.multiproofIntermediateBlockInterval != 0, "SystemDeploy: multiproof intermediate interval not set" ); require( - _input.multiproofSlowBlockInterval % _input.multiproofSlowIntermediateBlockInterval == 0, + _input.multiproofBlockInterval % _input.multiproofIntermediateBlockInterval == 0, "SystemDeploy: invalid multiproof block intervals" ); require(_input.teeProposer != address(0), "SystemDeploy: teeProposer not set"); diff --git a/scripts/multiproof/DeployDevBase.s.sol b/scripts/multiproof/DeployDevBase.s.sol index 7b097f3c3..5e2f89208 100644 --- a/scripts/multiproof/DeployDevBase.s.sol +++ b/scripts/multiproof/DeployDevBase.s.sol @@ -128,7 +128,8 @@ abstract contract DeployDevBase is Script { zkHashes, cfg.multiproofConfigHash(), cfg.l2ChainId(), - _intervalConfig(), + _blockInterval(), + _intermediateBlockInterval(), AggregateVerifier.ScheduleConfig({ protocolVersions: IProtocolVersions(address(protocolVersionsProxy)), genesisBlockNumber: cfg.l2GenesisBlockNumber(), @@ -158,7 +159,8 @@ abstract contract DeployDevBase is Script { console.log("Deployment saved to:", outPath); } - function _intervalConfig() internal pure virtual returns (AggregateVerifier.IntervalConfig memory); + function _blockInterval() internal pure virtual returns (uint256); + function _intermediateBlockInterval() internal pure virtual returns (uint256); function _initBond() internal pure virtual returns (uint256); function _outputSuffix() internal pure virtual returns (string memory); function _deployTEERegistryImpl() internal virtual returns (address); diff --git a/scripts/multiproof/DeployDevNoNitro.s.sol b/scripts/multiproof/DeployDevNoNitro.s.sol index a84acf448..3eb209552 100644 --- a/scripts/multiproof/DeployDevNoNitro.s.sol +++ b/scripts/multiproof/DeployDevNoNitro.s.sol @@ -8,27 +8,22 @@ import { INitroValidator } from "interfaces/L1/proofs/tee/INitroValidator.sol"; import { DevTEEProverRegistry } from "test/mocks/MockDevTEEProverRegistry.sol"; import { MockNitroValidator } from "test/mocks/MockNitroValidator.sol"; -import { AggregateVerifier } from "src/L1/proofs/AggregateVerifier.sol"; - import { DeployDevBase } from "./DeployDevBase.s.sol"; /// @title DeployDevNoNitro /// @notice Development deployment using DevTEEProverRegistry, which bypasses AWS Nitro attestation /// validation. See scripts/multiproof/README.md for usage. Not for production. contract DeployDevNoNitro is DeployDevBase { - uint256 public constant SLOW_BLOCK_INTERVAL = 100; - uint256 public constant SLOW_INTERMEDIATE_BLOCK_INTERVAL = 10; - uint256 public constant FAST_BLOCK_INTERVAL = 1000; - uint256 public constant FAST_INTERMEDIATE_BLOCK_INTERVAL = 100; + uint256 public constant BLOCK_INTERVAL = 100; + uint256 public constant INTERMEDIATE_BLOCK_INTERVAL = 10; uint256 public constant INIT_BOND = 0.001 ether; - function _intervalConfig() internal pure override returns (AggregateVerifier.IntervalConfig memory) { - return AggregateVerifier.IntervalConfig({ - slowBlockInterval: SLOW_BLOCK_INTERVAL, - slowIntermediateBlockInterval: SLOW_INTERMEDIATE_BLOCK_INTERVAL, - fastBlockInterval: FAST_BLOCK_INTERVAL, - fastIntermediateBlockInterval: FAST_INTERMEDIATE_BLOCK_INTERVAL - }); + function _blockInterval() internal pure override returns (uint256) { + return BLOCK_INTERVAL; + } + + function _intermediateBlockInterval() internal pure override returns (uint256) { + return INTERMEDIATE_BLOCK_INTERVAL; } function _initBond() internal pure override returns (uint256) { diff --git a/scripts/multiproof/DeployDevWithNitro.s.sol b/scripts/multiproof/DeployDevWithNitro.s.sol index 3562dc0bf..1ef4fe01f 100644 --- a/scripts/multiproof/DeployDevWithNitro.s.sol +++ b/scripts/multiproof/DeployDevWithNitro.s.sol @@ -7,8 +7,6 @@ import { IDisputeGameFactory } from "interfaces/L1/proofs/IDisputeGameFactory.so import { INitroValidator } from "interfaces/L1/proofs/tee/INitroValidator.sol"; import { TEEProverRegistry } from "src/L1/proofs/tee/TEEProverRegistry.sol"; -import { AggregateVerifier } from "src/L1/proofs/AggregateVerifier.sol"; - import { DeployDevBase } from "./DeployDevBase.s.sol"; /// @title DeployDevWithNitro @@ -19,21 +17,18 @@ import { DeployDevBase } from "./DeployDevBase.s.sol"; /// then set `nitroValidator` in the deploy config. AWS Nitro attestations are only valid /// for 60 minutes, and the certificate chain must be cached before registerSigner() is called. contract DeployDevWithNitro is DeployDevBase { - uint256 public constant SLOW_BLOCK_INTERVAL = 600; - uint256 public constant SLOW_INTERMEDIATE_BLOCK_INTERVAL = 30; - uint256 public constant FAST_BLOCK_INTERVAL = 6000; - uint256 public constant FAST_INTERMEDIATE_BLOCK_INTERVAL = 300; + uint256 public constant BLOCK_INTERVAL = 600; + uint256 public constant INTERMEDIATE_BLOCK_INTERVAL = 30; uint256 public constant INIT_BOND = 0.00001 ether; address public nitroValidatorAddr; - function _intervalConfig() internal pure override returns (AggregateVerifier.IntervalConfig memory) { - return AggregateVerifier.IntervalConfig({ - slowBlockInterval: SLOW_BLOCK_INTERVAL, - slowIntermediateBlockInterval: SLOW_INTERMEDIATE_BLOCK_INTERVAL, - fastBlockInterval: FAST_BLOCK_INTERVAL, - fastIntermediateBlockInterval: FAST_INTERMEDIATE_BLOCK_INTERVAL - }); + function _blockInterval() internal pure override returns (uint256) { + return BLOCK_INTERVAL; + } + + function _intermediateBlockInterval() internal pure override returns (uint256) { + return INTERMEDIATE_BLOCK_INTERVAL; } function _initBond() internal pure override returns (uint256) { diff --git a/scripts/multiproof/README.md b/scripts/multiproof/README.md index 35dec295b..f30531522 100644 --- a/scripts/multiproof/README.md +++ b/scripts/multiproof/README.md @@ -172,9 +172,7 @@ Games are created using `ProofType.ZK` with the `MockVerifier` (deployed by both ### Step 1: Set the anchor state -Pick an anchor block far enough behind the L2 tip to cover all the games you want to create. Each game covers one block interval of L2 blocks — 600 on slow (pre-Cobalt) blocks, 6,000 on fast (post-Cobalt) ones — so for 500 slow-block games you need 300,000 blocks of headroom. - -`SeedGames.s.sol` reads the interval off the deployed `AggregateVerifier` and picks the side that matches the anchor block, so nothing needs changing here for Cobalt. The contract exposes the two pairs as `SLOW_BLOCK_INTERVAL` / `SLOW_INTERMEDIATE_BLOCK_INTERVAL` and `FAST_BLOCK_INTERVAL` / `FAST_INTERMEDIATE_BLOCK_INTERVAL`. `generate-roots.sh` cannot see the chain, so pass `BLOCK_INTERVAL=6000 INTERMEDIATE_BLOCK_INTERVAL=300` when seeding a devnet on which Cobalt is already active; seeding will abort on a mismatched roots file rather than create bad games. +Pick an anchor block far enough behind the L2 tip to cover all the games you want to create. Each game covers `BLOCK_INTERVAL` (600) L2 blocks, so for 500 games you need 300,000 blocks of headroom. ```bash # Calculate an anchor block 300,000 blocks behind the L2 tip diff --git a/scripts/multiproof/SeedGames.s.sol b/scripts/multiproof/SeedGames.s.sol index 9081e4626..e04121dbd 100644 --- a/scripts/multiproof/SeedGames.s.sol +++ b/scripts/multiproof/SeedGames.s.sol @@ -26,6 +26,10 @@ import { MockAnchorStateRegistry } from "./mocks/MockAnchorStateRegistry.sol"; /// All transactions must confirm within the 256-block blockhash window of the /// L1 origin captured at simulation time. For large counts, use --slow. contract SeedGames is Script { + /// @notice Must match the AggregateVerifier deployment constants from DeployDevWithNitro/NoNitro. + uint256 public constant BLOCK_INTERVAL = 600; + uint256 public constant INTERMEDIATE_BLOCK_INTERVAL = 30; + uint256 public constant INTERMEDIATE_ROOTS_COUNT = BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL; uint32 public constant GAME_TYPE_ID = 621; uint256 public constant PROGRESS_LOG_INTERVAL = 100; @@ -34,8 +38,6 @@ contract SeedGames is Script { GameType gameType; uint256 initBond; uint256 anchorBlock; - uint256 slowBlockInterval; - uint256 intermediateRootsCount; bytes32[] roots; bytes proof; } @@ -54,8 +56,6 @@ contract SeedGames is Script { console.log("Roots file:", rootsPath); console.log("Game count:", gameCount); console.log("Game type:", uint256(GAME_TYPE_ID)); - console.log("Block interval:", ctx.slowBlockInterval); - console.log("Intermediate roots per game:", ctx.intermediateRootsCount); console.log("Init bond per game:", ctx.initBond); console.log("Anchor block:", ctx.anchorBlock); console.log("Total ETH required:", ctx.initBond * gameCount); @@ -64,8 +64,8 @@ contract SeedGames is Script { (address firstGame, address lastGame) = _createGames(ctx, asrAddr); vm.stopBroadcast(); - uint256 l2Start = ctx.anchorBlock + ctx.slowBlockInterval; - uint256 l2End = ctx.anchorBlock + ctx.slowBlockInterval * gameCount; + uint256 l2Start = ctx.anchorBlock + BLOCK_INTERVAL; + uint256 l2End = ctx.anchorBlock + BLOCK_INTERVAL * gameCount; console.log(""); console.log("=== Seeding Complete ==="); @@ -93,20 +93,10 @@ contract SeedGames is Script { ctx.initBond = ctx.factory.initBonds(ctx.gameType); (, ctx.anchorBlock) = MockAnchorStateRegistry(asrAddr).getAnchorRoot(); - // Read the proposal geometry off the deployment rather than restating it. AggregateVerifier - // carries both the slow- and fast-block pairs and picks per game, so a hardcoded pair here - // would silently seed unopenable games on a devnet with Cobalt scheduled. - // ponytail: resolved once from the anchor, so a chain seeded straight across the activation - // would be wrong for its later games. Seed before scheduling Cobalt, or seed each side - // separately; per-game resolution only matters if a devnet ever needs a straddling chain. - AggregateVerifier gameImpl = AggregateVerifier(address(ctx.factory.gameImpls(ctx.gameType))); - (ctx.slowBlockInterval,) = gameImpl.intervalsForStartingBlock(ctx.anchorBlock); - ctx.intermediateRootsCount = gameImpl.intermediateOutputRootsCount(); - string memory rootsJson = vm.readFile(rootsPath); ctx.roots = abi.decode(vm.parseJson(rootsJson, ".roots"), (bytes32[])); - uint256 expectedRoots = gameCount * ctx.intermediateRootsCount; + uint256 expectedRoots = gameCount * INTERMEDIATE_ROOTS_COUNT; require( ctx.roots.length == expectedRoots, string.concat( @@ -114,9 +104,7 @@ contract SeedGames is Script { vm.toString(ctx.roots.length), ", expected ", vm.toString(expectedRoots), - ". Re-run generate-roots.sh with matching game count and SLOW_BLOCK_INTERVAL=", - vm.toString(ctx.slowBlockInterval), - "." + ". Re-run generate-roots.sh with matching game count." ) ); @@ -127,7 +115,7 @@ contract SeedGames is Script { } function _createGames(SeedCtx memory ctx, address asrAddr) internal returns (address firstGame, address lastGame) { - uint256 count = ctx.roots.length / ctx.intermediateRootsCount; + uint256 count = ctx.roots.length / INTERMEDIATE_ROOTS_COUNT; address parentAddr = asrAddr; for (uint256 i = 0; i < count; i++) { @@ -145,12 +133,11 @@ contract SeedGames is Script { } function _createSingleGame(SeedCtx memory ctx, uint256 index, address parentAddr) internal returns (address) { - uint256 l2Block = ctx.anchorBlock + ctx.slowBlockInterval * (index + 1); - uint256 rootsOffset = index * ctx.intermediateRootsCount; - bytes32 rootClaimHash = ctx.roots[rootsOffset + ctx.intermediateRootsCount - 1]; + uint256 l2Block = ctx.anchorBlock + BLOCK_INTERVAL * (index + 1); + uint256 rootsOffset = index * INTERMEDIATE_ROOTS_COUNT; + bytes32 rootClaimHash = ctx.roots[rootsOffset + INTERMEDIATE_ROOTS_COUNT - 1]; - bytes memory extraData = - abi.encodePacked(l2Block, parentAddr, _sliceRoots(ctx.roots, rootsOffset, ctx.intermediateRootsCount)); + bytes memory extraData = abi.encodePacked(l2Block, parentAddr, _sliceRoots(ctx.roots, rootsOffset)); IDisputeGame created = ctx.factory.createWithInitData{ value: ctx.initBond }( ctx.gameType, Claim.wrap(rootClaimHash), extraData, ctx.proof @@ -158,9 +145,9 @@ contract SeedGames is Script { return address(created); } - function _sliceRoots(bytes32[] memory all, uint256 offset, uint256 count) internal pure returns (bytes memory) { - bytes32[] memory slice = new bytes32[](count); - for (uint256 j = 0; j < count; j++) { + function _sliceRoots(bytes32[] memory all, uint256 offset) internal pure returns (bytes memory) { + bytes32[] memory slice = new bytes32[](INTERMEDIATE_ROOTS_COUNT); + for (uint256 j = 0; j < INTERMEDIATE_ROOTS_COUNT; j++) { slice[j] = all[offset + j]; } return abi.encodePacked(slice); diff --git a/scripts/multiproof/generate-roots.sh b/scripts/multiproof/generate-roots.sh index f34145fd6..50b43f811 100755 --- a/scripts/multiproof/generate-roots.sh +++ b/scripts/multiproof/generate-roots.sh @@ -32,12 +32,9 @@ GAME_COUNT="${3:-500}" PARALLELISM="${4:-20}" OUTPUT_FILE="${5:-roots.json}" -# Must match the intervals the deployed AggregateVerifier selects for these games. The contract -# carries both the slow- and fast-block pairs, so override these when seeding a devnet on which Cobalt -# is already active: BLOCK_INTERVAL=6000 INTERMEDIATE_BLOCK_INTERVAL=300 ./generate-roots.sh ... -# SeedGames.s.sol reads the live values off the deployment and will refuse a mismatched roots file. -BLOCK_INTERVAL="${BLOCK_INTERVAL:-600}" -INTERMEDIATE_BLOCK_INTERVAL="${INTERMEDIATE_BLOCK_INTERVAL:-30}" +# Must match AggregateVerifier / SeedGames constants +BLOCK_INTERVAL=600 +INTERMEDIATE_BLOCK_INTERVAL=30 ROOTS_PER_GAME=$((BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL)) TOTAL_ROOTS=$((GAME_COUNT * ROOTS_PER_GAME)) @@ -46,7 +43,6 @@ LAST_BLOCK=$((ANCHOR_BLOCK + GAME_COUNT * BLOCK_INTERVAL)) echo "=== Generating Output Roots ===" echo "Anchor block: $ANCHOR_BLOCK" echo "Game count: $GAME_COUNT" -echo "Block interval: $BLOCK_INTERVAL" echo "Roots per game: $ROOTS_PER_GAME" echo "Total roots: $TOTAL_ROOTS" echo "L2 block range: [$((ANCHOR_BLOCK + INTERMEDIATE_BLOCK_INTERVAL)), $LAST_BLOCK]" diff --git a/snapshots/abi/AggregateVerifier.json b/snapshots/abi/AggregateVerifier.json index 618a657f6..ee3b801a1 100644 --- a/snapshots/abi/AggregateVerifier.json +++ b/snapshots/abi/AggregateVerifier.json @@ -59,31 +59,14 @@ "type": "uint256" }, { - "components": [ - { - "internalType": "uint256", - "name": "slowBlockInterval", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "slowIntermediateBlockInterval", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "fastBlockInterval", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "fastIntermediateBlockInterval", - "type": "uint256" - } - ], - "internalType": "struct AggregateVerifier.IntervalConfig", - "name": "intervalConfig", - "type": "tuple" + "internalType": "uint256", + "name": "blockInterval", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "intermediateBlockInterval", + "type": "uint256" }, { "components": [ @@ -129,6 +112,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "BLOCK_INTERVAL", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "CONFIG_HASH", @@ -194,19 +190,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "FAST_BLOCK_INTERVAL", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "FAST_FINALIZATION_DELAY", @@ -222,7 +205,7 @@ }, { "inputs": [], - "name": "FAST_INTERMEDIATE_BLOCK_INTERVAL", + "name": "INTERMEDIATE_BLOCK_INTERVAL", "outputs": [ { "internalType": "uint256", @@ -311,19 +294,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "SLOW_BLOCK_INTERVAL", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "SLOW_FINALIZATION_DELAY", @@ -337,19 +307,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "SLOW_INTERMEDIATE_BLOCK_INTERVAL", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "TEE_IMAGE_HASH", @@ -689,30 +646,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "startingBlock", - "type": "uint256" - } - ], - "name": "intervalsForStartingBlock", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "l1Head", @@ -1138,12 +1071,12 @@ "inputs": [ { "internalType": "uint256", - "name": "slowBlockInterval", + "name": "blockInterval", "type": "uint256" }, { "internalType": "uint256", - "name": "slowIntermediateBlockInterval", + "name": "intermediateBlockInterval", "type": "uint256" } ], @@ -1271,22 +1204,6 @@ "name": "L2TimestampOverflow", "type": "error" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "slowCount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "fastCount", - "type": "uint256" - } - ], - "name": "MismatchedIntermediateRootCount", - "type": "error" - }, { "inputs": [ { diff --git a/snapshots/semver-lock.json b/snapshots/semver-lock.json index cf5bd40ef..4250cb6cf 100644 --- a/snapshots/semver-lock.json +++ b/snapshots/semver-lock.json @@ -28,8 +28,8 @@ "sourceCodeHash": "0x780ff372493ba9010bc0d13100ac896f2bf75730a9b17d4bb63aaf694dc3c634" }, "src/L1/proofs/AggregateVerifier.sol:AggregateVerifier": { - "initCodeHash": "0xac5b40f2fadfbf26c206e5abb44870a93053063ba03ceb523a09799785c82e06", - "sourceCodeHash": "0x1234f4ea80d6da4f0c0e98cf11839b423d211da2027faf4c10ccf131aa62d8d7" + "initCodeHash": "0x84c6bf00e337c889993c409f18b17986f9d9546ac6754f7730962459d301c21d", + "sourceCodeHash": "0x15952c01559b5c8e08faba110a49da9fb8c20e7bd4a62f7884c902847783e201" }, "src/L1/proofs/AnchorStateRegistry.sol:AnchorStateRegistry": { "initCodeHash": "0x6f3afd2d0ef97a82ca3111976322b99343a270e54cd4a405028f2f29c75f7fb1", diff --git a/src/L1/proofs/AggregateVerifier.sol b/src/L1/proofs/AggregateVerifier.sol index 544d7b52c..6f864792e 100644 --- a/src/L1/proofs/AggregateVerifier.sol +++ b/src/L1/proofs/AggregateVerifier.sol @@ -53,16 +53,6 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { uint64 blockTime; } - /// @notice Proposal block intervals for each side of the block-speedup activation. - /// @dev Both pairs must yield the same intermediate root count, so the CWIA `extraData` layout - /// and `INITIALIZE_CALLDATA_SIZE` are identical on both sides of the fork. - struct IntervalConfig { - uint256 slowBlockInterval; - uint256 slowIntermediateBlockInterval; - uint256 fastBlockInterval; - uint256 fastIntermediateBlockInterval; - } - //////////////////////////////////////////////////////////////// // Constants // //////////////////////////////////////////////////////////////// @@ -85,19 +75,6 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { /// @notice The minimum number of proofs required to resolve the game. uint256 public constant PROOF_THRESHOLD = 1; - - /// @notice The ProtocolVersions upgrade index at which L2 blocks switch to the fast cadence. - /// @dev This is the one place the contract is tied to a specific hardfork: index 13 is Denim, - /// which drops the L2 block time from 2s to 200ms. Everything downstream is expressed as - /// slow-vs-fast blocks, so a later cadence change is a new index and new interval pair - /// rather than new machinery. - /// @dev Index 13 is one past the end of the current Base mainnet schedule, so `getSchedule()` - /// returns a shorter array until Denim is registered. `_firstFastBlock()` treats that as - /// unscheduled, which is the same state an index-in-range zero timestamp produces. - uint256 private constant FAST_BLOCK_UPGRADE_INDEX = 13; - - /// @notice The number of whole fast-cadence L2 blocks produced per second. - uint256 private constant FAST_BLOCKS_PER_SECOND = 5; //////////////////////////////////////////////////////////////// // Immutables // //////////////////////////////////////////////////////////////// @@ -137,24 +114,19 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { /// @notice The timestamp of the L2 genesis block. uint64 public immutable L2_GENESIS_TIMESTAMP; - /// @notice The legacy number of seconds between consecutive L2 blocks. + /// @notice The fixed number of seconds between consecutive L2 blocks. + /// @dev This verifier derives L2 timestamps linearly from the configured genesis anchor. If + /// the chain changes block time, deploy a new verifier anchored at the transition block + /// and migrate to that game type for post-transition claims. uint64 public immutable L2_BLOCK_TIME; - /// @notice The block interval between each proposal, for games starting on slow blocks. - /// @dev The parent's block number + SLOW_BLOCK_INTERVAL = this proposal's block number. - uint256 public immutable SLOW_BLOCK_INTERVAL; - - /// @notice The block interval for intermediate proposals, for games starting on slow blocks. - /// @dev SLOW_BLOCK_INTERVAL must be divisible by SLOW_INTERMEDIATE_BLOCK_INTERVAL. - uint256 public immutable SLOW_INTERMEDIATE_BLOCK_INTERVAL; - - /// @notice The block interval between each proposal, for games starting on fast blocks. - uint256 public immutable FAST_BLOCK_INTERVAL; + /// @notice The block interval between each proposal. + /// @dev The parent's block number + BLOCK_INTERVAL = this proposal's block number. + uint256 public immutable BLOCK_INTERVAL; - /// @notice The block interval for intermediate proposals, for games starting on fast blocks. - /// @dev FAST_BLOCK_INTERVAL must be divisible by FAST_INTERMEDIATE_BLOCK_INTERVAL, and their - /// ratio must equal the slow-block one. - uint256 public immutable FAST_INTERMEDIATE_BLOCK_INTERVAL; + /// @notice The block interval for intermediate proposals. + /// @dev BLOCK_INTERVAL must be divisible by INTERMEDIATE_BLOCK_INTERVAL. + uint256 public immutable INTERMEDIATE_BLOCK_INTERVAL; /// @notice The size of the initialize call data. uint256 internal immutable INITIALIZE_CALLDATA_SIZE; @@ -253,10 +225,7 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { // Errors // //////////////////////////////////////////////////////////////// /// @notice When the block interval or intermediate block interval is invalid. - error InvalidBlockInterval(uint256 slowBlockInterval, uint256 slowIntermediateBlockInterval); - - /// @notice When the slow- and fast-block intervals do not yield the same intermediate root count. - error MismatchedIntermediateRootCount(uint256 slowCount, uint256 fastCount); + error InvalidBlockInterval(uint256 blockInterval, uint256 intermediateBlockInterval); /// @notice When the block number is unexpected. error UnexpectedBlockNumber(uint256 expectedBlockNumber, uint256 actualBlockNumber); @@ -330,7 +299,8 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { /// @param zkHashes The hashes of the ZK range and aggregate programs. /// @param configHash The hash of the rollup configuration. /// @param l2ChainId The chain ID of the L2 network. - /// @param intervalConfig The slow- and fast-block proposal intervals. + /// @param blockInterval The block interval. + /// @param intermediateBlockInterval The intermediate block interval. /// @param scheduleConfig Upgrade registry and deterministic L2 timestamp configuration. constructor( GameType gameType_, @@ -342,10 +312,14 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { ZkHashes memory zkHashes, bytes32 configHash, uint256 l2ChainId, - IntervalConfig memory intervalConfig, + uint256 blockInterval, + uint256 intermediateBlockInterval, ScheduleConfig memory scheduleConfig ) { - _validateIntervals(intervalConfig); + // Block interval and intermediate block interval must be positive and divisible. + if (blockInterval == 0 || intermediateBlockInterval == 0 || blockInterval % intermediateBlockInterval != 0) { + revert InvalidBlockInterval(blockInterval, intermediateBlockInterval); + } if (scheduleConfig.blockTime == 0) revert InvalidL2BlockTime(); // Set up initial game state. @@ -363,10 +337,8 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { L2_GENESIS_BLOCK_NUMBER = scheduleConfig.genesisBlockNumber; L2_GENESIS_TIMESTAMP = scheduleConfig.genesisTimestamp; L2_BLOCK_TIME = scheduleConfig.blockTime; - SLOW_BLOCK_INTERVAL = intervalConfig.slowBlockInterval; - SLOW_INTERMEDIATE_BLOCK_INTERVAL = intervalConfig.slowIntermediateBlockInterval; - FAST_BLOCK_INTERVAL = intervalConfig.fastBlockInterval; - FAST_INTERMEDIATE_BLOCK_INTERVAL = intervalConfig.fastIntermediateBlockInterval; + BLOCK_INTERVAL = blockInterval; + INTERMEDIATE_BLOCK_INTERVAL = intermediateBlockInterval; PROTOCOL_VERSIONS = scheduleConfig.protocolVersions; INITIALIZE_CALLDATA_SIZE = 0x8E + 0x20 * intermediateOutputRootsCount(); @@ -394,8 +366,8 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { // - 0x20 l1 head (CWIA data offset: 0x34) // - 0x20 extraData (l2BlockNumber) (CWIA data offset: 0x54) // - 0x14 extraData (parent game address) (CWIA data offset: 0x74) - // - 0x20 x (SLOW_BLOCK_INTERVAL / SLOW_INTERMEDIATE_BLOCK_INTERVAL) extraData (intermediate roots) (CWIA data - // offset: 0x88) + // - 0x20 x (BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL) extraData (intermediate roots) (CWIA data offset: + // 0x88) // - 0x02 CWIA bytes // - 0x20 proof length location @@ -434,33 +406,27 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { startingOutputRoot = ANCHOR_STATE_REGISTRY.getStartingAnchorRoot(); } - // Resolved once and threaded through both fork-sensitive decisions below, which would - // otherwise re-read the schedule from `PROTOCOL_VERSIONS` a second time. - uint256 firstFastBlock = _firstFastBlock(); - - // The block number must be one block interval after the starting block number. The interval - // is selected on the starting block so the game chain stays contiguous across the speedup. - (uint256 slowBlockInterval,) = _intervalsAt(startingOutputRoot.l2SequenceNumber, firstFastBlock); - if (l2SequenceNumber() != startingOutputRoot.l2SequenceNumber + slowBlockInterval) { - revert UnexpectedBlockNumber(startingOutputRoot.l2SequenceNumber + slowBlockInterval, l2SequenceNumber()); + // The block number must be BLOCK_INTERVAL blocks after the starting block number. + if (l2SequenceNumber() != startingOutputRoot.l2SequenceNumber + BLOCK_INTERVAL) { + revert UnexpectedBlockNumber(startingOutputRoot.l2SequenceNumber + BLOCK_INTERVAL, l2SequenceNumber()); } // Set the game as initialized. initialized = true; - // Pinning the upgrades active at the ending L2 block makes the schedule independent of both - // the proof's L1 head and the L1 block in which this game is created. - // - // Note that this anchors on the *ending* block while the interval selection above anchors on - // the *starting* block. That is deliberate, and it is what makes the straddling game work: it - // spans the slow-block interval its start selects, while pinning the post-speedup schedule - // its end falls under, so the prover knows the fast cadence is active past the boundary. + // L2 timestamps are fixed by the rollup genesis and block time. Pinning the upgrades active + // at the ending L2 block makes the schedule independent of both the proof's L1 head and the + // L1 block in which this game is created. uint256 claimBlock = l2SequenceNumber(); if (claimBlock < L2_GENESIS_BLOCK_NUMBER) { revert L2BlockBeforeGenesis(claimBlock, L2_GENESIS_BLOCK_NUMBER); } - uint64 claimTimestamp = _l2Timestamp(claimBlock, firstFastBlock); + uint256 blocksSinceGenesis = claimBlock - L2_GENESIS_BLOCK_NUMBER; + uint256 maxBlocks = (type(uint64).max - L2_GENESIS_TIMESTAMP) / L2_BLOCK_TIME; + if (blocksSinceGenesis > maxBlocks) revert L2TimestampOverflow(claimBlock); + + uint64 claimTimestamp = L2_GENESIS_TIMESTAMP + uint64(blocksSinceGenesis * uint256(L2_BLOCK_TIME)); // `ProtocolVersions` freezes mutations to an activation `FREEZE_WINDOW` before it takes // effect. Requiring the claim timestamp to have been reached on L1 additionally ensures the @@ -803,27 +769,10 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { return expectedResolution.raw() <= block.timestamp; } - /// @notice Returns the proposal intervals that govern a game starting at `startingBlock`. - /// @dev Offchain proposers and challengers must resolve intervals per game through this getter - /// rather than reading `SLOW_BLOCK_INTERVAL` / `SLOW_INTERMEDIATE_BLOCK_INTERVAL`, which describe - /// only games starting on slow blocks. - /// @dev Selection is on the starting block rather than the ending block so the game chain stays - /// contiguous across the activation: every game satisfies - /// `end == parent.end + slowBlockInterval` for the interval its own start selects. Exactly one - /// game straddles the activation and is proven under the slow-block interval, which is - /// correct because provers apply fork rules per block by timestamp. - /// @param startingBlock The starting L2 block number of the game. - /// @return The block interval and the intermediate block interval governing that game. - function intervalsForStartingBlock(uint256 startingBlock) public view returns (uint256, uint256) { - return _intervalsAt(startingBlock, _firstFastBlock()); - } - /// @notice The number of intermediate output roots. /// @dev At least one as the proposal's root claim is considered an intermediate root. - /// The constructor requires both interval pairs to yield the same count, so this is constant - /// across the speedup activation and the CWIA `extraData` layout never changes. function intermediateOutputRootsCount() public view returns (uint256) { - return (SLOW_BLOCK_INTERVAL / SLOW_INTERMEDIATE_BLOCK_INTERVAL); + return (BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL); } /// @notice The intermediate output roots of the game. @@ -1154,102 +1103,15 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { bytes32 startingRoot = intermediateRootIndex == 0 ? startingOutputRoot.root.raw() : intermediateOutputRoot(intermediateRootIndex - 1); - (, uint256 slowIntermediateBlockInterval) = intervalsForStartingBlock(startingOutputRoot.l2SequenceNumber); uint64 startingL2SequenceNumber = - uint64(startingOutputRoot.l2SequenceNumber + intermediateRootIndex * slowIntermediateBlockInterval); - uint64 endingL2SequenceNumber = startingL2SequenceNumber + uint64(slowIntermediateBlockInterval); + uint64(startingOutputRoot.l2SequenceNumber + intermediateRootIndex * INTERMEDIATE_BLOCK_INTERVAL); + uint64 endingL2SequenceNumber = startingL2SequenceNumber + uint64(INTERMEDIATE_BLOCK_INTERVAL); return (startingRoot, startingL2SequenceNumber, endingL2SequenceNumber); } /// @notice Semantic version. - /// @custom:semver 0.2.0 + /// @custom:semver 0.1.0 function version() public pure virtual returns (string memory) { - return "0.2.0"; - } - - /// @notice Derives an L2 block timestamp: the slow cadence before the speedup, whole-second groups after it. - /// @param claimBlock The L2 block number to derive a timestamp for. - /// @param firstFastBlock The speedup activation block, as returned by `_firstFastBlock()`. - function _l2Timestamp(uint256 claimBlock, uint256 firstFastBlock) private view returns (uint64) { - if (claimBlock < firstFastBlock) return _slowL2Timestamp(claimBlock); - - uint256 claimTimestamp = - uint256(_slowL2Timestamp(firstFastBlock)) + (claimBlock - firstFastBlock) / FAST_BLOCKS_PER_SECOND; - if (claimTimestamp > type(uint64).max) revert L2TimestampOverflow(claimBlock); - return uint64(claimTimestamp); - } - - /// @notice Reverts unless both interval pairs are positive, divisible, and yield the same - /// intermediate root count. - function _validateIntervals(IntervalConfig memory intervalConfig) private pure { - uint256 slowBlockInterval = intervalConfig.slowBlockInterval; - uint256 slowIntermediateBlockInterval = intervalConfig.slowIntermediateBlockInterval; - uint256 fastBlockInterval = intervalConfig.fastBlockInterval; - uint256 fastIntermediateBlockInterval = intervalConfig.fastIntermediateBlockInterval; - - if ( - slowBlockInterval == 0 || slowIntermediateBlockInterval == 0 - || slowBlockInterval % slowIntermediateBlockInterval != 0 - ) { - revert InvalidBlockInterval(slowBlockInterval, slowIntermediateBlockInterval); - } - if ( - fastBlockInterval == 0 || fastIntermediateBlockInterval == 0 - || fastBlockInterval % fastIntermediateBlockInterval != 0 - ) { - revert InvalidBlockInterval(fastBlockInterval, fastIntermediateBlockInterval); - } - - // The intermediate root count fixes the CWIA `extraData` layout, which is frozen for the - // lifetime of this implementation. Both interval pairs must therefore agree on it. - uint256 slowCount = slowBlockInterval / slowIntermediateBlockInterval; - uint256 fastCount = fastBlockInterval / fastIntermediateBlockInterval; - if (slowCount != fastCount) revert MismatchedIntermediateRootCount(slowCount, fastCount); - } - - /// @notice Returns the first L2 block number produced at the fast cadence, or `type(uint256).max` - /// when the speedup is not scheduled. - /// @dev Reading the live schedule is safe despite it being mutable, in both directions: - /// - /// - A game that selected the fast-block intervals has a starting block at or past the - /// activation, so the activation is in the past. `ProtocolVersions._assertNotFrozen` - /// rejects every mutation of a passed activation, from `setTimestamp` and - /// `delayTimestamp` alike, so that game's selection can never be revoked. - /// - A game that selected the slow-block intervals cannot be pulled across the boundary - /// either, including by the owner moving the activation *earlier* rather than later. - /// `initializeWithInitData` rejects a game whose ending L2 timestamp L1 has not yet - /// reached, so every initialized game satisfies `startingTimestamp < endingTimestamp <= - /// block.timestamp`, while any new activation must clear `block.timestamp + MIN_NOTICE`. - /// The activation therefore always lands after the game's starting block. - function _firstFastBlock() private view returns (uint256) { - uint64[] memory schedule = PROTOCOL_VERSIONS.getSchedule(); - if (schedule.length <= FAST_BLOCK_UPGRADE_INDEX) return type(uint256).max; - - uint64 fastActivationTimestamp = schedule[FAST_BLOCK_UPGRADE_INDEX]; - if (fastActivationTimestamp == 0) return type(uint256).max; - - if (fastActivationTimestamp <= L2_GENESIS_TIMESTAMP) { - return L2_GENESIS_BLOCK_NUMBER; - } - - return L2_GENESIS_BLOCK_NUMBER - + FixedPointMathLib.divUp(fastActivationTimestamp - L2_GENESIS_TIMESTAMP, L2_BLOCK_TIME); - } - - /// @notice Selects the proposal intervals governing a game, from its starting block number and an - /// already-resolved speedup activation block. - /// @dev Takes `firstFastBlock` rather than resolving it so a caller making more than one - /// fork-sensitive decision pays for `PROTOCOL_VERSIONS.getSchedule()` once. - function _intervalsAt(uint256 startingBlock, uint256 firstFastBlock) private view returns (uint256, uint256) { - if (startingBlock < firstFastBlock) return (SLOW_BLOCK_INTERVAL, SLOW_INTERMEDIATE_BLOCK_INTERVAL); - return (FAST_BLOCK_INTERVAL, FAST_INTERMEDIATE_BLOCK_INTERVAL); - } - - /// @notice Derives an L2 block timestamp using the slow block cadence. - function _slowL2Timestamp(uint256 claimBlock) private view returns (uint64) { - uint256 blocksSinceGenesis = claimBlock - L2_GENESIS_BLOCK_NUMBER; - uint256 maxBlocks = (type(uint64).max - L2_GENESIS_TIMESTAMP) / L2_BLOCK_TIME; - if (blocksSinceGenesis > maxBlocks) revert L2TimestampOverflow(claimBlock); - return L2_GENESIS_TIMESTAMP + uint64(blocksSinceGenesis * uint256(L2_BLOCK_TIME)); + return "0.1.0"; } } diff --git a/test/L1/OptimismPortal2.t.sol b/test/L1/OptimismPortal2.t.sol index ff44eb887..afa597ae1 100644 --- a/test/L1/OptimismPortal2.t.sol +++ b/test/L1/OptimismPortal2.t.sol @@ -89,12 +89,8 @@ abstract contract OptimismPortal2_TestInit is DisputeGameFactory_TestInit { AggregateVerifier.ZkHashes(bytes32(uint256(2)), bytes32(uint256(3))), bytes32(uint256(4)), deploy.cfg().l2ChainId(), - AggregateVerifier.IntervalConfig({ - slowBlockInterval: 100, - slowIntermediateBlockInterval: 10, - fastBlockInterval: 1000, - fastIntermediateBlockInterval: 100 - }), + 100, + 10, AggregateVerifier.ScheduleConfig({ protocolVersions: protocolVersions, genesisBlockNumber: 0, genesisTimestamp: 1, blockTime: 2 }) @@ -103,8 +99,7 @@ abstract contract OptimismPortal2_TestInit is DisputeGameFactory_TestInit { disputeGameFactory.setInitBond(respectedGameType, 0); Proposal memory startingRoot = anchorStateRegistry.getStartingAnchorRoot(); - (uint256 slowBlockInterval,) = gameImpl.intervalsForStartingBlock(startingRoot.l2SequenceNumber); - _proposedBlockNumber = startingRoot.l2SequenceNumber + slowBlockInterval; + _proposedBlockNumber = startingRoot.l2SequenceNumber + gameImpl.BLOCK_INTERVAL(); depositor = makeAddr("depositor"); diff --git a/test/L1/proofs/AggregateVerifier.t.sol b/test/L1/proofs/AggregateVerifier.t.sol index d3ed4946b..4b714779f 100644 --- a/test/L1/proofs/AggregateVerifier.t.sol +++ b/test/L1/proofs/AggregateVerifier.t.sol @@ -20,9 +20,6 @@ import { BaseTest } from "./BaseTest.t.sol"; contract AggregateVerifierTest is BaseTest { using LibClone for address; - uint256 private constant FAST_BLOCK_UPGRADE_INDEX = 13; - uint256 private constant FAST_BLOCKS_PER_SECOND = 5; - AggregateVerifier private aggregateVerifierImpl; function setUp() public override { @@ -43,8 +40,8 @@ contract AggregateVerifierTest is BaseTest { /// @notice Initialization pins the upgrades active at the claimed L2 block, independently of /// the L1 game-creation timestamp, and later schedule changes cannot alter the pin. function test_initialize_pinsScheduleId_succeeds() public { - uint64 firstGameTimestamp = _l2Timestamp(SLOW_BLOCK_INTERVAL); - uint64 secondActivationTimestamp = _l2Timestamp(SLOW_BLOCK_INTERVAL + SLOW_BLOCK_INTERVAL / 2); + uint64 firstGameTimestamp = _l2Timestamp(BLOCK_INTERVAL); + uint64 secondActivationTimestamp = _l2Timestamp(BLOCK_INTERVAL + BLOCK_INTERVAL / 2); // The first upgrade is active at the first game's L2 timestamp; the second is not. uint64[] memory schedule = new uint64[](2); @@ -80,7 +77,7 @@ contract AggregateVerifierTest is BaseTest { /// @notice Consecutive games on opposite sides of an L2 activation boundary pin different /// schedule commitments. function test_initialize_scheduleChangesAtL2ActivationBoundary_succeeds() public { - uint64 activationTimestamp = _l2Timestamp(SLOW_BLOCK_INTERVAL + SLOW_BLOCK_INTERVAL / 2); + uint64 activationTimestamp = _l2Timestamp(BLOCK_INTERVAL + BLOCK_INTERVAL / 2); uint64[] memory schedule = new uint64[](1); schedule[0] = activationTimestamp; _importProtocolVersionsSchedule(schedule); @@ -106,157 +103,12 @@ contract AggregateVerifierTest is BaseTest { assertEq(secondGame.scheduleId(), protocolVersions.activatedScheduleId(_l2Timestamp(currentL2BlockNumber))); } - function test_initialize_fastBlockTimestamps_succeeds() public { - uint64 fastActivationTimestamp = L2_GENESIS_TIMESTAMP + 1; - uint64 firstFastBlockTimestamp = L2_GENESIS_TIMESTAMP + L2_BLOCK_TIME; - uint64[] memory schedule = new uint64[](FAST_BLOCK_UPGRADE_INDEX + 2); - for (uint256 i; i < FAST_BLOCK_UPGRADE_INDEX; i++) { - schedule[i] = L2_GENESIS_TIMESTAMP; - } - schedule[FAST_BLOCK_UPGRADE_INDEX] = fastActivationTimestamp; - schedule[FAST_BLOCK_UPGRADE_INDEX + 1] = firstFastBlockTimestamp + 1; - _importProtocolVersionsSchedule(schedule); - - _setSingleBlockAggregateVerifier(L2_GENESIS_TIMESTAMP); - - bytes32 speedupScheduleId = protocolVersions.scheduleId(FAST_BLOCK_UPGRADE_INDEX); - bytes32 postSpeedupScheduleId = protocolVersions.scheduleId(FAST_BLOCK_UPGRADE_INDEX + 1); - address parent = address(anchorStateRegistry); - - for (uint256 l2BlockNumber = 1; l2BlockNumber <= FAST_BLOCKS_PER_SECOND + 1; l2BlockNumber++) { - vm.warp(firstFastBlockTimestamp + (l2BlockNumber - 1) / FAST_BLOCKS_PER_SECOND); - AggregateVerifier game = _createSingleBlockGame(l2BlockNumber, parent); - assertEq( - game.scheduleId(), l2BlockNumber <= FAST_BLOCKS_PER_SECOND ? speedupScheduleId : postSpeedupScheduleId - ); - parent = address(game); - } - } - - function test_initialize_unscheduledSpeedupUsesSlowTimestamp_succeeds() public { - uint64[] memory schedule = new uint64[](FAST_BLOCK_UPGRADE_INDEX + 1); - for (uint256 i; i < FAST_BLOCK_UPGRADE_INDEX; i++) { - schedule[i] = L2_GENESIS_TIMESTAMP; - } - _importProtocolVersionsSchedule(schedule); - _setSingleBlockAggregateVerifier(L2_GENESIS_TIMESTAMP); - - uint64 legacyBlockTimestamp = L2_GENESIS_TIMESTAMP + L2_BLOCK_TIME; - vm.warp(legacyBlockTimestamp - 1); - vm.expectRevert( - abi.encodeWithSelector( - AggregateVerifier.L2TimestampInFuture.selector, legacyBlockTimestamp, legacyBlockTimestamp - 1 - ) - ); - _createSingleBlockGame(1, address(anchorStateRegistry)); - - vm.warp(legacyBlockTimestamp); - AggregateVerifier game = _createSingleBlockGame(1, address(anchorStateRegistry)); - assertEq(game.scheduleId(), protocolVersions.scheduleId(FAST_BLOCK_UPGRADE_INDEX - 1)); - } - - /// @notice Intervals are selected on the game's starting block relative to the first fast block, - /// so the chain of games stays contiguous across the fork. - function test_intervalsForStartingBlock_selectsOnFirstFastBlock_succeeds() public { - // divUp(86500 - L2_GENESIS_TIMESTAMP, L2_BLOCK_TIME) == 50. - _importSpeedupSchedule(L2_GENESIS_TIMESTAMP + 100); - uint256 firstFastBlock = 50; - - _assertIntervals(firstFastBlock - 1, SLOW_BLOCK_INTERVAL, SLOW_INTERMEDIATE_BLOCK_INTERVAL); - _assertIntervals(firstFastBlock, FAST_BLOCK_INTERVAL, FAST_INTERMEDIATE_BLOCK_INTERVAL); - _assertIntervals(firstFastBlock + 1, FAST_BLOCK_INTERVAL, FAST_INTERMEDIATE_BLOCK_INTERVAL); - } - - function test_intervalsForStartingBlock_speedupUnscheduled_succeeds() public view { - _assertIntervals(0, SLOW_BLOCK_INTERVAL, SLOW_INTERMEDIATE_BLOCK_INTERVAL); - _assertIntervals(type(uint64).max, SLOW_BLOCK_INTERVAL, SLOW_INTERMEDIATE_BLOCK_INTERVAL); - } - - /// @notice A game starting at or after the first fast block must span FAST_BLOCK_INTERVAL. - function test_initialize_fastIntervals_succeeds() public { - // The activation timestamp equals genesis, so every block including the anchor is fast. - _importSpeedupSchedule(L2_GENESIS_TIMESTAMP); - _assertIntervals(0, FAST_BLOCK_INTERVAL, FAST_INTERMEDIATE_BLOCK_INTERVAL); - - vm.expectRevert( - abi.encodeWithSelector( - AggregateVerifier.UnexpectedBlockNumber.selector, FAST_BLOCK_INTERVAL, SLOW_BLOCK_INTERVAL - ) - ); - _createGameEndingAt(SLOW_BLOCK_INTERVAL); - - AggregateVerifier game = _createGameEndingAt(FAST_BLOCK_INTERVAL); - assertEq(game.l2SequenceNumber(), FAST_BLOCK_INTERVAL); - } - - /// @notice The one game whose range contains the activation block starts before it, so it is - /// proven under the slow-block interval. - function test_initialize_straddlingGame_usesSlowInterval_succeeds() public { - // Activation block 50 falls inside the first game's [0, 100) range. - _importSpeedupSchedule(L2_GENESIS_TIMESTAMP + 100); - _assertIntervals(0, SLOW_BLOCK_INTERVAL, SLOW_INTERMEDIATE_BLOCK_INTERVAL); - - vm.expectRevert( - abi.encodeWithSelector( - AggregateVerifier.UnexpectedBlockNumber.selector, SLOW_BLOCK_INTERVAL, FAST_BLOCK_INTERVAL - ) - ); - _createGameEndingAt(FAST_BLOCK_INTERVAL); - - AggregateVerifier game = _createGameEndingAt(SLOW_BLOCK_INTERVAL); - assertEq(game.l2SequenceNumber(), SLOW_BLOCK_INTERVAL); - } - - /// @notice `challenge` derives the intermediate sub-range from the interval the game's starting - /// block selects. This is the second fork-sensitive call site, and unlike the block - /// number check its output goes into the journal the prover signs, so a stale interval - /// here makes a valid challenge unconstructable rather than reverting loudly. - function test_challenge_fastIntermediateInterval_succeeds() public { - _importSpeedupSchedule(L2_GENESIS_TIMESTAMP); - _assertChallengeIntermediateRange(FAST_BLOCK_INTERVAL, FAST_INTERMEDIATE_BLOCK_INTERVAL); - } - - /// @notice The straddling game's sub-ranges stay slow-block sized, matching the interval its own - /// starting block selects. - function test_challenge_straddlingGameUsesSlowIntermediateInterval_succeeds() public { - // Activation block 50 falls inside the first game's [0, 100) range. - _importSpeedupSchedule(L2_GENESIS_TIMESTAMP + 100); - _assertChallengeIntermediateRange(SLOW_BLOCK_INTERVAL, SLOW_INTERMEDIATE_BLOCK_INTERVAL); - } - - function test_constructor_mismatchedIntermediateRootCount_reverts() public { - // 100 / 10 == 10 intermediate roots, but 1000 / 200 == 5. - vm.expectRevert(abi.encodeWithSelector(AggregateVerifier.MismatchedIntermediateRootCount.selector, 10, 5)); - _deployAggregateVerifier( - AggregateVerifier.IntervalConfig({ - slowBlockInterval: SLOW_BLOCK_INTERVAL, - slowIntermediateBlockInterval: SLOW_INTERMEDIATE_BLOCK_INTERVAL, - fastBlockInterval: FAST_BLOCK_INTERVAL, - fastIntermediateBlockInterval: 200 - }), - _defaultScheduleConfig() - ); - } - - function test_constructor_invalidFastBlockIntervals_reverts() public { - vm.expectRevert(abi.encodeWithSelector(AggregateVerifier.InvalidBlockInterval.selector, 1000, 0)); - _deployAggregateVerifier( - AggregateVerifier.IntervalConfig({ - slowBlockInterval: SLOW_BLOCK_INTERVAL, - slowIntermediateBlockInterval: SLOW_INTERMEDIATE_BLOCK_INTERVAL, - fastBlockInterval: FAST_BLOCK_INTERVAL, - fastIntermediateBlockInterval: 0 - }), - _defaultScheduleConfig() - ); - } - /// @notice A claim whose L2 timestamp L1 has not yet reached cannot open a game, so a game can /// never pin an activation that the owner is still able to clear or delay. function test_initialize_l2TimestampInFuture_reverts() public { // Scheduling the upgrade at the first game's deterministic L2 timestamp and leaving the L1 // clock short of it is the window the finding exploits. - uint64 activationTimestamp = _l2Timestamp(SLOW_BLOCK_INTERVAL); + uint64 activationTimestamp = _l2Timestamp(BLOCK_INTERVAL); uint64[] memory schedule = new uint64[](1); schedule[0] = activationTimestamp; _importProtocolVersionsSchedule(schedule); @@ -305,7 +157,7 @@ contract AggregateVerifierTest is BaseTest { function test_initialize_l2BlockBeforeGenesis_reverts() public { AggregateVerifier.ScheduleConfig memory scheduleConfig = AggregateVerifier.ScheduleConfig({ protocolVersions: IProtocolVersions(address(protocolVersions)), - genesisBlockNumber: SLOW_BLOCK_INTERVAL + 1, + genesisBlockNumber: BLOCK_INTERVAL + 1, genesisTimestamp: 0, blockTime: L2_BLOCK_TIME }); @@ -315,7 +167,7 @@ contract AggregateVerifierTest is BaseTest { Claim rootClaim = _advanceL2BlockAndClaim(); vm.expectRevert( abi.encodeWithSelector( - AggregateVerifier.L2BlockBeforeGenesis.selector, currentL2BlockNumber, SLOW_BLOCK_INTERVAL + 1 + AggregateVerifier.L2BlockBeforeGenesis.selector, currentL2BlockNumber, BLOCK_INTERVAL + 1 ) ); _createAggregateVerifierGame( @@ -348,27 +200,6 @@ contract AggregateVerifierTest is BaseTest { ); } - function test_initialize_fastTimestampOverflow_reverts() public { - uint64 genesisTimestamp = type(uint64).max - L2_BLOCK_TIME; - uint64[] memory schedule = new uint64[](FAST_BLOCK_UPGRADE_INDEX + 1); - for (uint256 i; i < FAST_BLOCK_UPGRADE_INDEX; i++) { - schedule[i] = genesisTimestamp; - } - schedule[FAST_BLOCK_UPGRADE_INDEX] = genesisTimestamp + 1; - _importProtocolVersionsSchedule(schedule); - _setSingleBlockAggregateVerifier(genesisTimestamp); - - vm.warp(uint256(type(uint64).max) + 3); - address parent = address(anchorStateRegistry); - for (uint256 l2BlockNumber = 1; l2BlockNumber <= FAST_BLOCKS_PER_SECOND; l2BlockNumber++) { - parent = address(_createSingleBlockGame(l2BlockNumber, parent)); - } - - uint256 overflowingBlock = FAST_BLOCKS_PER_SECOND + 1; - vm.expectRevert(abi.encodeWithSelector(AggregateVerifier.L2TimestampOverflow.selector, overflowingBlock)); - _createSingleBlockGame(overflowingBlock, parent); - } - function testInitializeFailsIfInvalidCallDataSize() public { Claim rootClaim = _advanceL2BlockAndClaim(); @@ -489,7 +320,7 @@ contract AggregateVerifierTest is BaseTest { /// @dev Parent is a real `AggregateVerifier` clone initialized like a factory game, but deployed without /// `_finalizeGameCreation`, so the factory UUID mapping has no entry. function testInitializeFailsIfParentGameNotFactoryRegistered() public { - currentL2BlockNumber += SLOW_BLOCK_INTERVAL; + currentL2BlockNumber += BLOCK_INTERVAL; Claim parentRootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "parent"))); AggregateVerifier unregisteredParent = _deployAggregateVerifierCloneWithoutFactoryRegistration( @@ -500,7 +331,7 @@ contract AggregateVerifierTest is BaseTest { _generateProof("parent-tee", AggregateVerifier.ProofType.TEE) ); - currentL2BlockNumber += SLOW_BLOCK_INTERVAL; + currentL2BlockNumber += BLOCK_INTERVAL; Claim childRootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "child"))); vm.expectRevert(AggregateVerifier.InvalidParentGame.selector); @@ -592,50 +423,16 @@ contract AggregateVerifierTest is BaseTest { } function testDeployWithInvalidBlockIntervals() public { - _expectDeployWithInvalidBlockIntervalsReverts(0, SLOW_INTERMEDIATE_BLOCK_INTERVAL); - _expectDeployWithInvalidBlockIntervalsReverts(SLOW_BLOCK_INTERVAL, 0); + _expectDeployWithInvalidBlockIntervalsReverts(0, INTERMEDIATE_BLOCK_INTERVAL); + _expectDeployWithInvalidBlockIntervalsReverts(BLOCK_INTERVAL, 0); _expectDeployWithInvalidBlockIntervalsReverts(3, 2); } function _advanceL2BlockAndClaim() private returns (Claim rootClaim) { - currentL2BlockNumber += SLOW_BLOCK_INTERVAL; + currentL2BlockNumber += BLOCK_INTERVAL; return Claim.wrap(keccak256(abi.encode(currentL2BlockNumber))); } - function _createSingleBlockGame(uint256 l2BlockNumber, address parent) private returns (AggregateVerifier) { - Claim rootClaim = Claim.wrap(keccak256(abi.encode(l2BlockNumber))); - bytes memory extraData = abi.encodePacked(l2BlockNumber, parent, rootClaim.raw()); - bytes memory proof = _generateProof(abi.encode(l2BlockNumber), AggregateVerifier.ProofType.TEE); - - vm.deal(TEE_PROVER, INIT_BOND); - vm.prank(TEE_PROVER); - return AggregateVerifier( - address( - factory.createWithInitData{ value: INIT_BOND }( - GameTypes.AGGREGATE_VERIFIER, rootClaim, extraData, proof - ) - ) - ); - } - - function _setSingleBlockAggregateVerifier(uint64 genesisTimestamp) private { - AggregateVerifier implementation = _deployAggregateVerifier( - AggregateVerifier.IntervalConfig({ - slowBlockInterval: 1, - slowIntermediateBlockInterval: 1, - fastBlockInterval: 1, - fastIntermediateBlockInterval: 1 - }), - AggregateVerifier.ScheduleConfig({ - protocolVersions: IProtocolVersions(address(protocolVersions)), - genesisBlockNumber: L2_GENESIS_BLOCK_NUMBER, - genesisTimestamp: genesisTimestamp, - blockTime: L2_BLOCK_TIME - }) - ); - factory.setImplementation(GameTypes.AGGREGATE_VERIFIER, IDisputeGame(address(implementation))); - } - function _createAndAssertInitializedGame( bytes memory proofSalt, AggregateVerifier.ProofType proofType, @@ -730,17 +527,17 @@ contract AggregateVerifierTest is BaseTest { } function _expectDeployWithInvalidBlockIntervalsReverts( - uint256 slowBlockInterval, - uint256 slowIntermediateBlockInterval + uint256 blockInterval, + uint256 intermediateBlockInterval ) private { vm.expectRevert( abi.encodeWithSelector( - AggregateVerifier.InvalidBlockInterval.selector, slowBlockInterval, slowIntermediateBlockInterval + AggregateVerifier.InvalidBlockInterval.selector, blockInterval, intermediateBlockInterval ) ); - _deployAggregateVerifierWithIntervals(slowBlockInterval, slowIntermediateBlockInterval); + _deployAggregateVerifierWithIntervals(blockInterval, intermediateBlockInterval); } /// @notice Clones the implementation like the factory, but skips `_finalizeGameCreation`. @@ -769,19 +566,15 @@ contract AggregateVerifierTest is BaseTest { } function _deployAggregateVerifierWithIntervals( - uint256 slowBlockInterval, - uint256 slowIntermediateBlockInterval + uint256 blockInterval, + uint256 intermediateBlockInterval ) private returns (AggregateVerifier) { return _deployAggregateVerifier( - AggregateVerifier.IntervalConfig({ - slowBlockInterval: slowBlockInterval, - slowIntermediateBlockInterval: slowIntermediateBlockInterval, - fastBlockInterval: slowBlockInterval, - fastIntermediateBlockInterval: slowIntermediateBlockInterval - }), + blockInterval, + intermediateBlockInterval, AggregateVerifier.ScheduleConfig({ protocolVersions: IProtocolVersions(address(protocolVersions)), genesisBlockNumber: L2_GENESIS_BLOCK_NUMBER, @@ -795,118 +588,12 @@ contract AggregateVerifierTest is BaseTest { private returns (AggregateVerifier) { - return _deployAggregateVerifier(_defaultIntervalConfig(), scheduleConfig); - } - - /// @dev Registers a schedule whose only meaningful entry is the speedup activation, and rebinds - /// the implementation to it. - function _importSpeedupSchedule(uint64 fastActivationTimestamp) private { - uint64[] memory schedule = new uint64[](FAST_BLOCK_UPGRADE_INDEX + 1); - for (uint256 i; i < FAST_BLOCK_UPGRADE_INDEX; i++) { - schedule[i] = L2_GENESIS_TIMESTAMP; - } - schedule[FAST_BLOCK_UPGRADE_INDEX] = fastActivationTimestamp; - _importProtocolVersionsSchedule(schedule); - aggregateVerifierImpl = AggregateVerifier(address(factory.gameImpls(GameTypes.AGGREGATE_VERIFIER))); - } - - function _assertIntervals( - uint256 startingBlock, - uint256 expectedBlockInterval, - uint256 expectedIntermediateBlockInterval - ) - private - view - { - (uint256 slowBlockInterval, uint256 slowIntermediateBlockInterval) = - aggregateVerifierImpl.intervalsForStartingBlock(startingBlock); - assertEq(slowBlockInterval, expectedBlockInterval); - assertEq(slowIntermediateBlockInterval, expectedIntermediateBlockInterval); - } - - /// @dev Challenges intermediate root 0 of a game ending at `endingBlock` and asserts the range - /// handed to the ZK verifier is `[0, expectedIntermediateBlockInterval)`. The mock verifier - /// accepts anything, so the journal is checked by matching the call rather than by reverting. - function _assertChallengeIntermediateRange(uint256 endingBlock, uint256 expectedIntermediateBlockInterval) private { - AggregateVerifier game = _createGameEndingAt(endingBlock); - (Hash startingRoot,) = game.startingOutputRoot(); - - bytes32 counterRoot = keccak256("counter"); - bytes memory zkProof = abi.encodePacked(uint8(AggregateVerifier.ProofType.ZK), bytes1(0)); - - bytes32 expectedJournal = keccak256( - abi.encodePacked( - ZK_PROVER, - game.l1Head().raw(), - startingRoot.raw(), - uint64(0), - counterRoot, - uint64(expectedIntermediateBlockInterval), - abi.encodePacked(counterRoot), - CONFIG_HASH, - ZK_RANGE_HASH, - game.scheduleId() - ) - ); - - // `zkProof[1:]` is the single trailing zero byte. - vm.expectCall( - address(zkVerifier), abi.encodeCall(IVerifier.verify, (hex"00", ZK_AGGREGATE_HASH, expectedJournal)) - ); - vm.prank(ZK_PROVER); - game.challenge(zkProof, 0, counterRoot); - } - - /// @dev Creates a game off the anchor root. Intermediate root values are unchecked by the mock - /// verifiers, so only their count has to match the implementation. - function _createGameEndingAt(uint256 endingBlock) private returns (AggregateVerifier) { - Claim rootClaim = Claim.wrap(keccak256(abi.encode(endingBlock))); - // Both interval pairs are constructor-checked to yield the same count, so the slow-block ratio - // is the count on either side. Reading it off the implementation instead would put a - // staticcall between a caller's `vm.expectRevert` and the call it is meant to apply to. - uint256 count = SLOW_BLOCK_INTERVAL / SLOW_INTERMEDIATE_BLOCK_INTERVAL; - bytes32[] memory intermediateRoots = new bytes32[](count); - for (uint256 i; i < count - 1; i++) { - intermediateRoots[i] = keccak256(abi.encode(endingBlock, i)); - } - intermediateRoots[count - 1] = rootClaim.raw(); - - bytes memory extraData = - abi.encodePacked(endingBlock, address(anchorStateRegistry), abi.encodePacked(intermediateRoots)); - bytes memory proof = _generateProof(abi.encode(endingBlock), AggregateVerifier.ProofType.TEE); - - _warpToL2Timestamp(endingBlock); - vm.deal(TEE_PROVER, INIT_BOND); - vm.prank(TEE_PROVER); - return AggregateVerifier( - address( - factory.createWithInitData{ value: INIT_BOND }( - GameTypes.AGGREGATE_VERIFIER, rootClaim, extraData, proof - ) - ) - ); - } - - function _defaultScheduleConfig() private view returns (AggregateVerifier.ScheduleConfig memory) { - return AggregateVerifier.ScheduleConfig({ - protocolVersions: IProtocolVersions(address(protocolVersions)), - genesisBlockNumber: L2_GENESIS_BLOCK_NUMBER, - genesisTimestamp: L2_GENESIS_TIMESTAMP, - blockTime: L2_BLOCK_TIME - }); - } - - function _defaultIntervalConfig() private pure returns (AggregateVerifier.IntervalConfig memory) { - return AggregateVerifier.IntervalConfig({ - slowBlockInterval: SLOW_BLOCK_INTERVAL, - slowIntermediateBlockInterval: SLOW_INTERMEDIATE_BLOCK_INTERVAL, - fastBlockInterval: FAST_BLOCK_INTERVAL, - fastIntermediateBlockInterval: FAST_INTERMEDIATE_BLOCK_INTERVAL - }); + return _deployAggregateVerifier(BLOCK_INTERVAL, INTERMEDIATE_BLOCK_INTERVAL, scheduleConfig); } function _deployAggregateVerifier( - AggregateVerifier.IntervalConfig memory intervalConfig, + uint256 blockInterval, + uint256 intermediateBlockInterval, AggregateVerifier.ScheduleConfig memory scheduleConfig ) private @@ -922,7 +609,8 @@ contract AggregateVerifierTest is BaseTest { AggregateVerifier.ZkHashes(ZK_RANGE_HASH, ZK_AGGREGATE_HASH), CONFIG_HASH, L2_CHAIN_ID, - intervalConfig, + blockInterval, + intermediateBlockInterval, scheduleConfig ); } diff --git a/test/L1/proofs/AnchorStateRegistry.t.sol b/test/L1/proofs/AnchorStateRegistry.t.sol index b97f63c1c..0f794f967 100644 --- a/test/L1/proofs/AnchorStateRegistry.t.sol +++ b/test/L1/proofs/AnchorStateRegistry.t.sol @@ -50,7 +50,7 @@ abstract contract AnchorStateRegistry_TestInit is BaseTest { // Get the actual anchor roots (, uint256 l2BlockNumber) = anchorStateRegistry.getAnchorRoot(); - validL2BlockNumber = l2BlockNumber + SLOW_BLOCK_INTERVAL; + validL2BlockNumber = l2BlockNumber + BLOCK_INTERVAL; Claim rootClaim = Claim.wrap(keccak256(abi.encode(validL2BlockNumber))); bytes memory proof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE); gameProxy = IDisputeGame( diff --git a/test/L1/proofs/BaseTest.t.sol b/test/L1/proofs/BaseTest.t.sol index b0066d574..83296fa09 100644 --- a/test/L1/proofs/BaseTest.t.sol +++ b/test/L1/proofs/BaseTest.t.sol @@ -31,11 +31,9 @@ contract BaseTest is Test { uint64 internal constant L2_BLOCK_TIME = 2; // AggregateVerifier expects evenly spaced intermediate roots. - uint256 internal constant SLOW_BLOCK_INTERVAL = 100; - uint256 internal constant SLOW_INTERMEDIATE_BLOCK_INTERVAL = 10; - uint256 internal constant FAST_BLOCK_INTERVAL = 1000; - uint256 internal constant FAST_INTERMEDIATE_BLOCK_INTERVAL = 100; - uint256 private constant INTERMEDIATE_ROOTS_COUNT = SLOW_BLOCK_INTERVAL / SLOW_INTERMEDIATE_BLOCK_INTERVAL; + uint256 internal constant BLOCK_INTERVAL = 100; + uint256 internal constant INTERMEDIATE_BLOCK_INTERVAL = 10; + uint256 private constant INTERMEDIATE_ROOTS_COUNT = BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL; uint256 internal constant INIT_BOND = 1 ether; uint256 internal constant DELAYED_WETH_DELAY = 1 days; @@ -138,12 +136,8 @@ contract BaseTest is Test { AggregateVerifier.ZkHashes(ZK_RANGE_HASH, ZK_AGGREGATE_HASH), CONFIG_HASH, L2_CHAIN_ID, - AggregateVerifier.IntervalConfig({ - slowBlockInterval: SLOW_BLOCK_INTERVAL, - slowIntermediateBlockInterval: SLOW_INTERMEDIATE_BLOCK_INTERVAL, - fastBlockInterval: FAST_BLOCK_INTERVAL, - fastIntermediateBlockInterval: FAST_INTERMEDIATE_BLOCK_INTERVAL - }), + BLOCK_INTERVAL, + INTERMEDIATE_BLOCK_INTERVAL, AggregateVerifier.ScheduleConfig({ protocolVersions: IProtocolVersions(address(protocolVersions)), genesisBlockNumber: L2_GENESIS_BLOCK_NUMBER, @@ -226,10 +220,9 @@ contract BaseTest is Test { function _generateIntermediateRoots(uint256 l2BlockNumber, Claim rootClaim) internal pure returns (bytes memory) { bytes32[] memory intermediateRoots = new bytes32[](INTERMEDIATE_ROOTS_COUNT); - uint256 startingL2BlockNumber = l2BlockNumber - SLOW_BLOCK_INTERVAL; + uint256 startingL2BlockNumber = l2BlockNumber - BLOCK_INTERVAL; for (uint256 i = 1; i < INTERMEDIATE_ROOTS_COUNT; i++) { - intermediateRoots[i - 1] = - keccak256(abi.encode(startingL2BlockNumber + SLOW_INTERMEDIATE_BLOCK_INTERVAL * i)); + intermediateRoots[i - 1] = keccak256(abi.encode(startingL2BlockNumber + INTERMEDIATE_BLOCK_INTERVAL * i)); } intermediateRoots[INTERMEDIATE_ROOTS_COUNT - 1] = rootClaim.raw(); diff --git a/test/L1/proofs/Challenge.t.sol b/test/L1/proofs/Challenge.t.sol index 3e425684c..0aca7e4d2 100644 --- a/test/L1/proofs/Challenge.t.sol +++ b/test/L1/proofs/Challenge.t.sol @@ -12,7 +12,7 @@ import { Verifier } from "src/L1/proofs/Verifier.sol"; import { BaseTest } from "./BaseTest.t.sol"; contract ChallengeTest is BaseTest { - uint256 private constant LAST_INTERMEDIATE_ROOT_INDEX = SLOW_BLOCK_INTERVAL / SLOW_INTERMEDIATE_BLOCK_INTERVAL - 1; + uint256 private constant LAST_INTERMEDIATE_ROOT_INDEX = BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1; function testChallengeTEEProofWithZKProof() public { AggregateVerifier game = @@ -158,7 +158,7 @@ contract ChallengeTest is BaseTest { private returns (AggregateVerifier) { - currentL2BlockNumber += SLOW_BLOCK_INTERVAL; + currentL2BlockNumber += BLOCK_INTERVAL; Claim rootClaim = _claim(claimSalt); bytes memory proof = _generateProof(proofSalt, proofType); return _createAggregateVerifierGame(prover, rootClaim, currentL2BlockNumber, parent, proof); diff --git a/test/L1/proofs/DisputeGameFactory.t.sol b/test/L1/proofs/DisputeGameFactory.t.sol index a09931e65..367ecd2a7 100644 --- a/test/L1/proofs/DisputeGameFactory.t.sol +++ b/test/L1/proofs/DisputeGameFactory.t.sol @@ -45,10 +45,8 @@ contract DisputeGameFactory_FakeClone_Harness { abstract contract DisputeGameFactory_TestInit is CommonTest { uint256 internal constant DEFAULT_INIT_BOND = 0.08 ether; uint256 internal constant L2_CHAIN_ID = 111; - uint256 internal constant AGGREGATE_SLOW_BLOCK_INTERVAL = 100; - uint256 internal constant AGGREGATE_SLOW_INTERMEDIATE_BLOCK_INTERVAL = 10; - uint256 internal constant AGGREGATE_FAST_BLOCK_INTERVAL = 1000; - uint256 internal constant AGGREGATE_FAST_INTERMEDIATE_BLOCK_INTERVAL = 100; + uint256 internal constant AGGREGATE_BLOCK_INTERVAL = 100; + uint256 internal constant AGGREGATE_INTERMEDIATE_BLOCK_INTERVAL = 10; uint32 internal constant MAX_GAME_TYPE = 8; address internal constant NON_OWNER = address(0xBEEF); @@ -231,12 +229,8 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_TestInit { AggregateVerifier.ZkHashes(bytes32(uint256(2)), bytes32(uint256(3))), bytes32(uint256(4)), L2_CHAIN_ID, - AggregateVerifier.IntervalConfig({ - slowBlockInterval: AGGREGATE_SLOW_BLOCK_INTERVAL, - slowIntermediateBlockInterval: AGGREGATE_SLOW_INTERMEDIATE_BLOCK_INTERVAL, - fastBlockInterval: AGGREGATE_FAST_BLOCK_INTERVAL, - fastIntermediateBlockInterval: AGGREGATE_FAST_INTERMEDIATE_BLOCK_INTERVAL - }), + AGGREGATE_BLOCK_INTERVAL, + AGGREGATE_INTERMEDIATE_BLOCK_INTERVAL, AggregateVerifier.ScheduleConfig({ protocolVersions: protocolVersions, genesisBlockNumber: 0, genesisTimestamp: 0, blockTime: 2 }) @@ -250,14 +244,12 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_TestInit { for (uint256 i = 1; i < intermediateRootsCount; i++) { intermediateRoots = abi.encodePacked( intermediateRoots, - keccak256(abi.encode(startingRoot.l2SequenceNumber + AGGREGATE_SLOW_INTERMEDIATE_BLOCK_INTERVAL * i)) + keccak256(abi.encode(startingRoot.l2SequenceNumber + AGGREGATE_INTERMEDIATE_BLOCK_INTERVAL * i)) ); } intermediateRoots = abi.encodePacked(intermediateRoots, rootClaim.raw()); bytes memory extraData = abi.encodePacked( - startingRoot.l2SequenceNumber + AGGREGATE_SLOW_BLOCK_INTERVAL, - address(anchorStateRegistry), - intermediateRoots + startingRoot.l2SequenceNumber + AGGREGATE_BLOCK_INTERVAL, address(anchorStateRegistry), intermediateRoots ); bytes memory proof = abi.encodePacked( uint8(AggregateVerifier.ProofType.TEE), blockhash(block.number - 1), block.number - 1, bytes32(0) @@ -268,7 +260,7 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_TestInit { // The claimed L2 block's deterministic timestamp (block number x blockTime) must have // already passed on L1 for the game to be creatable. - vm.warp((startingRoot.l2SequenceNumber + AGGREGATE_SLOW_BLOCK_INTERVAL) * 2); + vm.warp((startingRoot.l2SequenceNumber + AGGREGATE_BLOCK_INTERVAL) * 2); uint256 gameCountBefore = disputeGameFactory.gameCount(); IDisputeGame proxy = disputeGameFactory.createWithInitData{ value: bondAmount }( @@ -283,13 +275,13 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_TestInit { assertEq(gameV2.extraData(), extraData); assertEq(gameV2.L2_CHAIN_ID(), L2_CHAIN_ID); assertEq(address(gameV2.gameCreator()), address(this)); - assertEq(gameV2.l2SequenceNumber(), startingRoot.l2SequenceNumber + AGGREGATE_SLOW_BLOCK_INTERVAL); + assertEq(gameV2.l2SequenceNumber(), startingRoot.l2SequenceNumber + AGGREGATE_BLOCK_INTERVAL); assertEq(gameV2.parentAddress(), address(anchorStateRegistry)); assertEq(address(gameV2.DELAYED_WETH()), address(delayedWeth)); assertEq(address(gameV2.anchorStateRegistry()), address(anchorStateRegistry)); assertEq(GameType.unwrap(gameV2.gameType()), GameType.unwrap(GameTypes.AGGREGATE_VERIFIER)); - assertEq(gameV2.SLOW_BLOCK_INTERVAL(), AGGREGATE_SLOW_BLOCK_INTERVAL); - assertEq(gameV2.SLOW_INTERMEDIATE_BLOCK_INTERVAL(), AGGREGATE_SLOW_INTERMEDIATE_BLOCK_INTERVAL); + assertEq(gameV2.BLOCK_INTERVAL(), AGGREGATE_BLOCK_INTERVAL); + assertEq(gameV2.INTERMEDIATE_BLOCK_INTERVAL(), AGGREGATE_INTERMEDIATE_BLOCK_INTERVAL); } } diff --git a/test/L1/proofs/Nullify.t.sol b/test/L1/proofs/Nullify.t.sol index f9303dfcf..841bc8cca 100644 --- a/test/L1/proofs/Nullify.t.sol +++ b/test/L1/proofs/Nullify.t.sol @@ -10,7 +10,7 @@ import { AggregateVerifier } from "src/L1/proofs/AggregateVerifier.sol"; import { BaseTest } from "./BaseTest.t.sol"; contract NullifyTest is BaseTest { - uint256 private constant LAST_INTERMEDIATE_ROOT_INDEX = SLOW_BLOCK_INTERVAL / SLOW_INTERMEDIATE_BLOCK_INTERVAL - 1; + uint256 private constant LAST_INTERMEDIATE_ROOT_INDEX = BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1; uint256 private constant NO_PROOF_CREDIT_CLAIM_DELAY = 14 days; function testNullifyWithTEEProof() public { @@ -142,7 +142,7 @@ contract NullifyTest is BaseTest { private returns (AggregateVerifier) { - currentL2BlockNumber += SLOW_BLOCK_INTERVAL; + currentL2BlockNumber += BLOCK_INTERVAL; return _createAggregateVerifierGame( prover, _claim(claimSalt), currentL2BlockNumber, parent, _generateProof(proofSalt, proofType) ); diff --git a/test/deploy/SystemDeploy.t.sol b/test/deploy/SystemDeploy.t.sol index 02d3e0f7f..e40bcbe9c 100644 --- a/test/deploy/SystemDeploy.t.sol +++ b/test/deploy/SystemDeploy.t.sol @@ -457,10 +457,8 @@ contract SystemDeploy_Test is Test, SystemDeployAssertions { genesisTimestamp: 1, blockTime: 2 }), - multiproofSlowBlockInterval: 100, - multiproofSlowIntermediateBlockInterval: 10, - multiproofFastBlockInterval: 1000, - multiproofFastIntermediateBlockInterval: 100, + multiproofBlockInterval: 100, + multiproofIntermediateBlockInterval: 10, sp1Verifier: ISP1Verifier(address(sp1Verifier)), teeProposer: proposer, teeChallenger: challenger, @@ -570,12 +568,8 @@ contract SystemDeploy_Test is Test, SystemDeployAssertions { l2GenesisBlockNumber: _input.implementationsInput.scheduleConfig.genesisBlockNumber, l2GenesisTimestamp: _input.implementationsInput.scheduleConfig.genesisTimestamp, l2BlockTime: _input.implementationsInput.scheduleConfig.blockTime, - multiproofSlowBlockInterval: _input.implementationsInput.multiproofSlowBlockInterval, - multiproofSlowIntermediateBlockInterval: _input.implementationsInput - .multiproofSlowIntermediateBlockInterval, - multiproofFastBlockInterval: _input.implementationsInput.multiproofFastBlockInterval, - multiproofFastIntermediateBlockInterval: _input.implementationsInput - .multiproofFastIntermediateBlockInterval, + multiproofBlockInterval: _input.implementationsInput.multiproofBlockInterval, + multiproofIntermediateBlockInterval: _input.implementationsInput.multiproofIntermediateBlockInterval, withdrawalDelaySeconds: _input.implementationsInput.withdrawalDelaySeconds }); } diff --git a/test/deploy/SystemDeployAssertions.sol b/test/deploy/SystemDeployAssertions.sol index 749ed5dcb..2d8d3130b 100644 --- a/test/deploy/SystemDeployAssertions.sol +++ b/test/deploy/SystemDeployAssertions.sol @@ -44,10 +44,8 @@ abstract contract SystemDeployAssertions is Test { uint256 l2GenesisBlockNumber; uint64 l2GenesisTimestamp; uint64 l2BlockTime; - uint256 multiproofSlowBlockInterval; - uint256 multiproofSlowIntermediateBlockInterval; - uint256 multiproofFastBlockInterval; - uint256 multiproofFastIntermediateBlockInterval; + uint256 multiproofBlockInterval; + uint256 multiproofIntermediateBlockInterval; uint256 withdrawalDelaySeconds; } @@ -259,17 +257,9 @@ abstract contract SystemDeployAssertions is Test { assertEq(_aggregateVerifier.L2_GENESIS_BLOCK_NUMBER(), _expected.l2GenesisBlockNumber, "AV-132"); assertEq(_aggregateVerifier.L2_GENESIS_TIMESTAMP(), _expected.l2GenesisTimestamp, "AV-134"); assertEq(_aggregateVerifier.L2_BLOCK_TIME(), _expected.l2BlockTime, "AV-136"); - assertEq(_aggregateVerifier.SLOW_BLOCK_INTERVAL(), _expected.multiproofSlowBlockInterval, "AV-140"); + assertEq(_aggregateVerifier.BLOCK_INTERVAL(), _expected.multiproofBlockInterval, "AV-140"); assertEq( - _aggregateVerifier.SLOW_INTERMEDIATE_BLOCK_INTERVAL(), - _expected.multiproofSlowIntermediateBlockInterval, - "AV-150" - ); - assertEq(_aggregateVerifier.FAST_BLOCK_INTERVAL(), _expected.multiproofFastBlockInterval, "AV-160"); - assertEq( - _aggregateVerifier.FAST_INTERMEDIATE_BLOCK_INTERVAL(), - _expected.multiproofFastIntermediateBlockInterval, - "AV-170" + _aggregateVerifier.INTERMEDIATE_BLOCK_INTERVAL(), _expected.multiproofIntermediateBlockInterval, "AV-150" ); }