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 }