Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions interfaces/L1/proofs/IAggregateVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { IDisputeGame } from "./IDisputeGame.sol";
import { IDisputeGameFactory } from "./IDisputeGameFactory.sol";
import { IDelayedWETH } from "./IDelayedWETH.sol";
import { IVerifier } from "./IVerifier.sol";
import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";
import { Proposal, Hash } from "src/libraries/bridge/Types.sol";
import { Timestamp } from "src/libraries/bridge/LibUDT.sol";

Expand All @@ -23,6 +24,7 @@ interface IAggregateVerifier is IDisputeGame {
function ZK_RANGE_HASH() external view returns (bytes32);
function ZK_AGGREGATE_HASH() external view returns (bytes32);
function CONFIG_HASH() external view returns (bytes32);
function PROTOCOL_VERSIONS() external view returns (IProtocolVersions);
function L2_CHAIN_ID() external view returns (uint256);
function BLOCK_INTERVAL() external view returns (uint256);
function INTERMEDIATE_BLOCK_INTERVAL() external view returns (uint256);
Expand All @@ -35,6 +37,7 @@ interface IAggregateVerifier is IDisputeGame {
function counteredByIntermediateRootIndexPlusOne() external view returns (uint256);
function expectedResolution() external view returns (Timestamp);
function proofCount() external view returns (uint8);
function scheduleId() external view returns (bytes32);

function initializeWithInitData(bytes calldata proof) external payable;
function verifyProposalProof(bytes calldata proofBytes) external;
Expand Down
7 changes: 5 additions & 2 deletions scripts/deploy/SystemDeploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ contract SystemDeploy is Script {
uint256 l2ChainId;
uint256 multiproofBlockInterval;
uint256 multiproofIntermediateBlockInterval;
IProtocolVersions protocolVersions;
}

struct MultiproofOutput {
Expand Down Expand Up @@ -1048,7 +1049,8 @@ contract SystemDeploy is Script {
multiproofConfigHash: _input.multiproofConfigHash,
l2ChainId: _opChainInput.l2ChainId,
multiproofBlockInterval: _input.multiproofBlockInterval,
multiproofIntermediateBlockInterval: _input.multiproofIntermediateBlockInterval
multiproofIntermediateBlockInterval: _input.multiproofIntermediateBlockInterval,
protocolVersions: _output.protocolVersionsProxy
})
);

Expand Down Expand Up @@ -1077,7 +1079,8 @@ contract SystemDeploy is Script {
_input.multiproofConfigHash,
_input.l2ChainId,
_input.multiproofBlockInterval,
_input.multiproofIntermediateBlockInterval
_input.multiproofIntermediateBlockInterval,
_input.protocolVersions
)
)
);
Expand Down
11 changes: 10 additions & 1 deletion scripts/multiproof/DeployDevBase.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { DeployUtils } from "scripts/libraries/DeployUtils.sol";

import { AggregateVerifier } from "src/L1/proofs/AggregateVerifier.sol";
import { IVerifier } from "interfaces/L1/proofs/IVerifier.sol";
import { ProtocolVersions } from "src/L1/ProtocolVersions.sol";
import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";
import { MockVerifier } from "test/mocks/MockVerifier.sol";
import { TEEProverRegistry } from "src/L1/proofs/tee/TEEProverRegistry.sol";
import { TEEVerifier } from "src/L1/proofs/tee/TEEVerifier.sol";
Expand Down Expand Up @@ -104,6 +106,12 @@ abstract contract DeployDevBase is Script {
AggregateVerifier.ZkHashes memory zkHashes =
AggregateVerifier.ZkHashes({ rangeHash: cfg.zkRangeHash(), aggregateHash: cfg.zkAggregationHash() });

Proxy protocolVersionsProxy = new Proxy(msg.sender);
protocolVersionsProxy.upgradeToAndCall(
address(new ProtocolVersions()), abi.encodeCall(IProtocolVersions.initialize, (address(0)))
);
protocolVersionsProxy.changeAdmin(address(0xdead));

aggregateVerifier = address(
new AggregateVerifier(
gameType,
Expand All @@ -116,7 +124,8 @@ abstract contract DeployDevBase is Script {
cfg.multiproofConfigHash(),
cfg.l2ChainId(),
_blockInterval(),
_intermediateBlockInterval()
_intermediateBlockInterval(),
IProtocolVersions(address(protocolVersionsProxy))
)
);

Expand Down
31 changes: 31 additions & 0 deletions snapshots/abi/AggregateVerifier.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@
"internalType": "uint256",
"name": "intermediateBlockInterval",
"type": "uint256"
},
{
"internalType": "contract IProtocolVersions",
"name": "protocolVersions",
"type": "address"
}
],
"stateMutability": "nonpayable",
Expand Down Expand Up @@ -215,6 +220,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "PROTOCOL_VERSIONS",
"outputs": [
{
"internalType": "contract IProtocolVersions",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "SLOW_FINALIZATION_DELAY",
Expand Down Expand Up @@ -681,6 +699,19 @@
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "scheduleId",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "startingBlockNumber",
Expand Down
4 changes: 2 additions & 2 deletions snapshots/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
"sourceCodeHash": "0xf122a50487efe9bd5a620262ba20ef4adbca14eeec2af7fd32e6e16739001596"
},
"src/L1/proofs/AggregateVerifier.sol:AggregateVerifier": {
"initCodeHash": "0x90629c679e821a70553d899a68e818bcddb672a004a0d2e09078d17028a2f082",
"sourceCodeHash": "0x4835d3de998b2951898f0e427c61b0c330ac3feb5f7a8dc9fd0deb78912a9b7a"
"initCodeHash": "0x6f3c53245830b9c72c8199695e93959d5ed3b0cb8352e5b50b3dfa28183ac787",
"sourceCodeHash": "0x1f2e2b07ebc4359fa31ea7400ace9bab0e4f6099d8ff3ff7b6a2b14cccfb89ca"
},
"src/L1/proofs/AnchorStateRegistry.sol:AnchorStateRegistry": {
"initCodeHash": "0x6f3afd2d0ef97a82ca3111976322b99343a270e54cd4a405028f2f29c75f7fb1",
Expand Down
7 changes: 7 additions & 0 deletions snapshots/storageLayout/AggregateVerifier.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,12 @@
"offset": 8,
"slot": "7",
"type": "uint8"
},
{
"bytes": "32",
"label": "scheduleId",
"offset": 0,
"slot": "8",
"type": "bytes32"
}
]
24 changes: 21 additions & 3 deletions src/L1/proofs/AggregateVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { ReentrancyGuard } from "lib/solady/src/utils/ReentrancyGuard.sol";

import { IVerifier } from "interfaces/L1/proofs/IVerifier.sol";
import { ISemver } from "interfaces/universal/ISemver.sol";
import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";

contract AggregateVerifier is Clone, ReentrancyGuard, ISemver {
////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -113,6 +114,9 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver {
/// @notice The game type ID.
GameType internal immutable GAME_TYPE;

/// @notice The ProtocolVersions upgrade schedule contract.
IProtocolVersions public immutable PROTOCOL_VERSIONS;

////////////////////////////////////////////////////////////////
// State Vars //
////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -162,6 +166,11 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver {
/// @notice The number of proofs provided.
uint8 public proofCount;

/// @notice The ProtocolVersions scheduleId snapshotted at game initialization.
/// @dev Pinned once at init; every proof in this game commits to this value, binding it to the
/// upgrade schedule in effect when the game was created.
bytes32 public scheduleId;

////////////////////////////////////////////////////////////////
// Events //
////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -259,6 +268,7 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver {
/// @param l2ChainId The chain ID of the L2 network.
/// @param blockInterval The block interval.
/// @param intermediateBlockInterval The intermediate block interval.
/// @param protocolVersions The ProtocolVersions upgrade schedule contract.
constructor(
GameType gameType_,
IAnchorStateRegistry anchorStateRegistry_,
Expand All @@ -270,7 +280,8 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver {
bytes32 configHash,
uint256 l2ChainId,
uint256 blockInterval,
uint256 intermediateBlockInterval
uint256 intermediateBlockInterval,
IProtocolVersions protocolVersions
) {
// Block interval and intermediate block interval must be positive and divisible.
if (blockInterval == 0 || intermediateBlockInterval == 0 || blockInterval % intermediateBlockInterval != 0) {
Expand All @@ -291,6 +302,7 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver {
L2_CHAIN_ID = l2ChainId;
BLOCK_INTERVAL = blockInterval;
INTERMEDIATE_BLOCK_INTERVAL = intermediateBlockInterval;
PROTOCOL_VERSIONS = protocolVersions;

INITIALIZE_CALLDATA_SIZE = 0x8E + 0x20 * intermediateOutputRootsCount();
}
Expand Down Expand Up @@ -364,6 +376,10 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver {
// Set the game as initialized.
initialized = true;

// Snapshot the scheduleId from ProtocolVersions. Every proof in this game commits to this
// value, pinning them to the upgrade schedule in effect at the game's creation block.
scheduleId = PROTOCOL_VERSIONS.scheduleId();

// Set the game's starting timestamp.
createdAt = Timestamp.wrap(uint64(block.timestamp));

Expand Down Expand Up @@ -899,7 +915,8 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver {
endingL2SequenceNumber,
intermediateRoots,
CONFIG_HASH,
TEE_IMAGE_HASH
TEE_IMAGE_HASH,
scheduleId
)
);

Expand Down Expand Up @@ -933,7 +950,8 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver {
endingL2SequenceNumber,
intermediateRoots,
CONFIG_HASH,
ZK_RANGE_HASH
ZK_RANGE_HASH,
scheduleId
)
);

Expand Down
3 changes: 2 additions & 1 deletion test/L1/OptimismPortal2.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ abstract contract OptimismPortal2_TestInit is DisputeGameFactory_TestInit {
bytes32(uint256(4)),
deploy.cfg().l2ChainId(),
100,
10
10,
protocolVersions
);
disputeGameFactory.setImplementation(respectedGameType, IDisputeGame(address(gameImpl)));
disputeGameFactory.setInitBond(respectedGameType, 0);
Expand Down
29 changes: 28 additions & 1 deletion test/L1/proofs/AggregateVerifier.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Claim, Timestamp } from "src/libraries/bridge/LibUDT.sol";

import { AggregateVerifier } from "src/L1/proofs/AggregateVerifier.sol";
import { IVerifier } from "interfaces/L1/proofs/IVerifier.sol";
import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";

import { LibClone } from "lib/solady/src/utils/LibClone.sol";

Expand All @@ -36,6 +37,31 @@ contract AggregateVerifierTest is BaseTest {
_createAndAssertInitializedGame("zk-proof", AggregateVerifier.ProofType.ZK, ZK_PROVER, address(0), ZK_PROVER);
}

/// @notice init snapshots the live scheduleId into storage and pins it: a later schedule change
/// must not alter the game's snapshot (proves it is stored once, not read live).
/// @dev Only covers the stored getter. That the snapshot flows into the proof journal is not
/// asserted here — MockVerifier ignores the journal, so journal binding is untestable.
function test_initialize_pinsScheduleId_succeeds() public {
// Register an upgrade so the schedule commitment is non-trivial (non-zero).
protocolVersions.registerUpgrade(uint64(block.timestamp) + protocolVersions.MIN_NOTICE() + 100, 1);
bytes32 pinned = protocolVersions.scheduleId();
assertTrue(pinned != bytes32(0));

Claim rootClaim = _advanceL2BlockAndClaim();
bytes memory proof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE);

AggregateVerifier game = _createAggregateVerifierGame(
TEE_PROVER, rootClaim, currentL2BlockNumber, address(anchorStateRegistry), proof
);

assertEq(game.scheduleId(), pinned);

// Move the live schedule after creation; the game's snapshot must stay pinned.
protocolVersions.registerUpgrade(uint64(block.timestamp) + protocolVersions.MIN_NOTICE() + 200, 2);
assertNotEq(protocolVersions.scheduleId(), pinned);
assertEq(game.scheduleId(), pinned);
}

function testInitializeFailsIfInvalidCallDataSize() public {
Claim rootClaim = _advanceL2BlockAndClaim();

Expand Down Expand Up @@ -417,7 +443,8 @@ contract AggregateVerifierTest is BaseTest {
CONFIG_HASH,
L2_CHAIN_ID,
blockInterval,
intermediateBlockInterval
intermediateBlockInterval,
IProtocolVersions(address(protocolVersions))
);
}
}
10 changes: 9 additions & 1 deletion test/L1/proofs/BaseTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { ProxyAdmin } from "src/universal/ProxyAdmin.sol";

import { AggregateVerifier } from "src/L1/proofs/AggregateVerifier.sol";
import { IVerifier } from "interfaces/L1/proofs/IVerifier.sol";
import { ProtocolVersions } from "src/L1/ProtocolVersions.sol";
import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";

import { MockVerifier } from "test/mocks/MockVerifier.sol";

Expand Down Expand Up @@ -54,6 +56,7 @@ contract BaseTest is Test {

MockVerifier internal teeVerifier;
MockVerifier internal zkVerifier;
ProtocolVersions internal protocolVersions;

function setUp() public virtual {
_deployContractsAndProxies();
Expand All @@ -78,9 +81,12 @@ contract BaseTest is Test {

proxyAdmin = new ProxyAdmin(address(this));

ProtocolVersions _protocolVersions = new ProtocolVersions();

anchorStateRegistry = AnchorStateRegistry(_deployProxy(address(_anchorStateRegistry)));
factory = DisputeGameFactory(_deployProxy(address(_factory)));
delayedWETH = DelayedWETH(payable(_deployProxy(address(_delayedWETH))));
protocolVersions = ProtocolVersions(_deployProxy(address(_protocolVersions)));

teeVerifier = new MockVerifier(IAnchorStateRegistry(address(anchorStateRegistry)));
zkVerifier = new MockVerifier(IAnchorStateRegistry(address(anchorStateRegistry)));
Expand All @@ -103,6 +109,7 @@ contract BaseTest is Test {
);
factory.initialize(address(this));
delayedWETH.initialize(systemConfig);
protocolVersions.initialize(address(0));
}

function _deployAndSetAggregateVerifier() internal {
Expand All @@ -117,7 +124,8 @@ contract BaseTest is Test {
CONFIG_HASH,
L2_CHAIN_ID,
BLOCK_INTERVAL,
INTERMEDIATE_BLOCK_INTERVAL
INTERMEDIATE_BLOCK_INTERVAL,
IProtocolVersions(address(protocolVersions))
);

factory.setImplementation(GameTypes.AGGREGATE_VERIFIER, IDisputeGame(address(aggregateVerifierImpl)));
Expand Down
3 changes: 2 additions & 1 deletion test/L1/proofs/DisputeGameFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,8 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_TestInit {
bytes32(uint256(4)),
L2_CHAIN_ID,
AGGREGATE_BLOCK_INTERVAL,
AGGREGATE_INTERMEDIATE_BLOCK_INTERVAL
AGGREGATE_INTERMEDIATE_BLOCK_INTERVAL,
protocolVersions
);
_setGame(address(gameImpl), GameTypes.AGGREGATE_VERIFIER);

Expand Down
Loading