Skip to content

Commit

Permalink
Update forge tests to handle L2OO dep on game init
Browse files Browse the repository at this point in the history
  • Loading branch information
clabby committed Aug 3, 2023
1 parent d3f3751 commit b7aa356
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 64 deletions.
60 changes: 30 additions & 30 deletions packages/contracts-bedrock/.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ AssetReceiverTest:test_withdrawETHwithAmount_unauthorized_reverts() (gas: 10738)
AttestationStationTest:test_attest_bulk_succeeds() (gas: 703740)
AttestationStationTest:test_attest_individual_succeeds() (gas: 632078)
AttestationStationTest:test_attest_single_succeeds() (gas: 651316)
BlockHashOracle_Test:test_load_noBlockHash_reverts() (gas: 10436)
BlockOracle_Test:test_load_noBlockHash_reverts() (gas: 12849)
Bytes_slice_Test:test_slice_acrossMultipleWords_works() (gas: 9413)
Bytes_slice_Test:test_slice_acrossWords_works() (gas: 1430)
Bytes_slice_Test:test_slice_fromNonZeroIdx_works() (gas: 17240)
Expand Down Expand Up @@ -47,9 +47,9 @@ CrossDomainOwnable_Test:test_onlyOwner_succeeds() (gas: 34883)
DeleteOutput:test_script_succeeds() (gas: 3100)
DeployerWhitelist_Test:test_owner_succeeds() (gas: 7582)
DeployerWhitelist_Test:test_storageSlots_succeeds() (gas: 33395)
DisputeGameFactory_Owner_Test:test_owner_succeeds() (gas: 12559)
DisputeGameFactory_Owner_Test:test_owner_succeeds() (gas: 12581)
DisputeGameFactory_SetImplementation_Test:test_setImplementation_notOwner_reverts() (gas: 16042)
DisputeGameFactory_SetImplementation_Test:test_setImplementation_succeeds() (gas: 44243)
DisputeGameFactory_SetImplementation_Test:test_setImplementation_succeeds() (gas: 44301)
DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_notOwner_reverts() (gas: 15950)
DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_succeeds() (gas: 18642)
Drippie_Test:test_create_calledTwice_reverts() (gas: 168931)
Expand Down Expand Up @@ -86,36 +86,36 @@ FaucetTest:test_nonAdmin_drip_fails() (gas: 262520)
FaucetTest:test_receive_succeeds() (gas: 17401)
FaucetTest:test_withdraw_nonAdmin_reverts() (gas: 13145)
FaucetTest:test_withdraw_succeeds() (gas: 78359)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 502154)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 508940)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 505653)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 508860)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot5:test_resolvesCorrectly_succeeds() (gas: 508149)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 500919)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 507705)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 504418)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 505625)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot5:test_resolvesCorrectly_succeeds() (gas: 504914)
FaultDisputeGame_Test:test_extraData_succeeds() (gas: 25514)
FaultDisputeGame_Test:test_gameData_succeeds() (gas: 26005)
FaultDisputeGame_Test:test_gameStart_succeeds() (gas: 10299)
FaultDisputeGame_Test:test_gameType_succeeds() (gas: 8288)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 498866)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 505608)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 502343)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 505550)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot5:test_resolvesCorrectly_succeeds() (gas: 504839)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 497631)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 504373)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 501108)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 502315)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot5:test_resolvesCorrectly_succeeds() (gas: 501604)
FaultDisputeGame_Test:test_extraData_succeeds() (gas: 32354)
FaultDisputeGame_Test:test_gameData_succeeds() (gas: 32828)
FaultDisputeGame_Test:test_gameStart_succeeds() (gas: 10410)
FaultDisputeGame_Test:test_gameType_succeeds() (gas: 8266)
FaultDisputeGame_Test:test_initialRootClaimData_succeeds() (gas: 17627)
FaultDisputeGame_Test:test_move_clockCorrectness_succeeds() (gas: 419219)
FaultDisputeGame_Test:test_move_clockTimeExceeded_reverts() (gas: 26427)
FaultDisputeGame_Test:test_move_defendRoot_reverts() (gas: 13344)
FaultDisputeGame_Test:test_move_duplicateClaim_reverts() (gas: 104132)
FaultDisputeGame_Test:test_move_gameDepthExceeded_reverts() (gas: 411559)
FaultDisputeGame_Test:test_move_clockCorrectness_succeeds() (gas: 415931)
FaultDisputeGame_Test:test_move_clockTimeExceeded_reverts() (gas: 26450)
FaultDisputeGame_Test:test_move_defendRoot_reverts() (gas: 13322)
FaultDisputeGame_Test:test_move_duplicateClaim_reverts() (gas: 103333)
FaultDisputeGame_Test:test_move_gameDepthExceeded_reverts() (gas: 408316)
FaultDisputeGame_Test:test_move_gameNotInProgress_reverts() (gas: 11046)
FaultDisputeGame_Test:test_move_nonExistentParent_reverts() (gas: 24667)
FaultDisputeGame_Test:test_move_simpleAttack_succeeds() (gas: 108122)
FaultDisputeGame_Test:test_resolve_challengeContested_succeeds() (gas: 226557)
FaultDisputeGame_Test:test_resolve_notInProgress_reverts() (gas: 9685)
FaultDisputeGame_Test:test_resolve_rootContested_succeeds() (gas: 110704)
FaultDisputeGame_Test:test_resolve_rootUncontestedClockNotExpired_succeeds() (gas: 21465)
FaultDisputeGame_Test:test_move_nonExistentParent_reverts() (gas: 24623)
FaultDisputeGame_Test:test_move_simpleAttack_succeeds() (gas: 107322)
FaultDisputeGame_Test:test_resolve_challengeContested_succeeds() (gas: 224891)
FaultDisputeGame_Test:test_resolve_notInProgress_reverts() (gas: 9663)
FaultDisputeGame_Test:test_resolve_rootContested_succeeds() (gas: 109882)
FaultDisputeGame_Test:test_resolve_rootUncontestedClockNotExpired_succeeds() (gas: 21487)
FaultDisputeGame_Test:test_resolve_rootUncontested_succeeds() (gas: 27344)
FaultDisputeGame_Test:test_resolve_teamDeathmatch_succeeds() (gas: 398895)
FaultDisputeGame_Test:test_rootClaim_succeeds() (gas: 8253)
FaultDisputeGame_Test:test_resolve_teamDeathmatch_succeeds() (gas: 395563)
FaultDisputeGame_Test:test_rootClaim_succeeds() (gas: 8275)
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
55 changes: 33 additions & 22 deletions packages/contracts-bedrock/src/dispute/FaultDisputeGame.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
/// @notice An append-only array of all claims made during the dispute game.
ClaimData[] public claimData;

/// @notice The starting and disputed output proposals, which are used to determine where
/// game participants should start executing Cannon and to verify the state transition,
/// respectively.
Types.OutputProposal[2] public proposals;
/// @notice The starting and disputed output proposal for the game. Includes information about
/// the output indexes in the `L2OutputOracle` and the output roots at the time of
/// game creation.
OutputProposal[2] public proposals;

/// @notice An internal mapping to allow for constant-time lookups of existing claims.
mapping(ClaimHash => bool) internal claims;
Expand All @@ -81,15 +81,15 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
/// @param _blockOracle The block oracle, used for loading block hashes further back
/// than the `BLOCKHASH` opcode allows as well as their estimated
/// timestamps.
/// @custom:semver 0.0.5
/// @custom:semver 0.0.6
constructor(
Claim _absolutePrestate,
uint256 _maxGameDepth,
Duration _gameDuration,
IBigStepper _vm,
L2OutputOracle _l2oo,
BlockOracle _blockOracle
) Semver(0, 0, 5) {
) Semver(0, 0, 6) {
ABSOLUTE_PRESTATE = _absolutePrestate;
MAX_GAME_DEPTH = _maxGameDepth;
GAME_DURATION = _gameDuration;
Expand Down Expand Up @@ -282,20 +282,21 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
// Load the L1 head hash into the game's local context in the preimage oracle.
oracle.loadLocalData(_ident, Hash.unwrap(l1Head), 32, _partOffset);
} else if (_ident == 2) {
// Load the earliest output root that commits to the passed L2 block number
// into the game's local context in the preimage oracle.
Types.OutputProposal memory proposal = L2_OUTPUT_ORACLE.getL2OutputAfter(
l2BlockNumber()
);
oracle.loadLocalData(_ident, proposal.outputRoot, 32, _partOffset);
// Load the starting output root into the game's local context in the preimage oracle.
oracle.loadLocalData(_ident, Hash.unwrap(proposals[0].outputRoot), 32, _partOffset);
} else if (_ident == 3) {
// Load the root claim into the game's local context in the preimage oracle.
oracle.loadLocalData(_ident, Claim.unwrap(rootClaim()), 32, _partOffset);
// Load the disputed output root into the game's local context in the preimage oracle.
oracle.loadLocalData(_ident, Hash.unwrap(proposals[1].outputRoot), 32, _partOffset);
} else if (_ident == 4) {
// Load the L2 block number into the game's local context in the preimage oracle.
// Load the starting l2 block number into the game's local context in the preimage oracle.
// The L2 block number is stored as a big-endian uint64 in the upper 8 bytes of the
// passed word.
oracle.loadLocalData(_ident, bytes32(l2BlockNumber() << 192), 8, _partOffset);
oracle.loadLocalData(
_ident,
bytes32(uint256(proposals[0].l2BlockNumber) << 192),
8,
_partOffset
);
} else if (_ident == 5) {
// Load the chain ID into the game's local context in the preimage oracle.
// The chain ID is stored as a big-endian uint64 in the upper 8 bytes of the
Expand Down Expand Up @@ -454,8 +455,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
// TODO(clabby): This is 2 calls too many for the information we need. Maybe
// add a function to the L2OO?
uint256 proposalIdx = L2_OUTPUT_ORACLE.getL2OutputIndexAfter(l2BlockNumber());
Types.OutputProposal memory starting = L2_OUTPUT_ORACLE.getL2Output(proposalIdx);
Types.OutputProposal memory disputed = L2_OUTPUT_ORACLE.getL2Output(proposalIdx + 1);
Types.OutputProposal memory starting = L2_OUTPUT_ORACLE.getL2Output(proposalIdx - 1);
Types.OutputProposal memory disputed = L2_OUTPUT_ORACLE.getL2Output(proposalIdx);
// SAFETY: This call can revert if the block hash oracle does not have information
// about the block number provided to it.
BlockOracle.BlockInfo memory blockInfo = BLOCK_ORACLE.load(l1BlockNumber());
Expand All @@ -467,10 +468,20 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
// estimation has room for error? This invariant cannot break.
if (Timestamp.unwrap(blockInfo.timestamp) < disputed.timestamp) revert L1HeadTooOld();

// Persist the output proposals fetched from the oracle.
// TODO(clabby): Docs on why we do this.
proposals[0] = starting;
proposals[1] = disputed;
// Persist the output proposals fetched from the oracle. These outputs will be referenced
// for loading local data into the preimage oracle as well as to authenticate the game's
// resolution. If the disputed output has changed in the oracle, the game cannot be
// resolved.
proposals[0] = OutputProposal({
index: uint128(proposalIdx - 1),
outputRoot: Hash.wrap(starting.outputRoot),
l2BlockNumber: starting.l2BlockNumber
});
proposals[1] = OutputProposal({
index: uint128(proposalIdx),
outputRoot: Hash.wrap(starting.outputRoot),
l2BlockNumber: starting.l2BlockNumber
});
// Persist the L1 head hash of the L1 block number provided.
l1Head = blockInfo.hash;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ interface IFaultDisputeGame is IDisputeGame {
Clock clock;
}

/// @notice The `OutputProposal` struct contains information about an output proposal in
/// the `L2OutputOracle` at a given index.
struct OutputProposal {
uint128 index;
uint128 l2BlockNumber;
Hash outputRoot;
}

/// @notice Emitted when a new claim is added to the DAG by `claimant`
/// @param parentIndex The index within the `claimData` array of the parent claim
/// @param claim The claim being added
Expand Down
7 changes: 5 additions & 2 deletions packages/contracts-bedrock/test/DisputeGameFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import { Test } from "forge-std/Test.sol";
import { DisputeGameFactory } from "../src/dispute/DisputeGameFactory.sol";
import { IDisputeGame } from "../src/dispute/interfaces/IDisputeGame.sol";
import { Proxy } from "../src/universal/Proxy.sol";
import { L2OutputOracle_Initializer } from "./CommonTest.t.sol";

contract DisputeGameFactory_Init is Test {
contract DisputeGameFactory_Init is L2OutputOracle_Initializer {
DisputeGameFactory factory;
FakeClone fakeClone;

Expand All @@ -21,7 +22,9 @@ contract DisputeGameFactory_Init is Test {

event ImplementationSet(address indexed impl, GameType indexed gameType);

function setUp() public virtual {
function setUp() public virtual override {
super.setUp();

Proxy proxy = new Proxy(address(this));
DisputeGameFactory impl = new DisputeGameFactory();

Expand Down
39 changes: 29 additions & 10 deletions packages/contracts-bedrock/test/FaultDisputeGame.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,60 @@ import { LibPosition } from "src/dispute/lib/LibPosition.sol";
import { IBigStepper, IPreimageOracle } from "src/dispute/interfaces/IBigStepper.sol";

contract FaultDisputeGame_Init is DisputeGameFactory_Init {
/// @dev The extra data passed to the game for initialization.
bytes internal constant EXTRA_DATA = abi.encode(1, 0);
/// @dev The type of the game being tested.
GameType internal constant GAME_TYPE = GameType.wrap(0);

/// @dev The implementation of the game.
FaultDisputeGame internal gameImpl;
/// @dev The `Clone` proxy of the game.
FaultDisputeGame internal gameProxy;
/// @dev The extra data passed to the game for initialization.
bytes internal extraData;

event Move(uint256 indexed parentIndex, Claim indexed pivot, address indexed claimant);

function init(Claim rootClaim, Claim absolutePrestate) public {
super.setUp();

// Advance the block number by 1.
vm.roll(block.number + 1);
// Set the time to a realistic date.
vm.warp(1690906994);

// Propose 2 mock outputs
vm.startPrank(oracle.PROPOSER());
for (uint256 i; i < 2; i++) {
oracle.proposeL2Output(
bytes32(i + 1),
oracle.nextBlockNumber(),
blockhash(i),
i
);

// Advance 1 block
vm.roll(block.number + 1);
vm.warp(block.timestamp + 13);
}
vm.stopPrank();

// Deploy a new block hash oracle and store the block hash for the genesis block.
BlockOracle blockOracle = new BlockOracle();
blockOracle.store(0);
blockOracle.store(block.number - 1);

// Set the extra data for the game creation
extraData = abi.encode(oracle.SUBMISSION_INTERVAL() * 2, block.number - 1);

// Deploy an implementation of the fault game
gameImpl = new FaultDisputeGame(
absolutePrestate,
4,
Duration.wrap(7 days),
new AlphabetVM(absolutePrestate),
L2OutputOracle(deployNoop()),
oracle,
blockOracle
);
// Register the game implementation with the factory.
factory.setImplementation(GAME_TYPE, gameImpl);
// Create a new game.
gameProxy = FaultDisputeGame(address(factory.create(GAME_TYPE, rootClaim, EXTRA_DATA)));
gameProxy = FaultDisputeGame(address(factory.create(GAME_TYPE, rootClaim, extraData)));

// Label the proxy
vm.label(address(gameProxy), "FaultDisputeGame_Clone");
Expand Down Expand Up @@ -78,7 +97,7 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {

/// @dev Tests that the game's extra data is set correctly.
function test_extraData_succeeds() public {
assertEq(gameProxy.extraData(), EXTRA_DATA);
assertEq(gameProxy.extraData(), extraData);
}

/// @dev Tests that the game's status is set correctly.
Expand All @@ -93,11 +112,11 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {

/// @dev Tests that the game's data is set correctly.
function test_gameData_succeeds() public {
(GameType gameType, Claim rootClaim, bytes memory extraData) = gameProxy.gameData();
(GameType gameType, Claim rootClaim, bytes memory _extraData) = gameProxy.gameData();

assertEq(GameType.unwrap(gameType), GameType.unwrap(GAME_TYPE));
assertEq(Claim.unwrap(rootClaim), Claim.unwrap(ROOT_CLAIM));
assertEq(extraData, EXTRA_DATA);
assertEq(_extraData, extraData);
}

////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit b7aa356

Please sign in to comment.