BenchmarkTest.t.sol 8.84 KB
Newer Older
1 2
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
3

4
// Testing utilities
5 6
import { Test } from "forge-std/Test.sol";
import { Vm } from "forge-std/Vm.sol";
7 8
import { CommonTest } from "test/setup/CommonTest.sol";
import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol";
9 10
import { CrossDomainMessenger } from "src/universal/CrossDomainMessenger.sol";
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) {
Mark Tyneway's avatar
Mark Tyneway committed
15
    _vm.store(address(_op), bytes32(uint256(1)), bytes32((block.number << 192) | _prevBaseFee));
16 17
}

18
contract SetPrevBaseFee_Test is CommonTest {
Mark Tyneway's avatar
Mark Tyneway committed
19
    function test_setPrevBaseFee_succeeds() external {
20 21
        setPrevBaseFee(vm, address(optimismPortal), 100 gwei);
        (uint128 prevBaseFee,, uint64 prevBlockNum) = optimismPortal.params();
22 23 24 25 26
        assertEq(uint256(prevBaseFee), 100 gwei);
        assertEq(uint256(prevBlockNum), block.number);
    }
}

27 28 29 30 31
// Tests for obtaining pure gas cost estimates for commonly used functions.
// The objective with these benchmarks is to strip down the actual test functions
// so that they are nothing more than the call we want measure the gas cost of.
// In order to achieve this we make no assertions, and handle everything else in the setUp()
// function.
32
contract GasBenchMark_OptimismPortal is CommonTest {
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
    // Reusable default values for a test withdrawal
    Types.WithdrawalTransaction _defaultTx;

    uint256 _proposedOutputIndex;
    uint256 _proposedBlockNumber;
    bytes[] _withdrawalProof;
    Types.OutputRootProof internal _outputRootProof;
    bytes32 _outputRoot;

    // Use a constructor to set the storage vars above, so as to minimize the number of ffi calls.
    constructor() {
        super.setUp();
        _defaultTx = Types.WithdrawalTransaction({
            nonce: 0,
            sender: alice,
            target: bob,
            value: 100,
            gasLimit: 100_000,
            data: hex""
        });

        // Get withdrawal proof data we can use for testing.
        bytes32 _storageRoot;
        bytes32 _stateRoot;
57
        (_stateRoot, _storageRoot, _outputRoot,, _withdrawalProof) = ffi.getProveWithdrawalTransactionInputs(_defaultTx);
58 59 60 61 62 63 64 65

        // Setup a dummy output root proof for reuse.
        _outputRootProof = Types.OutputRootProof({
            version: bytes32(uint256(0)),
            stateRoot: _stateRoot,
            messagePasserStorageRoot: _storageRoot,
            latestBlockhash: bytes32(uint256(0))
        });
66 67
        _proposedBlockNumber = l2OutputOracle.nextBlockNumber();
        _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 74 75
        vm.warp(l2OutputOracle.computeL2Timestamp(_proposedBlockNumber) + 1);
        vm.prank(l2OutputOracle.PROPOSER());
        l2OutputOracle.proposeL2Output(_outputRoot, _proposedBlockNumber, 0, 0);
76 77

        // Warp beyond the finalization period for the block we've proposed.
78 79 80 81
        vm.warp(
            l2OutputOracle.getL2Output(_proposedOutputIndex).timestamp + l2OutputOracle.FINALIZATION_PERIOD_SECONDS()
                + 1
        );
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 89
        optimismPortal.depositTransaction{ value: 100 }(
            address(1), 0, 50000, false, hex"0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff0000"
90 91 92 93
        );
    }

    function test_depositTransaction_benchmark_1() external {
94 95 96
        setPrevBaseFee(vm, address(optimismPortal), 1 gwei);
        optimismPortal.depositTransaction{ value: 100 }(
            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 111
        bytes memory data =
            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 121
        bytes memory data =
            hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
122
        vm.resumeGasMetering();
123
        l1CrossDomainMessenger.sendMessage(bob, data, uint32(100));
124 125 126 127 128 129 130 131
    }
}

contract GasBenchMark_L1StandardBridge_Deposit is Bridge_Initializer {
    function setUp() public virtual override {
        super.setUp();
        deal(address(L1Token), alice, 100000, true);
        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 155 156 157 158 159
            _localToken: address(L1Token),
            _remoteToken: address(L2Token),
            _amount: 100,
            _minGasLimit: 100_000,
            _extraData: hex""
        });
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 168 169 170 171 172
            _localToken: address(L1Token),
            _remoteToken: address(L2Token),
            _amount: 100,
            _minGasLimit: 100_000,
            _extraData: hex""
        });
173 174 175 176 177 178
    }
}

contract GasBenchMark_L1StandardBridge_Finalize is Bridge_Initializer {
    function setUp() public virtual override {
        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 186
        vm.startPrank(address(l1StandardBridge.messenger()));
        vm.deal(address(l1StandardBridge.messenger()), 100);
187 188 189 190 191 192
    }

    function test_finalizeETHWithdrawal_benchmark() external {
        // TODO: Make this more accurate. It is underestimating the cost because it pranks
        // the call coming from the messenger, which bypasses the portal
        // and oracle.
193
        l1StandardBridge.finalizeETHWithdrawal{ value: 100 }(alice, alice, 100, hex"");
194 195 196
    }
}

197
contract GasBenchMark_L2OutputOracle is CommonTest {
198 199 200 201
    uint256 nextBlockNumber;

    function setUp() public override {
        super.setUp();
202
        nextBlockNumber = l2OutputOracle.nextBlockNumber();
203
        warpToProposeTime(nextBlockNumber);
204
        address proposer = cfg.l2OutputOracleProposer();
205
        vm.startPrank(proposer);
206 207
    }

208
    function test_proposeL2Output_benchmark() external {
209
        l2OutputOracle.proposeL2Output(nonZeroHash, nextBlockNumber, 0, 0);
210 211
    }
}