From 9d44f2d9b7f53e0e12bc25c59fe1fb978be224b3 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Sat, 6 May 2023 21:43:40 -0600 Subject: [PATCH 01/15] Changes from nitro repo contracts-develop branch --- src/bridge/Bridge.sol | 4 ++-- src/bridge/ISequencerInbox.sol | 10 ++++++++++ src/bridge/SequencerInbox.sol | 8 ++++++++ src/libraries/IGasRefunder.sol | 5 +---- src/mocks/BridgeStub.sol | 2 +- test/storage/SequencerInbox.dot | 2 +- 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/bridge/Bridge.sol b/src/bridge/Bridge.sol index 722a5e28..e8a6764e 100644 --- a/src/bridge/Bridge.sol +++ b/src/bridge/Bridge.sol @@ -230,7 +230,7 @@ contract Bridge is Initializable, DelegateCallAware, IBridge { InOutInfo storage info = allowedDelayedInboxesMap[inbox]; bool alreadyEnabled = info.allowed; emit InboxToggle(inbox, enabled); - if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) { + if (alreadyEnabled == enabled) { return; } if (enabled) { @@ -252,7 +252,7 @@ contract Bridge is Initializable, DelegateCallAware, IBridge { InOutInfo storage info = allowedOutboxesMap[outbox]; bool alreadyEnabled = info.allowed; emit OutboxToggle(outbox, enabled); - if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) { + if (alreadyEnabled == enabled) { return; } if (enabled) { diff --git a/src/bridge/ISequencerInbox.sol b/src/bridge/ISequencerInbox.sol index d801dca3..994c7c01 100644 --- a/src/bridge/ISequencerInbox.sol +++ b/src/bridge/ISequencerInbox.sol @@ -69,6 +69,8 @@ interface ISequencerInbox is IDelayedMessageProvider { function isBatchPoster(address) external view returns (bool); + function isSequencer(address) external view returns (bool); + struct DasKeySetInfo { bool isValidKeyset; uint64 creationBlock; @@ -154,6 +156,14 @@ interface ISequencerInbox is IDelayedMessageProvider { */ function invalidateKeysetHash(bytes32 ksHash) external; + /** + * @notice Updates whether an address is authorized to be a sequencer. + * @dev The IsSequencer information is used only off-chain by the nitro node to validate sequencer feed signer. + * @param addr the address + * @param isSequencer_ if the specified address should be authorized as a sequencer + */ + function setIsSequencer(address addr, bool isSequencer_) external; + // ---------- initializer ---------- function initialize(IBridge bridge_, MaxTimeVariation calldata maxTimeVariation_) external; diff --git a/src/bridge/SequencerInbox.sol b/src/bridge/SequencerInbox.sol index 5072359b..c95cd70b 100644 --- a/src/bridge/SequencerInbox.sol +++ b/src/bridge/SequencerInbox.sol @@ -64,6 +64,8 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox uint256 internal immutable deployTimeChainId = block.chainid; + mapping(address => bool) public isSequencer; + function _chainIdChanged() internal view returns (bool) { return deployTimeChainId != block.chainid; } @@ -450,6 +452,12 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox emit OwnerFunctionCalled(3); } + /// @inheritdoc ISequencerInbox + function setIsSequencer(address addr, bool isSequencer_) external onlyRollupOwner { + isSequencer[addr] = isSequencer_; + emit OwnerFunctionCalled(4); + } + function isValidKeysetHash(bytes32 ksHash) external view returns (bool) { return dasKeySetInfo[ksHash].isValidKeyset; } diff --git a/src/libraries/IGasRefunder.sol b/src/libraries/IGasRefunder.sol index 3e915c3c..99e48bf5 100644 --- a/src/libraries/IGasRefunder.sol +++ b/src/libraries/IGasRefunder.sol @@ -21,10 +21,7 @@ abstract contract GasRefundEnabled { uint256 startGasLeft = gasleft(); _; if (address(gasRefunder) != address(0)) { - uint256 calldataSize; - assembly { - calldataSize := calldatasize() - } + uint256 calldataSize = msg.data.length; uint256 calldataWords = (calldataSize + 31) / 32; // account for the CALLDATACOPY cost of the proxy contract, including the memory expansion cost startGasLeft += calldataWords * 6 + (calldataWords**2) / 512; diff --git a/src/mocks/BridgeStub.sol b/src/mocks/BridgeStub.sol index 08dca5c4..261cfabf 100644 --- a/src/mocks/BridgeStub.sol +++ b/src/mocks/BridgeStub.sol @@ -139,7 +139,7 @@ contract BridgeStub is IBridge { InOutInfo storage info = allowedDelayedInboxesMap[inbox]; bool alreadyEnabled = info.allowed; emit InboxToggle(inbox, enabled); - if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) { + if (alreadyEnabled == enabled) { return; } if (enabled) { diff --git a/test/storage/SequencerInbox.dot b/test/storage/SequencerInbox.dot index 81ca079d..f9ea05ab 100644 --- a/test/storage/SequencerInbox.dot +++ b/test/storage/SequencerInbox.dot @@ -4,7 +4,7 @@ rankdir=LR color=black arrowhead=open node [shape=record, style=filled, fillcolor=gray95 fontname="Courier New"] -3 [label="SequencerInbox \<\\>\n | {{ slot| 0 | 1 | 2 | 3 | 4-7 | 8 } | { type: \.variable (bytes) | { uint256: totalDelayedMessagesRead (32) } | { unallocated (12) | IBridge: bridge (20) } | { unallocated (12) | IOwnable: rollup (20) } | { mapping\(address=\>bool\): isBatchPoster (32) } | { <9> ISequencerInbox.MaxTimeVariation: maxTimeVariation (128) } | { <12> mapping\(bytes32=\>DasKeySetInfo\): dasKeySetInfo (32) }}}"] +3 [label="SequencerInbox \<\\>\n | {{ slot| 0 | 1 | 2 | 3 | 4-7 | 8 | 9 } | { type: \.variable (bytes) | { uint256: totalDelayedMessagesRead (32) } | { unallocated (12) | IBridge: bridge (20) } | { unallocated (12) | IOwnable: rollup (20) } | { mapping\(address=\>bool\): isBatchPoster (32) } | { <9> ISequencerInbox.MaxTimeVariation: maxTimeVariation (128) } | { <12> mapping\(bytes32=\>DasKeySetInfo\): dasKeySetInfo (32) } | { mapping\(address=\>bool\): isSequencer (32) }}}"] 1 [label="ISequencerInbox.MaxTimeVariation \<\\>\n | {{ slot| 4 | 5 | 6 | 7 } | { type: variable (bytes) | { uint256: MaxTimeVariation.delayBlocks (32) } | { uint256: MaxTimeVariation.futureBlocks (32) } | { uint256: MaxTimeVariation.delaySeconds (32) } | { uint256: MaxTimeVariation.futureSeconds (32) }}}"] From b7df914ff65f2839f57500fd86f4eda4cf4ce0a4 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Wed, 10 May 2023 20:51:14 -0600 Subject: [PATCH 02/15] Use create2 to deploy the RollupProxy and predict address --- src/libraries/AdminFallbackProxy.sol | 4 ++-- src/rollup/RollupCreator.sol | 22 +++++++++++++------ src/rollup/RollupProxy.sol | 32 ++++++++++++++++++++-------- test/contract/arbRollup.spec.ts | 17 +++------------ 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/src/libraries/AdminFallbackProxy.sol b/src/libraries/AdminFallbackProxy.sol index 78334cdb..52dc9bff 100644 --- a/src/libraries/AdminFallbackProxy.sol +++ b/src/libraries/AdminFallbackProxy.sol @@ -107,13 +107,13 @@ contract AdminFallbackProxy is Proxy, DoubleLogicERC1967Upgrade { * Only the `adminAddr` is able to use the `adminLogic` functions * All other addresses can interact with the `userLogic` functions */ - constructor( + function _initialize( address adminLogic, bytes memory adminData, address userLogic, bytes memory userData, address adminAddr - ) payable { + ) internal { assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1)); assert( _IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1) diff --git a/src/rollup/RollupCreator.sol b/src/rollup/RollupCreator.sol index ed086560..53e160be 100644 --- a/src/rollup/RollupCreator.sol +++ b/src/rollup/RollupCreator.sol @@ -9,6 +9,7 @@ import "./BridgeCreator.sol"; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/utils/Create2.sol"; import "./RollupProxy.sol"; @@ -31,6 +32,10 @@ contract RollupCreator is Ownable { address public validatorUtils; address public validatorWalletCreator; + uint256 public deployedRollups; + bytes32 internal constant rollupProxyCreationCodeHash = + keccak256(type(RollupProxy).creationCode); + constructor() Ownable() {} function setTemplates( @@ -60,6 +65,7 @@ contract RollupCreator is Ownable { IRollupEventInbox rollupEventInbox; IOutbox outbox; RollupProxy rollup; + bytes32 rollupSalt; } // After this setup: @@ -67,13 +73,15 @@ contract RollupCreator is Ownable { // RollupOwner should be the owner of Rollup's ProxyAdmin // RollupOwner should be the owner of Rollup // Bridge should have a single inbox and outbox - function createRollup(Config memory config, address expectedRollupAddr) - external - returns (address) - { + function createRollup(Config memory config) external returns (address) { CreateRollupFrame memory frame; frame.admin = new ProxyAdmin(); + frame.rollupSalt = bytes32(deployedRollups++); + address expectedRollupAddr = Create2.computeAddress( + frame.rollupSalt, + rollupProxyCreationCodeHash + ); ( frame.bridge, frame.sequencerInbox, @@ -104,7 +112,10 @@ contract RollupCreator is Ownable { osp ); - frame.rollup = new RollupProxy( + frame.rollup = new RollupProxy{salt: frame.rollupSalt}(); + require(address(frame.rollup) == expectedRollupAddr, "WRONG_ROLLUP_ADDR"); + + frame.rollup.initializeProxy( config, ContractDependencies({ bridge: frame.bridge, @@ -119,7 +130,6 @@ contract RollupCreator is Ownable { validatorWalletCreator: validatorWalletCreator }) ); - require(address(frame.rollup) == expectedRollupAddr, "WRONG_ROLLUP_ADDR"); emit RollupCreated( address(frame.rollup), diff --git a/src/rollup/RollupProxy.sol b/src/rollup/RollupProxy.sol index 04531be6..2e885fc3 100644 --- a/src/rollup/RollupProxy.sol +++ b/src/rollup/RollupProxy.sol @@ -8,13 +8,27 @@ import "../libraries/AdminFallbackProxy.sol"; import "./IRollupLogic.sol"; contract RollupProxy is AdminFallbackProxy { - constructor(Config memory config, ContractDependencies memory connectedContracts) - AdminFallbackProxy( - address(connectedContracts.rollupAdminLogic), - abi.encodeWithSelector(IRollupAdmin.initialize.selector, config, connectedContracts), - address(connectedContracts.rollupUserLogic), - abi.encodeWithSelector(IRollupUserAbs.initialize.selector, config.stakeToken), - config.owner - ) - {} + function initializeProxy(Config memory config, ContractDependencies memory connectedContracts) + external + { + if ( + _getAdmin() == address(0) && + _getImplementation() == address(0) && + _getSecondaryImplementation() == address(0) + ) { + _initialize( + address(connectedContracts.rollupAdminLogic), + abi.encodeWithSelector( + IRollupAdmin.initialize.selector, + config, + connectedContracts + ), + address(connectedContracts.rollupUserLogic), + abi.encodeWithSelector(IRollupUserAbs.initialize.selector, config.stakeToken), + config.owner + ); + } else { + _fallback(); + } + } } diff --git a/test/contract/arbRollup.spec.ts b/test/contract/arbRollup.spec.ts index e3a8b084..0048650a 100644 --- a/test/contract/arbRollup.spec.ts +++ b/test/contract/arbRollup.spec.ts @@ -182,18 +182,7 @@ const setup = async () => { ethers.constants.AddressZero ) - const nonce = await rollupCreator.signer.provider!.getTransactionCount( - rollupCreator.address - ) - const expectedRollupAddress = ethers.utils.getContractAddress({ - from: rollupCreator.address, - nonce: nonce + 2, - }) - - const response = await rollupCreator.createRollup( - await getDefaultConfig(), - expectedRollupAddress - ) + const response = await rollupCreator.createRollup(await getDefaultConfig()) const rec = await response.wait() const rollupCreatedEvent = rollupCreator.interface.parseLog( @@ -201,10 +190,10 @@ const setup = async () => { ).args as RollupCreatedEvent['args'] const rollupAdmin = rollupAdminLogicFac - .attach(expectedRollupAddress) + .attach(rollupCreatedEvent.rollupAddress) .connect(rollupCreator.signer) const rollupUser = rollupUserLogicFac - .attach(expectedRollupAddress) + .attach(rollupCreatedEvent.rollupAddress) .connect(user) await rollupAdmin.setValidator( From 3dfcee42282ec0c0aa9885c3949373043a6bff45 Mon Sep 17 00:00:00 2001 From: gzeon <95478735+gzeoneth@users.noreply.github.com> Date: Fri, 26 May 2023 00:53:29 +0800 Subject: [PATCH 03/15] fix: resolve cyclic dependencies --- src/osp/IOneStepProver.sol | 1 + src/osp/OneStepProverHostIo.sol | 1 + src/osp/OneStepProverMemory.sol | 1 + src/rollup/Config.sol | 43 ++++++++++ src/rollup/IRollupAdmin.sol | 138 ++++++++++++++++++++++++++++++ src/rollup/IRollupCore.sol | 8 +- src/rollup/IRollupLogic.sol | 134 +---------------------------- src/rollup/Node.sol | 14 +++ src/rollup/RollupAdminLogic.sol | 12 ++- src/rollup/RollupCore.sol | 3 +- src/rollup/RollupCreator.sol | 2 +- src/rollup/RollupLib.sol | 41 +-------- src/rollup/RollupProxy.sol | 3 +- src/rollup/RollupUserLogic.sol | 8 +- src/rollup/ValidatorUtils.sol | 1 + src/state/Deserialize.sol | 2 +- src/state/Module.sol | 4 +- src/state/ModuleMemory.sol | 9 +- src/state/ModuleMemoryCompact.sol | 17 ++++ test/contract/arbRollup.spec.ts | 5 +- test/contract/common/rolluplib.ts | 9 +- 21 files changed, 250 insertions(+), 206 deletions(-) create mode 100644 src/rollup/Config.sol create mode 100644 src/rollup/IRollupAdmin.sol create mode 100644 src/state/ModuleMemoryCompact.sol diff --git a/src/osp/IOneStepProver.sol b/src/osp/IOneStepProver.sol index e26ff604..202d5859 100644 --- a/src/osp/IOneStepProver.sol +++ b/src/osp/IOneStepProver.sol @@ -7,6 +7,7 @@ pragma solidity ^0.8.0; import "../state/Machine.sol"; import "../state/Module.sol"; import "../state/Instructions.sol"; +import "../state/GlobalState.sol"; import "../bridge/ISequencerInbox.sol"; import "../bridge/IBridge.sol"; diff --git a/src/osp/OneStepProverHostIo.sol b/src/osp/OneStepProverHostIo.sol index bbedf000..a2cb8e31 100644 --- a/src/osp/OneStepProverHostIo.sol +++ b/src/osp/OneStepProverHostIo.sol @@ -7,6 +7,7 @@ pragma solidity ^0.8.0; import "../state/Value.sol"; import "../state/Machine.sol"; import "../state/Deserialize.sol"; +import "../state/ModuleMemory.sol"; import "./IOneStepProver.sol"; import "../bridge/Messages.sol"; import "../bridge/IBridge.sol"; diff --git a/src/osp/OneStepProverMemory.sol b/src/osp/OneStepProverMemory.sol index 0135ef67..7d33d55e 100644 --- a/src/osp/OneStepProverMemory.sol +++ b/src/osp/OneStepProverMemory.sol @@ -7,6 +7,7 @@ pragma solidity ^0.8.0; import "../state/Value.sol"; import "../state/Machine.sol"; import "../state/Deserialize.sol"; +import "../state/ModuleMemory.sol"; import "./IOneStepProver.sol"; contract OneStepProverMemory is IOneStepProver { diff --git a/src/rollup/Config.sol b/src/rollup/Config.sol new file mode 100644 index 00000000..41950a9b --- /dev/null +++ b/src/rollup/Config.sol @@ -0,0 +1,43 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.0; + +import "../state/GlobalState.sol"; +import "../state/Machine.sol"; +import "../bridge/ISequencerInbox.sol"; +import "../bridge/IBridge.sol"; +import "../bridge/IOutbox.sol"; +import "../bridge/IInbox.sol"; +import "./IRollupEventInbox.sol"; +import "./IRollupLogic.sol"; +import "../challenge/IChallengeManager.sol"; + +struct Config { + uint64 confirmPeriodBlocks; + uint64 extraChallengeTimeBlocks; + address stakeToken; + uint256 baseStake; + bytes32 wasmModuleRoot; + address owner; + address loserStakeEscrow; + uint256 chainId; + string chainConfig; + uint64 genesisBlockNum; + ISequencerInbox.MaxTimeVariation sequencerInboxMaxTimeVariation; +} + +struct ContractDependencies { + IBridge bridge; + ISequencerInbox sequencerInbox; + IInbox inbox; + IOutbox outbox; + IRollupEventInbox rollupEventInbox; + IChallengeManager challengeManager; + address rollupAdminLogic; + IRollupUser rollupUserLogic; + // misc contracts that are useful when interacting with the rollup + address validatorUtils; + address validatorWalletCreator; +} diff --git a/src/rollup/IRollupAdmin.sol b/src/rollup/IRollupAdmin.sol new file mode 100644 index 00000000..8420c29c --- /dev/null +++ b/src/rollup/IRollupAdmin.sol @@ -0,0 +1,138 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.0; + +import "./IRollupCore.sol"; +import "../bridge/ISequencerInbox.sol"; +import "../bridge/IOutbox.sol"; +import "../bridge/IOwnable.sol"; +import "./Config.sol"; + +interface IRollupAdmin { + event OwnerFunctionCalled(uint256 indexed id); + + function initialize(Config calldata config, ContractDependencies calldata connectedContracts) + external; + + /** + * @notice Add a contract authorized to put messages into this rollup's inbox + * @param _outbox Outbox contract to add + */ + function setOutbox(IOutbox _outbox) external; + + /** + * @notice Disable an old outbox from interacting with the bridge + * @param _outbox Outbox contract to remove + */ + function removeOldOutbox(address _outbox) external; + + /** + * @notice Enable or disable an inbox contract + * @param _inbox Inbox contract to add or remove + * @param _enabled New status of inbox + */ + function setDelayedInbox(address _inbox, bool _enabled) external; + + /** + * @notice Pause interaction with the rollup contract + */ + function pause() external; + + /** + * @notice Resume interaction with the rollup contract + */ + function resume() external; + + /** + * @notice Set the addresses of the validator whitelist + * @dev It is expected that both arrays are same length, and validator at + * position i corresponds to the value at position i + * @param _validator addresses to set in the whitelist + * @param _val value to set in the whitelist for corresponding address + */ + function setValidator(address[] memory _validator, bool[] memory _val) external; + + /** + * @notice Set a new owner address for the rollup proxy + * @param newOwner address of new rollup owner + */ + function setOwner(address newOwner) external; + + /** + * @notice Set minimum assertion period for the rollup + * @param newPeriod new minimum period for assertions + */ + function setMinimumAssertionPeriod(uint256 newPeriod) external; + + /** + * @notice Set number of blocks until a node is considered confirmed + * @param newConfirmPeriod new number of blocks until a node is confirmed + */ + function setConfirmPeriodBlocks(uint64 newConfirmPeriod) external; + + /** + * @notice Set number of extra blocks after a challenge + * @param newExtraTimeBlocks new number of blocks + */ + function setExtraChallengeTimeBlocks(uint64 newExtraTimeBlocks) external; + + /** + * @notice Set base stake required for an assertion + * @param newBaseStake maximum avmgas to be used per block + */ + function setBaseStake(uint256 newBaseStake) external; + + /** + * @notice Set the token used for stake, where address(0) == eth + * @dev Before changing the base stake token, you might need to change the + * implementation of the Rollup User logic! + * @param newStakeToken address of token used for staking + */ + function setStakeToken(address newStakeToken) external; + + /** + * @notice Upgrades the implementation of a beacon controlled by the rollup + * @param beacon address of beacon to be upgraded + * @param newImplementation new address of implementation + */ + function upgradeBeacon(address beacon, address newImplementation) external; + + function forceResolveChallenge(address[] memory stackerA, address[] memory stackerB) external; + + function forceRefundStaker(address[] memory stacker) external; + + function forceCreateNode( + uint64 prevNode, + uint256 prevNodeInboxMaxCount, + Assertion memory assertion, + bytes32 expectedNodeHash + ) external; + + function forceConfirmNode( + uint64 nodeNum, + bytes32 blockHash, + bytes32 sendRoot + ) external; + + function setLoserStakeEscrow(address newLoserStakerEscrow) external; + + /** + * @notice Set the proving WASM module root + * @param newWasmModuleRoot new module root + */ + function setWasmModuleRoot(bytes32 newWasmModuleRoot) external; + + /** + * @notice set a new sequencer inbox contract + * @param _sequencerInbox new address of sequencer inbox + */ + function setSequencerInbox(address _sequencerInbox) external; + + /** + * @notice set the validatorWhitelistDisabled flag + * @param _validatorWhitelistDisabled new value of validatorWhitelistDisabled, i.e. true = disabled + */ + function setValidatorWhitelistDisabled(bool _validatorWhitelistDisabled) external; +} diff --git a/src/rollup/IRollupCore.sol b/src/rollup/IRollupCore.sol index f66958a8..e17c27af 100644 --- a/src/rollup/IRollupCore.sol +++ b/src/rollup/IRollupCore.sol @@ -5,7 +5,11 @@ pragma solidity ^0.8.0; import "./Node.sol"; -import "./RollupLib.sol"; +import "../bridge/IBridge.sol"; +import "../bridge/IOutbox.sol"; +import "../bridge/IInbox.sol"; +import "./IRollupEventInbox.sol"; +import "../challenge/IChallengeManager.sol"; interface IRollupCore { struct Staker { @@ -24,7 +28,7 @@ interface IRollupCore { bytes32 indexed parentNodeHash, bytes32 indexed nodeHash, bytes32 executionHash, - RollupLib.Assertion assertion, + Assertion assertion, bytes32 afterInboxBatchAcc, bytes32 wasmModuleRoot, uint256 inboxMaxCount diff --git a/src/rollup/IRollupLogic.sol b/src/rollup/IRollupLogic.sol index 33cfdc51..d413b277 100644 --- a/src/rollup/IRollupLogic.sol +++ b/src/rollup/IRollupLogic.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.0; -import "./RollupLib.sol"; import "./IRollupCore.sol"; import "../bridge/ISequencerInbox.sol"; import "../bridge/IOutbox.sol"; @@ -28,7 +27,7 @@ interface IRollupUserAbs is IRollupCore, IOwnable { function stakeOnExistingNode(uint64 nodeNum, bytes32 nodeHash) external; function stakeOnNewNode( - RollupLib.Assertion memory assertion, + Assertion memory assertion, bytes32 expectedNodeHash, uint256 prevNodeInboxMaxCount ) external; @@ -75,7 +74,7 @@ interface IRollupUser is IRollupUserAbs { function newStakeOnExistingNode(uint64 nodeNum, bytes32 nodeHash) external payable; function newStakeOnNewNode( - RollupLib.Assertion calldata assertion, + Assertion calldata assertion, bytes32 expectedNodeHash, uint256 prevNodeInboxMaxCount ) external payable; @@ -92,137 +91,10 @@ interface IRollupUserERC20 is IRollupUserAbs { function newStakeOnNewNode( uint256 tokenAmount, - RollupLib.Assertion calldata assertion, + Assertion calldata assertion, bytes32 expectedNodeHash, uint256 prevNodeInboxMaxCount ) external; function addToDeposit(address stakerAddress, uint256 tokenAmount) external; } - -interface IRollupAdmin { - event OwnerFunctionCalled(uint256 indexed id); - - function initialize(Config calldata config, ContractDependencies calldata connectedContracts) - external; - - /** - * @notice Add a contract authorized to put messages into this rollup's inbox - * @param _outbox Outbox contract to add - */ - function setOutbox(IOutbox _outbox) external; - - /** - * @notice Disable an old outbox from interacting with the bridge - * @param _outbox Outbox contract to remove - */ - function removeOldOutbox(address _outbox) external; - - /** - * @notice Enable or disable an inbox contract - * @param _inbox Inbox contract to add or remove - * @param _enabled New status of inbox - */ - function setDelayedInbox(address _inbox, bool _enabled) external; - - /** - * @notice Pause interaction with the rollup contract - */ - function pause() external; - - /** - * @notice Resume interaction with the rollup contract - */ - function resume() external; - - /** - * @notice Set the addresses of the validator whitelist - * @dev It is expected that both arrays are same length, and validator at - * position i corresponds to the value at position i - * @param _validator addresses to set in the whitelist - * @param _val value to set in the whitelist for corresponding address - */ - function setValidator(address[] memory _validator, bool[] memory _val) external; - - /** - * @notice Set a new owner address for the rollup proxy - * @param newOwner address of new rollup owner - */ - function setOwner(address newOwner) external; - - /** - * @notice Set minimum assertion period for the rollup - * @param newPeriod new minimum period for assertions - */ - function setMinimumAssertionPeriod(uint256 newPeriod) external; - - /** - * @notice Set number of blocks until a node is considered confirmed - * @param newConfirmPeriod new number of blocks until a node is confirmed - */ - function setConfirmPeriodBlocks(uint64 newConfirmPeriod) external; - - /** - * @notice Set number of extra blocks after a challenge - * @param newExtraTimeBlocks new number of blocks - */ - function setExtraChallengeTimeBlocks(uint64 newExtraTimeBlocks) external; - - /** - * @notice Set base stake required for an assertion - * @param newBaseStake maximum avmgas to be used per block - */ - function setBaseStake(uint256 newBaseStake) external; - - /** - * @notice Set the token used for stake, where address(0) == eth - * @dev Before changing the base stake token, you might need to change the - * implementation of the Rollup User logic! - * @param newStakeToken address of token used for staking - */ - function setStakeToken(address newStakeToken) external; - - /** - * @notice Upgrades the implementation of a beacon controlled by the rollup - * @param beacon address of beacon to be upgraded - * @param newImplementation new address of implementation - */ - function upgradeBeacon(address beacon, address newImplementation) external; - - function forceResolveChallenge(address[] memory stackerA, address[] memory stackerB) external; - - function forceRefundStaker(address[] memory stacker) external; - - function forceCreateNode( - uint64 prevNode, - uint256 prevNodeInboxMaxCount, - RollupLib.Assertion memory assertion, - bytes32 expectedNodeHash - ) external; - - function forceConfirmNode( - uint64 nodeNum, - bytes32 blockHash, - bytes32 sendRoot - ) external; - - function setLoserStakeEscrow(address newLoserStakerEscrow) external; - - /** - * @notice Set the proving WASM module root - * @param newWasmModuleRoot new module root - */ - function setWasmModuleRoot(bytes32 newWasmModuleRoot) external; - - /** - * @notice set a new sequencer inbox contract - * @param _sequencerInbox new address of sequencer inbox - */ - function setSequencerInbox(address _sequencerInbox) external; - - /** - * @notice set the validatorWhitelistDisabled flag - * @param _validatorWhitelistDisabled new value of validatorWhitelistDisabled, i.e. true = disabled - */ - function setValidatorWhitelistDisabled(bool _validatorWhitelistDisabled) external; -} diff --git a/src/rollup/Node.sol b/src/rollup/Node.sol index 78bb19a1..a5a50270 100644 --- a/src/rollup/Node.sol +++ b/src/rollup/Node.sol @@ -4,6 +4,20 @@ pragma solidity ^0.8.0; +import "../state/GlobalState.sol"; +import "../state/Machine.sol"; + +struct ExecutionState { + GlobalState globalState; + MachineStatus machineStatus; +} + +struct Assertion { + ExecutionState beforeState; + ExecutionState afterState; + uint64 numBlocks; +} + struct Node { // Hash of the state of the chain as of this node bytes32 stateHash; diff --git a/src/rollup/RollupAdminLogic.sol b/src/rollup/RollupAdminLogic.sol index dd813fd5..44a9989c 100644 --- a/src/rollup/RollupAdminLogic.sol +++ b/src/rollup/RollupAdminLogic.sol @@ -4,7 +4,8 @@ pragma solidity ^0.8.0; -import {IRollupAdmin, IRollupUser} from "./IRollupLogic.sol"; +import "./IRollupAdmin.sol"; +import "./IRollupLogic.sol"; import "./RollupCore.sol"; import "../bridge/IOutbox.sol"; import "../bridge/ISequencerInbox.sol"; @@ -76,7 +77,7 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, DoubleLogicUUPSUpgradeabl function createInitialNode() private view returns (Node memory) { GlobalState memory emptyGlobalState; bytes32 state = RollupLib.stateHashMem( - RollupLib.ExecutionState(emptyGlobalState, MachineStatus.FINISHED), + ExecutionState(emptyGlobalState, MachineStatus.FINISHED), 1 // inboxMaxCount - force the first assertion to read a message ); return @@ -285,7 +286,7 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, DoubleLogicUUPSUpgradeabl function forceCreateNode( uint64 prevNode, uint256 prevNodeInboxMaxCount, - RollupLib.Assertion calldata assertion, + Assertion calldata assertion, bytes32 expectedNodeHash ) external override whenPaused { require(prevNode == latestConfirmed(), "ONLY_LATEST_CONFIRMED"); @@ -340,10 +341,7 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, DoubleLogicUUPSUpgradeabl emit OwnerFunctionCalled(28); } - function createNitroMigrationGenesis(RollupLib.Assertion calldata assertion) - external - whenPaused - { + function createNitroMigrationGenesis(Assertion calldata assertion) external whenPaused { bytes32 expectedSendRoot = bytes32(0); uint64 expectedInboxCount = 1; diff --git a/src/rollup/RollupCore.sol b/src/rollup/RollupCore.sol index f96f609b..ec417596 100644 --- a/src/rollup/RollupCore.sol +++ b/src/rollup/RollupCore.sol @@ -7,7 +7,6 @@ pragma solidity ^0.8.0; import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import "./Node.sol"; -import "./IRollupCore.sol"; import "./RollupLib.sol"; import "./IRollupEventInbox.sol"; import "./IRollupCore.sol"; @@ -568,7 +567,7 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable { } function createNewNode( - RollupLib.Assertion calldata assertion, + Assertion calldata assertion, uint64 prevNodeNum, uint256 prevNodeInboxMaxCount, bytes32 expectedNodeHash diff --git a/src/rollup/RollupCreator.sol b/src/rollup/RollupCreator.sol index ed086560..e0e20f51 100644 --- a/src/rollup/RollupCreator.sol +++ b/src/rollup/RollupCreator.sol @@ -113,7 +113,7 @@ contract RollupCreator is Ownable { outbox: frame.outbox, rollupEventInbox: frame.rollupEventInbox, challengeManager: challengeManager, - rollupAdminLogic: rollupAdminLogic, + rollupAdminLogic: address(rollupAdminLogic), rollupUserLogic: rollupUserLogic, validatorUtils: validatorUtils, validatorWalletCreator: validatorWalletCreator diff --git a/src/rollup/RollupLib.sol b/src/rollup/RollupLib.sol index a46ec42c..8120fe83 100644 --- a/src/rollup/RollupLib.sol +++ b/src/rollup/RollupLib.sol @@ -12,45 +12,12 @@ import "../bridge/ISequencerInbox.sol"; import "../bridge/IBridge.sol"; import "../bridge/IOutbox.sol"; import "../bridge/IInbox.sol"; +import "./Node.sol"; import "./IRollupEventInbox.sol"; -import "./IRollupLogic.sol"; - -struct Config { - uint64 confirmPeriodBlocks; - uint64 extraChallengeTimeBlocks; - address stakeToken; - uint256 baseStake; - bytes32 wasmModuleRoot; - address owner; - address loserStakeEscrow; - uint256 chainId; - string chainConfig; - uint64 genesisBlockNum; - ISequencerInbox.MaxTimeVariation sequencerInboxMaxTimeVariation; -} - -struct ContractDependencies { - IBridge bridge; - ISequencerInbox sequencerInbox; - IInbox inbox; - IOutbox outbox; - IRollupEventInbox rollupEventInbox; - IChallengeManager challengeManager; - IRollupAdmin rollupAdminLogic; - IRollupUser rollupUserLogic; - // misc contracts that are useful when interacting with the rollup - address validatorUtils; - address validatorWalletCreator; -} library RollupLib { using GlobalStateLib for GlobalState; - struct ExecutionState { - GlobalState globalState; - MachineStatus machineStatus; - } - function stateHash(ExecutionState calldata execState, uint256 inboxMaxCount) internal pure @@ -82,12 +49,6 @@ library RollupLib { ); } - struct Assertion { - ExecutionState beforeState; - ExecutionState afterState; - uint64 numBlocks; - } - function executionHash(Assertion memory assertion) internal pure returns (bytes32) { MachineStatus[2] memory statuses; statuses[0] = assertion.beforeState.machineStatus; diff --git a/src/rollup/RollupProxy.sol b/src/rollup/RollupProxy.sol index 04531be6..7d302037 100644 --- a/src/rollup/RollupProxy.sol +++ b/src/rollup/RollupProxy.sol @@ -5,7 +5,8 @@ pragma solidity ^0.8.0; import "../libraries/AdminFallbackProxy.sol"; -import "./IRollupLogic.sol"; +import "./IRollupAdmin.sol"; +import "./Config.sol"; contract RollupProxy is AdminFallbackProxy { constructor(Config memory config, ContractDependencies memory connectedContracts) diff --git a/src/rollup/RollupUserLogic.sol b/src/rollup/RollupUserLogic.sol index c1d307dd..00145fa2 100644 --- a/src/rollup/RollupUserLogic.sol +++ b/src/rollup/RollupUserLogic.sol @@ -9,6 +9,8 @@ import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import {IRollupUser} from "./IRollupLogic.sol"; import "../libraries/UUPSNotUpgradeable.sol"; import "./RollupCore.sol"; +import "./IRollupLogic.sol"; + import {ETH_POS_BLOCK_TIME} from "../libraries/Constants.sol"; abstract contract AbsRollupUserLogic is @@ -189,7 +191,7 @@ abstract contract AbsRollupUserLogic is * @param expectedNodeHash The hash of the node being created (protects against reorgs) */ function stakeOnNewNode( - RollupLib.Assertion calldata assertion, + Assertion calldata assertion, bytes32 expectedNodeHash, uint256 prevNodeInboxMaxCount ) public onlyValidator whenNotPaused { @@ -632,7 +634,7 @@ contract RollupUserLogic is AbsRollupUserLogic, IRollupUser { * @param prevNodeInboxMaxCount Total of messages in the inbox as of the previous node */ function newStakeOnNewNode( - RollupLib.Assertion calldata assertion, + Assertion calldata assertion, bytes32 expectedNodeHash, uint256 prevNodeInboxMaxCount ) external payable override { @@ -701,7 +703,7 @@ contract ERC20RollupUserLogic is AbsRollupUserLogic, IRollupUserERC20 { */ function newStakeOnNewNode( uint256 tokenAmount, - RollupLib.Assertion calldata assertion, + Assertion calldata assertion, bytes32 expectedNodeHash, uint256 prevNodeInboxMaxCount ) external override { diff --git a/src/rollup/ValidatorUtils.sol b/src/rollup/ValidatorUtils.sol index 561cc1c2..a7bb7d9d 100644 --- a/src/rollup/ValidatorUtils.sol +++ b/src/rollup/ValidatorUtils.sol @@ -8,6 +8,7 @@ pragma experimental ABIEncoderV2; import "../rollup/IRollupCore.sol"; import "../challenge/IChallengeManager.sol"; +import "./IRollupLogic.sol"; import {NO_CHAL_INDEX} from "../libraries/Constants.sol"; diff --git a/src/state/Deserialize.sol b/src/state/Deserialize.sol index 8c98baa1..b0f15007 100644 --- a/src/state/Deserialize.sol +++ b/src/state/Deserialize.sol @@ -10,7 +10,7 @@ import "./Machine.sol"; import "./Instructions.sol"; import "./StackFrame.sol"; import "./MerkleProof.sol"; -import "./ModuleMemory.sol"; +import "./ModuleMemoryCompact.sol"; import "./Module.sol"; import "./GlobalState.sol"; diff --git a/src/state/Module.sol b/src/state/Module.sol index 71c775c2..46d64de2 100644 --- a/src/state/Module.sol +++ b/src/state/Module.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; -import "./ModuleMemory.sol"; +import "./ModuleMemoryCompact.sol"; struct Module { bytes32 globalsMerkleRoot; @@ -15,7 +15,7 @@ struct Module { } library ModuleLib { - using ModuleMemoryLib for ModuleMemory; + using ModuleMemoryCompactLib for ModuleMemory; function hash(Module memory mod) internal pure returns (bytes32) { return diff --git a/src/state/ModuleMemory.sol b/src/state/ModuleMemory.sol index c1f0adb1..76e64ec1 100644 --- a/src/state/ModuleMemory.sol +++ b/src/state/ModuleMemory.sol @@ -6,18 +6,13 @@ pragma solidity ^0.8.0; import "./MerkleProof.sol"; import "./Deserialize.sol"; - -struct ModuleMemory { - uint64 size; - uint64 maxSize; - bytes32 merkleRoot; -} +import "./ModuleMemoryCompact.sol"; library ModuleMemoryLib { using MerkleProofLib for MerkleProof; function hash(ModuleMemory memory mem) internal pure returns (bytes32) { - return keccak256(abi.encodePacked("Memory:", mem.size, mem.maxSize, mem.merkleRoot)); + return ModuleMemoryCompactLib.hash(mem); } function proveLeaf( diff --git a/src/state/ModuleMemoryCompact.sol b/src/state/ModuleMemoryCompact.sol new file mode 100644 index 00000000..935fdf38 --- /dev/null +++ b/src/state/ModuleMemoryCompact.sol @@ -0,0 +1,17 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.0; + +struct ModuleMemory { + uint64 size; + uint64 maxSize; + bytes32 merkleRoot; +} + +library ModuleMemoryCompactLib { + function hash(ModuleMemory memory mem) internal pure returns (bytes32) { + return keccak256(abi.encodePacked("Memory:", mem.size, mem.maxSize, mem.merkleRoot)); + } +} diff --git a/test/contract/arbRollup.spec.ts b/test/contract/arbRollup.spec.ts index f9b35379..f5d9d83d 100644 --- a/test/contract/arbRollup.spec.ts +++ b/test/contract/arbRollup.spec.ts @@ -50,9 +50,8 @@ import { forceCreateNode, assertionEquals, } from './common/rolluplib' -import { RollupLib } from '../../build/types/src/rollup/RollupUserLogic.sol/RollupUserLogic' -type AssertionStruct = RollupLib.AssertionStruct -type ExecutionStateStruct = RollupLib.ExecutionStateStruct +import { AssertionStruct } from '../../build/types/src/rollup/RollupCore' +import { ExecutionStateStruct } from '../../build/types/src/rollup/RollupCore' import { keccak256 } from 'ethers/lib/utils' import { ConfigStruct, diff --git a/test/contract/common/rolluplib.ts b/test/contract/common/rolluplib.ts index 2f19859b..4ef9c10a 100644 --- a/test/contract/common/rolluplib.ts +++ b/test/contract/common/rolluplib.ts @@ -10,12 +10,9 @@ import { RollupAdminLogic, SequencerInbox, } from '../../../build/types' -import { - RollupLib, - NodeCreatedEvent, -} from '../../../build/types/src/rollup/RollupUserLogic.sol/RollupUserLogic' -type AssertionStruct = RollupLib.AssertionStruct -type ExecutionStateStruct = RollupLib.ExecutionStateStruct +import { NodeCreatedEvent } from '../../../build/types/src/rollup/RollupUserLogic.sol/RollupUserLogic' +import { AssertionStruct } from '../../../build/types/src/rollup/RollupCore' +import { ExecutionStateStruct } from '../../../build/types/src/rollup/RollupCore' import { blockStateHash, hashChallengeState } from './challengeLib' import * as globalStateLib from './globalStateLib' import { constants } from 'ethers' From 7436762ab4236d31578e1f599a328eedeb2a632f Mon Sep 17 00:00:00 2001 From: amsanghi Date: Thu, 25 May 2023 22:41:13 +0530 Subject: [PATCH 04/15] add getBlockDifficulty to mock simple --- src/mocks/Simple.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mocks/Simple.sol b/src/mocks/Simple.sol index 1563fdb4..25d4b67b 100644 --- a/src/mocks/Simple.sol +++ b/src/mocks/Simple.sol @@ -43,6 +43,10 @@ contract Simple { return block.number; } + function getBlockDifficulty() external view returns (uint256) { + return block.difficulty; + } + function noop() external pure {} function pleaseRevert() external pure { From efbd3e0e1178d66662c842cbec897a0d3d0750ff Mon Sep 17 00:00:00 2001 From: gzeon <95478735+gzeoneth@users.noreply.github.com> Date: Fri, 26 May 2023 01:30:37 +0800 Subject: [PATCH 05/15] refactor: no need predict address --- src/rollup/RollupCreator.sol | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/rollup/RollupCreator.sol b/src/rollup/RollupCreator.sol index 53e160be..bb887266 100644 --- a/src/rollup/RollupCreator.sol +++ b/src/rollup/RollupCreator.sol @@ -9,7 +9,6 @@ import "./BridgeCreator.sol"; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; -import "@openzeppelin/contracts/utils/Create2.sol"; import "./RollupProxy.sol"; @@ -33,8 +32,6 @@ contract RollupCreator is Ownable { address public validatorWalletCreator; uint256 public deployedRollups; - bytes32 internal constant rollupProxyCreationCodeHash = - keccak256(type(RollupProxy).creationCode); constructor() Ownable() {} @@ -77,11 +74,8 @@ contract RollupCreator is Ownable { CreateRollupFrame memory frame; frame.admin = new ProxyAdmin(); - frame.rollupSalt = bytes32(deployedRollups++); - address expectedRollupAddr = Create2.computeAddress( - frame.rollupSalt, - rollupProxyCreationCodeHash - ); + frame.rollupSalt = keccak256(abi.encode(config, deployedRollups++)); + frame.rollup = new RollupProxy{salt: frame.rollupSalt}(); ( frame.bridge, frame.sequencerInbox, @@ -90,7 +84,7 @@ contract RollupCreator is Ownable { frame.outbox ) = bridgeCreator.createBridge( address(frame.admin), - expectedRollupAddr, + address(frame.rollup), config.sequencerInboxMaxTimeVariation ); @@ -106,15 +100,12 @@ contract RollupCreator is Ownable { ) ); challengeManager.initialize( - IChallengeResultReceiver(expectedRollupAddr), + IChallengeResultReceiver(address(frame.rollup)), frame.sequencerInbox, frame.bridge, osp ); - frame.rollup = new RollupProxy{salt: frame.rollupSalt}(); - require(address(frame.rollup) == expectedRollupAddr, "WRONG_ROLLUP_ADDR"); - frame.rollup.initializeProxy( config, ContractDependencies({ From 4ac9791a8397f705dde6997e334d84df0b3e4721 Mon Sep 17 00:00:00 2001 From: gzeon <95478735+gzeoneth@users.noreply.github.com> Date: Fri, 26 May 2023 01:34:21 +0800 Subject: [PATCH 06/15] refactor: remove scoping --- src/rollup/RollupCreator.sol | 73 ++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 41 deletions(-) diff --git a/src/rollup/RollupCreator.sol b/src/rollup/RollupCreator.sol index bb887266..cae767e5 100644 --- a/src/rollup/RollupCreator.sol +++ b/src/rollup/RollupCreator.sol @@ -54,66 +54,57 @@ contract RollupCreator is Ownable { emit TemplatesUpdated(); } - struct CreateRollupFrame { - ProxyAdmin admin; - IBridge bridge; - ISequencerInbox sequencerInbox; - IInbox inbox; - IRollupEventInbox rollupEventInbox; - IOutbox outbox; - RollupProxy rollup; - bytes32 rollupSalt; - } - // After this setup: // Rollup should be the owner of bridge // RollupOwner should be the owner of Rollup's ProxyAdmin // RollupOwner should be the owner of Rollup // Bridge should have a single inbox and outbox function createRollup(Config memory config) external returns (address) { - CreateRollupFrame memory frame; - frame.admin = new ProxyAdmin(); + ProxyAdmin proxyAdmin = new ProxyAdmin(); + + bytes32 rollupSalt = keccak256(abi.encode(config, deployedRollups++)); + + // Create the rollup proxy to figure out the address and initialize it later + RollupProxy rollup = new RollupProxy{salt: rollupSalt}(); - frame.rollupSalt = keccak256(abi.encode(config, deployedRollups++)); - frame.rollup = new RollupProxy{salt: frame.rollupSalt}(); ( - frame.bridge, - frame.sequencerInbox, - frame.inbox, - frame.rollupEventInbox, - frame.outbox + IBridge bridge, + ISequencerInbox sequencerInbox, + IInbox inbox, + IRollupEventInbox rollupEventInbox, + IOutbox outbox ) = bridgeCreator.createBridge( - address(frame.admin), - address(frame.rollup), - config.sequencerInboxMaxTimeVariation - ); + address(proxyAdmin), + address(rollup), + config.sequencerInboxMaxTimeVariation + ); - frame.admin.transferOwnership(config.owner); + proxyAdmin.transferOwnership(config.owner); IChallengeManager challengeManager = IChallengeManager( address( new TransparentUpgradeableProxy( address(challengeManagerTemplate), - address(frame.admin), + address(proxyAdmin), "" ) ) ); challengeManager.initialize( - IChallengeResultReceiver(address(frame.rollup)), - frame.sequencerInbox, - frame.bridge, + IChallengeResultReceiver(address(rollup)), + sequencerInbox, + bridge, osp ); - frame.rollup.initializeProxy( + rollup.initializeProxy( config, ContractDependencies({ - bridge: frame.bridge, - sequencerInbox: frame.sequencerInbox, - inbox: frame.inbox, - outbox: frame.outbox, - rollupEventInbox: frame.rollupEventInbox, + bridge: bridge, + sequencerInbox: sequencerInbox, + inbox: inbox, + outbox: outbox, + rollupEventInbox: rollupEventInbox, challengeManager: challengeManager, rollupAdminLogic: rollupAdminLogic, rollupUserLogic: rollupUserLogic, @@ -123,12 +114,12 @@ contract RollupCreator is Ownable { ); emit RollupCreated( - address(frame.rollup), - address(frame.inbox), - address(frame.admin), - address(frame.sequencerInbox), - address(frame.bridge) + address(rollup), + address(inbox), + address(proxyAdmin), + address(sequencerInbox), + address(bridge) ); - return address(frame.rollup); + return address(rollup); } } From b4413b4193bc33664ecdbc61058344a25e675427 Mon Sep 17 00:00:00 2001 From: gzeon <95478735+gzeoneth@users.noreply.github.com> Date: Fri, 26 May 2023 01:37:42 +0800 Subject: [PATCH 07/15] refactor: remove nonce --- src/rollup/RollupCreator.sol | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/rollup/RollupCreator.sol b/src/rollup/RollupCreator.sol index cae767e5..1360b4ef 100644 --- a/src/rollup/RollupCreator.sol +++ b/src/rollup/RollupCreator.sol @@ -31,8 +31,6 @@ contract RollupCreator is Ownable { address public validatorUtils; address public validatorWalletCreator; - uint256 public deployedRollups; - constructor() Ownable() {} function setTemplates( @@ -62,10 +60,8 @@ contract RollupCreator is Ownable { function createRollup(Config memory config) external returns (address) { ProxyAdmin proxyAdmin = new ProxyAdmin(); - bytes32 rollupSalt = keccak256(abi.encode(config, deployedRollups++)); - // Create the rollup proxy to figure out the address and initialize it later - RollupProxy rollup = new RollupProxy{salt: rollupSalt}(); + RollupProxy rollup = new RollupProxy{salt: keccak256(abi.encode(config))}(); ( IBridge bridge, From 2a1f27b3494cb8e00f2efb3757ba810b8ee1387f Mon Sep 17 00:00:00 2001 From: Daniel Goldman Date: Thu, 25 May 2023 15:22:13 -0400 Subject: [PATCH 08/15] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fdfeb383..8fc3d98c 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ For the token bridge contracts see https://github.com/OffchainLabs/token-bridge- Compile these contracts locally by running ```bash -git clone https://github.com/offchainlabs/rollup-contracts -cd rollup-contracts +git clone https://github.com/offchainlabs/nitro-contracts +cd nitro-contracts yarn install yarn build ``` From 174cd7d25065940206903e850bc60955fb5488db Mon Sep 17 00:00:00 2001 From: shotaronowhere Date: Fri, 26 May 2023 12:33:07 +0700 Subject: [PATCH 09/15] chore(ISequencerInbox): Add Missing views --- src/bridge/ISequencerInbox.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bridge/ISequencerInbox.sol b/src/bridge/ISequencerInbox.sol index 994c7c01..749c9e48 100644 --- a/src/bridge/ISequencerInbox.sol +++ b/src/bridge/ISequencerInbox.sol @@ -76,9 +76,9 @@ interface ISequencerInbox is IDelayedMessageProvider { uint64 creationBlock; } - // https://github.com/ethereum/solidity/issues/11826 - // function maxTimeVariation() external view returns (MaxTimeVariation calldata); - // function dasKeySetInfo(bytes32) external view returns (DasKeySetInfo calldata); + function maxTimeVariation() external view returns (uint256, uint256, uint256, uint256); + + function dasKeySetInfo(bytes32) external view returns (bool, uint64); /// @notice Remove force inclusion delay after a L1 chainId fork function removeDelayAfterFork() external; From b109b0d180adf318b292964b9a3a52a6cc9e1015 Mon Sep 17 00:00:00 2001 From: gzeon <95478735+gzeoneth@users.noreply.github.com> Date: Mon, 29 May 2023 16:44:51 +0800 Subject: [PATCH 10/15] format: yarn format --- src/bridge/ISequencerInbox.sol | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/bridge/ISequencerInbox.sol b/src/bridge/ISequencerInbox.sol index 749c9e48..55454a88 100644 --- a/src/bridge/ISequencerInbox.sol +++ b/src/bridge/ISequencerInbox.sol @@ -76,7 +76,15 @@ interface ISequencerInbox is IDelayedMessageProvider { uint64 creationBlock; } - function maxTimeVariation() external view returns (uint256, uint256, uint256, uint256); + function maxTimeVariation() + external + view + returns ( + uint256, + uint256, + uint256, + uint256 + ); function dasKeySetInfo(bytes32) external view returns (bool, uint64); From ea697669ba7f7f410d8849ca30a59b30232cccc8 Mon Sep 17 00:00:00 2001 From: Harry Kalodner Date: Mon, 12 Jun 2023 14:28:21 -0400 Subject: [PATCH 11/15] Add clabot config --- .clabot | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .clabot diff --git a/.clabot b/.clabot new file mode 100644 index 00000000..b4ac3516 --- /dev/null +++ b/.clabot @@ -0,0 +1,5 @@ +{ + "contributors": "https://api.github.com/repos/OffchainLabs/clabot-config/contents/nitro-contributors.json", + "message": "We require contributors to sign our Contributor License Agreement. In order for us to review and merge your code, please sign the linked documents below to get yourself added. https://na3.docusign.net/Member/PowerFormSigning.aspx?PowerFormId=b15c81cc-b5ea-42a6-9107-3992526f2898&env=na3&acct=6e152afc-6284-44af-a4c1-d8ef291db402&v=2", + "label": "s" +} \ No newline at end of file From 17a08edd7bd12a1c627f0a0ef86907aa2db22e7a Mon Sep 17 00:00:00 2001 From: fredlacs <32464905+fredlacs@users.noreply.github.com> Date: Mon, 12 Jun 2023 19:58:34 -0300 Subject: [PATCH 12/15] Update RollupEventInbox.sol (#21) --- src/rollup/RollupEventInbox.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rollup/RollupEventInbox.sol b/src/rollup/RollupEventInbox.sol index 9d7353fc..ba63a95b 100644 --- a/src/rollup/RollupEventInbox.sol +++ b/src/rollup/RollupEventInbox.sol @@ -36,7 +36,8 @@ contract RollupEventInbox is IRollupEventInbox, IDelayedMessageProvider, Delegat onlyRollup { require(bytes(chainConfig).length > 0, "EMPTY_CHAIN_CONFIG"); - bytes memory initMsg = abi.encodePacked(chainId, uint8(0), chainConfig); + uint8 initMsgVersion = 0; + bytes memory initMsg = abi.encodePacked(chainId, initMsgVersion, chainConfig); uint256 num = bridge.enqueueDelayedMessage( INITIALIZATION_MSG_TYPE, address(0), From e32dc9b655bc159c1dd1bbdc73f0afad606145a6 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Fri, 16 Jun 2023 10:42:41 -0600 Subject: [PATCH 13/15] Include L1 gas charges in L3 batch posting reports --- src/bridge/SequencerInbox.sol | 11 +++++++++++ src/libraries/ArbitrumChecker.sol | 16 ++++++++++++++++ src/rollup/RollupCore.sol | 10 ++-------- 3 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 src/libraries/ArbitrumChecker.sol diff --git a/src/bridge/SequencerInbox.sol b/src/bridge/SequencerInbox.sol index c95cd70b..1698e115 100644 --- a/src/bridge/SequencerInbox.sol +++ b/src/bridge/SequencerInbox.sol @@ -27,10 +27,12 @@ import "./IInbox.sol"; import "./ISequencerInbox.sol"; import "../rollup/IRollupLogic.sol"; import "./Messages.sol"; +import "../precompiles/ArbGasInfo.sol"; import {L1MessageType_batchPostingReport} from "../libraries/MessageTypes.sol"; import {GasRefundEnabled, IGasRefunder} from "../libraries/IGasRefunder.sol"; import "../libraries/DelegateCallAware.sol"; +import "../libraries/ArbitrumChecker.sol"; import {MAX_DATA_SIZE} from "../libraries/Constants.sol"; /** @@ -66,6 +68,9 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox mapping(address => bool) public isSequencer; + // If the chain this SequencerInbox is deployed on is an Arbitrum chain. + bool internal immutable hostChainIsArbitrum = ArbitrumChecker.runningOnArbitrum(); + function _chainIdChanged() internal view returns (bool) { return deployTimeChainId != block.chainid; } @@ -394,6 +399,12 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox seqMessageIndex, block.basefee ); + if (hostChainIsArbitrum) { + // Include extra gas for the host chain's L1 gas charging + uint256 l1Fees = ArbGasInfo(address(0x6c)).getCurrentTxL1GasFees(); + uint64 extraGas = uint64(l1Fees / block.basefee); + spendingReportMsg = abi.encodePacked(spendingReportMsg, extraGas); + } uint256 msgNum = bridge.submitBatchSpendingReport( batchPoster, keccak256(spendingReportMsg) diff --git a/src/libraries/ArbitrumChecker.sol b/src/libraries/ArbitrumChecker.sol new file mode 100644 index 00000000..714c4e75 --- /dev/null +++ b/src/libraries/ArbitrumChecker.sol @@ -0,0 +1,16 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.0; + +import "../precompiles/ArbSys.sol"; + +library ArbitrumChecker { + function runningOnArbitrum() internal view returns (bool) { + (bool ok, bytes memory data) = address(100).staticcall( + abi.encodeWithSelector(ArbSys.arbOSVersion.selector) + ); + return ok && data.length == 32; + } +} diff --git a/src/rollup/RollupCore.sol b/src/rollup/RollupCore.sol index ec417596..d12fb149 100644 --- a/src/rollup/RollupCore.sol +++ b/src/rollup/RollupCore.sol @@ -19,6 +19,7 @@ import "../bridge/IOutbox.sol"; import "../precompiles/ArbSys.sol"; +import "../libraries/ArbitrumChecker.sol"; import {NO_CHAL_INDEX} from "../libraries/Constants.sol"; abstract contract RollupCore is IRollupCore, PausableUpgradeable { @@ -78,17 +79,10 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable { bool public validatorWhitelistDisabled; // If the chain this RollupCore is deployed on is an Arbitrum chain. - bool internal immutable _hostChainIsArbitrum; + bool internal immutable _hostChainIsArbitrum = ArbitrumChecker.runningOnArbitrum(); // If the chain RollupCore is deployed on, this will contain the ArbSys.blockNumber() at each node's creation. mapping(uint64 => uint256) internal _nodeCreatedAtArbSysBlock; - constructor() { - (bool ok, bytes memory data) = address(100).staticcall( - abi.encodeWithSelector(ArbSys.arbOSVersion.selector) - ); - _hostChainIsArbitrum = ok && data.length == 32; - } - /** * @notice Get a storage reference to the Node for the given node index * @param nodeNum Index of the node From 5eb3ff91b009263004167230895387dcb30965d6 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Fri, 16 Jun 2023 13:05:54 -0600 Subject: [PATCH 14/15] Wrap in L1 cost to data gas cost --- src/bridge/SequencerInbox.sol | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/bridge/SequencerInbox.sol b/src/bridge/SequencerInbox.sol index 1698e115..b0c88a32 100644 --- a/src/bridge/SequencerInbox.sol +++ b/src/bridge/SequencerInbox.sol @@ -392,19 +392,18 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox // this msg isn't included in the current sequencer batch, but instead added to // the delayed messages queue that is yet to be included address batchPoster = msg.sender; + uint256 dataCost = block.basefee; + if (hostChainIsArbitrum) { + // Include extra cost for the host chain's L1 gas charging + dataCost += ArbGasInfo(address(0x6c)).getL1BaseFeeEstimate(); + } bytes memory spendingReportMsg = abi.encodePacked( block.timestamp, batchPoster, dataHash, seqMessageIndex, - block.basefee + dataCost ); - if (hostChainIsArbitrum) { - // Include extra gas for the host chain's L1 gas charging - uint256 l1Fees = ArbGasInfo(address(0x6c)).getCurrentTxL1GasFees(); - uint64 extraGas = uint64(l1Fees / block.basefee); - spendingReportMsg = abi.encodePacked(spendingReportMsg, extraGas); - } uint256 msgNum = bridge.submitBatchSpendingReport( batchPoster, keccak256(spendingReportMsg) From 51cd55901676ec998c5260f779c385b77855d817 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Fri, 16 Jun 2023 13:08:35 -0600 Subject: [PATCH 15/15] Include the current data cost in the init message --- src/rollup/RollupEventInbox.sol | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/rollup/RollupEventInbox.sol b/src/rollup/RollupEventInbox.sol index ba63a95b..3a56288d 100644 --- a/src/rollup/RollupEventInbox.sol +++ b/src/rollup/RollupEventInbox.sol @@ -7,7 +7,9 @@ pragma solidity ^0.8.0; import "./IRollupEventInbox.sol"; import "../bridge/IBridge.sol"; import "../bridge/IDelayedMessageProvider.sol"; +import "../precompiles/ArbGasInfo.sol"; import "../libraries/DelegateCallAware.sol"; +import "../libraries/ArbitrumChecker.sol"; import {INITIALIZATION_MSG_TYPE} from "../libraries/MessageTypes.sol"; import {AlreadyInit, HadZeroInit} from "../libraries/Error.sol"; @@ -36,8 +38,17 @@ contract RollupEventInbox is IRollupEventInbox, IDelayedMessageProvider, Delegat onlyRollup { require(bytes(chainConfig).length > 0, "EMPTY_CHAIN_CONFIG"); - uint8 initMsgVersion = 0; - bytes memory initMsg = abi.encodePacked(chainId, initMsgVersion, chainConfig); + uint8 initMsgVersion = 1; + uint256 currentDataCost = block.basefee; + if (ArbitrumChecker.runningOnArbitrum()) { + currentDataCost += ArbGasInfo(address(0x6c)).getL1BaseFeeEstimate(); + } + bytes memory initMsg = abi.encodePacked( + chainId, + initMsgVersion, + currentDataCost, + chainConfig + ); uint256 num = bridge.enqueueDelayedMessage( INITIALIZATION_MSG_TYPE, address(0),