Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions packages/contracts/chugsplash-deploy/deploy-l2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"contracts": {
"OVM_L2ToL1MessagePasser": {
"address": "0x4200000000000000000000000000000000000000",
"source": "OVM_L2ToL1MessagePasser"
},
"OVM_L1MessageSender": {
"address": "0x4200000000000000000000000000000000000001",
"source": "OVM_L1MessageSender"
},
"OVM_DeployerWhitelist": {
"address": "0x4200000000000000000000000000000000000002",
"source": "OVM_DeployerWhitelist",
"variables": {
"owner": "{{ env.DEPLOYER_WHITELIST_OWNER }}"
}
},
"OVM_ECDSAContractAccount": {
"address": "0x4200000000000000000000000000000000000003",
"source": "OVM_ECDSAContractAccount"
},
"OVM_SequencerEntrypoint": {
"address": "0x4200000000000000000000000000000000000005",
"source": "OVM_SequencerEntrypoint"
},
"OVM_ETH": {
"address": "0x4200000000000000000000000000000000000006",
"source": "OVM_ETH",
"variables": {
"l1TokenGateway": "{{ env.L1_ETH_GATEWAY_ADDRESS }}",
"messenger": "{{ contracts.OVM_L2CrossDomainMessenger }}",
"name": "Ether",
"symbol": "ETH"
}
},
"OVM_L2CrossDomainMessenger": {
"address": "0x4200000000000000000000000000000000000007",
"source": "OVM_L2CrossDomainMessenger",
"variables": {
"ovmL2ToL1MessagePasser": "{{ contracts.OVM_L2ToL1MessagePasser }}",
"ovmL1MessageSender": "{{ contracts.OVM_L1MessageSender }}",
"ovmL1CrossDomainMessenger": "{{ env.L1_CROSS_DOMAIN_MESSENGER_ADDRESS }}"
}
},
"OVM_ProxyEOA": {
"address": "0x4200000000000000000000000000000000000009",
"source": "OVM_ProxyEOA"
},
"ERC1820Registry": {
"address": "0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24",
"source": "ERC1820Registry"
}
}
}
198 changes: 198 additions & 0 deletions packages/contracts/contracts/chugsplash/L2/ChugSplashDeployer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// SPDX-License-Identifier: MIT
// @unsupported: evm
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;

/* Library Imports */
import { Lib_ExecutionManagerWrapper } from "../../optimistic-ethereum/libraries/wrappers/Lib_ExecutionManagerWrapper.sol";
import { Lib_MerkleTree } from "../../optimistic-ethereum/libraries/utils/Lib_MerkleTree.sol";

/**
* @title ChugSplashDeployer
*/
contract ChugSplashDeployer {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw one high level bit of feedback here is I think that more 'deployment'-esque words could make the operation of this contract clearer. For instance hasActiveBundle seems more implicit than hasActiveDeployment.

I feel like it's OK to have deploy-specific terminology here because the ChugSplashDeployer is going to have to handle logic for things like shutting down the contracts to begin a deploy, and restarting them to end the deploy. So idk it seems like it's low value to make things more abstract than they need to be at least at first. Eventually we can break it out into a BundleExecutor or something like that, but in the meantime I just like reminding folks what they are reading


/*********
* Enums *
*********/

enum ActionType {
SET_CODE,
SET_STORAGE
}


/***********
* Structs *
***********/

struct ChugSplashAction {
ActionType actionType;
uint256 gasLimit;
address target;
bytes data;
}

struct ChugSplashActionProof {
uint256 actionIndex;
bytes32[] siblings;
}


/*************
* Variables *
*************/

// Address that can approve new transaction bundles.
address public owner;
bytes32 public currentBundleHash;
uint256 public currentBundleSize;
uint256 public currentBundleTxsExecuted;


/***************
* Constructor *
***************/

/**
* @param _owner Initial owner address.
*/
constructor(
address _owner
) {
owner = _owner;
}


/**********************
* Function Modifiers *
**********************/

/**
* Marks a function as only callable by the owner.
*/
modifier onlyOwner() {
require(
msg.sender == owner,
"ChugSplashDeployer: sender is not owner"
);
_;
}


/********************
* Public Functions *
********************/

/**
* Changes the owner. Only callable by the current owner.
* @param _owner New owner address.
*/
function setOwner(
address _owner
)
public
onlyOwner
{
owner = _owner;
}

function hasActiveBundle()
public
view
returns (
bool
)
{
return (
currentBundleHash != bytes32(0)
&& currentBundleTxsExecuted < currentBundleSize
);
}

function approveTransactionBundle(
bytes32 _bundleHash,
uint256 _bundleSize

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also take in a version string I think which we can emit and thereby track the versions of each deployment. Or alternatively there is a version in the bundle

)
public
onlyOwner
{
require(
hasActiveBundle() == false,
"ChugSplashDeployer: previous bundle has not yet been fully executed"
);

currentBundleHash = _bundleHash;
currentBundleSize = _bundleSize;
currentBundleTxsExecuted = 0;

// TODO: Set system status to "upgrading".
}

function executeAction(
ChugSplashAction memory _action,
ChugSplashActionProof memory _proof
)
public
{
// TODO: Do we need to validate enums or does solidity do it for us?

require(
hasActiveBundle() == true,
"ChugSplashDeployer: there is no active bundle"
);

// Make sure the user has provided enough gas to perform this action successfully.
require(
gasleft() > _action.gasLimit,
"ChugSplashDeployer: sender didn't supply enough gas"
);

// Make sure that the owner did actually sign off on this action.
require(
Lib_MerkleTree.verify(
currentBundleHash,
keccak256(
abi.encodePacked(
_action.actionType,
_action.gasLimit,
_action.target,
_action.data
)
),
_proof.actionIndex,
_proof.siblings,
currentBundleSize
),
"ChugSplashDeployer: invalid action proof"
);

if (_action.actionType == ActionType.SET_CODE) {
// When the action is SET_CODE, we expect that the data is exactly the bytecode that
// the user wants to set the code to.
Lib_ExecutionManagerWrapper.ovmSETCODE(
_action.target,
_action.data
);
} else {
// When the action is SET_STORAGE, we expect that the data is actually an ABI encoded
// key/value pair. So we'll need to decode that first.
(bytes32 key, bytes32 value) = abi.decode(
_action.data,
(bytes32, bytes32)
);

Lib_ExecutionManagerWrapper.ovmSETSTORAGE(
_action.target,
key,
value
);
}

currentBundleTxsExecuted++;
if (currentBundleSize == currentBundleTxsExecuted) {
currentBundleHash = bytes32(0);
// TODO: Set system status to "done upgrading/active".
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;

/* Library Imports */
import { Lib_AddressResolver } from "../../../libraries/resolver/Lib_AddressResolver.sol";

/* Interface Imports */
import { iOVM_L2CrossDomainMessenger } from "../../../iOVM/bridge/messaging/iOVM_L2CrossDomainMessenger.sol";
import { iOVM_L1MessageSender } from "../../../iOVM/predeploys/iOVM_L1MessageSender.sol";
Expand All @@ -21,20 +18,15 @@ import { Abs_BaseCrossDomainMessenger } from "./Abs_BaseCrossDomainMessenger.sol
* Compiler used: optimistic-solc
* Runtime target: OVM
*/
contract OVM_L2CrossDomainMessenger is iOVM_L2CrossDomainMessenger, Abs_BaseCrossDomainMessenger, Lib_AddressResolver {
contract OVM_L2CrossDomainMessenger is iOVM_L2CrossDomainMessenger, Abs_BaseCrossDomainMessenger {

/***************
* Constructor *
***************/
/*************
* Variables *
*************/

/**
* @param _libAddressManager Address of the Address Manager.
*/
constructor(
address _libAddressManager
)
Lib_AddressResolver(_libAddressManager)
{}
address public ovmL1CrossDomainMessenger;
iOVM_L1MessageSender public ovmL1MessageSender;
iOVM_L2ToL1MessagePasser public ovmL2ToL1MessagePasser;


/********************
Expand Down Expand Up @@ -77,7 +69,7 @@ contract OVM_L2CrossDomainMessenger is iOVM_L2CrossDomainMessenger, Abs_BaseCros
// Prevent calls to OVM_L2ToL1MessagePasser, which would enable
// an attacker to maliciously craft the _message to spoof
// a call from any L2 account.
if(_target == resolve("OVM_L2ToL1MessagePasser")){
if(_target == address(ovmL2ToL1MessagePasser)){
// Write to the successfulMessages mapping and return immediately.
successfulMessages[xDomainCalldataHash] = true;
return;
Expand Down Expand Up @@ -116,19 +108,17 @@ contract OVM_L2CrossDomainMessenger is iOVM_L2CrossDomainMessenger, Abs_BaseCros

/**
* Verifies that a received cross domain message is valid.
* @return _valid Whether or not the message is valid.
* @return Whether or not the message is valid.
*/
function _verifyXDomainMessage()
view
internal
returns (
bool _valid
bool
)
{
return (
iOVM_L1MessageSender(
resolve("OVM_L1MessageSender")
).getL1MessageSender() == resolve("OVM_L1CrossDomainMessenger")
ovmL1MessageSender.getL1MessageSender() == ovmL1CrossDomainMessenger
);
}

Expand All @@ -144,6 +134,6 @@ contract OVM_L2CrossDomainMessenger is iOVM_L2CrossDomainMessenger, Abs_BaseCros
override
internal
{
iOVM_L2ToL1MessagePasser(resolve("OVM_L2ToL1MessagePasser")).passMessageToL1(_message);
ovmL2ToL1MessagePasser.passMessageToL1(_message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,49 @@ library Lib_ExecutionManagerWrapper {
return abi.decode(returndata, (uint256));
}

/**
* Calls the ovmSETCODE opcode. Only callable by the upgrade deployer.
* @param _address Address to set the code of.
* @param _code New code for the address.
*/
function ovmSETCODE(
address _address,
bytes memory _code
)
internal
{
_safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmSETCODE(address,bytes)",
_address,
_code
)
);
}

/**
* Calls the ovmSETSTORAGE opcode. Only callable by the upgrade deployer.
* @param _address Address to set a storage slot for.
* @param _key Storage slot key to modify.
* @param _val Storage slot value.
*/
function ovmSETSTORAGE(
address _address,
bytes32 _key,
bytes32 _val
)
internal
{
_safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmSETSTORAGE(address,bytes32,bytes32)",
_address,
_key,
_val
)
);
}


/*********************
* Private Functions *
Expand Down
Loading