Commit 987658bc authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

Merge pull request #3053 from ethereum-optimism/sc/ctb-types-struct

feat(ctb): introduce Types.sol
parents bad725d7 5c8133f1
---
'@eth-optimism/contracts-bedrock': patch
---
Introduces Types.sol
This diff is collapsed.
This diff is collapsed.
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
// This file is a generated binding and any manual changes will be lost. // This file is a generated binding and any manual changes will be lost.
package bindings package bindings
var L2ToL1MessagePasserDeployedBin = "0x60806040526004361061005e5760003560e01c806382e3702d1161004357806382e3702d146100c7578063affed0e014610107578063c2b3e5ac1461012b57600080fd5b806344df8e701461008757806354fd4d501461009c57600080fd5b366100825761008033620186a060405180602001604052806000815250610139565b005b600080fd5b34801561009357600080fd5b506100806101ef565b3480156100a857600080fd5b506100b1610227565b6040516100be91906104fb565b60405180910390f35b3480156100d357600080fd5b506100f76100e2366004610515565b60006020819052908152604090205460ff1681565b60405190151581526020016100be565b34801561011357600080fd5b5061011d60015481565b6040519081526020016100be565b61008061013936600461055d565b600061014b60015433863487876102ca565b6000818152602081905260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915554905191925073ffffffffffffffffffffffffffffffffffffffff8616913391907f87bf7b546c8de873abb0db5b579ec131f8d0cf5b14f39933551cf9ced23a6136906101d990349089908990610661565b60405180910390a4505060018054810190555050565b476101f981610309565b60405181907f7967de617a5ac1cc7eba2d6f37570a0135afa950d8bb77cdd35f0d0b4e85a16f90600090a250565b60606102527f0000000000000000000000000000000000000000000000000000000000000000610338565b61027b7f0000000000000000000000000000000000000000000000000000000000000000610338565b6102a47f0000000000000000000000000000000000000000000000000000000000000000610338565b6040516020016102b693929190610689565b604051602081830303815290604052905090565b60008686868686866040516020016102e7969594939291906106ff565b6040516020818303038152906040528051906020012090509695505050505050565b8060405161031690610475565b6040518091039082f0905080158015610333573d6000803e3d6000fd5b505050565b60608160000361037b57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156103a5578061038f81610785565b915061039e9050600a836107ec565b915061037f565b60008167ffffffffffffffff8111156103c0576103c061052e565b6040519080825280601f01601f1916602001820160405280156103ea576020820181803683370190505b5090505b841561046d576103ff600183610800565b915061040c600a86610817565b61041790603061082b565b60f81b81838151811061042c5761042c610843565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350610466600a866107ec565b94506103ee565b949350505050565b60088061087383390190565b60005b8381101561049c578181015183820152602001610484565b838111156104ab576000848401525b50505050565b600081518084526104c9816020860160208601610481565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061050e60208301846104b1565b9392505050565b60006020828403121561052757600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561057257600080fd5b833573ffffffffffffffffffffffffffffffffffffffff8116811461059657600080fd5b925060208401359150604084013567ffffffffffffffff808211156105ba57600080fd5b818601915086601f8301126105ce57600080fd5b8135818111156105e0576105e061052e565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156106265761062661052e565b8160405282815289602084870101111561063f57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b83815282602082015260606040820152600061068060608301846104b1565b95945050505050565b6000845161069b818460208901610481565b80830190507f2e0000000000000000000000000000000000000000000000000000000000000080825285516106d7816001850160208a01610481565b600192019182015283516106f2816002840160208801610481565b0160020195945050505050565b868152600073ffffffffffffffffffffffffffffffffffffffff808816602084015280871660408401525084606083015283608083015260c060a083015261074a60c08301846104b1565b98975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036107b6576107b6610756565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826107fb576107fb6107bd565b500490565b60008282101561081257610812610756565b500390565b600082610826576108266107bd565b500690565b6000821982111561083e5761083e610756565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfe608060405230fffea164736f6c634300080f000a" var L2ToL1MessagePasserDeployedBin = "0x60806040526004361061005e5760003560e01c806382e3702d1161004357806382e3702d146100c7578063affed0e014610107578063c2b3e5ac1461012b57600080fd5b806344df8e701461008757806354fd4d501461009c57600080fd5b366100825761008033620186a060405180602001604052806000815250610139565b005b600080fd5b34801561009357600080fd5b50610080610242565b3480156100a857600080fd5b506100b161027a565b6040516100be919061055c565b60405180910390f35b3480156100d357600080fd5b506100f76100e2366004610576565b60006020819052908152604090205460ff1681565b60405190151581526020016100be565b34801561011357600080fd5b5061011d60015481565b6040519081526020016100be565b6100806101393660046105be565b600061019e6040518060c0016040528060015481526020013373ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1681526020013481526020018581526020018481525061031d565b6000818152602081905260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915554905191925073ffffffffffffffffffffffffffffffffffffffff8616913391907f87bf7b546c8de873abb0db5b579ec131f8d0cf5b14f39933551cf9ced23a61369061022c903490899089906106c2565b60405180910390a4505060018054810190555050565b4761024c8161036a565b60405181907f7967de617a5ac1cc7eba2d6f37570a0135afa950d8bb77cdd35f0d0b4e85a16f90600090a250565b60606102a57f0000000000000000000000000000000000000000000000000000000000000000610399565b6102ce7f0000000000000000000000000000000000000000000000000000000000000000610399565b6102f77f0000000000000000000000000000000000000000000000000000000000000000610399565b604051602001610309939291906106ea565b604051602081830303815290604052905090565b80516020808301516040808501516060860151608087015160a0880151935160009761034d979096959101610760565b604051602081830303815290604052805190602001209050919050565b80604051610377906104d6565b6040518091039082f0905080158015610394573d6000803e3d6000fd5b505050565b6060816000036103dc57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b811561040657806103f0816107e6565b91506103ff9050600a8361084d565b91506103e0565b60008167ffffffffffffffff8111156104215761042161058f565b6040519080825280601f01601f19166020018201604052801561044b576020820181803683370190505b5090505b84156104ce57610460600183610861565b915061046d600a86610878565b61047890603061088c565b60f81b81838151811061048d5761048d6108a4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506104c7600a8661084d565b945061044f565b949350505050565b6008806108d483390190565b60005b838110156104fd5781810151838201526020016104e5565b8381111561050c576000848401525b50505050565b6000815180845261052a8160208601602086016104e2565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061056f6020830184610512565b9392505050565b60006020828403121561058857600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156105d357600080fd5b833573ffffffffffffffffffffffffffffffffffffffff811681146105f757600080fd5b925060208401359150604084013567ffffffffffffffff8082111561061b57600080fd5b818601915086601f83011261062f57600080fd5b8135818111156106415761064161058f565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156106875761068761058f565b816040528281528960208487010111156106a057600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b8381528260208201526060604082015260006106e16060830184610512565b95945050505050565b600084516106fc8184602089016104e2565b80830190507f2e000000000000000000000000000000000000000000000000000000000000008082528551610738816001850160208a016104e2565b600192019182015283516107538160028401602088016104e2565b0160020195945050505050565b868152600073ffffffffffffffffffffffffffffffffffffffff808816602084015280871660408401525084606083015283608083015260c060a08301526107ab60c0830184610512565b98975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610817576108176107b7565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261085c5761085c61081e565b500490565b600082821015610873576108736107b7565b500390565b6000826108875761088761081e565b500690565b6000821982111561089f5761089f6107b7565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfe608060405230fffea164736f6c634300080f000a"
This diff is collapsed.
...@@ -899,12 +899,14 @@ func TestWithdrawals(t *testing.T) { ...@@ -899,12 +899,14 @@ func TestWithdrawals(t *testing.T) {
opts.Value = nil opts.Value = nil
tx, err = portal.FinalizeWithdrawalTransaction( tx, err = portal.FinalizeWithdrawalTransaction(
opts, opts,
params.Nonce, bindings.TypesWithdrawalTransaction{
params.Sender, Nonce: params.Nonce,
params.Target, Sender: params.Sender,
params.Value, Target: params.Target,
params.GasLimit, Value: params.Value,
params.Data, GasLimit: params.GasLimit,
Data: params.Data,
},
params.BlockNumber, params.BlockNumber,
params.OutputRootProof, params.OutputRootProof,
params.WithdrawalProof, params.WithdrawalProof,
......
...@@ -154,7 +154,7 @@ type FinalizedWithdrawalParameters struct { ...@@ -154,7 +154,7 @@ type FinalizedWithdrawalParameters struct {
GasLimit *big.Int GasLimit *big.Int
BlockNumber *big.Int BlockNumber *big.Int
Data []byte Data []byte
OutputRootProof bindings.HashingOutputRootProof OutputRootProof bindings.TypesOutputRootProof
WithdrawalProof []byte // RLP Encoded list of trie nodes to prove L2 storage WithdrawalProof []byte // RLP Encoded list of trie nodes to prove L2 storage
} }
...@@ -210,7 +210,7 @@ func FinalizeWithdrawalParameters(ctx context.Context, l2client ProofClient, txH ...@@ -210,7 +210,7 @@ func FinalizeWithdrawalParameters(ctx context.Context, l2client ProofClient, txH
GasLimit: ev.GasLimit, GasLimit: ev.GasLimit,
BlockNumber: new(big.Int).Set(header.Number), BlockNumber: new(big.Int).Set(header.Number),
Data: ev.Data, Data: ev.Data,
OutputRootProof: bindings.HashingOutputRootProof{ OutputRootProof: bindings.TypesOutputRootProof{
Version: [32]byte{}, // Empty for version 1 Version: [32]byte{}, // Empty for version 1
StateRoot: header.Root, StateRoot: header.Root,
WithdrawerStorageRoot: p.StorageHash, WithdrawerStorageRoot: p.StorageHash,
......
This diff is collapsed.
...@@ -62,25 +62,25 @@ ...@@ -62,25 +62,25 @@
➡ L2OutputOracle ➡ L2OutputOracle
======================= =======================
+-------------------+----------------------------------------------------------+------+--------+-------+------------------------------------------------+ +-------------------+-------------------------------------------------+------+--------+-------+------------------------------------------------+
| Name | Type | Slot | Offset | Bytes | Contract | | Name | Type | Slot | Offset | Bytes | Contract |
+=======================================================================================================================================================+ +==============================================================================================================================================+
| _initialized | uint8 | 0 | 0 | 1 | contracts/L1/L2OutputOracle.sol:L2OutputOracle | | _initialized | uint8 | 0 | 0 | 1 | contracts/L1/L2OutputOracle.sol:L2OutputOracle |
|-------------------+----------------------------------------------------------+------+--------+-------+------------------------------------------------| |-------------------+-------------------------------------------------+------+--------+-------+------------------------------------------------|
| _initializing | bool | 0 | 1 | 1 | contracts/L1/L2OutputOracle.sol:L2OutputOracle | | _initializing | bool | 0 | 1 | 1 | contracts/L1/L2OutputOracle.sol:L2OutputOracle |
|-------------------+----------------------------------------------------------+------+--------+-------+------------------------------------------------| |-------------------+-------------------------------------------------+------+--------+-------+------------------------------------------------|
| __gap | uint256[50] | 1 | 0 | 1600 | contracts/L1/L2OutputOracle.sol:L2OutputOracle | | __gap | uint256[50] | 1 | 0 | 1600 | contracts/L1/L2OutputOracle.sol:L2OutputOracle |
|-------------------+----------------------------------------------------------+------+--------+-------+------------------------------------------------| |-------------------+-------------------------------------------------+------+--------+-------+------------------------------------------------|
| _owner | address | 51 | 0 | 20 | contracts/L1/L2OutputOracle.sol:L2OutputOracle | | _owner | address | 51 | 0 | 20 | contracts/L1/L2OutputOracle.sol:L2OutputOracle |
|-------------------+----------------------------------------------------------+------+--------+-------+------------------------------------------------| |-------------------+-------------------------------------------------+------+--------+-------+------------------------------------------------|
| __gap | uint256[49] | 52 | 0 | 1568 | contracts/L1/L2OutputOracle.sol:L2OutputOracle | | __gap | uint256[49] | 52 | 0 | 1568 | contracts/L1/L2OutputOracle.sol:L2OutputOracle |
|-------------------+----------------------------------------------------------+------+--------+-------+------------------------------------------------| |-------------------+-------------------------------------------------+------+--------+-------+------------------------------------------------|
| proposer | address | 101 | 0 | 20 | contracts/L1/L2OutputOracle.sol:L2OutputOracle | | proposer | address | 101 | 0 | 20 | contracts/L1/L2OutputOracle.sol:L2OutputOracle |
|-------------------+----------------------------------------------------------+------+--------+-------+------------------------------------------------| |-------------------+-------------------------------------------------+------+--------+-------+------------------------------------------------|
| latestBlockNumber | uint256 | 102 | 0 | 32 | contracts/L1/L2OutputOracle.sol:L2OutputOracle | | latestBlockNumber | uint256 | 102 | 0 | 32 | contracts/L1/L2OutputOracle.sol:L2OutputOracle |
|-------------------+----------------------------------------------------------+------+--------+-------+------------------------------------------------| |-------------------+-------------------------------------------------+------+--------+-------+------------------------------------------------|
| l2Outputs | mapping(uint256 => struct L2OutputOracle.OutputProposal) | 103 | 0 | 32 | contracts/L1/L2OutputOracle.sol:L2OutputOracle | | l2Outputs | mapping(uint256 => struct Types.OutputProposal) | 103 | 0 | 32 | contracts/L1/L2OutputOracle.sol:L2OutputOracle |
+-------------------+----------------------------------------------------------+------+--------+-------+------------------------------------------------+ +-------------------+-------------------------------------------------+------+--------+-------+------------------------------------------------+
======================= =======================
➡ OptimismPortal ➡ OptimismPortal
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
The repo currently uses solidity tests (run with Forge). The project uses the default hardhat directory structure, and all build/test steps should be run using the yarn scripts to ensure The repo currently uses solidity tests (run with Forge). The project uses the default hardhat directory structure, and all build/test steps should be run using the yarn scripts to ensure
the correct options are set. the correct options are set.
Install node modules with yarn (v1), and Node.js (14+). Install node modules with yarn (v1), and Node.js (16+).
```shell ```shell
yarn yarn
...@@ -27,6 +27,8 @@ Then the full test suite can be executed via `yarn`: ...@@ -27,6 +27,8 @@ Then the full test suite can be executed via `yarn`:
yarn test yarn test
``` ```
The differential tests require typescript to be compiled to javascript.
## Deployment ## Deployment
Create a file that corresponds to the network name in the `deploy-config` Create a file that corresponds to the network name in the `deploy-config`
......
...@@ -5,6 +5,7 @@ import { ...@@ -5,6 +5,7 @@ import {
OwnableUpgradeable OwnableUpgradeable
} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { Semver } from "../universal/Semver.sol"; import { Semver } from "../universal/Semver.sol";
import { Types } from "../libraries/Types.sol";
/** /**
* @custom:proxied * @custom:proxied
...@@ -15,17 +16,6 @@ import { Semver } from "../universal/Semver.sol"; ...@@ -15,17 +16,6 @@ import { Semver } from "../universal/Semver.sol";
*/ */
// slither-disable-next-line locked-ether // slither-disable-next-line locked-ether
contract L2OutputOracle is OwnableUpgradeable, Semver { contract L2OutputOracle is OwnableUpgradeable, Semver {
/**
* @notice OutputProposal represents a commitment to the L2 state.
* The timestamp is the L1 timestamp that the output root is posted.
* This timestamp is used to verify that the finalization period
* has passed since the output root was submitted.
*/
struct OutputProposal {
bytes32 outputRoot;
uint256 timestamp;
}
/** /**
* @notice Emitted when an output is proposed. * @notice Emitted when an output is proposed.
* *
...@@ -105,7 +95,7 @@ contract L2OutputOracle is OwnableUpgradeable, Semver { ...@@ -105,7 +95,7 @@ contract L2OutputOracle is OwnableUpgradeable, Semver {
* outputs should not be considered finalized until the finalization period (as defined * outputs should not be considered finalized until the finalization period (as defined
* in the Optimism Portal) has passed. * in the Optimism Portal) has passed.
*/ */
mapping(uint256 => OutputProposal) internal l2Outputs; mapping(uint256 => Types.OutputProposal) internal l2Outputs;
/** /**
* @notice Reverts if called by any account other than the proposer. * @notice Reverts if called by any account other than the proposer.
...@@ -165,7 +155,7 @@ contract L2OutputOracle is OwnableUpgradeable, Semver { ...@@ -165,7 +155,7 @@ contract L2OutputOracle is OwnableUpgradeable, Semver {
address _proposer, address _proposer,
address _owner address _owner
) public initializer { ) public initializer {
l2Outputs[_startingBlockNumber] = OutputProposal(_genesisL2Output, block.timestamp); l2Outputs[_startingBlockNumber] = Types.OutputProposal(_genesisL2Output, block.timestamp);
latestBlockNumber = _startingBlockNumber; latestBlockNumber = _startingBlockNumber;
__Ownable_init(); __Ownable_init();
changeProposer(_proposer); changeProposer(_proposer);
...@@ -218,7 +208,7 @@ contract L2OutputOracle is OwnableUpgradeable, Semver { ...@@ -218,7 +208,7 @@ contract L2OutputOracle is OwnableUpgradeable, Semver {
); );
} }
l2Outputs[_l2BlockNumber] = OutputProposal(_outputRoot, block.timestamp); l2Outputs[_l2BlockNumber] = Types.OutputProposal(_outputRoot, block.timestamp);
latestBlockNumber = _l2BlockNumber; latestBlockNumber = _l2BlockNumber;
emit OutputProposed(_outputRoot, block.timestamp, _l2BlockNumber); emit OutputProposed(_outputRoot, block.timestamp, _l2BlockNumber);
...@@ -233,8 +223,8 @@ contract L2OutputOracle is OwnableUpgradeable, Semver { ...@@ -233,8 +223,8 @@ contract L2OutputOracle is OwnableUpgradeable, Semver {
* *
* @param _proposal Represents the output proposal to delete * @param _proposal Represents the output proposal to delete
*/ */
function deleteL2Output(OutputProposal memory _proposal) external onlyOwner { function deleteL2Output(Types.OutputProposal memory _proposal) external onlyOwner {
OutputProposal memory outputToDelete = l2Outputs[latestBlockNumber]; Types.OutputProposal memory outputToDelete = l2Outputs[latestBlockNumber];
require( require(
_proposal.outputRoot == outputToDelete.outputRoot, _proposal.outputRoot == outputToDelete.outputRoot,
...@@ -268,7 +258,11 @@ contract L2OutputOracle is OwnableUpgradeable, Semver { ...@@ -268,7 +258,11 @@ contract L2OutputOracle is OwnableUpgradeable, Semver {
* *
* @param _l2BlockNumber The L2 block number of the target block. * @param _l2BlockNumber The L2 block number of the target block.
*/ */
function getL2Output(uint256 _l2BlockNumber) external view returns (OutputProposal memory) { function getL2Output(uint256 _l2BlockNumber)
external
view
returns (Types.OutputProposal memory)
{
require( require(
_l2BlockNumber >= STARTING_BLOCK_NUMBER, _l2BlockNumber >= STARTING_BLOCK_NUMBER,
"L2OutputOracle: block number cannot be less than the starting block number." "L2OutputOracle: block number cannot be less than the starting block number."
...@@ -283,7 +277,7 @@ contract L2OutputOracle is OwnableUpgradeable, Semver { ...@@ -283,7 +277,7 @@ contract L2OutputOracle is OwnableUpgradeable, Semver {
? _l2BlockNumber ? _l2BlockNumber
: _l2BlockNumber + (SUBMISSION_INTERVAL - offset); : _l2BlockNumber + (SUBMISSION_INTERVAL - offset);
OutputProposal memory output = l2Outputs[lookupBlockNumber]; Types.OutputProposal memory output = l2Outputs[lookupBlockNumber];
require( require(
output.outputRoot != bytes32(0), output.outputRoot != bytes32(0),
"L2OutputOracle: No output found for that block number." "L2OutputOracle: No output found for that block number."
......
...@@ -4,6 +4,7 @@ pragma solidity 0.8.15; ...@@ -4,6 +4,7 @@ pragma solidity 0.8.15;
import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import { ExcessivelySafeCall } from "excessively-safe-call/src/ExcessivelySafeCall.sol"; import { ExcessivelySafeCall } from "excessively-safe-call/src/ExcessivelySafeCall.sol";
import { L2OutputOracle } from "./L2OutputOracle.sol"; import { L2OutputOracle } from "./L2OutputOracle.sol";
import { Types } from "../libraries/Types.sol";
import { Hashing } from "../libraries/Hashing.sol"; import { Hashing } from "../libraries/Hashing.sol";
import { SecureMerkleTrie } from "../libraries/trie/SecureMerkleTrie.sol"; import { SecureMerkleTrie } from "../libraries/trie/SecureMerkleTrie.sol";
import { AddressAliasHelper } from "../vendor/AddressAliasHelper.sol"; import { AddressAliasHelper } from "../vendor/AddressAliasHelper.sol";
...@@ -175,8 +176,7 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver { ...@@ -175,8 +176,7 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
* @param _l2BlockNumber The number of the L2 block. * @param _l2BlockNumber The number of the L2 block.
*/ */
function isBlockFinalized(uint256 _l2BlockNumber) external view returns (bool) { function isBlockFinalized(uint256 _l2BlockNumber) external view returns (bool) {
L2OutputOracle.OutputProposal memory proposal = L2_ORACLE.getL2Output(_l2BlockNumber); Types.OutputProposal memory proposal = L2_ORACLE.getL2Output(_l2BlockNumber);
return _isOutputFinalized(proposal); return _isOutputFinalized(proposal);
} }
...@@ -185,7 +185,7 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver { ...@@ -185,7 +185,7 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
* *
* @param _proposal The output proposal to check. * @param _proposal The output proposal to check.
*/ */
function _isOutputFinalized(L2OutputOracle.OutputProposal memory _proposal) function _isOutputFinalized(Types.OutputProposal memory _proposal)
internal internal
view view
returns (bool) returns (bool)
...@@ -196,25 +196,15 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver { ...@@ -196,25 +196,15 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
/** /**
* @notice Finalizes a withdrawal transaction. * @notice Finalizes a withdrawal transaction.
* *
* @param _nonce Nonce for the provided message. * @param _tx Withdrawal transaction to finalize.
* @param _sender Message sender address on L2.
* @param _target Target address on L1.
* @param _value ETH to send to the target.
* @param _gasLimit Minumum gas to be forwarded to the target.
* @param _data Data to send to the target.
* @param _l2BlockNumber L2 block number of the outputRoot. * @param _l2BlockNumber L2 block number of the outputRoot.
* @param _outputRootProof Inclusion proof of the withdrawer contracts storage root. * @param _outputRootProof Inclusion proof of the withdrawer contracts storage root.
* @param _withdrawalProof Inclusion proof for the given withdrawal in the withdrawer contract. * @param _withdrawalProof Inclusion proof for the given withdrawal in the withdrawer contract.
*/ */
function finalizeWithdrawalTransaction( function finalizeWithdrawalTransaction(
uint256 _nonce, Types.WithdrawalTransaction memory _tx,
address _sender,
address _target,
uint256 _value,
uint256 _gasLimit,
bytes calldata _data,
uint256 _l2BlockNumber, uint256 _l2BlockNumber,
Hashing.OutputRootProof calldata _outputRootProof, Types.OutputRootProof calldata _outputRootProof,
bytes calldata _withdrawalProof bytes calldata _withdrawalProof
) external payable { ) external payable {
// Prevent nested withdrawals within withdrawals. // Prevent nested withdrawals within withdrawals.
...@@ -226,13 +216,13 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver { ...@@ -226,13 +216,13 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
// Prevent users from creating a deposit transaction where this address is the message // Prevent users from creating a deposit transaction where this address is the message
// sender on L2. // sender on L2.
require( require(
_target != address(this), _tx.target != address(this),
"OptimismPortal: you cannot send messages to the portal contract" "OptimismPortal: you cannot send messages to the portal contract"
); );
// Get the output root. This will fail if there is no // Get the output root. This will fail if there is no
// output root for the given block number. // output root for the given block number.
L2OutputOracle.OutputProposal memory proposal = L2_ORACLE.getL2Output(_l2BlockNumber); Types.OutputProposal memory proposal = L2_ORACLE.getL2Output(_l2BlockNumber);
// Ensure that enough time has passed since the proposal was submitted before allowing a // Ensure that enough time has passed since the proposal was submitted before allowing a
// withdrawal. Under the assumption that the fault proof mechanism is operating correctly, // withdrawal. Under the assumption that the fault proof mechanism is operating correctly,
...@@ -248,14 +238,7 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver { ...@@ -248,14 +238,7 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
// All withdrawals have a unique hash, we'll use this as the identifier for the withdrawal // All withdrawals have a unique hash, we'll use this as the identifier for the withdrawal
// and to prevent replay attacks. // and to prevent replay attacks.
bytes32 withdrawalHash = Hashing.hashWithdrawal( bytes32 withdrawalHash = Hashing.hashWithdrawal(_tx);
_nonce,
_sender,
_target,
_value,
_gasLimit,
_data
);
// Verify that the hash of this withdrawal was stored in the withdrawal contract on L2. If // Verify that the hash of this withdrawal was stored in the withdrawal contract on L2. If
// this is true, then we know that this withdrawal was actually triggered on L2 can can // this is true, then we know that this withdrawal was actually triggered on L2 can can
...@@ -282,22 +265,22 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver { ...@@ -282,22 +265,22 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
// target contract is at least the gas limit specified by the user. We can do this by // target contract is at least the gas limit specified by the user. We can do this by
// enforcing that, at this point in time, we still have gaslimit + buffer gas available. // enforcing that, at this point in time, we still have gaslimit + buffer gas available.
require( require(
gasleft() >= _gasLimit + FINALIZE_GAS_BUFFER, gasleft() >= _tx.gasLimit + FINALIZE_GAS_BUFFER,
"OptimismPortal: insufficient gas to finalize withdrawal" "OptimismPortal: insufficient gas to finalize withdrawal"
); );
// Set the l2Sender so contracts know who triggered this withdrawal on L2. // Set the l2Sender so contracts know who triggered this withdrawal on L2.
l2Sender = _sender; l2Sender = _tx.sender;
// Trigger the call to the target contract. We use excessivelySafeCall because we don't // Trigger the call to the target contract. We use excessivelySafeCall because we don't
// care about the returndata and we don't want target contracts to be able to force this // care about the returndata and we don't want target contracts to be able to force this
// call to run out of gas. // call to run out of gas.
(bool success, ) = ExcessivelySafeCall.excessivelySafeCall( (bool success, ) = ExcessivelySafeCall.excessivelySafeCall(
_target, _tx.target,
_gasLimit, _tx.gasLimit,
_value, _tx.value,
0, 0,
_data _tx.data
); );
// Reset the l2Sender back to the default value. // Reset the l2Sender back to the default value.
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { Types } from "../libraries/Types.sol";
import { Hashing } from "../libraries/Hashing.sol"; import { Hashing } from "../libraries/Hashing.sol";
import { Burn } from "../libraries/Burn.sol"; import { Burn } from "../libraries/Burn.sol";
import { Semver } from "../universal/Semver.sol"; import { Semver } from "../universal/Semver.sol";
...@@ -80,12 +81,14 @@ contract L2ToL1MessagePasser is Semver { ...@@ -80,12 +81,14 @@ contract L2ToL1MessagePasser is Semver {
bytes memory _data bytes memory _data
) public payable { ) public payable {
bytes32 withdrawalHash = Hashing.hashWithdrawal( bytes32 withdrawalHash = Hashing.hashWithdrawal(
nonce, Types.WithdrawalTransaction({
msg.sender, nonce: nonce,
_target, sender: msg.sender,
msg.value, target: _target,
_gasLimit, value: msg.value,
_data gasLimit: _gasLimit,
data: _data
})
); );
sentMessages[withdrawalHash] = true; sentMessages[withdrawalHash] = true;
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; pragma solidity ^0.8.0;
import { Types } from "./Types.sol";
import { Hashing } from "./Hashing.sol"; import { Hashing } from "./Hashing.sol";
import { RLPWriter } from "./rlp/RLPWriter.sol"; import { RLPWriter } from "./rlp/RLPWriter.sol";
...@@ -13,38 +14,24 @@ library Encoding { ...@@ -13,38 +14,24 @@ library Encoding {
* @notice RLP encodes the L2 transaction that would be generated when a given deposit is sent * @notice RLP encodes the L2 transaction that would be generated when a given deposit is sent
* to the L2 system. Useful for searching for a deposit in the L2 system. * to the L2 system. Useful for searching for a deposit in the L2 system.
* *
* @param _from Address of the sender of the deposit. * @param _tx User deposit transaction to encode.
* @param _to Address of the receiver of the deposit.
* @param _value ETH value to send to the receiver.
* @param _mint ETH value to mint on L2.
* @param _gasLimit Gas limit to use for the transaction.
* @param _isCreation Whether or not the transaction is a contract creation.
* @param _data Data to send with the transaction.
* @param _l1BlockHash Hash of the L1 block where the deposit was included.
* @param _logIndex Index of the deposit event in the L1 block.
* *
* @return RLP encoded L2 deposit transaction. * @return RLP encoded L2 deposit transaction.
*/ */
function encodeDepositTransaction( function encodeDepositTransaction(Types.UserDepositTransaction memory _tx)
address _from, internal
address _to, pure
uint256 _value, returns (bytes memory)
uint256 _mint, {
uint64 _gasLimit, bytes32 source = Hashing.hashDepositSource(_tx.l1BlockHash, _tx.logIndex);
bool _isCreation,
bytes memory _data,
bytes32 _l1BlockHash,
uint256 _logIndex
) internal pure returns (bytes memory) {
bytes32 source = Hashing.hashDepositSource(_l1BlockHash, _logIndex);
bytes[] memory raw = new bytes[](7); bytes[] memory raw = new bytes[](7);
raw[0] = RLPWriter.writeBytes(abi.encodePacked(source)); raw[0] = RLPWriter.writeBytes(abi.encodePacked(source));
raw[1] = RLPWriter.writeAddress(_from); raw[1] = RLPWriter.writeAddress(_tx.from);
raw[2] = _isCreation ? RLPWriter.writeBytes("") : RLPWriter.writeAddress(_to); raw[2] = _tx.isCreation ? RLPWriter.writeBytes("") : RLPWriter.writeAddress(_tx.to);
raw[3] = RLPWriter.writeUint(_mint); raw[3] = RLPWriter.writeUint(_tx.mint);
raw[4] = RLPWriter.writeUint(_value); raw[4] = RLPWriter.writeUint(_tx.value);
raw[5] = RLPWriter.writeUint(uint256(_gasLimit)); raw[5] = RLPWriter.writeUint(uint256(_tx.gasLimit));
raw[6] = RLPWriter.writeBytes(_data); raw[6] = RLPWriter.writeBytes(_tx.data);
return abi.encodePacked(uint8(0x7e), RLPWriter.writeList(raw)); return abi.encodePacked(uint8(0x7e), RLPWriter.writeList(raw));
} }
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; pragma solidity ^0.8.0;
import { Types } from "./Types.sol";
import { Encoding } from "./Encoding.sol"; import { Encoding } from "./Encoding.sol";
/** /**
...@@ -8,58 +9,21 @@ import { Encoding } from "./Encoding.sol"; ...@@ -8,58 +9,21 @@ import { Encoding } from "./Encoding.sol";
* @notice Hashing handles Optimism's various different hashing schemes. * @notice Hashing handles Optimism's various different hashing schemes.
*/ */
library Hashing { library Hashing {
/**
* @notice Struct representing the elements that are hashed together to generate an output root
* which itself represents a snapshot of the L2 state.
*/
struct OutputRootProof {
bytes32 version;
bytes32 stateRoot;
bytes32 withdrawerStorageRoot;
bytes32 latestBlockhash;
}
/** /**
* @notice Computes the hash of the RLP encoded L2 transaction that would be generated when a * @notice Computes the hash of the RLP encoded L2 transaction that would be generated when a
* given deposit is sent to the L2 system. Useful for searching for a deposit in the L2 * given deposit is sent to the L2 system. Useful for searching for a deposit in the L2
* system. * system.
* *
* @param _from Address of the sender of the deposit. * @param _tx User deposit transaction to hash.
* @param _to Address of the receiver of the deposit.
* @param _value ETH value to send to the receiver.
* @param _mint ETH value to mint on L2.
* @param _gasLimit Gas limit to use for the transaction.
* @param _isCreation Whether or not the transaction is a contract creation.
* @param _data Data to send with the transaction.
* @param _l1BlockHash Hash of the L1 block where the deposit was included.
* @param _logIndex Index of the deposit event in the L1 block.
* *
* @return Hash of the RLP encoded L2 deposit transaction. * @return Hash of the RLP encoded L2 deposit transaction.
*/ */
function hashDepositTransaction( function hashDepositTransaction(Types.UserDepositTransaction memory _tx)
address _from, internal
address _to, pure
uint256 _value, returns (bytes32)
uint256 _mint, {
uint64 _gasLimit, return keccak256(Encoding.encodeDepositTransaction(_tx));
bool _isCreation,
bytes memory _data,
bytes32 _l1BlockHash,
uint256 _logIndex
) internal pure returns (bytes32) {
bytes memory raw = Encoding.encodeDepositTransaction(
_from,
_to,
_value,
_mint,
_gasLimit,
_isCreation,
_data,
_l1BlockHash,
_logIndex
);
return keccak256(raw);
} }
/** /**
...@@ -166,22 +130,20 @@ library Hashing { ...@@ -166,22 +130,20 @@ library Hashing {
/** /**
* @notice Derives the withdrawal hash according to the encoding in the L2 Withdrawer contract * @notice Derives the withdrawal hash according to the encoding in the L2 Withdrawer contract
* @param _nonce Nonce for the provided message. *
* @param _sender Message sender address on L2. * @param _tx Withdrawal transaction to hash.
* @param _target Target address on L1. *
* @param _value ETH to send to the target. * @return Hashed withdrawal transaction.
* @param _gasLimit Gas to be forwarded to the target.
* @param _data Data to send to the target.
*/ */
function hashWithdrawal( function hashWithdrawal(Types.WithdrawalTransaction memory _tx)
uint256 _nonce, internal
address _sender, pure
address _target, returns (bytes32)
uint256 _value, {
uint256 _gasLimit, return
bytes memory _data keccak256(
) internal pure returns (bytes32) { abi.encode(_tx.nonce, _tx.sender, _tx.target, _tx.value, _tx.gasLimit, _tx.data)
return keccak256(abi.encode(_nonce, _sender, _target, _value, _gasLimit, _data)); );
} }
/** /**
...@@ -192,7 +154,7 @@ library Hashing { ...@@ -192,7 +154,7 @@ library Hashing {
* *
* @return Hashed output root proof. * @return Hashed output root proof.
*/ */
function hashOutputRootProof(OutputRootProof memory _outputRootProof) function hashOutputRootProof(Types.OutputRootProof memory _outputRootProof)
internal internal
pure pure
returns (bytes32) returns (bytes32)
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/**
* @title Types
* @notice Contains various types used throughout the Optimism contract system.
*/
library Types {
/**
* @notice OutputProposal represents a commitment to the L2 state. The timestamp is the L1
* timestamp that the output root is posted. This timestamp is used to verify that the
* finalization period has passed since the output root was submitted.
*/
struct OutputProposal {
bytes32 outputRoot;
uint256 timestamp;
}
/**
* @notice Struct representing the elements that are hashed together to generate an output root
* which itself represents a snapshot of the L2 state.
*/
struct OutputRootProof {
bytes32 version;
bytes32 stateRoot;
bytes32 withdrawerStorageRoot;
bytes32 latestBlockhash;
}
/**
* @notice Struct representing a deposit transaction (L1 => L2 transaction) created by an end
* user (as opposed to a system deposit transaction generated by the system).
*/
struct UserDepositTransaction {
address from;
address to;
uint256 value;
uint256 mint;
uint64 gasLimit;
bool isCreation;
bytes data;
bytes32 l1BlockHash;
uint256 logIndex;
}
/**
* @notice Struct representing a withdrawal transaction.
*/
struct WithdrawalTransaction {
uint256 nonce;
address sender;
address target;
uint256 value;
uint256 gasLimit;
bytes data;
}
}
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { CommonTest } from "./CommonTest.t.sol"; import { CommonTest } from "./CommonTest.t.sol";
import { Types } from "../libraries/Types.sol";
import { Encoding } from "../libraries/Encoding.sol"; import { Encoding } from "../libraries/Encoding.sol";
contract Encoding_Test is CommonTest { contract Encoding_Test is CommonTest {
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { CommonTest } from "./CommonTest.t.sol"; import { CommonTest } from "./CommonTest.t.sol";
import { Types } from "../libraries/Types.sol";
import { Hashing } from "../libraries/Hashing.sol"; import { Hashing } from "../libraries/Hashing.sol";
import { Encoding } from "../libraries/Encoding.sol"; import { Encoding } from "../libraries/Encoding.sol";
...@@ -64,12 +65,14 @@ contract Hashing_Test is CommonTest { ...@@ -64,12 +65,14 @@ contract Hashing_Test is CommonTest {
bytes memory _data bytes memory _data
) external { ) external {
bytes32 hash = Hashing.hashWithdrawal( bytes32 hash = Hashing.hashWithdrawal(
_nonce, Types.WithdrawalTransaction(
_sender, _nonce,
_target, _sender,
_value, _target,
_gasLimit, _value,
_data _gasLimit,
_data
)
); );
bytes32 _hash = ffi.hashWithdrawal( bytes32 _hash = ffi.hashWithdrawal(
...@@ -90,7 +93,7 @@ contract Hashing_Test is CommonTest { ...@@ -90,7 +93,7 @@ contract Hashing_Test is CommonTest {
bytes32 _withdrawerStorageRoot, bytes32 _withdrawerStorageRoot,
bytes32 _latestBlockhash bytes32 _latestBlockhash
) external { ) external {
Hashing.OutputRootProof memory proof = Hashing.OutputRootProof({ Types.OutputRootProof memory proof = Types.OutputRootProof({
version: _version, version: _version,
stateRoot: _stateRoot, stateRoot: _stateRoot,
withdrawerStorageRoot: _withdrawerStorageRoot, withdrawerStorageRoot: _withdrawerStorageRoot,
...@@ -121,15 +124,17 @@ contract Hashing_Test is CommonTest { ...@@ -121,15 +124,17 @@ contract Hashing_Test is CommonTest {
uint256 _logIndex uint256 _logIndex
) external { ) external {
bytes32 hash = Hashing.hashDepositTransaction( bytes32 hash = Hashing.hashDepositTransaction(
_from, Types.UserDepositTransaction(
_to, _from,
_value, _to,
_mint, _value,
_gas, _mint,
false, // isCreate _gas,
_data, false, // isCreate
bytes32(uint256(0)), _data,
_logIndex bytes32(uint256(0)),
_logIndex
)
); );
bytes32 _hash = ffi.hashDepositTransaction( bytes32 _hash = ffi.hashDepositTransaction(
......
...@@ -4,7 +4,7 @@ pragma solidity 0.8.15; ...@@ -4,7 +4,7 @@ pragma solidity 0.8.15;
import { L2OutputOracle_Initializer, NextImpl } from "./CommonTest.t.sol"; import { L2OutputOracle_Initializer, NextImpl } from "./CommonTest.t.sol";
import { L2OutputOracle } from "../L1/L2OutputOracle.sol"; import { L2OutputOracle } from "../L1/L2OutputOracle.sol";
import { Proxy } from "../universal/Proxy.sol"; import { Proxy } from "../universal/Proxy.sol";
import { Types } from "../libraries/Types.sol";
contract L2OutputOracleTest is L2OutputOracle_Initializer { contract L2OutputOracleTest is L2OutputOracle_Initializer {
bytes32 proposedOutput1 = keccak256(abi.encode(1)); bytes32 proposedOutput1 = keccak256(abi.encode(1));
...@@ -23,7 +23,7 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer { ...@@ -23,7 +23,7 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer {
assertEq(oracle.proposer(), proposer); assertEq(oracle.proposer(), proposer);
assertEq(oracle.owner(), owner); assertEq(oracle.owner(), owner);
L2OutputOracle.OutputProposal memory proposal = oracle.getL2Output(startingBlockNumber); Types.OutputProposal memory proposal = oracle.getL2Output(startingBlockNumber);
assertEq(proposal.outputRoot, genesisL2Output); assertEq(proposal.outputRoot, genesisL2Output);
assertEq(proposal.timestamp, initL1Time); assertEq(proposal.timestamp, initL1Time);
} }
...@@ -50,7 +50,7 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer { ...@@ -50,7 +50,7 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer {
vm.prank(proposer); vm.prank(proposer);
oracle.proposeL2Output(proposedOutput1, nextBlockNumber, 0, 0); oracle.proposeL2Output(proposedOutput1, nextBlockNumber, 0, 0);
L2OutputOracle.OutputProposal memory proposal = oracle.getL2Output(nextBlockNumber); Types.OutputProposal memory proposal = oracle.getL2Output(nextBlockNumber);
assertEq(proposal.outputRoot, proposedOutput1); assertEq(proposal.outputRoot, proposedOutput1);
assertEq(proposal.timestamp, block.timestamp); assertEq(proposal.timestamp, block.timestamp);
...@@ -61,11 +61,11 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer { ...@@ -61,11 +61,11 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer {
// The block number is too low: // The block number is too low:
vm.expectRevert("L2OutputOracle: block number cannot be less than the starting block number."); vm.expectRevert("L2OutputOracle: block number cannot be less than the starting block number.");
proposal = oracle.getL2Output(0); oracle.getL2Output(0);
// The block number is larger than the latest proposed output: // The block number is larger than the latest proposed output:
vm.expectRevert("L2OutputOracle: No output found for that block number."); vm.expectRevert("L2OutputOracle: No output found for that block number.");
proposal = oracle.getL2Output(nextBlockNumber + 1); oracle.getL2Output(nextBlockNumber + 1);
} }
// Test: nextBlockNumber() should return the correct value // Test: nextBlockNumber() should return the correct value
...@@ -268,10 +268,10 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer { ...@@ -268,10 +268,10 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer {
test_proposingAnotherOutput(); test_proposingAnotherOutput();
uint256 latestBlockNumber = oracle.latestBlockNumber(); uint256 latestBlockNumber = oracle.latestBlockNumber();
L2OutputOracle.OutputProposal memory proposalToDelete = oracle.getL2Output( Types.OutputProposal memory proposalToDelete = oracle.getL2Output(
latestBlockNumber latestBlockNumber
); );
L2OutputOracle.OutputProposal memory newLatestOutput = oracle.getL2Output( Types.OutputProposal memory newLatestOutput = oracle.getL2Output(
latestBlockNumber - submissionInterval latestBlockNumber - submissionInterval
); );
...@@ -288,7 +288,7 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer { ...@@ -288,7 +288,7 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer {
uint256 latestBlockNumberAfter = oracle.latestBlockNumber(); uint256 latestBlockNumberAfter = oracle.latestBlockNumber();
assertEq(latestBlockNumber - submissionInterval, latestBlockNumberAfter); assertEq(latestBlockNumber - submissionInterval, latestBlockNumberAfter);
L2OutputOracle.OutputProposal memory proposal = oracle.getL2Output(latestBlockNumberAfter); Types.OutputProposal memory proposal = oracle.getL2Output(latestBlockNumberAfter);
// validate that the new latest output is as expected. // validate that the new latest output is as expected.
assertEq(newLatestOutput.outputRoot, proposal.outputRoot); assertEq(newLatestOutput.outputRoot, proposal.outputRoot);
assertEq(newLatestOutput.timestamp, proposal.timestamp); assertEq(newLatestOutput.timestamp, proposal.timestamp);
...@@ -300,7 +300,7 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer { ...@@ -300,7 +300,7 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer {
function testCannot_deleteL2Output_ifNotOwner() external { function testCannot_deleteL2Output_ifNotOwner() external {
uint256 latestBlockNumber = oracle.latestBlockNumber(); uint256 latestBlockNumber = oracle.latestBlockNumber();
L2OutputOracle.OutputProposal memory proposal = oracle.getL2Output(latestBlockNumber); Types.OutputProposal memory proposal = oracle.getL2Output(latestBlockNumber);
vm.expectRevert("Ownable: caller is not the owner"); vm.expectRevert("Ownable: caller is not the owner");
oracle.deleteL2Output(proposal); oracle.deleteL2Output(proposal);
...@@ -310,7 +310,7 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer { ...@@ -310,7 +310,7 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer {
test_proposingAnotherOutput(); test_proposingAnotherOutput();
uint256 previousBlockNumber = oracle.latestBlockNumber() - submissionInterval; uint256 previousBlockNumber = oracle.latestBlockNumber() - submissionInterval;
L2OutputOracle.OutputProposal memory proposalToDelete = oracle.getL2Output( Types.OutputProposal memory proposalToDelete = oracle.getL2Output(
previousBlockNumber previousBlockNumber
); );
...@@ -325,7 +325,7 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer { ...@@ -325,7 +325,7 @@ contract L2OutputOracleTest is L2OutputOracle_Initializer {
test_proposingAnotherOutput(); test_proposingAnotherOutput();
uint256 latestBlockNumber = oracle.latestBlockNumber(); uint256 latestBlockNumber = oracle.latestBlockNumber();
L2OutputOracle.OutputProposal memory proposalToDelete = oracle.getL2Output( Types.OutputProposal memory proposalToDelete = oracle.getL2Output(
latestBlockNumber latestBlockNumber
); );
...@@ -354,7 +354,7 @@ contract L2OutputOracleUpgradeable_Test is L2OutputOracle_Initializer { ...@@ -354,7 +354,7 @@ contract L2OutputOracleUpgradeable_Test is L2OutputOracle_Initializer {
assertEq(startingTimestamp, oracleImpl.STARTING_TIMESTAMP()); assertEq(startingTimestamp, oracleImpl.STARTING_TIMESTAMP());
assertEq(l2BlockTime, oracleImpl.L2_BLOCK_TIME()); assertEq(l2BlockTime, oracleImpl.L2_BLOCK_TIME());
L2OutputOracle.OutputProposal memory initOutput = oracleImpl.getL2Output( Types.OutputProposal memory initOutput = oracleImpl.getL2Output(
startingBlockNumber startingBlockNumber
); );
assertEq(genesisL2Output, initOutput.outputRoot); assertEq(genesisL2Output, initOutput.outputRoot);
......
...@@ -3,6 +3,7 @@ pragma solidity 0.8.15; ...@@ -3,6 +3,7 @@ pragma solidity 0.8.15;
import { CommonTest } from "./CommonTest.t.sol"; import { CommonTest } from "./CommonTest.t.sol";
import { L2ToL1MessagePasser } from "../L2/L2ToL1MessagePasser.sol"; import { L2ToL1MessagePasser } from "../L2/L2ToL1MessagePasser.sol";
import { Types } from "../libraries/Types.sol";
import { Hashing } from "../libraries/Hashing.sol"; import { Hashing } from "../libraries/Hashing.sol";
contract L2ToL1MessagePasserTest is CommonTest { contract L2ToL1MessagePasserTest is CommonTest {
...@@ -65,12 +66,14 @@ contract L2ToL1MessagePasserTest is CommonTest { ...@@ -65,12 +66,14 @@ contract L2ToL1MessagePasserTest is CommonTest {
); );
bytes32 withdrawalHash = Hashing.hashWithdrawal( bytes32 withdrawalHash = Hashing.hashWithdrawal(
nonce, Types.WithdrawalTransaction(
alice, nonce,
target, alice,
value, target,
gasLimit, value,
data gasLimit,
data
)
); );
messagePasser.initiateWithdrawal{ value: value }( messagePasser.initiateWithdrawal{ value: value }(
......
...@@ -5,6 +5,7 @@ import { Portal_Initializer, CommonTest, NextImpl } from "./CommonTest.t.sol"; ...@@ -5,6 +5,7 @@ import { Portal_Initializer, CommonTest, NextImpl } from "./CommonTest.t.sol";
import { AddressAliasHelper } from "../vendor/AddressAliasHelper.sol"; import { AddressAliasHelper } from "../vendor/AddressAliasHelper.sol";
import { L2OutputOracle } from "../L1/L2OutputOracle.sol"; import { L2OutputOracle } from "../L1/L2OutputOracle.sol";
import { OptimismPortal } from "../L1/OptimismPortal.sol"; import { OptimismPortal } from "../L1/OptimismPortal.sol";
import { Types } from "../libraries/Types.sol";
import { Hashing } from "../libraries/Hashing.sol"; import { Hashing } from "../libraries/Hashing.sol";
import { Proxy } from "../universal/Proxy.sol"; import { Proxy } from "../universal/Proxy.sol";
...@@ -214,11 +215,8 @@ contract OptimismPortal_Test is Portal_Initializer { ...@@ -214,11 +215,8 @@ contract OptimismPortal_Test is Portal_Initializer {
assertEq(address(op).balance, NON_ZERO_VALUE); assertEq(address(op).balance, NON_ZERO_VALUE);
} }
// TODO: test this deeply function test_cannotVerifyRecentWithdrawal() external {
// function test_verifyWithdrawal() external {} Types.OutputRootProof memory outputRootProof = Types
function test_cannotFinalizeRecentWithdrawal() external {
Hashing.OutputRootProof memory outputRootProof = Hashing
.OutputRootProof({ .OutputRootProof({
version: bytes32(0), version: bytes32(0),
stateRoot: bytes32(0), stateRoot: bytes32(0),
...@@ -230,20 +228,21 @@ contract OptimismPortal_Test is Portal_Initializer { ...@@ -230,20 +228,21 @@ contract OptimismPortal_Test is Portal_Initializer {
vm.mockCall( vm.mockCall(
address(op.L2_ORACLE()), address(op.L2_ORACLE()),
abi.encodeWithSelector(L2OutputOracle.getL2Output.selector), abi.encodeWithSelector(L2OutputOracle.getL2Output.selector),
abi.encode(L2OutputOracle.OutputProposal(bytes32(uint256(1)), recentTimestamp)) abi.encode(Types.OutputProposal(bytes32(uint256(1)), recentTimestamp))
); );
vm.expectRevert("OptimismPortal: proposal is not yet finalized"); vm.expectRevert("OptimismPortal: proposal is not yet finalized");
op.finalizeWithdrawalTransaction(0, alice, alice, 0, 0, hex"", 0, outputRootProof, hex""); op.finalizeWithdrawalTransaction(Types.WithdrawalTransaction(0, alice, alice, 0, 0, hex""), 0, outputRootProof, hex"");
} }
function test_invalidWithdrawalProof() external { function test_invalidWithdrawalProof() external {
vm.mockCall( vm.mockCall(
address(op.L2_ORACLE()), address(op.L2_ORACLE()),
abi.encodeWithSelector(L2OutputOracle.getL2Output.selector), abi.encodeWithSelector(L2OutputOracle.getL2Output.selector),
abi.encode(L2OutputOracle.OutputProposal(bytes32(uint256(1)), block.timestamp)) abi.encode(Types.OutputProposal(bytes32(uint256(1)), block.timestamp))
); );
Hashing.OutputRootProof memory outputRootProof = Hashing
Types.OutputRootProof memory outputRootProof = Types
.OutputRootProof({ .OutputRootProof({
version: bytes32(0), version: bytes32(0),
stateRoot: bytes32(0), stateRoot: bytes32(0),
...@@ -257,7 +256,7 @@ contract OptimismPortal_Test is Portal_Initializer { ...@@ -257,7 +256,7 @@ contract OptimismPortal_Test is Portal_Initializer {
); );
vm.expectRevert("OptimismPortal: invalid output root proof"); vm.expectRevert("OptimismPortal: invalid output root proof");
op.finalizeWithdrawalTransaction(0, alice, alice, 0, 0, hex"", 0, outputRootProof, hex""); op.finalizeWithdrawalTransaction(Types.WithdrawalTransaction(0, alice, alice, 0, 0, hex""), 0, outputRootProof, hex"");
} }
function test_simple_isBlockFinalized() external { function test_simple_isBlockFinalized() external {
...@@ -267,7 +266,7 @@ contract OptimismPortal_Test is Portal_Initializer { ...@@ -267,7 +266,7 @@ contract OptimismPortal_Test is Portal_Initializer {
L2OutputOracle.getL2Output.selector L2OutputOracle.getL2Output.selector
), ),
abi.encode( abi.encode(
L2OutputOracle.OutputProposal( Types.OutputProposal(
bytes32(uint256(1)), bytes32(uint256(1)),
startingBlockNumber startingBlockNumber
) )
...@@ -321,7 +320,6 @@ contract OptimismPortal_Test is Portal_Initializer { ...@@ -321,7 +320,6 @@ contract OptimismPortal_Test is Portal_Initializer {
) external { ) external {
// Cannot call the optimism portal // Cannot call the optimism portal
vm.assume(_target != address(op)); vm.assume(_target != address(op));
uint256 _nonce = messagePasser.nonce(); uint256 _nonce = messagePasser.nonce();
( (
...@@ -339,22 +337,23 @@ contract OptimismPortal_Test is Portal_Initializer { ...@@ -339,22 +337,23 @@ contract OptimismPortal_Test is Portal_Initializer {
_data _data
); );
Hashing.OutputRootProof memory proof = Hashing.OutputRootProof({ // Ensure the values returned from ffi are correct
assertEq(outputRoot, Hashing.hashOutputRootProof(Types.OutputRootProof({
version: bytes32(uint256(0)), version: bytes32(uint256(0)),
stateRoot: stateRoot, stateRoot: stateRoot,
withdrawerStorageRoot: storageRoot, withdrawerStorageRoot: storageRoot,
latestBlockhash: bytes32(uint256(0)) latestBlockhash: bytes32(uint256(0))
}); })));
// Ensure the values returned from ffi are correct
assertEq(outputRoot, Hashing.hashOutputRootProof(proof));
assertEq(withdrawalHash, Hashing.hashWithdrawal( assertEq(withdrawalHash, Hashing.hashWithdrawal(
_nonce, Types.WithdrawalTransaction(
_sender, _nonce,
_target, _sender,
_value, _target,
uint64(_gasLimit), _value,
_data uint64(_gasLimit),
_data
)
)); ));
// Mock the call to the oracle // Mock the call to the oracle
...@@ -378,14 +377,21 @@ contract OptimismPortal_Test is Portal_Initializer { ...@@ -378,14 +377,21 @@ contract OptimismPortal_Test is Portal_Initializer {
vm.warp(op.FINALIZATION_PERIOD_SECONDS() + 1); vm.warp(op.FINALIZATION_PERIOD_SECONDS() + 1);
op.finalizeWithdrawalTransaction{ value: _value }( op.finalizeWithdrawalTransaction{ value: _value }(
messagePasser.nonce() - 1, Types.WithdrawalTransaction(
_sender, messagePasser.nonce() - 1,
_target, _sender,
_value, _target,
uint64(_gasLimit), _value,
_data, uint64(_gasLimit),
_data
),
100, // l2BlockNumber 100, // l2BlockNumber
proof, Types.OutputRootProof({
version: bytes32(uint256(0)),
stateRoot: stateRoot,
withdrawerStorageRoot: storageRoot,
latestBlockhash: bytes32(uint256(0))
}),
withdrawalProof withdrawalProof
); );
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment