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  }