github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/dispute/PermissionedDisputeGame.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 { PermissionedDisputeGame } from "src/dispute/PermissionedDisputeGame.sol";
     9  import { DelayedWETH } from "src/dispute/weth/DelayedWETH.sol";
    10  import { L2OutputOracle } from "src/L1/L2OutputOracle.sol";
    11  import { PreimageOracle } from "src/cannon/PreimageOracle.sol";
    12  import { PreimageKeyLib } from "src/cannon/PreimageKeyLib.sol";
    13  
    14  import "src/libraries/DisputeTypes.sol";
    15  import "src/libraries/DisputeErrors.sol";
    16  import { Types } from "src/libraries/Types.sol";
    17  import { LibClock } from "src/dispute/lib/LibUDT.sol";
    18  import { LibPosition } from "src/dispute/lib/LibPosition.sol";
    19  import { IBigStepper, IPreimageOracle } from "src/dispute/interfaces/IBigStepper.sol";
    20  import { AlphabetVM } from "test/mocks/AlphabetVM.sol";
    21  
    22  import { DisputeActor, HonestDisputeActor } from "test/actors/FaultDisputeActors.sol";
    23  
    24  contract PermissionedDisputeGame_Init is DisputeGameFactory_Init {
    25      /// @dev The type of the game being tested.
    26      GameType internal constant GAME_TYPE = GameType.wrap(1);
    27      /// @dev Mock proposer key
    28      address internal constant PROPOSER = address(0xfacade9);
    29      /// @dev Mock challenger key
    30      address internal constant CHALLENGER = address(0xfacadec);
    31  
    32      /// @dev The implementation of the game.
    33      PermissionedDisputeGame internal gameImpl;
    34      /// @dev The `Clone` proxy of the game.
    35      PermissionedDisputeGame internal gameProxy;
    36  
    37      /// @dev The extra data passed to the game for initialization.
    38      bytes internal extraData;
    39  
    40      event Move(uint256 indexed parentIndex, Claim indexed pivot, address indexed claimant);
    41  
    42      function init(Claim rootClaim, Claim absolutePrestate, uint256 l2BlockNumber) public {
    43          // Set the time to a realistic date.
    44          vm.warp(1690906994);
    45  
    46          // Set the extra data for the game creation
    47          extraData = abi.encode(l2BlockNumber);
    48  
    49          AlphabetVM _vm = new AlphabetVM(absolutePrestate, new PreimageOracle(0, 0));
    50  
    51          // Use a 7 day delayed WETH to simulate withdrawals.
    52          DelayedWETH _weth = new DelayedWETH(7 days);
    53  
    54          // Deploy an implementation of the fault game
    55          gameImpl = new PermissionedDisputeGame({
    56              _gameType: GAME_TYPE,
    57              _absolutePrestate: absolutePrestate,
    58              _maxGameDepth: 2 ** 3,
    59              _splitDepth: 2 ** 2,
    60              _gameDuration: Duration.wrap(7 days),
    61              _vm: _vm,
    62              _weth: _weth,
    63              _anchorStateRegistry: anchorStateRegistry,
    64              _l2ChainId: 10,
    65              _proposer: PROPOSER,
    66              _challenger: CHALLENGER
    67          });
    68          // Register the game implementation with the factory.
    69          disputeGameFactory.setImplementation(GAME_TYPE, gameImpl);
    70          // Create a new game.
    71          vm.prank(PROPOSER, PROPOSER);
    72          gameProxy =
    73              PermissionedDisputeGame(payable(address(disputeGameFactory.create(GAME_TYPE, rootClaim, extraData))));
    74  
    75          // Check immutables
    76          assertEq(gameProxy.gameType().raw(), GAME_TYPE.raw());
    77          assertEq(gameProxy.absolutePrestate().raw(), absolutePrestate.raw());
    78          assertEq(gameProxy.maxGameDepth(), 2 ** 3);
    79          assertEq(gameProxy.splitDepth(), 2 ** 2);
    80          assertEq(gameProxy.gameDuration().raw(), 7 days);
    81          assertEq(address(gameProxy.vm()), address(_vm));
    82  
    83          // Label the proxy
    84          vm.label(address(gameProxy), "FaultDisputeGame_Clone");
    85      }
    86  
    87      fallback() external payable { }
    88  
    89      receive() external payable { }
    90  }
    91  
    92  contract PermissionedDisputeGame_Test is PermissionedDisputeGame_Init {
    93      /// @dev The root claim of the game.
    94      Claim internal constant ROOT_CLAIM = Claim.wrap(bytes32((uint256(1) << 248) | uint256(10)));
    95      /// @dev Minimum bond value that covers all possible moves.
    96      uint256 internal constant MIN_BOND = 50 ether;
    97  
    98      /// @dev The preimage of the absolute prestate claim
    99      bytes internal absolutePrestateData;
   100      /// @dev The absolute prestate of the trace.
   101      Claim internal absolutePrestate;
   102  
   103      function setUp() public override {
   104          absolutePrestateData = abi.encode(0);
   105          absolutePrestate = _changeClaimStatus(Claim.wrap(keccak256(absolutePrestateData)), VMStatuses.UNFINISHED);
   106  
   107          super.setUp();
   108          super.init({ rootClaim: ROOT_CLAIM, absolutePrestate: absolutePrestate, l2BlockNumber: 0x10 });
   109      }
   110  
   111      /// @dev Tests that the proposer can create a permissioned dispute game.
   112      function test_createGame_proposer_succeeds() public {
   113          vm.prank(PROPOSER, PROPOSER);
   114          disputeGameFactory.create(GAME_TYPE, ROOT_CLAIM, abi.encode(0x420));
   115      }
   116  
   117      /// @dev Tests that the permissioned game cannot be created by any address other than the proposer.
   118      function testFuzz_createGame_notProposer_reverts(address _p) public {
   119          vm.assume(_p != PROPOSER);
   120  
   121          vm.prank(_p, _p);
   122          vm.expectRevert(BadAuth.selector);
   123          disputeGameFactory.create(GAME_TYPE, ROOT_CLAIM, abi.encode(0x420));
   124      }
   125  
   126      /// @dev Tests that the challenger can participate in a permissioned dispute game.
   127      function test_participateInGame_challenger_succeeds() public {
   128          vm.startPrank(CHALLENGER, CHALLENGER);
   129          vm.deal(CHALLENGER, MIN_BOND * 3);
   130          gameProxy.attack{ value: MIN_BOND }(0, Claim.wrap(0));
   131          gameProxy.defend{ value: MIN_BOND }(1, Claim.wrap(0));
   132          gameProxy.move{ value: MIN_BOND }(2, Claim.wrap(0), true);
   133          vm.stopPrank();
   134      }
   135  
   136      /// @dev Tests that the proposer can participate in a permissioned dispute game.
   137      function test_participateInGame_proposer_succeeds() public {
   138          vm.startPrank(PROPOSER, PROPOSER);
   139          vm.deal(PROPOSER, MIN_BOND * 3);
   140          gameProxy.attack{ value: MIN_BOND }(0, Claim.wrap(0));
   141          gameProxy.defend{ value: MIN_BOND }(1, Claim.wrap(0));
   142          gameProxy.move{ value: MIN_BOND }(2, Claim.wrap(0), true);
   143          vm.stopPrank();
   144      }
   145  
   146      /// @dev Tests that addresses that are not the proposer or challenger cannot participate in a permissioned dispute
   147      ///      game.
   148      function test_participateInGame_notAuthorized_reverts(address _p) public {
   149          vm.assume(_p != PROPOSER && _p != CHALLENGER);
   150  
   151          vm.startPrank(_p, _p);
   152          vm.expectRevert(BadAuth.selector);
   153          gameProxy.attack(0, Claim.wrap(0));
   154          vm.expectRevert(BadAuth.selector);
   155          gameProxy.defend(1, Claim.wrap(0));
   156          vm.expectRevert(BadAuth.selector);
   157          gameProxy.move(2, Claim.wrap(0), true);
   158          vm.stopPrank();
   159      }
   160  }
   161  
   162  /// @dev Helper to change the VM status byte of a claim.
   163  function _changeClaimStatus(Claim _claim, VMStatus _status) pure returns (Claim out_) {
   164      assembly {
   165          out_ := or(and(not(shl(248, 0xFF)), _claim), shl(248, _status))
   166      }
   167  }