Skip to content

Commit

Permalink
Merge pull request #6611 from ethereum-optimism/clabby/ctb/add-local-…
Browse files Browse the repository at this point in the history
…data-tests

feat(ctb): Add unit tests for `addLocalData`
  • Loading branch information
OptimismBot authored Aug 6, 2023
2 parents d0d4010 + cf9448c commit 556e5ad
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 42 deletions.
2 changes: 1 addition & 1 deletion op-bindings/bindings/alphabetvm.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion op-bindings/bindings/faultdisputegame.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion op-bindings/bindings/faultdisputegame_more.go

Large diffs are not rendered by default.

31 changes: 16 additions & 15 deletions packages/contracts-bedrock/.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -97,28 +97,29 @@ FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2:test_resolvesCorrectly_succeed
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 501212)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 502409)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot5:test_resolvesCorrectly_succeeds() (gas: 501698)
FaultDisputeGame_Test:test_createdAt_succeeds() (gas: 10364)
FaultDisputeGame_Test:test_extraData_succeeds() (gas: 32354)
FaultDisputeGame_Test:test_gameData_succeeds() (gas: 32806)
FaultDisputeGame_Test:test_gameType_succeeds() (gas: 8272)
FaultDisputeGame_Test:test_initialize_correctData_succeeds() (gas: 57716)
FaultDisputeGame_Test:test_initialize_firstOutput_reverts() (gas: 210532)
FaultDisputeGame_Test:test_initialize_l1HeadTooOld_reverts() (gas: 228402)
FaultDisputeGame_Test:test_addLocalData_static_succeeds() (gas: 640503)
FaultDisputeGame_Test:test_createdAt_succeeds() (gas: 10342)
FaultDisputeGame_Test:test_extraData_succeeds() (gas: 32377)
FaultDisputeGame_Test:test_gameData_succeeds() (gas: 32829)
FaultDisputeGame_Test:test_gameType_succeeds() (gas: 8250)
FaultDisputeGame_Test:test_initialize_correctData_succeeds() (gas: 57694)
FaultDisputeGame_Test:test_initialize_firstOutput_reverts() (gas: 210576)
FaultDisputeGame_Test:test_initialize_l1HeadTooOld_reverts() (gas: 228425)
FaultDisputeGame_Test:test_move_clockCorrectness_succeeds() (gas: 415993)
FaultDisputeGame_Test:test_move_clockTimeExceeded_reverts() (gas: 23175)
FaultDisputeGame_Test:test_move_clockTimeExceeded_reverts() (gas: 23219)
FaultDisputeGame_Test:test_move_defendRoot_reverts() (gas: 13366)
FaultDisputeGame_Test:test_move_duplicateClaim_reverts() (gas: 102942)
FaultDisputeGame_Test:test_move_duplicateClaim_reverts() (gas: 102920)
FaultDisputeGame_Test:test_move_gameDepthExceeded_reverts() (gas: 407913)
FaultDisputeGame_Test:test_move_gameNotInProgress_reverts() (gas: 11024)
FaultDisputeGame_Test:test_move_nonExistentParent_reverts() (gas: 24667)
FaultDisputeGame_Test:test_move_simpleAttack_succeeds() (gas: 107318)
FaultDisputeGame_Test:test_resolve_challengeContested_succeeds() (gas: 224883)
FaultDisputeGame_Test:test_move_nonExistentParent_reverts() (gas: 24732)
FaultDisputeGame_Test:test_move_simpleAttack_succeeds() (gas: 107341)
FaultDisputeGame_Test:test_resolve_challengeContested_succeeds() (gas: 224906)
FaultDisputeGame_Test:test_resolve_notInProgress_reverts() (gas: 9664)
FaultDisputeGame_Test:test_resolve_rootContested_succeeds() (gas: 109856)
FaultDisputeGame_Test:test_resolve_rootUncontestedClockNotExpired_succeeds() (gas: 21443)
FaultDisputeGame_Test:test_resolve_rootUncontested_succeeds() (gas: 27278)
FaultDisputeGame_Test:test_resolve_rootUncontestedClockNotExpired_succeeds() (gas: 21421)
FaultDisputeGame_Test:test_resolve_rootUncontested_succeeds() (gas: 27256)
FaultDisputeGame_Test:test_resolve_teamDeathmatch_succeeds() (gas: 395635)
FaultDisputeGame_Test:test_rootClaim_succeeds() (gas: 8253)
FaultDisputeGame_Test:test_rootClaim_succeeds() (gas: 8276)
FeeVault_Test:test_constructor_succeeds() (gas: 18185)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 352113)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2950320)
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-bedrock/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"src/L2/L2StandardBridge.sol": "0x73a4fea3dca8ac7d7ba32e38aadeb69bd344042666a40a75e8c28849f01999e5",
"src/L2/L2ToL1MessagePasser.sol": "0xed800b600cb3f67e18a1ab10750e3934a8b3e42178f422bcacfde770a6e8e8bd",
"src/L2/SequencerFeeVault.sol": "0xd57c143b1f042400430b991b806bf971628e6980406c751e82d19ae80eeb4e8d",
"src/dispute/FaultDisputeGame.sol": "0xc191d9caad8498c46035e9bceb1ee372be24f9d7f6cb9f8fda8f646bc875d338",
"src/dispute/FaultDisputeGame.sol": "0x2a7f367443752f841d734f339a596c4ad93e16f7df0230f1cdd5e6f0b4b58368",
"src/legacy/DeployerWhitelist.sol": "0x5e80f7b13ef73f06c63bd9b118a49da1ff06a5c0fcf8067b5a3365d731c23765",
"src/legacy/L1BlockNumber.sol": "0x84cc587148de5920dfcd19da44d28e769f0e4d08ca2bcc93f18aa78c6cc2ebe6",
"src/legacy/LegacyMessagePasser.sol": "0x2692b50b227e5f75a53439c0cf303498edfd4fc087555b3fc9bc4bceb518229b",
Expand Down
3 changes: 2 additions & 1 deletion packages/contracts-bedrock/src/dispute/FaultDisputeGame.sol
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,10 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
if (status != GameStatus.IN_PROGRESS) revert GameNotInProgress();

IPreimageOracle oracle = VM.oracle();
bytes4 loadLocalDataSelector = IPreimageOracle.loadLocalData.selector;
assembly {
// Store the `loadLocalData(uint256,bytes32,uint256,uint256)` selector
mstore(0x00, 0x9a1f5e7f)
mstore(0x1C, loadLocalDataSelector)
// Store the `_ident` argument
mstore(0x20, _ident)
// Store the data to load
Expand Down
88 changes: 66 additions & 22 deletions packages/contracts-bedrock/test/FaultDisputeGame.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
import { FaultDisputeGame } from "src/dispute/FaultDisputeGame.sol";
import { L2OutputOracle } from "src/L1/L2OutputOracle.sol";
import { BlockOracle } from "src/dispute/BlockOracle.sol";
import { PreimageOracle } from "src/cannon/PreimageOracle.sol";
import { PreimageKeyLib } from "src/cannon/PreimageKeyLib.sol";

import "src/libraries/DisputeTypes.sol";
import "src/libraries/DisputeErrors.sol";
Expand Down Expand Up @@ -38,12 +40,7 @@ contract FaultDisputeGame_Init is DisputeGameFactory_Init {
// Propose 2 mock outputs
vm.startPrank(oracle.PROPOSER());
for (uint256 i; i < 2; i++) {
oracle.proposeL2Output(
bytes32(i + 1),
oracle.nextBlockNumber(),
blockhash(i),
i
);
oracle.proposeL2Output(bytes32(i + 1), oracle.nextBlockNumber(), blockhash(i), i);

// Advance 1 block
vm.roll(block.number + 1);
Expand Down Expand Up @@ -129,7 +126,11 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
/// contain the disputed L2 output root.
function test_initialize_l1HeadTooOld_reverts() public {
// Store a mock block hash for the genesis block. The timestamp will default to 0.
vm.store(address(gameImpl.BLOCK_ORACLE()), keccak256(abi.encode(0, 0)), bytes32(uint256(1)));
vm.store(
address(gameImpl.BLOCK_ORACLE()),
keccak256(abi.encode(0, 0)),
bytes32(uint256(1))
);
bytes memory _extraData = abi.encode(oracle.SUBMISSION_INTERVAL() * 2, 0);

vm.expectRevert(L1HeadTooOld.selector);
Expand All @@ -149,7 +150,10 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
/// @dev Tests that the game is initialized with the correct data.
function test_initialize_correctData_succeeds() public {
// Starting
(FaultDisputeGame.OutputProposal memory startingProp, FaultDisputeGame.OutputProposal memory disputedProp) = gameProxy.proposals();
(
FaultDisputeGame.OutputProposal memory startingProp,
FaultDisputeGame.OutputProposal memory disputedProp
) = gameProxy.proposals();
Types.OutputProposal memory starting = oracle.getL2Output(startingProp.index);
assertEq(startingProp.index, 0);
assertEq(startingProp.l2BlockNumber, starting.l2BlockNumber);
Expand Down Expand Up @@ -421,6 +425,59 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
assertEq(uint8(status), uint8(GameStatus.CHALLENGER_WINS));
assertEq(uint8(gameProxy.status()), uint8(GameStatus.CHALLENGER_WINS));
}

/// @dev Tests that adding local data with an out of bounds identifier reverts.
function testFuzz_addLocalData_oob_reverts(uint256 _ident) public {
// [1, 5] are valid local data identifiers.
if (_ident <= 5) _ident = 0;

vm.expectRevert(InvalidLocalIdent.selector);
gameProxy.addLocalData(_ident, 0);
}

/// @dev Tests that local data is loaded into the preimage oracle correctly.
function test_addLocalData_static_succeeds() public {
IPreimageOracle oracle = IPreimageOracle(address(gameProxy.VM().oracle()));
(
FaultDisputeGame.OutputProposal memory starting,
FaultDisputeGame.OutputProposal memory disputed
) = gameProxy.proposals();

bytes32[5] memory data = [
Hash.unwrap(gameProxy.l1Head()),
Hash.unwrap(starting.outputRoot),
Hash.unwrap(disputed.outputRoot),
bytes32(uint256(starting.l2BlockNumber) << 0xC0),
bytes32(block.chainid << 0xC0)
];

for (uint256 i = 1; i <= 5; i++) {
uint256 expectedLen = i > 3 ? 8 : 32;

gameProxy.addLocalData(i, 0);
bytes32 key = _getKey(i);
(bytes32 dat, uint256 datLen) = oracle.readPreimage(key, 0);
assertEq(dat >> 0xC0, bytes32(expectedLen));
// Account for the length prefix if i > 3 (the data stored
// at identifiers i <= 3 are 32 bytes long, so the expected
// length is already correct. If i > 3, the data is only 8
// bytes long, so the length prefix + the data is 16 bytes
// total.)
assertEq(datLen, expectedLen + (i > 3 ? 8 : 0));

gameProxy.addLocalData(i, 8);
key = _getKey(i);
(dat, datLen) = oracle.readPreimage(key, 8);
assertEq(dat, data[i - 1]);
assertEq(datLen, expectedLen);
}
}

/// @dev Helper to get the localized key for an identifier in the context of the game proxy.
function _getKey(uint256 _ident) internal view returns (bytes32) {
bytes32 h = keccak256(abi.encode(_ident | (1 << 248), address(gameProxy)));
return bytes32((uint256(h) & ~uint256(0xFF << 248)) | (1 << 248));
}
}

/// @notice A generic game player actor with a configurable trace.
Expand Down Expand Up @@ -963,7 +1020,7 @@ contract AlphabetVM is IBigStepper {

constructor(Claim _absolutePrestate) {
ABSOLUTE_PRESTATE = _absolutePrestate;
oracle = IPreimageOracle(deployNoop());
oracle = new PreimageOracle();
}

/// @inheritdoc IBigStepper
Expand All @@ -987,16 +1044,3 @@ contract AlphabetVM is IBigStepper {
postState_ = keccak256(abi.encode(traceIndex, claim + 1));
}
}

////////////////////////////////////////////////////////////////
// HELPERS //
////////////////////////////////////////////////////////////////

/// @notice Deploys a noop contract.
function deployNoop() returns (address noop_) {
assembly {
mstore(0x00, 0x60016000F3)
let size := 5
noop_ := create(0, sub(0x20, size), size)
}
}

0 comments on commit 556e5ad

Please sign in to comment.