Skip to content

Commit

Permalink
Merge branch 'develop' into opsm/deploy-implementation-contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
mds1 committed Aug 21, 2024
2 parents 53414d3 + 7c83398 commit b2edcd7
Show file tree
Hide file tree
Showing 11 changed files with 752 additions and 51 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ require (
github.com/onsi/gomega v1.34.1
github.com/pkg/errors v0.9.1
github.com/pkg/profile v1.7.0
github.com/prometheus/client_golang v1.20.0
github.com/prometheus/client_golang v1.20.1
github.com/protolambda/ctxlock v0.1.0
github.com/stretchr/testify v1.9.0
github.com/urfave/cli/v2 v2.27.4
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -644,8 +644,8 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI=
github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.20.1 h1:IMJXHOD6eARkQpxo8KkhgEVFlBNm+nkrFUyGlIu7Na8=
github.com/prometheus/client_golang v1.20.1/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
Expand Down
6 changes: 3 additions & 3 deletions op-chain-ops/cmd/receipt-reference-builder/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"errors"
"maps"
"sort"

"github.com/ethereum/go-ethereum/log"
Expand Down Expand Up @@ -96,9 +97,8 @@ func checkBlockRanges(aggregates []aggregate) error {
func mergeAggregates(a1, a2 aggregate, log log.Logger) aggregate {
log.Info("merging", "a1", a1, "a2", a2)
// merge the results
for k, v := range a2.Results {
a1.Results[k] = v
}
maps.Copy(a1.Results, a2.Results)

a1.Last = a2.Last
log.Info("result", "aggregate", a1)
return a1
Expand Down
383 changes: 383 additions & 0 deletions packages/contracts-bedrock/scripts/DeploySuperchain.s.sol

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/contracts-bedrock/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@
"sourceCodeHash": "0x3a725791a0f5ed84dc46dcdae26f6170a759b2fe3dc360d704356d088b76cfd6"
},
"src/L2/CrossL2Inbox.sol": {
"initCodeHash": "0x80124454d2127d5ff340b0ef048be6d5bf5984e84c75021b6a1ffa81703a2503",
"sourceCodeHash": "0xfb26fc80fbc7febdc91ac73ea91ceb479b238e0e81804a0a21192d78c261a755"
"initCodeHash": "0x071b53cd8cf0503af856c4ee0ee34643e85059d53c096453891225472e02abfa",
"sourceCodeHash": "0x3c78129b91d9f06afa4787d4b3039f45a3b22b3edf5155ed73d4f0c3ab33c6c8"
},
"src/L2/ETHLiquidity.sol": {
"initCodeHash": "0x98177562fca0de0dfea5313c9acefe2fdbd73dee5ce6c1232055601f208f0177",
Expand Down
30 changes: 30 additions & 0 deletions packages/contracts-bedrock/snapshots/abi/CrossL2Inbox.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,19 @@
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "interopStart",
"outputs": [
{
"internalType": "uint256",
"name": "interopStart_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "logIndex",
Expand All @@ -101,6 +114,13 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "setInteropStart",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "timestamp",
Expand Down Expand Up @@ -218,6 +238,11 @@
"name": "ExecutingMessage",
"type": "event"
},
{
"inputs": [],
"name": "InteropStartAlreadySet",
"type": "error"
},
{
"inputs": [],
"name": "InvalidChainId",
Expand All @@ -228,6 +253,11 @@
"name": "InvalidTimestamp",
"type": "error"
},
{
"inputs": [],
"name": "NotDepositor",
"type": "error"
},
{
"inputs": [],
"name": "NotEntered",
Expand Down
43 changes: 40 additions & 3 deletions packages/contracts-bedrock/src/L2/CrossL2Inbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ interface IDependencySet {
function isInDependencySet(uint256 _chainId) external view returns (bool);
}

/// @notice Thrown when the caller is not DEPOSITOR_ACCOUNT when calling `setInteropStart()`
error NotDepositor();

/// @notice Thrown when attempting to set interop start when it's already set.
error InteropStartAlreadySet();

/// @notice Thrown when a non-written transient storage slot is attempted to be read from.
error NotEntered();

Expand All @@ -35,6 +41,10 @@ error TargetCallFailed();
/// @notice The CrossL2Inbox is responsible for executing a cross chain message on the destination
/// chain. It is permissionless to execute a cross chain message on behalf of any user.
contract CrossL2Inbox is ICrossL2Inbox, ISemver, TransientReentrancyAware {
/// @notice Storage slot that the interop start timestamp is stored at.
/// Equal to bytes32(uint256(keccak256("crossl2inbox.interopstart")) - 1)
bytes32 internal constant INTEROP_START_SLOT = 0x5c769ee0ee8887661922049dc52480bb60322d765161507707dd9b190af5c149;

/// @notice Transient storage slot that the origin for an Identifier is stored at.
/// Equal to bytes32(uint256(keccak256("crossl2inbox.identifier.origin")) - 1)
bytes32 internal constant ORIGIN_SLOT = 0xd2b7c5071ec59eb3ff0017d703a8ea513a7d0da4779b0dbefe845808c300c815;
Expand All @@ -55,15 +65,42 @@ contract CrossL2Inbox is ICrossL2Inbox, ISemver, TransientReentrancyAware {
/// Equal to bytes32(uint256(keccak256("crossl2inbox.identifier.chainid")) - 1)
bytes32 internal constant CHAINID_SLOT = 0x6e0446e8b5098b8c8193f964f1b567ec3a2bdaeba33d36acb85c1f1d3f92d313;

/// @notice The address that represents the system caller responsible for L1 attributes
/// transactions.
address internal constant DEPOSITOR_ACCOUNT = 0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001;

/// @notice Semantic version.
/// @custom:semver 1.0.0-beta.4
string public constant version = "1.0.0-beta.4";
/// @custom:semver 1.0.0-beta.5
string public constant version = "1.0.0-beta.5";

/// @notice Emitted when a cross chain message is being executed.
/// @param msgHash Hash of message payload being executed.
/// @param id Encoded Identifier of the message.
event ExecutingMessage(bytes32 indexed msgHash, Identifier id);

/// @notice Sets the Interop Start Timestamp for this chain. Can only be performed once and when the caller is the
/// DEPOSITOR_ACCOUNT.
function setInteropStart() external {
// Check that caller is the DEPOSITOR_ACCOUNT
if (msg.sender != DEPOSITOR_ACCOUNT) revert NotDepositor();

// Check that it has not been set already
if (interopStart() != 0) revert InteropStartAlreadySet();

// Set Interop Start to block.timestamp
assembly {
sstore(INTEROP_START_SLOT, timestamp())
}
}

/// @notice Returns the interop start timestamp.
/// @return interopStart_ interop start timestamp.
function interopStart() public view returns (uint256 interopStart_) {
assembly {
interopStart_ := sload(INTEROP_START_SLOT)
}
}

/// @notice Returns the origin address of the Identifier. If not entered, reverts.
/// @return Origin address of the Identifier.
function origin() external view notEntered returns (address) {
Expand Down Expand Up @@ -140,7 +177,7 @@ contract CrossL2Inbox is ICrossL2Inbox, ISemver, TransientReentrancyAware {
/// is in the destination chain's dependency set.
/// @param _id Identifier of the message.
function _checkIdentifier(Identifier calldata _id) internal view {
if (_id.timestamp > block.timestamp) revert InvalidTimestamp();
if (_id.timestamp > block.timestamp || _id.timestamp <= interopStart()) revert InvalidTimestamp();
if (!IDependencySet(Predeploys.L1_BLOCK_ATTRIBUTES).isInDependencySet(_id.chainId)) {
revert InvalidChainId();
}
Expand Down
12 changes: 12 additions & 0 deletions packages/contracts-bedrock/src/L2/ICrossL2Inbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ interface ICrossL2Inbox {
uint256 chainId;
}

/// @notice Returns the interop start timestamp.
/// @return interopStart_ interop start timestamp.
function interopStart() external view returns (uint256 interopStart_);

/// @notice Returns the origin address of the Identifier.
/// @return _origin The origin address of the Identifier.
function origin() external view returns (address _origin);
Expand Down Expand Up @@ -44,4 +48,12 @@ interface ICrossL2Inbox {
)
external
payable;

/// @notice Validates a cross chain message on the destination chain
/// and emits an ExecutingMessage event. This function is useful
/// for applications that understand the schema of the _message payload and want to
/// process it in a custom way.
/// @param _id Identifier of the message.
/// @param _msgHash Hash of the message payload to call target with.
function validateMessage(Identifier calldata _id, bytes32 _msgHash) external;
}
107 changes: 107 additions & 0 deletions packages/contracts-bedrock/test/DeploySuperchain.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import { Test } from "forge-std/Test.sol";

import { Proxy } from "src/universal/Proxy.sol";
import { ProtocolVersion } from "src/L1/ProtocolVersions.sol";
import { DeploySuperchainInput, DeploySuperchain, DeploySuperchainOutput } from "scripts/DeploySuperchain.s.sol";

/// @notice Deploys the Superchain contracts that can be shared by many chains.
contract DeploySuperchain_Test is Test {
DeploySuperchain deploySuperchain;
DeploySuperchainInput dsi;
DeploySuperchainOutput dso;

// Define a default input struct for testing.
DeploySuperchainInput.Input input = DeploySuperchainInput.Input({
roles: DeploySuperchainInput.Roles({
proxyAdminOwner: makeAddr("defaultProxyAdminOwner"),
protocolVersionsOwner: makeAddr("defaultProtocolVersionsOwner"),
guardian: makeAddr("defaultGuardian")
}),
paused: false,
requiredProtocolVersion: ProtocolVersion.wrap(1),
recommendedProtocolVersion: ProtocolVersion.wrap(2)
});

function setUp() public {
deploySuperchain = new DeploySuperchain();
(dsi, dso) = deploySuperchain.getIOContracts();
}

function unwrap(ProtocolVersion _pv) internal pure returns (uint256) {
return ProtocolVersion.unwrap(_pv);
}

function test_run_succeeds(DeploySuperchainInput.Input memory _input) public {
vm.assume(_input.roles.proxyAdminOwner != address(0));
vm.assume(_input.roles.protocolVersionsOwner != address(0));
vm.assume(_input.roles.guardian != address(0));

DeploySuperchainOutput.Output memory output = deploySuperchain.run(_input);

// Assert that individual input fields were properly set based on the input struct.
assertEq(_input.roles.proxyAdminOwner, dsi.proxyAdminOwner(), "100");
assertEq(_input.roles.protocolVersionsOwner, dsi.protocolVersionsOwner(), "200");
assertEq(_input.roles.guardian, dsi.guardian(), "300");
assertEq(_input.paused, dsi.paused(), "400");
assertEq(unwrap(_input.requiredProtocolVersion), unwrap(dsi.requiredProtocolVersion()), "500");
assertEq(unwrap(_input.recommendedProtocolVersion), unwrap(dsi.recommendedProtocolVersion()), "600");

// Assert that individual output fields were properly set based on the output struct.
assertEq(address(output.superchainProxyAdmin), address(dso.superchainProxyAdmin()), "700");
assertEq(address(output.superchainConfigImpl), address(dso.superchainConfigImpl()), "800");
assertEq(address(output.superchainConfigProxy), address(dso.superchainConfigProxy()), "900");
assertEq(address(output.protocolVersionsImpl), address(dso.protocolVersionsImpl()), "1000");
assertEq(address(output.protocolVersionsProxy), address(dso.protocolVersionsProxy()), "1100");

// Assert that the full input and output structs were properly set.
assertEq(keccak256(abi.encode(_input)), keccak256(abi.encode(DeploySuperchainInput(dsi).input())), "1200");
assertEq(keccak256(abi.encode(output)), keccak256(abi.encode(DeploySuperchainOutput(dso).output())), "1300");

// Assert inputs were properly passed through to the contract initializers.
assertEq(address(output.superchainProxyAdmin.owner()), _input.roles.proxyAdminOwner, "1400");
assertEq(address(output.protocolVersionsProxy.owner()), _input.roles.protocolVersionsOwner, "1500");
assertEq(address(output.superchainConfigProxy.guardian()), _input.roles.guardian, "1600");
assertEq(output.superchainConfigProxy.paused(), _input.paused, "1700");
assertEq(unwrap(output.protocolVersionsProxy.required()), unwrap(_input.requiredProtocolVersion), "1800");
assertEq(unwrap(output.protocolVersionsProxy.recommended()), unwrap(_input.recommendedProtocolVersion), "1900");

// Architecture assertions.
// We prank as the zero address due to the Proxy's `proxyCallIfNotAdmin` modifier.
Proxy superchainConfigProxy = Proxy(payable(address(output.superchainConfigProxy)));
Proxy protocolVersionsProxy = Proxy(payable(address(output.protocolVersionsProxy)));

vm.startPrank(address(0));
assertEq(superchainConfigProxy.implementation(), address(output.superchainConfigImpl), "900");
assertEq(protocolVersionsProxy.implementation(), address(output.protocolVersionsImpl), "1000");
assertEq(superchainConfigProxy.admin(), protocolVersionsProxy.admin(), "1100");
assertEq(superchainConfigProxy.admin(), address(output.superchainProxyAdmin), "1200");
vm.stopPrank();

// Ensure that `checkOutput` passes. This is called by the `run` function during execution,
// so this just acts as a sanity check. It reverts on failure.
dso.checkOutput();
}

function test_run_ZeroAddressRoles_reverts() public {
// Snapshot the state so we can revert to the default `input` struct between assertions.
uint256 snapshotId = vm.snapshot();

// Assert over each role being set to the zero address.
input.roles.proxyAdminOwner = address(0);
vm.expectRevert("DeploySuperchainInput: Null proxyAdminOwner");
deploySuperchain.run(input);

vm.revertTo(snapshotId);
input.roles.protocolVersionsOwner = address(0);
vm.expectRevert("DeploySuperchainInput: Null protocolVersionsOwner");
deploySuperchain.run(input);

vm.revertTo(snapshotId);
input.roles.guardian = address(0);
vm.expectRevert("DeploySuperchainInput: Null guardian");
deploySuperchain.run(input);
}
}
Loading

0 comments on commit b2edcd7

Please sign in to comment.