BenchmarkTest.t.sol 8.5 KB
Newer Older
1 2
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
3 4 5 6 7 8 9 10 11 12 13 14 15 16

/* Testing utilities */
import { Test } from "forge-std/Test.sol";
import { Vm } from "forge-std/Vm.sol";
import "./CommonTest.t.sol";
import { CrossDomainMessenger } from "../universal/CrossDomainMessenger.sol";
import { ResourceMetering } from "../L1/ResourceMetering.sol";

// Free function for setting the prevBaseFee param in the OptimismPortal.
function setPrevBaseFee(
    Vm _vm,
    address _op,
    uint128 _prevBaseFee
) {
Mark Tyneway's avatar
Mark Tyneway committed
17
    _vm.store(address(_op), bytes32(uint256(1)), bytes32((block.number << 192) | _prevBaseFee));
18 19
}

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

29 30 31 32 33 34
// 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.
contract GasBenchMark_OptimismPortal is Portal_Initializer {
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
    // 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;
        (_stateRoot, _storageRoot, _outputRoot, , _withdrawalProof) = ffi
            .getProveWithdrawalTransactionInputs(_defaultTx);

        // Setup a dummy output root proof for reuse.
        _outputRootProof = Types.OutputRootProof({
            version: bytes32(uint256(0)),
            stateRoot: _stateRoot,
            messagePasserStorageRoot: _storageRoot,
            latestBlockhash: bytes32(uint256(0))
        });
        _proposedBlockNumber = oracle.nextBlockNumber();
        _proposedOutputIndex = oracle.nextOutputIndex();
    }

    // Get the system into a nice ready-to-use state.
74
    function setUp() public virtual override {
75 76 77 78 79 80 81 82
        // Configure the oracle to return the output root we've prepared.
        vm.warp(oracle.computeL2Timestamp(_proposedBlockNumber) + 1);
        vm.prank(oracle.PROPOSER());
        oracle.proposeL2Output(_outputRoot, _proposedBlockNumber, 0, 0);

        // Warp beyond the finalization period for the block we've proposed.
        vm.warp(
            oracle.getL2Output(_proposedOutputIndex).timestamp +
83
                oracle.FINALIZATION_PERIOD_SECONDS() +
84 85
                1
        );
86

87 88 89 90
        // Fund the portal so that we can withdraw ETH.
        vm.deal(address(op), 0xFFFFFFFF);
    }

91 92 93 94 95 96 97 98 99 100 101
    function test_depositTransaction_benchmark() external {
        op.depositTransaction{ value: NON_ZERO_VALUE }(
            NON_ZERO_ADDRESS,
            ZERO_VALUE,
            NON_ZERO_GASLIMIT,
            false,
            NON_ZERO_DATA
        );
    }

    function test_depositTransaction_benchmark_1() external {
102
        setPrevBaseFee(vm, address(op), 1 gwei);
103 104 105 106 107 108 109 110
        op.depositTransaction{ value: NON_ZERO_VALUE }(
            NON_ZERO_ADDRESS,
            ZERO_VALUE,
            NON_ZERO_GASLIMIT,
            false,
            NON_ZERO_DATA
        );
    }
111 112 113 114 115 116 117 118 119

    function test_proveWithdrawalTransaction_benchmark() external {
        op.proveWithdrawalTransaction(
            _defaultTx,
            _proposedOutputIndex,
            _outputRootProof,
            _withdrawalProof
        );
    }
120 121 122
}

contract GasBenchMark_L1CrossDomainMessenger is Messenger_Initializer {
123
    function test_sendMessage_benchmark_0() external {
124
        vm.pauseGasMetering();
125
        setPrevBaseFee(vm, address(op), 1 gwei);
126 127 128
        // The amount of data typically sent during a bridge deposit.
        bytes
            memory data = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
129
        vm.resumeGasMetering();
130 131 132
        L1Messenger.sendMessage(bob, data, uint32(100));
    }

133
    function test_sendMessage_benchmark_1() external {
134
        vm.pauseGasMetering();
135
        setPrevBaseFee(vm, address(op), 10 gwei);
136 137 138
        // The amount of data typically sent during a bridge deposit.
        bytes
            memory data = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
139
        vm.resumeGasMetering();
140 141 142 143 144 145 146 147 148
        L1Messenger.sendMessage(bob, data, uint32(100));
    }
}

contract GasBenchMark_L1StandardBridge_Deposit is Bridge_Initializer {
    function setUp() public virtual override {
        super.setUp();
        deal(address(L1Token), alice, 100000, true);
        vm.startPrank(alice, alice);
149
        L1Token.approve(address(L1Bridge), type(uint256).max);
150 151 152
    }

    function test_depositETH_benchmark_0() external {
153
        vm.pauseGasMetering();
154
        setPrevBaseFee(vm, address(op), 1 gwei);
155
        vm.resumeGasMetering();
156 157 158 159
        L1Bridge.depositETH{ value: 500 }(50000, hex"");
    }

    function test_depositETH_benchmark_1() external {
160
        vm.pauseGasMetering();
161
        setPrevBaseFee(vm, address(op), 10 gwei);
162
        vm.resumeGasMetering();
163 164 165 166
        L1Bridge.depositETH{ value: 500 }(50000, hex"");
    }

    function test_depositERC20_benchmark_0() external {
167
        vm.pauseGasMetering();
168
        setPrevBaseFee(vm, address(op), 1 gwei);
169
        vm.resumeGasMetering();
170 171 172 173 174 175 176
        L1Bridge.bridgeERC20({
            _localToken: address(L1Token),
            _remoteToken: address(L2Token),
            _amount: 100,
            _minGasLimit: 100_000,
            _extraData: hex""
        });
177 178 179
    }

    function test_depositERC20_benchmark_1() external {
180
        vm.pauseGasMetering();
181
        setPrevBaseFee(vm, address(op), 10 gwei);
182
        vm.resumeGasMetering();
183 184 185 186 187 188 189
        L1Bridge.bridgeERC20({
            _localToken: address(L1Token),
            _remoteToken: address(L2Token),
            _amount: 100,
            _minGasLimit: 100_000,
            _extraData: hex""
        });
190 191 192 193 194 195 196 197 198 199
    }
}

contract GasBenchMark_L1StandardBridge_Finalize is Bridge_Initializer {
    function setUp() public virtual override {
        super.setUp();
        deal(address(L1Token), address(L1Bridge), 100, true);
        vm.mockCall(
            address(L1Bridge.messenger()),
            abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector),
200
            abi.encode(address(L1Bridge.OTHER_BRIDGE()))
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
        );
        vm.startPrank(address(L1Bridge.messenger()));
        vm.deal(address(L1Bridge.messenger()), 100);
    }

    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.
        L1Bridge.finalizeETHWithdrawal{ value: 100 }(alice, alice, 100, hex"");
    }
}

contract GasBenchMark_L2OutputOracle is L2OutputOracle_Initializer {
    uint256 nextBlockNumber;

    function setUp() public override {
        super.setUp();
        nextBlockNumber = oracle.nextBlockNumber();
220 221
        warpToProposeTime(nextBlockNumber);
        vm.startPrank(proposer);
222 223
    }

224 225
    function test_proposeL2Output_benchmark() external {
        oracle.proposeL2Output(nonZeroHash, nextBlockNumber, 0, 0);
226 227
    }
}