github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/BenchmarkTest.t.sol (about) 1 // SPDX-License-Identifier: MIT 2 pragma solidity 0.8.15; 3 4 // Testing utilities 5 import { Test } from "forge-std/Test.sol"; 6 import { Vm } from "forge-std/Vm.sol"; 7 import { CommonTest } from "test/setup/CommonTest.sol"; 8 import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; 9 import { CrossDomainMessenger } from "src/universal/CrossDomainMessenger.sol"; 10 import { ResourceMetering } from "src/L1/ResourceMetering.sol"; 11 import { Types } from "src/libraries/Types.sol"; 12 13 // Free function for setting the prevBaseFee param in the OptimismPortal. 14 function setPrevBaseFee(Vm _vm, address _op, uint128 _prevBaseFee) { 15 _vm.store(address(_op), bytes32(uint256(1)), bytes32((block.number << 192) | _prevBaseFee)); 16 } 17 18 contract SetPrevBaseFee_Test is CommonTest { 19 function test_setPrevBaseFee_succeeds() external { 20 setPrevBaseFee(vm, address(optimismPortal), 100 gwei); 21 (uint128 prevBaseFee,, uint64 prevBlockNum) = optimismPortal.params(); 22 assertEq(uint256(prevBaseFee), 100 gwei); 23 assertEq(uint256(prevBlockNum), block.number); 24 } 25 } 26 27 // Tests for obtaining pure gas cost estimates for commonly used functions. 28 // The objective with these benchmarks is to strip down the actual test functions 29 // so that they are nothing more than the call we want measure the gas cost of. 30 // In order to achieve this we make no assertions, and handle everything else in the setUp() 31 // function. 32 contract GasBenchMark_OptimismPortal is CommonTest { 33 // Reusable default values for a test withdrawal 34 Types.WithdrawalTransaction _defaultTx; 35 36 uint256 _proposedOutputIndex; 37 uint256 _proposedBlockNumber; 38 bytes[] _withdrawalProof; 39 Types.OutputRootProof internal _outputRootProof; 40 bytes32 _outputRoot; 41 42 // Use a constructor to set the storage vars above, so as to minimize the number of ffi calls. 43 constructor() { 44 super.setUp(); 45 _defaultTx = Types.WithdrawalTransaction({ 46 nonce: 0, 47 sender: alice, 48 target: bob, 49 value: 100, 50 gasLimit: 100_000, 51 data: hex"" 52 }); 53 54 // Get withdrawal proof data we can use for testing. 55 bytes32 _storageRoot; 56 bytes32 _stateRoot; 57 (_stateRoot, _storageRoot, _outputRoot,, _withdrawalProof) = ffi.getProveWithdrawalTransactionInputs(_defaultTx); 58 59 // Setup a dummy output root proof for reuse. 60 _outputRootProof = Types.OutputRootProof({ 61 version: bytes32(uint256(0)), 62 stateRoot: _stateRoot, 63 messagePasserStorageRoot: _storageRoot, 64 latestBlockhash: bytes32(uint256(0)) 65 }); 66 _proposedBlockNumber = l2OutputOracle.nextBlockNumber(); 67 _proposedOutputIndex = l2OutputOracle.nextOutputIndex(); 68 } 69 70 // Get the system into a nice ready-to-use state. 71 function setUp() public virtual override { 72 // Configure the oracle to return the output root we've prepared. 73 vm.warp(l2OutputOracle.computeL2Timestamp(_proposedBlockNumber) + 1); 74 vm.prank(l2OutputOracle.PROPOSER()); 75 l2OutputOracle.proposeL2Output(_outputRoot, _proposedBlockNumber, 0, 0); 76 77 // Warp beyond the finalization period for the block we've proposed. 78 vm.warp( 79 l2OutputOracle.getL2Output(_proposedOutputIndex).timestamp + l2OutputOracle.FINALIZATION_PERIOD_SECONDS() 80 + 1 81 ); 82 83 // Fund the portal so that we can withdraw ETH. 84 vm.deal(address(optimismPortal), 0xFFFFFFFF); 85 } 86 87 function test_depositTransaction_benchmark() external { 88 optimismPortal.depositTransaction{ value: 100 }( 89 address(1), 0, 50000, false, hex"0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff0000" 90 ); 91 } 92 93 function test_depositTransaction_benchmark_1() external { 94 setPrevBaseFee(vm, address(optimismPortal), 1 gwei); 95 optimismPortal.depositTransaction{ value: 100 }( 96 address(1), 0, 50000, false, hex"0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff0000" 97 ); 98 } 99 100 function test_proveWithdrawalTransaction_benchmark() external { 101 optimismPortal.proveWithdrawalTransaction(_defaultTx, _proposedOutputIndex, _outputRootProof, _withdrawalProof); 102 } 103 } 104 105 contract GasBenchMark_L1CrossDomainMessenger is Bridge_Initializer { 106 function test_sendMessage_benchmark_0() external { 107 vm.pauseGasMetering(); 108 setPrevBaseFee(vm, address(optimismPortal), 1 gwei); 109 // The amount of data typically sent during a bridge deposit. 110 bytes memory data = 111 hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; 112 vm.resumeGasMetering(); 113 l1CrossDomainMessenger.sendMessage(bob, data, uint32(100)); 114 } 115 116 function test_sendMessage_benchmark_1() external { 117 vm.pauseGasMetering(); 118 setPrevBaseFee(vm, address(optimismPortal), 10 gwei); 119 // The amount of data typically sent during a bridge deposit. 120 bytes memory data = 121 hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; 122 vm.resumeGasMetering(); 123 l1CrossDomainMessenger.sendMessage(bob, data, uint32(100)); 124 } 125 } 126 127 contract GasBenchMark_L1StandardBridge_Deposit is Bridge_Initializer { 128 function setUp() public virtual override { 129 super.setUp(); 130 deal(address(L1Token), alice, 100000, true); 131 vm.startPrank(alice, alice); 132 L1Token.approve(address(l1StandardBridge), type(uint256).max); 133 } 134 135 function test_depositETH_benchmark_0() external { 136 vm.pauseGasMetering(); 137 setPrevBaseFee(vm, address(optimismPortal), 1 gwei); 138 vm.resumeGasMetering(); 139 l1StandardBridge.depositETH{ value: 500 }(50000, hex""); 140 } 141 142 function test_depositETH_benchmark_1() external { 143 vm.pauseGasMetering(); 144 setPrevBaseFee(vm, address(optimismPortal), 10 gwei); 145 vm.resumeGasMetering(); 146 l1StandardBridge.depositETH{ value: 500 }(50000, hex""); 147 } 148 149 function test_depositERC20_benchmark_0() external { 150 vm.pauseGasMetering(); 151 setPrevBaseFee(vm, address(optimismPortal), 1 gwei); 152 vm.resumeGasMetering(); 153 l1StandardBridge.bridgeERC20({ 154 _localToken: address(L1Token), 155 _remoteToken: address(L2Token), 156 _amount: 100, 157 _minGasLimit: 100_000, 158 _extraData: hex"" 159 }); 160 } 161 162 function test_depositERC20_benchmark_1() external { 163 vm.pauseGasMetering(); 164 setPrevBaseFee(vm, address(optimismPortal), 10 gwei); 165 vm.resumeGasMetering(); 166 l1StandardBridge.bridgeERC20({ 167 _localToken: address(L1Token), 168 _remoteToken: address(L2Token), 169 _amount: 100, 170 _minGasLimit: 100_000, 171 _extraData: hex"" 172 }); 173 } 174 } 175 176 contract GasBenchMark_L1StandardBridge_Finalize is Bridge_Initializer { 177 function setUp() public virtual override { 178 super.setUp(); 179 deal(address(L1Token), address(l1StandardBridge), 100, true); 180 vm.mockCall( 181 address(l1StandardBridge.messenger()), 182 abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector), 183 abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) 184 ); 185 vm.startPrank(address(l1StandardBridge.messenger())); 186 vm.deal(address(l1StandardBridge.messenger()), 100); 187 } 188 189 function test_finalizeETHWithdrawal_benchmark() external { 190 // TODO: Make this more accurate. It is underestimating the cost because it pranks 191 // the call coming from the messenger, which bypasses the portal 192 // and oracle. 193 l1StandardBridge.finalizeETHWithdrawal{ value: 100 }(alice, alice, 100, hex""); 194 } 195 } 196 197 contract GasBenchMark_L2OutputOracle is CommonTest { 198 uint256 nextBlockNumber; 199 200 function setUp() public override { 201 super.setUp(); 202 nextBlockNumber = l2OutputOracle.nextBlockNumber(); 203 warpToProposeTime(nextBlockNumber); 204 address proposer = deploy.cfg().l2OutputOracleProposer(); 205 vm.startPrank(proposer); 206 } 207 208 function test_proposeL2Output_benchmark() external { 209 l2OutputOracle.proposeL2Output(nonZeroHash, nextBlockNumber, 0, 0); 210 } 211 }