github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/dispute/FaultDisputeGame.t.sol (about)

     1  // SPDX-License-Identifier: MIT
     2  pragma solidity ^0.8.15;
     3  
     4  import { Test } from "forge-std/Test.sol";
     5  import { Vm } from "forge-std/Vm.sol";
     6  import { DisputeGameFactory_Init } from "test/dispute/DisputeGameFactory.t.sol";
     7  import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
     8  import { FaultDisputeGame } from "src/dispute/FaultDisputeGame.sol";
     9  import { DelayedWETH } from "src/dispute/weth/DelayedWETH.sol";
    10  import { PreimageOracle } from "src/cannon/PreimageOracle.sol";
    11  
    12  import "src/libraries/DisputeTypes.sol";
    13  import "src/libraries/DisputeErrors.sol";
    14  import { LibClock } from "src/dispute/lib/LibUDT.sol";
    15  import { LibPosition } from "src/dispute/lib/LibPosition.sol";
    16  import { IPreimageOracle } from "src/dispute/interfaces/IBigStepper.sol";
    17  import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol";
    18  import { AlphabetVM } from "test/mocks/AlphabetVM.sol";
    19  
    20  import { DisputeActor, HonestDisputeActor } from "test/actors/FaultDisputeActors.sol";
    21  
    22  contract FaultDisputeGame_Init is DisputeGameFactory_Init {
    23      /// @dev The type of the game being tested.
    24      GameType internal constant GAME_TYPE = GameType.wrap(0);
    25  
    26      /// @dev The implementation of the game.
    27      FaultDisputeGame internal gameImpl;
    28      /// @dev The `Clone` proxy of the game.
    29      FaultDisputeGame internal gameProxy;
    30  
    31      /// @dev The extra data passed to the game for initialization.
    32      bytes internal extraData;
    33  
    34      event Move(uint256 indexed parentIndex, Claim indexed pivot, address indexed claimant);
    35  
    36      function init(Claim rootClaim, Claim absolutePrestate, uint256 l2BlockNumber) public {
    37          // Set the time to a realistic date.
    38          vm.warp(1690906994);
    39  
    40          // Set the extra data for the game creation
    41          extraData = abi.encode(l2BlockNumber);
    42  
    43          AlphabetVM _vm = new AlphabetVM(absolutePrestate, new PreimageOracle(0, 0));
    44  
    45          // Deploy an implementation of the fault game
    46          gameImpl = new FaultDisputeGame({
    47              _gameType: GAME_TYPE,
    48              _absolutePrestate: absolutePrestate,
    49              _maxGameDepth: 2 ** 3,
    50              _splitDepth: 2 ** 2,
    51              _gameDuration: Duration.wrap(7 days),
    52              _vm: _vm,
    53              _weth: delayedWeth,
    54              _anchorStateRegistry: anchorStateRegistry,
    55              _l2ChainId: 10
    56          });
    57  
    58          // Register the game implementation with the factory.
    59          disputeGameFactory.setImplementation(GAME_TYPE, gameImpl);
    60          // Create a new game.
    61          gameProxy = FaultDisputeGame(payable(address(disputeGameFactory.create(GAME_TYPE, rootClaim, extraData))));
    62  
    63          // Check immutables
    64          assertEq(gameProxy.gameType().raw(), GAME_TYPE.raw());
    65          assertEq(gameProxy.absolutePrestate().raw(), absolutePrestate.raw());
    66          assertEq(gameProxy.maxGameDepth(), 2 ** 3);
    67          assertEq(gameProxy.splitDepth(), 2 ** 2);
    68          assertEq(gameProxy.gameDuration().raw(), 7 days);
    69          assertEq(address(gameProxy.vm()), address(_vm));
    70  
    71          // Label the proxy
    72          vm.label(address(gameProxy), "FaultDisputeGame_Clone");
    73      }
    74  
    75      fallback() external payable { }
    76  
    77      receive() external payable { }
    78  }
    79  
    80  contract FaultDisputeGame_Test is FaultDisputeGame_Init {
    81      /// @dev The root claim of the game.
    82      Claim internal constant ROOT_CLAIM = Claim.wrap(bytes32((uint256(1) << 248) | uint256(10)));
    83  
    84      /// @dev The preimage of the absolute prestate claim
    85      bytes internal absolutePrestateData;
    86      /// @dev The absolute prestate of the trace.
    87      Claim internal absolutePrestate;
    88  
    89      /// @dev Minimum bond value that covers all possible moves.
    90      uint256 internal constant MIN_BOND = 50 ether;
    91  
    92      function setUp() public override {
    93          absolutePrestateData = abi.encode(0);
    94          absolutePrestate = _changeClaimStatus(Claim.wrap(keccak256(absolutePrestateData)), VMStatuses.UNFINISHED);
    95  
    96          super.setUp();
    97          super.init({ rootClaim: ROOT_CLAIM, absolutePrestate: absolutePrestate, l2BlockNumber: 0x10 });
    98      }
    99  
   100      ////////////////////////////////////////////////////////////////
   101      //            `IDisputeGame` Implementation Tests             //
   102      ////////////////////////////////////////////////////////////////
   103  
   104      /// @dev Tests that the constructor of the `FaultDisputeGame` reverts when the `_splitDepth`
   105      ///      parameter is greater than or equal to the `MAX_GAME_DEPTH`
   106      function test_constructor_wrongArgs_reverts(uint256 _splitDepth) public {
   107          AlphabetVM alphabetVM = new AlphabetVM(absolutePrestate, new PreimageOracle(0, 0));
   108  
   109          // Test that the constructor reverts when the `_splitDepth` parameter is greater than or equal
   110          // to the `MAX_GAME_DEPTH` parameter.
   111          _splitDepth = bound(_splitDepth, 2 ** 3, type(uint256).max);
   112          vm.expectRevert(InvalidSplitDepth.selector);
   113          new FaultDisputeGame({
   114              _gameType: GAME_TYPE,
   115              _absolutePrestate: absolutePrestate,
   116              _maxGameDepth: 2 ** 3,
   117              _splitDepth: _splitDepth,
   118              _gameDuration: Duration.wrap(7 days),
   119              _vm: alphabetVM,
   120              _weth: DelayedWETH(payable(address(0))),
   121              _anchorStateRegistry: IAnchorStateRegistry(address(0)),
   122              _l2ChainId: 10
   123          });
   124      }
   125  
   126      /// @dev Tests that the game's root claim is set correctly.
   127      function test_rootClaim_succeeds() public {
   128          assertEq(gameProxy.rootClaim().raw(), ROOT_CLAIM.raw());
   129      }
   130  
   131      /// @dev Tests that the game's extra data is set correctly.
   132      function test_extraData_succeeds() public {
   133          assertEq(gameProxy.extraData(), extraData);
   134      }
   135  
   136      /// @dev Tests that the game's starting timestamp is set correctly.
   137      function test_createdAt_succeeds() public {
   138          assertEq(gameProxy.createdAt().raw(), block.timestamp);
   139      }
   140  
   141      /// @dev Tests that the game's type is set correctly.
   142      function test_gameType_succeeds() public {
   143          assertEq(gameProxy.gameType().raw(), GAME_TYPE.raw());
   144      }
   145  
   146      /// @dev Tests that the game's data is set correctly.
   147      function test_gameData_succeeds() public {
   148          (GameType gameType, Claim rootClaim, bytes memory _extraData) = gameProxy.gameData();
   149  
   150          assertEq(gameType.raw(), GAME_TYPE.raw());
   151          assertEq(rootClaim.raw(), ROOT_CLAIM.raw());
   152          assertEq(_extraData, extraData);
   153      }
   154  
   155      ////////////////////////////////////////////////////////////////
   156      //          `IFaultDisputeGame` Implementation Tests       //
   157      ////////////////////////////////////////////////////////////////
   158  
   159      /// @dev Tests that the game cannot be initialized with an output root that commits to <= the configured starting
   160      ///      block number
   161      function testFuzz_initialize_cannotProposeGenesis_reverts(uint256 _blockNumber) public {
   162          (, uint256 startingL2Block) = gameProxy.startingOutputRoot();
   163          _blockNumber = bound(_blockNumber, 0, startingL2Block);
   164  
   165          Claim claim = _dummyClaim();
   166          vm.expectRevert(abi.encodeWithSelector(UnexpectedRootClaim.selector, claim));
   167          gameProxy =
   168              FaultDisputeGame(payable(address(disputeGameFactory.create(GAME_TYPE, claim, abi.encode(_blockNumber)))));
   169      }
   170  
   171      /// @dev Tests that the proxy receives ETH from the dispute game factory.
   172      function test_initialize_receivesETH_succeeds(uint128 _value) public {
   173          _value = uint128(bound(_value, gameProxy.getRequiredBond(Position.wrap(1)), type(uint128).max));
   174          vm.deal(address(this), _value);
   175  
   176          assertEq(address(gameProxy).balance, 0);
   177          gameProxy = FaultDisputeGame(
   178              payable(address(disputeGameFactory.create{ value: _value }(GAME_TYPE, ROOT_CLAIM, abi.encode(1))))
   179          );
   180          assertEq(address(gameProxy).balance, 0);
   181          assertEq(delayedWeth.balanceOf(address(gameProxy)), _value);
   182      }
   183  
   184      /// @dev Tests that the game cannot be initialized with extra data > 64 bytes long (root claim + l2 block number
   185      ///      concatenated)
   186      function testFuzz_initialize_extraDataTooLong_reverts(uint256 _extraDataLen) public {
   187          // The `DisputeGameFactory` will pack the root claim and the extra data into a single array, which is enforced
   188          // to be at least 64 bytes long.
   189          // We bound the upper end to 23.5KB to ensure that the minimal proxy never surpasses the contract size limit
   190          // in this test, as CWIA proxies store the immutable args in their bytecode.
   191          // [33 bytes, 23.5 KB]
   192          _extraDataLen = bound(_extraDataLen, 33, 23_500);
   193          bytes memory _extraData = new bytes(_extraDataLen);
   194  
   195          // Assign the first 32 bytes in `extraData` to a valid L2 block number passed the starting block.
   196          (, uint256 startingL2Block) = gameProxy.startingOutputRoot();
   197          assembly {
   198              mstore(add(_extraData, 0x20), add(startingL2Block, 1))
   199          }
   200  
   201          Claim claim = _dummyClaim();
   202          vm.expectRevert(abi.encodeWithSelector(ExtraDataTooLong.selector));
   203          gameProxy = FaultDisputeGame(payable(address(disputeGameFactory.create(GAME_TYPE, claim, _extraData))));
   204      }
   205  
   206      /// @dev Tests that the game is initialized with the correct data.
   207      function test_initialize_correctData_succeeds() public {
   208          // Assert that the root claim is initialized correctly.
   209          (
   210              uint32 parentIndex,
   211              address counteredBy,
   212              address claimant,
   213              uint128 bond,
   214              Claim claim,
   215              Position position,
   216              Clock clock
   217          ) = gameProxy.claimData(0);
   218          assertEq(parentIndex, type(uint32).max);
   219          assertEq(counteredBy, address(0));
   220          assertEq(claimant, DEFAULT_SENDER);
   221          assertEq(bond, 0);
   222          assertEq(claim.raw(), ROOT_CLAIM.raw());
   223          assertEq(position.raw(), 1);
   224          assertEq(clock.raw(), LibClock.wrap(Duration.wrap(0), Timestamp.wrap(uint64(block.timestamp))).raw());
   225  
   226          // Assert that the `createdAt` timestamp is correct.
   227          assertEq(gameProxy.createdAt().raw(), block.timestamp);
   228  
   229          // Assert that the blockhash provided is correct.
   230          assertEq(gameProxy.l1Head().raw(), blockhash(block.number - 1));
   231      }
   232  
   233      /// @dev Tests that the game cannot be initialized twice.
   234      function test_initialize_onlyOnce_succeeds() public {
   235          vm.expectRevert(AlreadyInitialized.selector);
   236          gameProxy.initialize();
   237      }
   238  
   239      /// @dev Tests that the bond during the bisection game depths is correct.
   240      function test_getRequiredBond_succeeds() public {
   241          for (uint64 i = 0; i < uint64(gameProxy.splitDepth()); i++) {
   242              Position pos = LibPosition.wrap(i, 0);
   243              uint256 bond = gameProxy.getRequiredBond(pos);
   244  
   245              // Reasonable approximation for a max depth of 8.
   246              uint256 expected = 0.08 ether;
   247              for (uint64 j = 0; j < i; j++) {
   248                  expected = expected * 217456;
   249                  expected = expected / 100000;
   250              }
   251  
   252              assertApproxEqAbs(bond, expected, 0.01 ether);
   253          }
   254      }
   255  
   256      /// @dev Tests that the bond at a depth greater than the maximum game depth reverts.
   257      function test_getRequiredBond_outOfBounds_reverts() public {
   258          Position pos = LibPosition.wrap(uint64(gameProxy.maxGameDepth() + 1), 0);
   259          vm.expectRevert(GameDepthExceeded.selector);
   260          gameProxy.getRequiredBond(pos);
   261      }
   262  
   263      /// @dev Tests that a move while the game status is not `IN_PROGRESS` causes the call to revert
   264      ///      with the `GameNotInProgress` error
   265      function test_move_gameNotInProgress_reverts() public {
   266          uint256 chalWins = uint256(GameStatus.CHALLENGER_WINS);
   267  
   268          // Replace the game status in storage. It exists in slot 0 at offset 16.
   269          uint256 slot = uint256(vm.load(address(gameProxy), bytes32(0)));
   270          uint256 offset = 16 << 3;
   271          uint256 mask = 0xFF << offset;
   272          // Replace the byte in the slot value with the challenger wins status.
   273          slot = (slot & ~mask) | (chalWins << offset);
   274          vm.store(address(gameProxy), bytes32(0), bytes32(slot));
   275  
   276          // Ensure that the game status was properly updated.
   277          GameStatus status = gameProxy.status();
   278          assertEq(uint256(status), chalWins);
   279  
   280          // Attempt to make a move. Should revert.
   281          vm.expectRevert(GameNotInProgress.selector);
   282          gameProxy.attack(0, Claim.wrap(0));
   283      }
   284  
   285      /// @dev Tests that an attempt to defend the root claim reverts with the `CannotDefendRootClaim` error.
   286      function test_move_defendRoot_reverts() public {
   287          vm.expectRevert(CannotDefendRootClaim.selector);
   288          gameProxy.defend(0, _dummyClaim());
   289      }
   290  
   291      /// @dev Tests that an attempt to move against a claim that does not exist reverts with the
   292      ///      `ParentDoesNotExist` error.
   293      function test_move_nonExistentParent_reverts() public {
   294          Claim claim = _dummyClaim();
   295  
   296          // Expect an out of bounds revert for an attack
   297          vm.expectRevert(abi.encodeWithSignature("Panic(uint256)", 0x32));
   298          gameProxy.attack(1, claim);
   299  
   300          // Expect an out of bounds revert for a defense
   301          vm.expectRevert(abi.encodeWithSignature("Panic(uint256)", 0x32));
   302          gameProxy.defend(1, claim);
   303      }
   304  
   305      /// @dev Tests that an attempt to move at the maximum game depth reverts with the
   306      ///      `GameDepthExceeded` error.
   307      function test_move_gameDepthExceeded_reverts() public {
   308          Claim claim = _changeClaimStatus(_dummyClaim(), VMStatuses.PANIC);
   309  
   310          uint256 maxDepth = gameProxy.maxGameDepth();
   311  
   312          for (uint256 i = 0; i <= maxDepth; i++) {
   313              // At the max game depth, the `_move` function should revert with
   314              // the `GameDepthExceeded` error.
   315              if (i == maxDepth) {
   316                  vm.expectRevert(GameDepthExceeded.selector);
   317              }
   318              gameProxy.attack{ value: MIN_BOND }(i, claim);
   319          }
   320      }
   321  
   322      /// @dev Tests that a move made after the clock time has exceeded reverts with the
   323      ///      `ClockTimeExceeded` error.
   324      function test_move_clockTimeExceeded_reverts() public {
   325          // Warp ahead past the clock time for the first move (3 1/2 days)
   326          vm.warp(block.timestamp + 3 days + 12 hours + 1);
   327          vm.expectRevert(ClockTimeExceeded.selector);
   328          gameProxy.attack{ value: MIN_BOND }(0, _dummyClaim());
   329      }
   330  
   331      /// @notice Static unit test for the correctness of the chess clock incrementation.
   332      function test_move_clockCorrectness_succeeds() public {
   333          (,,,,,, Clock clock) = gameProxy.claimData(0);
   334          assertEq(clock.raw(), LibClock.wrap(Duration.wrap(0), Timestamp.wrap(uint64(block.timestamp))).raw());
   335  
   336          Claim claim = _dummyClaim();
   337  
   338          vm.warp(block.timestamp + 15);
   339          gameProxy.attack{ value: MIN_BOND }(0, claim);
   340          (,,,,,, clock) = gameProxy.claimData(1);
   341          assertEq(clock.raw(), LibClock.wrap(Duration.wrap(15), Timestamp.wrap(uint64(block.timestamp))).raw());
   342  
   343          vm.warp(block.timestamp + 10);
   344          gameProxy.attack{ value: MIN_BOND }(1, claim);
   345          (,,,,,, clock) = gameProxy.claimData(2);
   346          assertEq(clock.raw(), LibClock.wrap(Duration.wrap(10), Timestamp.wrap(uint64(block.timestamp))).raw());
   347  
   348          // We are at the split depth, so we need to set the status byte of the claim
   349          // for the next move.
   350          claim = _changeClaimStatus(claim, VMStatuses.PANIC);
   351  
   352          vm.warp(block.timestamp + 10);
   353          gameProxy.attack{ value: MIN_BOND }(2, claim);
   354          (,,,,,, clock) = gameProxy.claimData(3);
   355          assertEq(clock.raw(), LibClock.wrap(Duration.wrap(25), Timestamp.wrap(uint64(block.timestamp))).raw());
   356  
   357          vm.warp(block.timestamp + 10);
   358          gameProxy.attack{ value: MIN_BOND }(3, claim);
   359          (,,,,,, clock) = gameProxy.claimData(4);
   360          assertEq(clock.raw(), LibClock.wrap(Duration.wrap(20), Timestamp.wrap(uint64(block.timestamp))).raw());
   361      }
   362  
   363      /// @dev Tests that an identical claim cannot be made twice. The duplicate claim attempt should
   364      ///      revert with the `ClaimAlreadyExists` error.
   365      function test_move_duplicateClaim_reverts() public {
   366          Claim claim = _dummyClaim();
   367  
   368          // Make the first move. This should succeed.
   369          gameProxy.attack{ value: MIN_BOND }(0, claim);
   370  
   371          // Attempt to make the same move again.
   372          vm.expectRevert(ClaimAlreadyExists.selector);
   373          gameProxy.attack{ value: MIN_BOND }(0, claim);
   374      }
   375  
   376      /// @dev Static unit test asserting that identical claims at the same position can be made in different subgames.
   377      function test_move_duplicateClaimsDifferentSubgames_succeeds() public {
   378          Claim claimA = _dummyClaim();
   379          Claim claimB = _dummyClaim();
   380  
   381          // Make the first moves. This should succeed.
   382          gameProxy.attack{ value: MIN_BOND }(0, claimA);
   383          gameProxy.attack{ value: MIN_BOND }(0, claimB);
   384  
   385          // Perform an attack at the same position with the same claim value in both subgames.
   386          // These both should succeed.
   387          gameProxy.attack{ value: MIN_BOND }(1, claimA);
   388          gameProxy.attack{ value: MIN_BOND }(2, claimA);
   389      }
   390  
   391      /// @dev Static unit test for the correctness of an opening attack.
   392      function test_move_simpleAttack_succeeds() public {
   393          // Warp ahead 5 seconds.
   394          vm.warp(block.timestamp + 5);
   395  
   396          Claim counter = _dummyClaim();
   397  
   398          // Perform the attack.
   399          vm.expectEmit(true, true, true, false);
   400          emit Move(0, counter, address(this));
   401          gameProxy.attack{ value: MIN_BOND }(0, counter);
   402  
   403          // Grab the claim data of the attack.
   404          (
   405              uint32 parentIndex,
   406              address counteredBy,
   407              address claimant,
   408              uint128 bond,
   409              Claim claim,
   410              Position position,
   411              Clock clock
   412          ) = gameProxy.claimData(1);
   413  
   414          // Assert correctness of the attack claim's data.
   415          assertEq(parentIndex, 0);
   416          assertEq(counteredBy, address(0));
   417          assertEq(claimant, address(this));
   418          assertEq(bond, MIN_BOND);
   419          assertEq(claim.raw(), counter.raw());
   420          assertEq(position.raw(), Position.wrap(1).move(true).raw());
   421          assertEq(clock.raw(), LibClock.wrap(Duration.wrap(5), Timestamp.wrap(uint64(block.timestamp))).raw());
   422  
   423          // Grab the claim data of the parent.
   424          (parentIndex, counteredBy, claimant, bond, claim, position, clock) = gameProxy.claimData(0);
   425  
   426          // Assert correctness of the parent claim's data.
   427          assertEq(parentIndex, type(uint32).max);
   428          assertEq(counteredBy, address(0));
   429          assertEq(claimant, DEFAULT_SENDER);
   430          assertEq(bond, 0);
   431          assertEq(claim.raw(), ROOT_CLAIM.raw());
   432          assertEq(position.raw(), 1);
   433          assertEq(clock.raw(), LibClock.wrap(Duration.wrap(0), Timestamp.wrap(uint64(block.timestamp - 5))).raw());
   434      }
   435  
   436      /// @dev Tests that making a claim at the execution trace bisection root level with an invalid status
   437      ///      byte reverts with the `UnexpectedRootClaim` error.
   438      function test_move_incorrectStatusExecRoot_reverts() public {
   439          for (uint256 i; i < 4; i++) {
   440              gameProxy.attack{ value: MIN_BOND }(i, _dummyClaim());
   441          }
   442  
   443          vm.expectRevert(abi.encodeWithSelector(UnexpectedRootClaim.selector, bytes32(0)));
   444          gameProxy.attack{ value: MIN_BOND }(4, Claim.wrap(bytes32(0)));
   445      }
   446  
   447      /// @dev Tests that making a claim at the execution trace bisection root level with a valid status
   448      ///      byte succeeds.
   449      function test_move_correctStatusExecRoot_succeeds() public {
   450          for (uint256 i; i < 4; i++) {
   451              gameProxy.attack{ value: MIN_BOND }(i, _dummyClaim());
   452          }
   453          gameProxy.attack{ value: MIN_BOND }(4, _changeClaimStatus(_dummyClaim(), VMStatuses.PANIC));
   454      }
   455  
   456      /// @dev Static unit test asserting that a move reverts when the bond is insufficient.
   457      function test_move_insufficientBond_reverts() public {
   458          vm.expectRevert(InsufficientBond.selector);
   459          gameProxy.attack{ value: 0 }(0, _dummyClaim());
   460      }
   461  
   462      /// @dev Tests that a claim cannot be stepped against twice.
   463      function test_step_duplicateStep_reverts() public {
   464          // Give the test contract some ether
   465          vm.deal(address(this), 1000 ether);
   466  
   467          // Make claims all the way down the tree.
   468          gameProxy.attack{ value: MIN_BOND }(0, _dummyClaim());
   469          gameProxy.attack{ value: MIN_BOND }(1, _dummyClaim());
   470          gameProxy.attack{ value: MIN_BOND }(2, _dummyClaim());
   471          gameProxy.attack{ value: MIN_BOND }(3, _dummyClaim());
   472          gameProxy.attack{ value: MIN_BOND }(4, _changeClaimStatus(_dummyClaim(), VMStatuses.PANIC));
   473          gameProxy.attack{ value: MIN_BOND }(5, _dummyClaim());
   474          gameProxy.attack{ value: MIN_BOND }(6, _dummyClaim());
   475          gameProxy.attack{ value: MIN_BOND }(7, _dummyClaim());
   476          gameProxy.addLocalData(LocalPreimageKey.DISPUTED_L2_BLOCK_NUMBER, 8, 0);
   477          gameProxy.step(8, true, absolutePrestateData, hex"");
   478  
   479          vm.expectRevert(DuplicateStep.selector);
   480          gameProxy.step(8, true, absolutePrestateData, hex"");
   481      }
   482  
   483      /// @dev Static unit test for the correctness an uncontested root resolution.
   484      function test_resolve_rootUncontested_succeeds() public {
   485          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   486          gameProxy.resolveClaim(0);
   487          assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.DEFENDER_WINS));
   488      }
   489  
   490      /// @dev Static unit test for the correctness an uncontested root resolution.
   491      function test_resolve_rootUncontestedClockNotExpired_succeeds() public {
   492          vm.warp(block.timestamp + 3 days + 12 hours);
   493          vm.expectRevert(ClockNotExpired.selector);
   494          gameProxy.resolveClaim(0);
   495      }
   496  
   497      /// @dev Static unit test asserting that resolve reverts when the absolute root
   498      ///      subgame has not been resolved.
   499      function test_resolve_rootUncontestedButUnresolved_reverts() public {
   500          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   501          vm.expectRevert(OutOfOrderResolution.selector);
   502          gameProxy.resolve();
   503      }
   504  
   505      /// @dev Static unit test asserting that resolve reverts when the game state is
   506      ///      not in progress.
   507      function test_resolve_notInProgress_reverts() public {
   508          uint256 chalWins = uint256(GameStatus.CHALLENGER_WINS);
   509  
   510          // Replace the game status in storage. It exists in slot 0 at offset 16.
   511          uint256 slot = uint256(vm.load(address(gameProxy), bytes32(0)));
   512          uint256 offset = 16 << 3;
   513          uint256 mask = 0xFF << offset;
   514          // Replace the byte in the slot value with the challenger wins status.
   515          slot = (slot & ~mask) | (chalWins << offset);
   516  
   517          vm.store(address(gameProxy), bytes32(uint256(0)), bytes32(slot));
   518          vm.expectRevert(GameNotInProgress.selector);
   519          gameProxy.resolveClaim(0);
   520      }
   521  
   522      /// @dev Static unit test for the correctness of resolving a single attack game state.
   523      function test_resolve_rootContested_succeeds() public {
   524          gameProxy.attack{ value: MIN_BOND }(0, _dummyClaim());
   525  
   526          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   527  
   528          gameProxy.resolveClaim(0);
   529          assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.CHALLENGER_WINS));
   530      }
   531  
   532      /// @dev Static unit test for the correctness of resolving a game with a contested challenge claim.
   533      function test_resolve_challengeContested_succeeds() public {
   534          gameProxy.attack{ value: MIN_BOND }(0, _dummyClaim());
   535          gameProxy.defend{ value: MIN_BOND }(1, _dummyClaim());
   536  
   537          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   538  
   539          gameProxy.resolveClaim(1);
   540          gameProxy.resolveClaim(0);
   541          assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.DEFENDER_WINS));
   542      }
   543  
   544      /// @dev Static unit test for the correctness of resolving a game with multiplayer moves.
   545      function test_resolve_teamDeathmatch_succeeds() public {
   546          gameProxy.attack{ value: MIN_BOND }(0, _dummyClaim());
   547          gameProxy.attack{ value: MIN_BOND }(0, _dummyClaim());
   548          gameProxy.defend{ value: MIN_BOND }(1, _dummyClaim());
   549          gameProxy.defend{ value: MIN_BOND }(1, _dummyClaim());
   550  
   551          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   552  
   553          gameProxy.resolveClaim(1);
   554          gameProxy.resolveClaim(0);
   555          assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.CHALLENGER_WINS));
   556      }
   557  
   558      /// @dev Static unit test for the correctness of resolving a game that reaches max game depth.
   559      function test_resolve_stepReached_succeeds() public {
   560          Claim claim = _dummyClaim();
   561          for (uint256 i; i < gameProxy.splitDepth(); i++) {
   562              gameProxy.attack{ value: MIN_BOND }(i, claim);
   563          }
   564  
   565          claim = _changeClaimStatus(claim, VMStatuses.PANIC);
   566          for (uint256 i = gameProxy.claimDataLen() - 1; i < gameProxy.maxGameDepth(); i++) {
   567              gameProxy.attack{ value: MIN_BOND }(i, claim);
   568          }
   569  
   570          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   571  
   572          // resolving claim at 8 isn't necessary
   573          for (uint256 i = 8; i > 0; i--) {
   574              gameProxy.resolveClaim(i - 1);
   575          }
   576          assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.DEFENDER_WINS));
   577      }
   578  
   579      /// @dev Static unit test asserting that resolve reverts when attempting to resolve a subgame multiple times
   580      function test_resolve_claimAlreadyResolved_reverts() public {
   581          vm.deal(address(this), 2 * MIN_BOND);
   582  
   583          Claim claim = _dummyClaim();
   584          gameProxy.attack{ value: MIN_BOND }(0, claim);
   585          gameProxy.attack{ value: MIN_BOND }(1, claim);
   586  
   587          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   588  
   589          assertEq(address(this).balance, 0);
   590          gameProxy.resolveClaim(1);
   591  
   592          // Wait for the withdrawal delay.
   593          vm.warp(block.timestamp + delayedWeth.delay() + 1 seconds);
   594  
   595          gameProxy.claimCredit(address(this));
   596          assertEq(address(this).balance, MIN_BOND);
   597  
   598          vm.expectRevert(ClaimAlreadyResolved.selector);
   599          gameProxy.resolveClaim(1);
   600          assertEq(address(this).balance, MIN_BOND);
   601      }
   602  
   603      /// @dev Static unit test asserting that resolve reverts when attempting to resolve a subgame at max depth
   604      function test_resolve_claimAtMaxDepthAlreadyResolved_reverts() public {
   605          Claim claim = _dummyClaim();
   606          for (uint256 i; i < gameProxy.splitDepth(); i++) {
   607              gameProxy.attack{ value: MIN_BOND }(i, claim);
   608          }
   609  
   610          vm.deal(address(this), 10000 ether);
   611          claim = _changeClaimStatus(claim, VMStatuses.PANIC);
   612          for (uint256 i = gameProxy.claimDataLen() - 1; i < gameProxy.maxGameDepth(); i++) {
   613              gameProxy.attack{ value: MIN_BOND }(i, claim);
   614          }
   615  
   616          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   617  
   618          // Resolve to claim bond
   619          uint256 balanceBefore = address(this).balance;
   620          gameProxy.resolveClaim(8);
   621  
   622          // Wait for the withdrawal delay.
   623          vm.warp(block.timestamp + delayedWeth.delay() + 1 seconds);
   624  
   625          gameProxy.claimCredit(address(this));
   626          assertEq(address(this).balance, balanceBefore + MIN_BOND);
   627  
   628          vm.expectRevert(ClaimAlreadyResolved.selector);
   629          gameProxy.resolveClaim(8);
   630      }
   631  
   632      /// @dev Static unit test asserting that resolve reverts when attempting to resolve subgames out of order
   633      function test_resolve_outOfOrderResolution_reverts() public {
   634          gameProxy.attack{ value: MIN_BOND }(0, _dummyClaim());
   635          gameProxy.attack{ value: MIN_BOND }(1, _dummyClaim());
   636  
   637          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   638  
   639          vm.expectRevert(OutOfOrderResolution.selector);
   640          gameProxy.resolveClaim(0);
   641      }
   642  
   643      /// @dev Static unit test asserting that resolve pays out bonds on step, output bisection, and execution trace
   644      /// moves.
   645      function test_resolve_bondPayouts_succeeds() public {
   646          // Give the test contract some ether
   647          uint256 bal = 1000 ether;
   648          vm.deal(address(this), bal);
   649  
   650          // Make claims all the way down the tree.
   651          gameProxy.attack{ value: MIN_BOND }(0, _dummyClaim());
   652          gameProxy.attack{ value: MIN_BOND }(1, _dummyClaim());
   653          gameProxy.attack{ value: MIN_BOND }(2, _dummyClaim());
   654          gameProxy.attack{ value: MIN_BOND }(3, _dummyClaim());
   655          gameProxy.attack{ value: MIN_BOND }(4, _changeClaimStatus(_dummyClaim(), VMStatuses.PANIC));
   656          gameProxy.attack{ value: MIN_BOND }(5, _dummyClaim());
   657          gameProxy.attack{ value: MIN_BOND }(6, _dummyClaim());
   658          gameProxy.attack{ value: MIN_BOND }(7, _dummyClaim());
   659          gameProxy.addLocalData(LocalPreimageKey.DISPUTED_L2_BLOCK_NUMBER, 8, 0);
   660          gameProxy.step(8, true, absolutePrestateData, hex"");
   661  
   662          // Ensure that the step successfully countered the leaf claim.
   663          (, address counteredBy,,,,,) = gameProxy.claimData(8);
   664          assertEq(counteredBy, address(this));
   665  
   666          // Ensure we bonded the correct amounts
   667          uint256 bonded = (gameProxy.claimDataLen() - 1) * MIN_BOND;
   668          assertEq(address(this).balance, bal - bonded);
   669          assertEq(address(gameProxy).balance, 0);
   670          assertEq(delayedWeth.balanceOf(address(gameProxy)), bonded);
   671  
   672          // Resolve all claims
   673          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   674          for (uint256 i = gameProxy.claimDataLen(); i > 0; i--) {
   675              (bool success,) = address(gameProxy).call(abi.encodeCall(gameProxy.resolveClaim, (i - 1)));
   676              assertTrue(success);
   677          }
   678          gameProxy.resolve();
   679  
   680          // Wait for the withdrawal delay.
   681          vm.warp(block.timestamp + delayedWeth.delay() + 1 seconds);
   682  
   683          gameProxy.claimCredit(address(this));
   684  
   685          // Ensure that bonds were paid out correctly.
   686          assertEq(address(this).balance, bal);
   687          assertEq(address(gameProxy).balance, 0);
   688          assertEq(delayedWeth.balanceOf(address(gameProxy)), 0);
   689  
   690          // Ensure that the init bond for the game is 0, in case we change it in the test suite in the future.
   691          assertEq(disputeGameFactory.initBonds(GAME_TYPE), 0);
   692      }
   693  
   694      /// @dev Static unit test asserting that resolve pays out bonds on step, output bisection, and execution trace
   695      /// moves with 2 actors and a dishonest root claim.
   696      function test_resolve_bondPayoutsSeveralActors_succeeds() public {
   697          // Give the test contract and bob some ether
   698          uint256 bal = 1000 ether;
   699          address bob = address(0xb0b);
   700          vm.deal(address(this), bal);
   701          vm.deal(bob, bal);
   702  
   703          // Make claims all the way down the tree, trading off between bob and the test contract.
   704          gameProxy.attack{ value: MIN_BOND }(0, _dummyClaim());
   705  
   706          vm.prank(bob);
   707          gameProxy.attack{ value: MIN_BOND }(1, _dummyClaim());
   708  
   709          gameProxy.attack{ value: MIN_BOND }(2, _dummyClaim());
   710  
   711          vm.prank(bob);
   712          gameProxy.attack{ value: MIN_BOND }(3, _dummyClaim());
   713  
   714          gameProxy.attack{ value: MIN_BOND }(4, _changeClaimStatus(_dummyClaim(), VMStatuses.PANIC));
   715  
   716          vm.prank(bob);
   717          gameProxy.attack{ value: MIN_BOND }(5, _dummyClaim());
   718  
   719          gameProxy.attack{ value: MIN_BOND }(6, _dummyClaim());
   720  
   721          vm.prank(bob);
   722          gameProxy.attack{ value: MIN_BOND }(7, _dummyClaim());
   723  
   724          gameProxy.addLocalData(LocalPreimageKey.DISPUTED_L2_BLOCK_NUMBER, 8, 0);
   725          gameProxy.step(8, true, absolutePrestateData, hex"");
   726  
   727          // Ensure that the step successfully countered the leaf claim.
   728          (, address counteredBy,,,,,) = gameProxy.claimData(8);
   729          assertEq(counteredBy, address(this));
   730  
   731          // Ensure we bonded the correct amounts
   732          uint256 bonded = ((gameProxy.claimDataLen() - 1) / 2) * MIN_BOND;
   733          assertEq(address(this).balance, bal - bonded);
   734          assertEq(bob.balance, bal - bonded);
   735          assertEq(address(gameProxy).balance, 0);
   736          assertEq(delayedWeth.balanceOf(address(gameProxy)), bonded * 2);
   737  
   738          // Resolve all claims
   739          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   740          for (uint256 i = gameProxy.claimDataLen(); i > 0; i--) {
   741              (bool success,) = address(gameProxy).call(abi.encodeCall(gameProxy.resolveClaim, (i - 1)));
   742              assertTrue(success);
   743          }
   744          gameProxy.resolve();
   745  
   746          // Wait for the withdrawal delay.
   747          vm.warp(block.timestamp + delayedWeth.delay() + 1 seconds);
   748  
   749          gameProxy.claimCredit(address(this));
   750  
   751          // Bob's claim should revert since it's value is 0
   752          vm.expectRevert(NoCreditToClaim.selector);
   753          gameProxy.claimCredit(bob);
   754  
   755          // Ensure that bonds were paid out correctly.
   756          assertEq(address(this).balance, bal + bonded);
   757          assertEq(bob.balance, bal - bonded);
   758          assertEq(address(gameProxy).balance, 0);
   759          assertEq(delayedWeth.balanceOf(address(gameProxy)), 0);
   760  
   761          // Ensure that the init bond for the game is 0, in case we change it in the test suite in the future.
   762          assertEq(disputeGameFactory.initBonds(GAME_TYPE), 0);
   763      }
   764  
   765      /// @dev Static unit test asserting that resolve pays out bonds on moves to the leftmost actor
   766      /// in subgames containing successful counters.
   767      function test_resolve_leftmostBondPayout_succeeds() public {
   768          uint256 bal = 1000 ether;
   769          address alice = address(0xa11ce);
   770          address bob = address(0xb0b);
   771          address charlie = address(0xc0c);
   772          vm.deal(address(this), bal);
   773          vm.deal(alice, bal);
   774          vm.deal(bob, bal);
   775          vm.deal(charlie, bal);
   776  
   777          // Make claims with bob, charlie and the test contract on defense, and alice as the challenger
   778          // charlie is successfully countered by alice
   779          // alice is successfully countered by both bob and the test contract
   780          vm.prank(alice);
   781          gameProxy.attack{ value: MIN_BOND }(0, _dummyClaim());
   782  
   783          vm.prank(bob);
   784          gameProxy.defend{ value: MIN_BOND }(1, _dummyClaim());
   785          vm.prank(charlie);
   786          gameProxy.attack{ value: MIN_BOND }(1, _dummyClaim());
   787          gameProxy.attack{ value: MIN_BOND }(1, _dummyClaim());
   788  
   789          vm.prank(alice);
   790          gameProxy.attack{ value: MIN_BOND }(3, _dummyClaim());
   791  
   792          // Resolve all claims
   793          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   794          for (uint256 i = gameProxy.claimDataLen(); i > 0; i--) {
   795              (bool success,) = address(gameProxy).call(abi.encodeCall(gameProxy.resolveClaim, (i - 1)));
   796              assertTrue(success);
   797          }
   798          gameProxy.resolve();
   799  
   800          // Wait for the withdrawal delay.
   801          vm.warp(block.timestamp + delayedWeth.delay() + 1 seconds);
   802  
   803          gameProxy.claimCredit(address(this));
   804          gameProxy.claimCredit(alice);
   805          gameProxy.claimCredit(bob);
   806  
   807          // Charlie's claim should revert since it's value is 0
   808          vm.expectRevert(NoCreditToClaim.selector);
   809          gameProxy.claimCredit(charlie);
   810  
   811          // Ensure that bonds were paid out correctly.
   812          uint256 aliceLosses = MIN_BOND;
   813          uint256 charlieLosses = MIN_BOND;
   814          assertEq(address(this).balance, bal + aliceLosses, "incorrect this balance");
   815          assertEq(alice.balance, bal - aliceLosses + charlieLosses, "incorrect alice balance");
   816          assertEq(bob.balance, bal, "incorrect bob balance");
   817          assertEq(charlie.balance, bal - charlieLosses, "incorrect charlie balance");
   818          assertEq(address(gameProxy).balance, 0);
   819  
   820          // Ensure that the init bond for the game is 0, in case we change it in the test suite in the future.
   821          assertEq(disputeGameFactory.initBonds(GAME_TYPE), 0);
   822      }
   823  
   824      /// @dev Static unit test asserting that the anchor state updates when the game resolves in
   825      /// favor of the defender and the anchor state is older than the game state.
   826      function test_resolve_validNewerStateUpdatesAnchor_succeeds() public {
   827          // Confirm that the anchor state is older than the game state.
   828          (Hash root, uint256 l2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType());
   829          assert(l2BlockNumber < gameProxy.l2BlockNumber());
   830  
   831          // Resolve the game.
   832          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   833          gameProxy.resolveClaim(0);
   834          assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.DEFENDER_WINS));
   835  
   836          // Confirm that the anchor state is now the same as the game state.
   837          (root, l2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType());
   838          assertEq(l2BlockNumber, gameProxy.l2BlockNumber());
   839          assertEq(root.raw(), gameProxy.rootClaim().raw());
   840      }
   841  
   842      /// @dev Static unit test asserting that the anchor state does not change when the game
   843      /// resolves in favor of the defender but the game state is not newer than the anchor state.
   844      function test_resolve_validOlderStateSameAnchor_succeeds() public {
   845          // Mock the game block to be older than the game state.
   846          vm.mockCall(address(gameProxy), abi.encodeWithSelector(gameProxy.l2BlockNumber.selector), abi.encode(0));
   847  
   848          // Confirm that the anchor state is newer than the game state.
   849          (Hash root, uint256 l2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType());
   850          assert(l2BlockNumber >= gameProxy.l2BlockNumber());
   851  
   852          // Resolve the game.
   853          vm.mockCall(address(gameProxy), abi.encodeWithSelector(gameProxy.l2BlockNumber.selector), abi.encode(0));
   854          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   855          gameProxy.resolveClaim(0);
   856          assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.DEFENDER_WINS));
   857  
   858          // Confirm that the anchor state is the same as the initial anchor state.
   859          (Hash updatedRoot, uint256 updatedL2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType());
   860          assertEq(updatedL2BlockNumber, l2BlockNumber);
   861          assertEq(updatedRoot.raw(), root.raw());
   862      }
   863  
   864      /// @dev Static unit test asserting that the anchor state does not change when the game
   865      /// resolves in favor of the challenger, even if the game state is newer than the anchor.
   866      function test_resolve_invalidStateSameAnchor_succeeds() public {
   867          // Confirm that the anchor state is older than the game state.
   868          (Hash root, uint256 l2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType());
   869          assert(l2BlockNumber < gameProxy.l2BlockNumber());
   870  
   871          // Challenge the claim and resolve it.
   872          gameProxy.attack{ value: MIN_BOND }(0, _dummyClaim());
   873          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   874          gameProxy.resolveClaim(0);
   875          assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.CHALLENGER_WINS));
   876  
   877          // Confirm that the anchor state is the same as the initial anchor state.
   878          (Hash updatedRoot, uint256 updatedL2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType());
   879          assertEq(updatedL2BlockNumber, l2BlockNumber);
   880          assertEq(updatedRoot.raw(), root.raw());
   881      }
   882  
   883      /// @dev Static unit test asserting that credit may not be drained past allowance through reentrancy.
   884      function test_claimCredit_claimAlreadyResolved_reverts() public {
   885          ClaimCreditReenter reenter = new ClaimCreditReenter(gameProxy, vm);
   886          vm.startPrank(address(reenter));
   887  
   888          // Give the test contract some ether to bond.
   889          vm.deal(address(reenter), MIN_BOND * 2);
   890          // Give the game proxy 1 extra ether, unregistered.
   891          vm.deal(address(gameProxy), 1 ether);
   892  
   893          // Perform a bonded move.
   894          Claim claim = _dummyClaim();
   895          gameProxy.attack{ value: MIN_BOND }(0, claim);
   896          gameProxy.attack{ value: MIN_BOND }(1, claim);
   897  
   898          // Warp past the finalization period
   899          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
   900  
   901          // Ensure that we bonded all the test contract's ETH
   902          assertEq(address(reenter).balance, 0);
   903          // Ensure the game proxy has 1 ether in it.
   904          assertEq(address(gameProxy).balance, 1 ether);
   905          // Ensure the game has a balance of 2 * MIN_BOND in the delayedWeth contract.
   906          assertEq(delayedWeth.balanceOf(address(gameProxy)), MIN_BOND * 2);
   907  
   908          // Resolve the claim at gindex 1 and claim the reenter contract's credit.
   909          gameProxy.resolveClaim(1);
   910  
   911          // Ensure that the game registered the `reenter` contract's credit.
   912          assertEq(gameProxy.credit(address(reenter)), MIN_BOND);
   913  
   914          // Wait for the withdrawal delay.
   915          vm.warp(block.timestamp + delayedWeth.delay() + 1 seconds);
   916  
   917          // Initiate the reentrant credit claim.
   918          reenter.claimCredit(address(reenter));
   919  
   920          // The reenter contract should have performed 2 calls to `claimCredit`.
   921          // Once all the credit is claimed, all subsequent calls will revert since there is 0 credit left to claim.
   922          // The claimant must only have received the amount bonded for the gindex 1 subgame.
   923          // The root claim bond and the unregistered ETH should still exist in the game proxy.
   924          assertEq(reenter.numCalls(), 2);
   925          assertEq(address(reenter).balance, MIN_BOND);
   926          assertEq(address(gameProxy).balance, 1 ether);
   927          assertEq(delayedWeth.balanceOf(address(gameProxy)), MIN_BOND);
   928  
   929          vm.stopPrank();
   930      }
   931  
   932      /// @dev Tests that adding local data with an out of bounds identifier reverts.
   933      function testFuzz_addLocalData_oob_reverts(uint256 _ident) public {
   934          // Get a claim below the split depth so that we can add local data for an execution trace subgame.
   935          for (uint256 i; i < 4; i++) {
   936              gameProxy.attack{ value: MIN_BOND }(i, _dummyClaim());
   937          }
   938          gameProxy.attack{ value: MIN_BOND }(4, _changeClaimStatus(_dummyClaim(), VMStatuses.PANIC));
   939  
   940          // [1, 5] are valid local data identifiers.
   941          if (_ident <= 5) _ident = 0;
   942  
   943          vm.expectRevert(InvalidLocalIdent.selector);
   944          gameProxy.addLocalData(_ident, 5, 0);
   945      }
   946  
   947      /// @dev Tests that local data is loaded into the preimage oracle correctly in the subgame
   948      ///      that is disputing the transition from `GENESIS -> GENESIS + 1`
   949      function test_addLocalDataGenesisTransition_static_succeeds() public {
   950          IPreimageOracle oracle = IPreimageOracle(address(gameProxy.vm().oracle()));
   951  
   952          // Get a claim below the split depth so that we can add local data for an execution trace subgame.
   953          for (uint256 i; i < 4; i++) {
   954              gameProxy.attack{ value: MIN_BOND }(i, Claim.wrap(bytes32(i)));
   955          }
   956          gameProxy.attack{ value: MIN_BOND }(4, _changeClaimStatus(_dummyClaim(), VMStatuses.PANIC));
   957  
   958          // Expected start/disputed claims
   959          (Hash root,) = gameProxy.startingOutputRoot();
   960          bytes32 startingClaim = root.raw();
   961          bytes32 disputedClaim = bytes32(uint256(3));
   962          Position disputedPos = LibPosition.wrap(4, 0);
   963  
   964          // Expected local data
   965          bytes32[5] memory data = [
   966              gameProxy.l1Head().raw(),
   967              startingClaim,
   968              disputedClaim,
   969              bytes32(uint256(1) << 0xC0),
   970              bytes32(gameProxy.l2ChainId() << 0xC0)
   971          ];
   972  
   973          for (uint256 i = 1; i <= 5; i++) {
   974              uint256 expectedLen = i > 3 ? 8 : 32;
   975              bytes32 key = _getKey(i, keccak256(abi.encode(disputedClaim, disputedPos)));
   976  
   977              gameProxy.addLocalData(i, 5, 0);
   978              (bytes32 dat, uint256 datLen) = oracle.readPreimage(key, 0);
   979              assertEq(dat >> 0xC0, bytes32(expectedLen));
   980              // Account for the length prefix if i > 3 (the data stored
   981              // at identifiers i <= 3 are 32 bytes long, so the expected
   982              // length is already correct. If i > 3, the data is only 8
   983              // bytes long, so the length prefix + the data is 16 bytes
   984              // total.)
   985              assertEq(datLen, expectedLen + (i > 3 ? 8 : 0));
   986  
   987              gameProxy.addLocalData(i, 5, 8);
   988              (dat, datLen) = oracle.readPreimage(key, 8);
   989              assertEq(dat, data[i - 1]);
   990              assertEq(datLen, expectedLen);
   991          }
   992      }
   993  
   994      /// @dev Tests that local data is loaded into the preimage oracle correctly.
   995      function test_addLocalDataMiddle_static_succeeds() public {
   996          IPreimageOracle oracle = IPreimageOracle(address(gameProxy.vm().oracle()));
   997  
   998          // Get a claim below the split depth so that we can add local data for an execution trace subgame.
   999          for (uint256 i; i < 4; i++) {
  1000              gameProxy.attack{ value: MIN_BOND }(i, Claim.wrap(bytes32(i)));
  1001          }
  1002          gameProxy.defend{ value: MIN_BOND }(4, _changeClaimStatus(ROOT_CLAIM, VMStatuses.VALID));
  1003  
  1004          // Expected start/disputed claims
  1005          bytes32 startingClaim = bytes32(uint256(3));
  1006          Position startingPos = LibPosition.wrap(4, 0);
  1007          bytes32 disputedClaim = bytes32(uint256(2));
  1008          Position disputedPos = LibPosition.wrap(3, 0);
  1009  
  1010          // Expected local data
  1011          bytes32[5] memory data = [
  1012              gameProxy.l1Head().raw(),
  1013              startingClaim,
  1014              disputedClaim,
  1015              bytes32(uint256(2) << 0xC0),
  1016              bytes32(gameProxy.l2ChainId() << 0xC0)
  1017          ];
  1018  
  1019          for (uint256 i = 1; i <= 5; i++) {
  1020              uint256 expectedLen = i > 3 ? 8 : 32;
  1021              bytes32 key = _getKey(i, keccak256(abi.encode(startingClaim, startingPos, disputedClaim, disputedPos)));
  1022  
  1023              gameProxy.addLocalData(i, 5, 0);
  1024              (bytes32 dat, uint256 datLen) = oracle.readPreimage(key, 0);
  1025              assertEq(dat >> 0xC0, bytes32(expectedLen));
  1026              // Account for the length prefix if i > 3 (the data stored
  1027              // at identifiers i <= 3 are 32 bytes long, so the expected
  1028              // length is already correct. If i > 3, the data is only 8
  1029              // bytes long, so the length prefix + the data is 16 bytes
  1030              // total.)
  1031              assertEq(datLen, expectedLen + (i > 3 ? 8 : 0));
  1032  
  1033              gameProxy.addLocalData(i, 5, 8);
  1034              (dat, datLen) = oracle.readPreimage(key, 8);
  1035              assertEq(dat, data[i - 1]);
  1036              assertEq(datLen, expectedLen);
  1037          }
  1038      }
  1039  
  1040      /// @dev Helper to return a pseudo-random claim
  1041      function _dummyClaim() internal view returns (Claim) {
  1042          return Claim.wrap(keccak256(abi.encode(gasleft())));
  1043      }
  1044  
  1045      /// @dev Helper to get the localized key for an identifier in the context of the game proxy.
  1046      function _getKey(uint256 _ident, bytes32 _localContext) internal view returns (bytes32) {
  1047          bytes32 h = keccak256(abi.encode(_ident | (1 << 248), address(gameProxy), _localContext));
  1048          return bytes32((uint256(h) & ~uint256(0xFF << 248)) | (1 << 248));
  1049      }
  1050  }
  1051  
  1052  contract FaultDispute_1v1_Actors_Test is FaultDisputeGame_Init {
  1053      /// @dev The honest actor
  1054      DisputeActor internal honest;
  1055      /// @dev The dishonest actor
  1056      DisputeActor internal dishonest;
  1057  
  1058      function setUp() public override {
  1059          // Setup the `FaultDisputeGame`
  1060          super.setUp();
  1061      }
  1062  
  1063      /// @notice Fuzz test for a 1v1 output bisection dispute.
  1064      /// @dev The alphabet game has a constant status byte, and is not safe from someone being dishonest in
  1065      ///      output bisection and then posting a correct execution trace bisection root claim. This test
  1066      ///      does not cover this case (i.e. root claim of output bisection is dishonest, root claim of
  1067      ///      execution trace bisection is made by the dishonest actor but is honest, honest actor cannot
  1068      ///      attack it without risk of losing).
  1069      function testFuzz_outputBisection1v1honestRoot_succeeds(uint8 _divergeOutput, uint8 _divergeStep) public {
  1070          uint256[] memory honestL2Outputs = new uint256[](16);
  1071          for (uint256 i; i < honestL2Outputs.length; i++) {
  1072              honestL2Outputs[i] = i + 1;
  1073          }
  1074          bytes memory honestTrace = new bytes(256);
  1075          for (uint256 i; i < honestTrace.length; i++) {
  1076              honestTrace[i] = bytes1(uint8(i));
  1077          }
  1078  
  1079          uint256 divergeAtOutput = bound(_divergeOutput, 0, 15);
  1080          uint256 divergeAtStep = bound(_divergeStep, 0, 7);
  1081          uint256 divergeStepOffset = (divergeAtOutput << 4) + divergeAtStep;
  1082  
  1083          uint256[] memory dishonestL2Outputs = new uint256[](16);
  1084          for (uint256 i; i < dishonestL2Outputs.length; i++) {
  1085              dishonestL2Outputs[i] = i >= divergeAtOutput ? 0xFF : i + 1;
  1086          }
  1087          bytes memory dishonestTrace = new bytes(256);
  1088          for (uint256 i; i < dishonestTrace.length; i++) {
  1089              dishonestTrace[i] = i >= divergeStepOffset ? bytes1(uint8(0xFF)) : bytes1(uint8(i));
  1090          }
  1091  
  1092          // Run the actor test
  1093          _actorTest({
  1094              _rootClaim: 16,
  1095              _absolutePrestateData: 0,
  1096              _honestTrace: honestTrace,
  1097              _honestL2Outputs: honestL2Outputs,
  1098              _dishonestTrace: dishonestTrace,
  1099              _dishonestL2Outputs: dishonestL2Outputs,
  1100              _expectedStatus: GameStatus.DEFENDER_WINS
  1101          });
  1102      }
  1103  
  1104      /// @notice Static unit test for a 1v1 output bisection dispute.
  1105      function test_static_1v1honestRootGenesisAbsolutePrestate_succeeds() public {
  1106          // The honest l2 outputs are from [1, 16] in this game.
  1107          uint256[] memory honestL2Outputs = new uint256[](16);
  1108          for (uint256 i; i < honestL2Outputs.length; i++) {
  1109              honestL2Outputs[i] = i + 1;
  1110          }
  1111          // The honest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
  1112          // of bytes [0, 255].
  1113          bytes memory honestTrace = new bytes(256);
  1114          for (uint256 i; i < honestTrace.length; i++) {
  1115              honestTrace[i] = bytes1(uint8(i));
  1116          }
  1117  
  1118          // The dishonest l2 outputs are from [2, 17] in this game.
  1119          uint256[] memory dishonestL2Outputs = new uint256[](16);
  1120          for (uint256 i; i < dishonestL2Outputs.length; i++) {
  1121              dishonestL2Outputs[i] = i + 2;
  1122          }
  1123          // The dishonest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
  1124          // of all set bits.
  1125          bytes memory dishonestTrace = new bytes(256);
  1126          for (uint256 i; i < dishonestTrace.length; i++) {
  1127              dishonestTrace[i] = bytes1(0xFF);
  1128          }
  1129  
  1130          // Run the actor test
  1131          _actorTest({
  1132              _rootClaim: 16,
  1133              _absolutePrestateData: 0,
  1134              _honestTrace: honestTrace,
  1135              _honestL2Outputs: honestL2Outputs,
  1136              _dishonestTrace: dishonestTrace,
  1137              _dishonestL2Outputs: dishonestL2Outputs,
  1138              _expectedStatus: GameStatus.DEFENDER_WINS
  1139          });
  1140      }
  1141  
  1142      /// @notice Static unit test for a 1v1 output bisection dispute.
  1143      function test_static_1v1dishonestRootGenesisAbsolutePrestate_succeeds() public {
  1144          // The honest l2 outputs are from [1, 16] in this game.
  1145          uint256[] memory honestL2Outputs = new uint256[](16);
  1146          for (uint256 i; i < honestL2Outputs.length; i++) {
  1147              honestL2Outputs[i] = i + 1;
  1148          }
  1149          // The honest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
  1150          // of bytes [0, 255].
  1151          bytes memory honestTrace = new bytes(256);
  1152          for (uint256 i; i < honestTrace.length; i++) {
  1153              honestTrace[i] = bytes1(uint8(i));
  1154          }
  1155  
  1156          // The dishonest l2 outputs are from [2, 17] in this game.
  1157          uint256[] memory dishonestL2Outputs = new uint256[](16);
  1158          for (uint256 i; i < dishonestL2Outputs.length; i++) {
  1159              dishonestL2Outputs[i] = i + 2;
  1160          }
  1161          // The dishonest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
  1162          // of all set bits.
  1163          bytes memory dishonestTrace = new bytes(256);
  1164          for (uint256 i; i < dishonestTrace.length; i++) {
  1165              dishonestTrace[i] = bytes1(0xFF);
  1166          }
  1167  
  1168          // Run the actor test
  1169          _actorTest({
  1170              _rootClaim: 17,
  1171              _absolutePrestateData: 0,
  1172              _honestTrace: honestTrace,
  1173              _honestL2Outputs: honestL2Outputs,
  1174              _dishonestTrace: dishonestTrace,
  1175              _dishonestL2Outputs: dishonestL2Outputs,
  1176              _expectedStatus: GameStatus.CHALLENGER_WINS
  1177          });
  1178      }
  1179  
  1180      /// @notice Static unit test for a 1v1 output bisection dispute.
  1181      function test_static_1v1honestRoot_succeeds() public {
  1182          // The honest l2 outputs are from [1, 16] in this game.
  1183          uint256[] memory honestL2Outputs = new uint256[](16);
  1184          for (uint256 i; i < honestL2Outputs.length; i++) {
  1185              honestL2Outputs[i] = i + 1;
  1186          }
  1187          // The honest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
  1188          // of bytes [0, 255].
  1189          bytes memory honestTrace = new bytes(256);
  1190          for (uint256 i; i < honestTrace.length; i++) {
  1191              honestTrace[i] = bytes1(uint8(i));
  1192          }
  1193  
  1194          // The dishonest l2 outputs are from [2, 17] in this game.
  1195          uint256[] memory dishonestL2Outputs = new uint256[](16);
  1196          for (uint256 i; i < dishonestL2Outputs.length; i++) {
  1197              dishonestL2Outputs[i] = i + 2;
  1198          }
  1199          // The dishonest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
  1200          // of all zeros.
  1201          bytes memory dishonestTrace = new bytes(256);
  1202  
  1203          // Run the actor test
  1204          _actorTest({
  1205              _rootClaim: 16,
  1206              _absolutePrestateData: 0,
  1207              _honestTrace: honestTrace,
  1208              _honestL2Outputs: honestL2Outputs,
  1209              _dishonestTrace: dishonestTrace,
  1210              _dishonestL2Outputs: dishonestL2Outputs,
  1211              _expectedStatus: GameStatus.DEFENDER_WINS
  1212          });
  1213      }
  1214  
  1215      /// @notice Static unit test for a 1v1 output bisection dispute.
  1216      function test_static_1v1dishonestRoot_succeeds() public {
  1217          // The honest l2 outputs are from [1, 16] in this game.
  1218          uint256[] memory honestL2Outputs = new uint256[](16);
  1219          for (uint256 i; i < honestL2Outputs.length; i++) {
  1220              honestL2Outputs[i] = i + 1;
  1221          }
  1222          // The honest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
  1223          // of bytes [0, 255].
  1224          bytes memory honestTrace = new bytes(256);
  1225          for (uint256 i; i < honestTrace.length; i++) {
  1226              honestTrace[i] = bytes1(uint8(i));
  1227          }
  1228  
  1229          // The dishonest l2 outputs are from [2, 17] in this game.
  1230          uint256[] memory dishonestL2Outputs = new uint256[](16);
  1231          for (uint256 i; i < dishonestL2Outputs.length; i++) {
  1232              dishonestL2Outputs[i] = i + 2;
  1233          }
  1234          // The dishonest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
  1235          // of all zeros.
  1236          bytes memory dishonestTrace = new bytes(256);
  1237  
  1238          // Run the actor test
  1239          _actorTest({
  1240              _rootClaim: 17,
  1241              _absolutePrestateData: 0,
  1242              _honestTrace: honestTrace,
  1243              _honestL2Outputs: honestL2Outputs,
  1244              _dishonestTrace: dishonestTrace,
  1245              _dishonestL2Outputs: dishonestL2Outputs,
  1246              _expectedStatus: GameStatus.CHALLENGER_WINS
  1247          });
  1248      }
  1249  
  1250      /// @notice Static unit test for a 1v1 output bisection dispute.
  1251      function test_static_1v1correctRootHalfWay_succeeds() public {
  1252          // The honest l2 outputs are from [1, 16] in this game.
  1253          uint256[] memory honestL2Outputs = new uint256[](16);
  1254          for (uint256 i; i < honestL2Outputs.length; i++) {
  1255              honestL2Outputs[i] = i + 1;
  1256          }
  1257          // The honest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
  1258          // of bytes [0, 255].
  1259          bytes memory honestTrace = new bytes(256);
  1260          for (uint256 i; i < honestTrace.length; i++) {
  1261              honestTrace[i] = bytes1(uint8(i));
  1262          }
  1263  
  1264          // The dishonest l2 outputs are half correct, half incorrect.
  1265          uint256[] memory dishonestL2Outputs = new uint256[](16);
  1266          for (uint256 i; i < dishonestL2Outputs.length; i++) {
  1267              dishonestL2Outputs[i] = i > 7 ? 0xFF : i + 1;
  1268          }
  1269          // The dishonest trace is half correct, half incorrect.
  1270          bytes memory dishonestTrace = new bytes(256);
  1271          for (uint256 i; i < dishonestTrace.length; i++) {
  1272              dishonestTrace[i] = i > (127 + 4) ? bytes1(0xFF) : bytes1(uint8(i));
  1273          }
  1274  
  1275          // Run the actor test
  1276          _actorTest({
  1277              _rootClaim: 16,
  1278              _absolutePrestateData: 0,
  1279              _honestTrace: honestTrace,
  1280              _honestL2Outputs: honestL2Outputs,
  1281              _dishonestTrace: dishonestTrace,
  1282              _dishonestL2Outputs: dishonestL2Outputs,
  1283              _expectedStatus: GameStatus.DEFENDER_WINS
  1284          });
  1285      }
  1286  
  1287      /// @notice Static unit test for a 1v1 output bisection dispute.
  1288      function test_static_1v1dishonestRootHalfWay_succeeds() public {
  1289          // The honest l2 outputs are from [1, 16] in this game.
  1290          uint256[] memory honestL2Outputs = new uint256[](16);
  1291          for (uint256 i; i < honestL2Outputs.length; i++) {
  1292              honestL2Outputs[i] = i + 1;
  1293          }
  1294          // The honest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
  1295          // of bytes [0, 255].
  1296          bytes memory honestTrace = new bytes(256);
  1297          for (uint256 i; i < honestTrace.length; i++) {
  1298              honestTrace[i] = bytes1(uint8(i));
  1299          }
  1300  
  1301          // The dishonest l2 outputs are half correct, half incorrect.
  1302          uint256[] memory dishonestL2Outputs = new uint256[](16);
  1303          for (uint256 i; i < dishonestL2Outputs.length; i++) {
  1304              dishonestL2Outputs[i] = i > 7 ? 0xFF : i + 1;
  1305          }
  1306          // The dishonest trace is half correct, half incorrect.
  1307          bytes memory dishonestTrace = new bytes(256);
  1308          for (uint256 i; i < dishonestTrace.length; i++) {
  1309              dishonestTrace[i] = i > (127 + 4) ? bytes1(0xFF) : bytes1(uint8(i));
  1310          }
  1311  
  1312          // Run the actor test
  1313          _actorTest({
  1314              _rootClaim: 0xFF,
  1315              _absolutePrestateData: 0,
  1316              _honestTrace: honestTrace,
  1317              _honestL2Outputs: honestL2Outputs,
  1318              _dishonestTrace: dishonestTrace,
  1319              _dishonestL2Outputs: dishonestL2Outputs,
  1320              _expectedStatus: GameStatus.CHALLENGER_WINS
  1321          });
  1322      }
  1323  
  1324      /// @notice Static unit test for a 1v1 output bisection dispute.
  1325      function test_static_1v1correctAbsolutePrestate_succeeds() public {
  1326          // The honest l2 outputs are from [1, 16] in this game.
  1327          uint256[] memory honestL2Outputs = new uint256[](16);
  1328          for (uint256 i; i < honestL2Outputs.length; i++) {
  1329              honestL2Outputs[i] = i + 1;
  1330          }
  1331          // The honest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
  1332          // of bytes [0, 255].
  1333          bytes memory honestTrace = new bytes(256);
  1334          for (uint256 i; i < honestTrace.length; i++) {
  1335              honestTrace[i] = bytes1(uint8(i));
  1336          }
  1337  
  1338          // The dishonest l2 outputs are half correct, half incorrect.
  1339          uint256[] memory dishonestL2Outputs = new uint256[](16);
  1340          for (uint256 i; i < dishonestL2Outputs.length; i++) {
  1341              dishonestL2Outputs[i] = i > 7 ? 0xFF : i + 1;
  1342          }
  1343          // The dishonest trace correct is half correct, half incorrect.
  1344          bytes memory dishonestTrace = new bytes(256);
  1345          for (uint256 i; i < dishonestTrace.length; i++) {
  1346              dishonestTrace[i] = i > 127 ? bytes1(0xFF) : bytes1(uint8(i));
  1347          }
  1348  
  1349          // Run the actor test
  1350          _actorTest({
  1351              _rootClaim: 16,
  1352              _absolutePrestateData: 0,
  1353              _honestTrace: honestTrace,
  1354              _honestL2Outputs: honestL2Outputs,
  1355              _dishonestTrace: dishonestTrace,
  1356              _dishonestL2Outputs: dishonestL2Outputs,
  1357              _expectedStatus: GameStatus.DEFENDER_WINS
  1358          });
  1359      }
  1360  
  1361      /// @notice Static unit test for a 1v1 output bisection dispute.
  1362      function test_static_1v1dishonestAbsolutePrestate_succeeds() public {
  1363          // The honest l2 outputs are from [1, 16] in this game.
  1364          uint256[] memory honestL2Outputs = new uint256[](16);
  1365          for (uint256 i; i < honestL2Outputs.length; i++) {
  1366              honestL2Outputs[i] = i + 1;
  1367          }
  1368          // The honest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
  1369          // of bytes [0, 255].
  1370          bytes memory honestTrace = new bytes(256);
  1371          for (uint256 i; i < honestTrace.length; i++) {
  1372              honestTrace[i] = bytes1(uint8(i));
  1373          }
  1374  
  1375          // The dishonest l2 outputs are half correct, half incorrect.
  1376          uint256[] memory dishonestL2Outputs = new uint256[](16);
  1377          for (uint256 i; i < dishonestL2Outputs.length; i++) {
  1378              dishonestL2Outputs[i] = i > 7 ? 0xFF : i + 1;
  1379          }
  1380          // The dishonest trace correct is half correct, half incorrect.
  1381          bytes memory dishonestTrace = new bytes(256);
  1382          for (uint256 i; i < dishonestTrace.length; i++) {
  1383              dishonestTrace[i] = i > 127 ? bytes1(0xFF) : bytes1(uint8(i));
  1384          }
  1385  
  1386          // Run the actor test
  1387          _actorTest({
  1388              _rootClaim: 0xFF,
  1389              _absolutePrestateData: 0,
  1390              _honestTrace: honestTrace,
  1391              _honestL2Outputs: honestL2Outputs,
  1392              _dishonestTrace: dishonestTrace,
  1393              _dishonestL2Outputs: dishonestL2Outputs,
  1394              _expectedStatus: GameStatus.CHALLENGER_WINS
  1395          });
  1396      }
  1397  
  1398      /// @notice Static unit test for a 1v1 output bisection dispute.
  1399      function test_static_1v1honestRootFinalInstruction_succeeds() public {
  1400          // The honest l2 outputs are from [1, 16] in this game.
  1401          uint256[] memory honestL2Outputs = new uint256[](16);
  1402          for (uint256 i; i < honestL2Outputs.length; i++) {
  1403              honestL2Outputs[i] = i + 1;
  1404          }
  1405          // The honest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
  1406          // of bytes [0, 255].
  1407          bytes memory honestTrace = new bytes(256);
  1408          for (uint256 i; i < honestTrace.length; i++) {
  1409              honestTrace[i] = bytes1(uint8(i));
  1410          }
  1411  
  1412          // The dishonest l2 outputs are half correct, half incorrect.
  1413          uint256[] memory dishonestL2Outputs = new uint256[](16);
  1414          for (uint256 i; i < dishonestL2Outputs.length; i++) {
  1415              dishonestL2Outputs[i] = i > 7 ? 0xFF : i + 1;
  1416          }
  1417          // The dishonest trace is half correct, and correct all the way up to the final instruction of the exec
  1418          // subgame.
  1419          bytes memory dishonestTrace = new bytes(256);
  1420          for (uint256 i; i < dishonestTrace.length; i++) {
  1421              dishonestTrace[i] = i > (127 + 7) ? bytes1(0xFF) : bytes1(uint8(i));
  1422          }
  1423  
  1424          // Run the actor test
  1425          _actorTest({
  1426              _rootClaim: 16,
  1427              _absolutePrestateData: 0,
  1428              _honestTrace: honestTrace,
  1429              _honestL2Outputs: honestL2Outputs,
  1430              _dishonestTrace: dishonestTrace,
  1431              _dishonestL2Outputs: dishonestL2Outputs,
  1432              _expectedStatus: GameStatus.DEFENDER_WINS
  1433          });
  1434      }
  1435  
  1436      /// @notice Static unit test for a 1v1 output bisection dispute.
  1437      function test_static_1v1dishonestRootFinalInstruction_succeeds() public {
  1438          // The honest l2 outputs are from [1, 16] in this game.
  1439          uint256[] memory honestL2Outputs = new uint256[](16);
  1440          for (uint256 i; i < honestL2Outputs.length; i++) {
  1441              honestL2Outputs[i] = i + 1;
  1442          }
  1443          // The honest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
  1444          // of bytes [0, 255].
  1445          bytes memory honestTrace = new bytes(256);
  1446          for (uint256 i; i < honestTrace.length; i++) {
  1447              honestTrace[i] = bytes1(uint8(i));
  1448          }
  1449  
  1450          // The dishonest l2 outputs are half correct, half incorrect.
  1451          uint256[] memory dishonestL2Outputs = new uint256[](16);
  1452          for (uint256 i; i < dishonestL2Outputs.length; i++) {
  1453              dishonestL2Outputs[i] = i > 7 ? 0xFF : i + 1;
  1454          }
  1455          // The dishonest trace is half correct, and correct all the way up to the final instruction of the exec
  1456          // subgame.
  1457          bytes memory dishonestTrace = new bytes(256);
  1458          for (uint256 i; i < dishonestTrace.length; i++) {
  1459              dishonestTrace[i] = i > (127 + 7) ? bytes1(0xFF) : bytes1(uint8(i));
  1460          }
  1461  
  1462          // Run the actor test
  1463          _actorTest({
  1464              _rootClaim: 0xFF,
  1465              _absolutePrestateData: 0,
  1466              _honestTrace: honestTrace,
  1467              _honestL2Outputs: honestL2Outputs,
  1468              _dishonestTrace: dishonestTrace,
  1469              _dishonestL2Outputs: dishonestL2Outputs,
  1470              _expectedStatus: GameStatus.CHALLENGER_WINS
  1471          });
  1472      }
  1473  
  1474      ////////////////////////////////////////////////////////////////
  1475      //                          HELPERS                           //
  1476      ////////////////////////////////////////////////////////////////
  1477  
  1478      /// @dev Helper to run a 1v1 actor test
  1479      function _actorTest(
  1480          uint256 _rootClaim,
  1481          uint256 _absolutePrestateData,
  1482          bytes memory _honestTrace,
  1483          uint256[] memory _honestL2Outputs,
  1484          bytes memory _dishonestTrace,
  1485          uint256[] memory _dishonestL2Outputs,
  1486          GameStatus _expectedStatus
  1487      )
  1488          internal
  1489      {
  1490          // Setup the environment
  1491          bytes memory absolutePrestateData =
  1492              _setup({ _absolutePrestateData: _absolutePrestateData, _rootClaim: _rootClaim });
  1493  
  1494          // Create actors
  1495          _createActors({
  1496              _honestTrace: _honestTrace,
  1497              _honestPreStateData: absolutePrestateData,
  1498              _honestL2Outputs: _honestL2Outputs,
  1499              _dishonestTrace: _dishonestTrace,
  1500              _dishonestPreStateData: absolutePrestateData,
  1501              _dishonestL2Outputs: _dishonestL2Outputs
  1502          });
  1503  
  1504          // Exhaust all moves from both actors
  1505          _exhaustMoves();
  1506  
  1507          // Resolve the game and assert that the defender won
  1508          _warpAndResolve();
  1509          assertEq(uint8(gameProxy.status()), uint8(_expectedStatus));
  1510      }
  1511  
  1512      /// @dev Helper to setup the 1v1 test
  1513      function _setup(
  1514          uint256 _absolutePrestateData,
  1515          uint256 _rootClaim
  1516      )
  1517          internal
  1518          returns (bytes memory absolutePrestateData_)
  1519      {
  1520          absolutePrestateData_ = abi.encode(_absolutePrestateData);
  1521          Claim absolutePrestateExec =
  1522              _changeClaimStatus(Claim.wrap(keccak256(absolutePrestateData_)), VMStatuses.UNFINISHED);
  1523          Claim rootClaim = Claim.wrap(bytes32(uint256(_rootClaim)));
  1524          super.init({ rootClaim: rootClaim, absolutePrestate: absolutePrestateExec, l2BlockNumber: _rootClaim });
  1525      }
  1526  
  1527      /// @dev Helper to create actors for the 1v1 dispute.
  1528      function _createActors(
  1529          bytes memory _honestTrace,
  1530          bytes memory _honestPreStateData,
  1531          uint256[] memory _honestL2Outputs,
  1532          bytes memory _dishonestTrace,
  1533          bytes memory _dishonestPreStateData,
  1534          uint256[] memory _dishonestL2Outputs
  1535      )
  1536          internal
  1537      {
  1538          honest = new HonestDisputeActor({
  1539              _gameProxy: gameProxy,
  1540              _l2Outputs: _honestL2Outputs,
  1541              _trace: _honestTrace,
  1542              _preStateData: _honestPreStateData
  1543          });
  1544          dishonest = new HonestDisputeActor({
  1545              _gameProxy: gameProxy,
  1546              _l2Outputs: _dishonestL2Outputs,
  1547              _trace: _dishonestTrace,
  1548              _preStateData: _dishonestPreStateData
  1549          });
  1550  
  1551          vm.deal(address(honest), 100 ether);
  1552          vm.deal(address(dishonest), 100 ether);
  1553          vm.label(address(honest), "HonestActor");
  1554          vm.label(address(dishonest), "DishonestActor");
  1555      }
  1556  
  1557      /// @dev Helper to exhaust all moves from both actors.
  1558      function _exhaustMoves() internal {
  1559          while (true) {
  1560              // Allow the dishonest actor to make their moves, and then the honest actor.
  1561              (uint256 numMovesA,) = dishonest.move();
  1562              (uint256 numMovesB, bool success) = honest.move();
  1563  
  1564              require(success, "Honest actor's moves should always be successful");
  1565  
  1566              // If both actors have run out of moves, we're done.
  1567              if (numMovesA == 0 && numMovesB == 0) break;
  1568          }
  1569      }
  1570  
  1571      /// @dev Helper to warp past the chess clock and resolve all claims within the dispute game.
  1572      function _warpAndResolve() internal {
  1573          // Warp past the chess clock
  1574          vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
  1575  
  1576          // Resolve all claims in reverse order. We allow `resolveClaim` calls to fail due to
  1577          // the check that prevents claims with no subgames attached from being passed to
  1578          // `resolveClaim`. There's also a check in `resolve` to ensure all children have been
  1579          // resolved before global resolution, which catches any unresolved subgames here.
  1580          for (uint256 i = gameProxy.claimDataLen(); i > 0; i--) {
  1581              (bool success,) = address(gameProxy).call(abi.encodeCall(gameProxy.resolveClaim, (i - 1)));
  1582              assertTrue(success);
  1583          }
  1584          gameProxy.resolve();
  1585      }
  1586  }
  1587  
  1588  contract ClaimCreditReenter {
  1589      Vm internal immutable vm;
  1590      FaultDisputeGame internal immutable GAME;
  1591      uint256 public numCalls;
  1592  
  1593      constructor(FaultDisputeGame _gameProxy, Vm _vm) {
  1594          GAME = _gameProxy;
  1595          vm = _vm;
  1596      }
  1597  
  1598      function claimCredit(address _recipient) public {
  1599          numCalls += 1;
  1600          if (numCalls > 1) {
  1601              vm.expectRevert(NoCreditToClaim.selector);
  1602          }
  1603          GAME.claimCredit(_recipient);
  1604      }
  1605  
  1606      receive() external payable {
  1607          if (numCalls == 5) {
  1608              return;
  1609          }
  1610          claimCredit(address(this));
  1611      }
  1612  }
  1613  
  1614  /// @dev Helper to change the VM status byte of a claim.
  1615  function _changeClaimStatus(Claim _claim, VMStatus _status) pure returns (Claim out_) {
  1616      assembly {
  1617          out_ := or(and(not(shl(248, 0xFF)), _claim), shl(248, _status))
  1618      }
  1619  }