@arbitrum/nitro-contracts 1.0.0-beta.7 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. package/package.json +13 -2
  2. package/src/bridge/Bridge.sol +49 -29
  3. package/src/bridge/IBridge.sol +58 -45
  4. package/src/bridge/IDelayedMessageProvider.sol +2 -1
  5. package/src/bridge/IInbox.sol +133 -50
  6. package/src/bridge/IOutbox.sol +95 -27
  7. package/src/bridge/IOwnable.sol +2 -1
  8. package/src/bridge/ISequencerInbox.sol +79 -31
  9. package/src/bridge/Inbox.sol +171 -108
  10. package/src/bridge/Outbox.sol +26 -41
  11. package/src/bridge/SequencerInbox.sol +152 -62
  12. package/src/challenge/ChallengeManager.sol +0 -9
  13. package/src/challenge/IChallengeManager.sol +0 -2
  14. package/src/libraries/AdminFallbackProxy.sol +4 -4
  15. package/src/libraries/Constants.sol +3 -0
  16. package/src/libraries/{SecondaryLogicUUPSUpgradeable.sol → DoubleLogicUUPSUpgradeable.sol} +2 -1
  17. package/src/libraries/Error.sol +119 -0
  18. package/src/libraries/IGasRefunder.sol +13 -6
  19. package/src/libraries/MerkleLib.sol +5 -3
  20. package/src/mocks/BridgeStub.sol +22 -1
  21. package/src/mocks/BridgeUnproxied.sol +17 -0
  22. package/src/mocks/InboxStub.sol +49 -2
  23. package/src/mocks/SequencerInboxStub.sol +13 -3
  24. package/src/mocks/Simple.sol +69 -0
  25. package/src/node-interface/NodeInterface.sol +69 -7
  26. package/src/precompiles/ArbGasInfo.sol +16 -4
  27. package/src/precompiles/ArbOwner.sol +18 -0
  28. package/src/precompiles/ArbOwnerPublic.sol +3 -0
  29. package/src/precompiles/ArbSys.sol +7 -4
  30. package/src/rollup/IRollupCore.sol +2 -0
  31. package/src/rollup/IRollupLogic.sol +10 -0
  32. package/src/rollup/RollupAdminLogic.sol +69 -3
  33. package/src/rollup/RollupCore.sol +8 -2
  34. package/src/rollup/RollupCreator.sol +3 -3
  35. package/src/rollup/RollupEventInbox.sol +3 -6
  36. package/src/rollup/RollupLib.sol +1 -0
  37. package/src/{libraries/ArbitrumProxy.sol → rollup/RollupProxy.sol} +3 -3
  38. package/src/rollup/RollupUserLogic.sol +47 -10
  39. package/src/state/GlobalState.sol +7 -0
  40. package/src/test-helpers/BridgeTester.sol +17 -1
  41. package/src/test-helpers/InterfaceCompatibilityTester.sol +11 -0
  42. package/src/test-helpers/OutboxWithoutOptTester.sol +33 -7
@@ -0,0 +1,17 @@
1
+ // Copyright 2021-2022, Offchain Labs, Inc.
2
+ // For license information, see https://github.com/nitro/blob/master/LICENSE
3
+ // SPDX-License-Identifier: BUSL-1.1
4
+
5
+ pragma solidity ^0.8.0;
6
+
7
+ import "./InboxStub.sol";
8
+ import {BadSequencerMessageNumber} from "../libraries/Error.sol";
9
+
10
+ import "../bridge/Bridge.sol";
11
+
12
+ contract BridgeUnproxied is Bridge {
13
+ constructor() {
14
+ _activeOutbox = EMPTY_ACTIVEOUTBOX;
15
+ rollup = IOwnable(msg.sender);
16
+ }
17
+ }
@@ -19,10 +19,19 @@ import {
19
19
 
20
20
  contract InboxStub is IInbox {
21
21
  IBridge public override bridge;
22
+ ISequencerInbox public override sequencerInbox;
22
23
 
23
24
  bool public paused;
24
25
 
25
- function initialize(IBridge _bridge) external {
26
+ function pause() external pure {
27
+ revert("NOT IMPLEMENTED");
28
+ }
29
+
30
+ function unpause() external pure {
31
+ revert("NOT IMPLEMENTED");
32
+ }
33
+
34
+ function initialize(IBridge _bridge, ISequencerInbox) external {
26
35
  require(address(bridge) == address(0), "ALREADY_INIT");
27
36
  bridge = _bridge;
28
37
  }
@@ -125,11 +134,49 @@ contract InboxStub is IInbox {
125
134
  revert("NOT_IMPLEMENTED");
126
135
  }
127
136
 
137
+ function sendL1FundedUnsignedTransactionToFork(
138
+ uint256,
139
+ uint256,
140
+ uint256,
141
+ address,
142
+ bytes calldata
143
+ ) external payable returns (uint256) {
144
+ revert("NOT_IMPLEMENTED");
145
+ }
146
+
147
+ function sendUnsignedTransactionToFork(
148
+ uint256,
149
+ uint256,
150
+ uint256,
151
+ address,
152
+ uint256,
153
+ bytes calldata
154
+ ) external returns (uint256) {
155
+ revert("NOT_IMPLEMENTED");
156
+ }
157
+
158
+ function sendWithdrawEthToFork(
159
+ uint256,
160
+ uint256,
161
+ uint256,
162
+ uint256,
163
+ address
164
+ ) external returns (uint256) {
165
+ revert("NOT_IMPLEMENTED");
166
+ }
167
+
128
168
  function depositEth() external payable override returns (uint256) {
129
169
  revert("NOT_IMPLEMENTED");
130
170
  }
131
171
 
132
- function depositEth(uint256) external payable override returns (uint256) {
172
+ function postUpgradeInit(IBridge _bridge) external {}
173
+
174
+ function calculateRetryableSubmissionFee(uint256, uint256)
175
+ external
176
+ pure
177
+ override
178
+ returns (uint256)
179
+ {
133
180
  revert("NOT_IMPLEMENTED");
134
181
  }
135
182
  }
@@ -5,6 +5,7 @@
5
5
  pragma solidity ^0.8.0;
6
6
 
7
7
  import "../bridge/SequencerInbox.sol";
8
+ import {INITIALIZATION_MSG_TYPE} from "../libraries/MessageTypes.sol";
8
9
 
9
10
  contract SequencerInboxStub is SequencerInbox {
10
11
  constructor(
@@ -18,14 +19,23 @@ contract SequencerInboxStub is SequencerInbox {
18
19
  isBatchPoster[sequencer_] = true;
19
20
  }
20
21
 
21
- function addInitMessage() external {
22
- (bytes32 dataHash, TimeBounds memory timeBounds) = formEmptyDataHash(0);
22
+ function addInitMessage(uint256 chainId) external {
23
+ bytes memory initMsg = abi.encodePacked(chainId);
24
+ uint256 num = bridge.enqueueDelayedMessage(
25
+ INITIALIZATION_MSG_TYPE,
26
+ address(0),
27
+ keccak256(initMsg)
28
+ );
29
+ require(num == 0, "ALREADY_DELAYED_INIT");
30
+ emit InboxMessageDelivered(num, initMsg);
31
+ (bytes32 dataHash, TimeBounds memory timeBounds) = formEmptyDataHash(1);
23
32
  (
24
33
  uint256 sequencerMessageCount,
25
34
  bytes32 beforeAcc,
26
35
  bytes32 delayedAcc,
27
36
  bytes32 afterAcc
28
- ) = addSequencerL2BatchImpl(dataHash, 0, 0);
37
+ ) = addSequencerL2BatchImpl(dataHash, 1, 0, 0, 1);
38
+ require(sequencerMessageCount == 0, "ALREADY_SEQ_INIT");
29
39
  emit SequencerBatchDelivered(
30
40
  sequencerMessageCount,
31
41
  beforeAcc,
@@ -5,6 +5,7 @@
5
5
  pragma solidity ^0.8.0;
6
6
 
7
7
  import "../precompiles/ArbRetryableTx.sol";
8
+ import "../precompiles/ArbSys.sol";
8
9
 
9
10
  contract Simple {
10
11
  uint64 public counter;
@@ -35,4 +36,72 @@ contract Simple {
35
36
  require(blockhash(block.number - 1) != blockhash(block.number - 2), "SAME_BLOCK_HASH");
36
37
  return block.number;
37
38
  }
39
+
40
+ function noop() external pure {}
41
+
42
+ function pleaseRevert() external pure {
43
+ revert("SOLIDITY_REVERTING");
44
+ }
45
+
46
+ function checkIsTopLevelOrWasAliased(bool useTopLevel, bool expected) public view {
47
+ if (useTopLevel) {
48
+ require(ArbSys(address(100)).isTopLevelCall() == expected, "UNEXPECTED_RESULT");
49
+ } else {
50
+ require(
51
+ ArbSys(address(100)).wasMyCallersAddressAliased() == expected,
52
+ "UNEXPECTED_RESULT"
53
+ );
54
+ }
55
+ }
56
+
57
+ function checkCalls(
58
+ bool useTopLevel,
59
+ bool directCase,
60
+ bool staticCase,
61
+ bool delegateCase,
62
+ bool callcodeCase,
63
+ bool callCase
64
+ ) public {
65
+ // DIRECT CALL
66
+ if (useTopLevel) {
67
+ require(ArbSys(address(100)).isTopLevelCall() == directCase, "UNEXPECTED_RESULT");
68
+ } else {
69
+ require(
70
+ ArbSys(address(100)).wasMyCallersAddressAliased() == directCase,
71
+ "UNEXPECTED_RESULT"
72
+ );
73
+ }
74
+
75
+ // STATIC CALL
76
+ this.checkIsTopLevelOrWasAliased(useTopLevel, staticCase);
77
+
78
+ // DELEGATE CALL
79
+ bytes memory data = abi.encodeWithSelector(
80
+ this.checkIsTopLevelOrWasAliased.selector,
81
+ useTopLevel,
82
+ delegateCase
83
+ );
84
+ (bool success, ) = address(this).delegatecall(data);
85
+ require(success, "DELEGATE_CALL_FAILED");
86
+
87
+ // CALLCODE
88
+ data = abi.encodeWithSelector(
89
+ this.checkIsTopLevelOrWasAliased.selector,
90
+ useTopLevel,
91
+ callcodeCase
92
+ );
93
+ assembly {
94
+ success := callcode(gas(), address(), 0, add(data, 32), mload(data), 0, 0)
95
+ }
96
+ require(success, "CALLCODE_FAILED");
97
+
98
+ // CALL
99
+ data = abi.encodeWithSelector(
100
+ this.checkIsTopLevelOrWasAliased.selector,
101
+ useTopLevel,
102
+ callCase
103
+ );
104
+ (success, ) = address(this).call(data);
105
+ require(success, "CALL_FAILED");
106
+ }
38
107
  }
@@ -11,9 +11,10 @@ pragma solidity >=0.4.21 <0.9.0;
11
11
  */
12
12
  interface NodeInterface {
13
13
  /**
14
- * @notice Estimate the cost of putting a message in the L2 inbox that is reexecuted.
15
- * Use eth_estimateGas to call.
16
- * @param sender sender of the L1 and L2 transaction
14
+ * @notice Simulate the execution of a retryable ticket
15
+ * @dev Use eth_estimateGas on this call to estimate gas usage of retryable ticket
16
+ * Since gas usage is not yet known, you may need to add extra deposit (e.g. 1e18 wei) during estimation
17
+ * @param sender unaliased sender of the L1 and L2 transaction
17
18
  * @param deposit amount to deposit to sender in L2
18
19
  * @param to destination L2 contract address
19
20
  * @param l2CallValue call value for retryable L2 message
@@ -33,7 +34,7 @@ interface NodeInterface {
33
34
 
34
35
  /**
35
36
  * @notice Constructs an outbox proof of an l2->l1 send's existence in the outbox accumulator.
36
- * Use eth_call to call.
37
+ * @dev Use eth_call to call.
37
38
  * @param size the number of elements in the accumulator
38
39
  * @param leaf the position of the send in the accumulator
39
40
  * @return send the l2->l1 send's hash
@@ -54,7 +55,7 @@ interface NodeInterface {
54
55
  * Use eth_call to call.
55
56
  * Throws if block doesn't exist, or if block number is 0. Use eth_call
56
57
  * @param blockNum The L2 block being queried
57
- * @return batch The L1 block containing the requested L2 block
58
+ * @return batch The sequencer batch number containing the requested L2 block
58
59
  */
59
60
  function findBatchContainingBlock(uint64 blockNum) external view returns (uint64 batch);
60
61
 
@@ -62,14 +63,16 @@ interface NodeInterface {
62
63
  * @notice Gets the number of L1 confirmations of the sequencer batch producing the requested L2 block
63
64
  * This gets the number of L1 confirmations for the input message producing the L2 block,
64
65
  * which happens well before the L1 rollup contract confirms the L2 block.
65
- * Throws if block doesnt exist in the L2 chain. Use eth_call to call.
66
+ * Throws if block doesnt exist in the L2 chain.
67
+ * @dev Use eth_call to call.
66
68
  * @param blockHash The hash of the L2 block being queried
67
69
  * @return confirmations The number of L1 confirmations the sequencer batch has. Returns 0 if block not yet included in an L1 batch.
68
70
  */
69
71
  function getL1Confirmations(bytes32 blockHash) external view returns (uint64 confirmations);
70
72
 
71
73
  /**
72
- * @notice Same as native gas estimation, but with additional info on the l1 costs. Use eth_call to call.
74
+ * @notice Same as native gas estimation, but with additional info on the l1 costs.
75
+ * @dev Use eth_call to call.
73
76
  * @param data the tx's calldata. Everything else like "From" and "Gas" are copied over
74
77
  * @param to the tx's "To" (ignored when contractCreation is true)
75
78
  * @param contractCreation whether "To" is omitted
@@ -91,4 +94,63 @@ interface NodeInterface {
91
94
  uint256 baseFee,
92
95
  uint256 l1BaseFeeEstimate
93
96
  );
97
+
98
+ /**
99
+ * @notice Estimates a transaction's l1 costs.
100
+ * @dev Use eth_call to call.
101
+ * This method is exactly like gasEstimateComponents, but doesn't include the l2 component
102
+ * so that the l1 component can be known even when the tx may fail.
103
+ * @param data the tx's calldata. Everything else like "From" and "Gas" are copied over
104
+ * @param to the tx's "To" (ignored when contractCreation is true)
105
+ * @param contractCreation whether "To" is omitted
106
+ * @return gasEstimateForL1 an estimate of the amount of gas needed for the l1 component of this tx
107
+ * @return baseFee the l2 base fee
108
+ * @return l1BaseFeeEstimate ArbOS's l1 estimate of the l1 base fee
109
+ */
110
+ function gasEstimateL1Component(
111
+ address to,
112
+ bool contractCreation,
113
+ bytes calldata data
114
+ )
115
+ external
116
+ payable
117
+ returns (
118
+ uint64 gasEstimateForL1,
119
+ uint256 baseFee,
120
+ uint256 l1BaseFeeEstimate
121
+ );
122
+
123
+ /**
124
+ * @notice Returns the proof necessary to redeem a message
125
+ * @param batchNum index of outbox entry (i.e., outgoing messages Merkle root) in array of outbox entries
126
+ * @param index index of outgoing message in outbox entry
127
+ * @return proof Merkle proof of message inclusion in outbox entry
128
+ * @return path Merkle path to message
129
+ * @return l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1)
130
+ * @return l1Dest destination address for L1 contract call
131
+ * @return l2Block l2 block number at which sendTxToL1 call was made
132
+ * @return l1Block l1 block number at which sendTxToL1 call was made
133
+ * @return timestamp l2 Timestamp at which sendTxToL1 call was made
134
+ * @return amount value in L1 message in wei
135
+ * @return calldataForL1 abi-encoded L1 message data
136
+ */
137
+ function legacyLookupMessageBatchProof(uint256 batchNum, uint64 index)
138
+ external
139
+ view
140
+ returns (
141
+ bytes32[] memory proof,
142
+ uint256 path,
143
+ address l2Sender,
144
+ address l1Dest,
145
+ uint256 l2Block,
146
+ uint256 l1Block,
147
+ uint256 timestamp,
148
+ uint256 amount,
149
+ bytes memory calldataForL1
150
+ );
151
+
152
+ // @notice Returns the first block produced using the Nitro codebase
153
+ // @dev returns 0 for chains like Nova that don't contain classic blocks
154
+ // @return number the block number
155
+ function nitroGenesisBlock() external pure returns (uint256 number);
94
156
  }
@@ -13,7 +13,7 @@ interface ArbGasInfo {
13
13
  /// @return return gas prices in wei
14
14
  /// (
15
15
  /// per L2 tx,
16
- /// per L1 calldata unit, (a byte, non-zero or otherwise, is 16 units)
16
+ /// per L1 calldata byte
17
17
  /// per storage allocation,
18
18
  /// per ArbGas base,
19
19
  /// per ArbGas congestion,
@@ -35,7 +35,7 @@ interface ArbGasInfo {
35
35
  /// @return return gas prices in wei
36
36
  /// (
37
37
  /// per L2 tx,
38
- /// per L1 calldata unit, (a byte, non-zero or otherwise, is 16 units)
38
+ /// per L1 calldata byte
39
39
  /// per storage allocation,
40
40
  /// per ArbGas base,
41
41
  /// per ArbGas congestion,
@@ -54,7 +54,7 @@ interface ArbGasInfo {
54
54
  );
55
55
 
56
56
  /// @notice Get prices in ArbGas for the supplied aggregator
57
- /// @return (per L2 tx, per L1 calldata unit, per storage allocation)
57
+ /// @return (per L2 tx, per L1 calldata byte, per storage allocation)
58
58
  function getPricesInArbGasWithAggregator(address aggregator)
59
59
  external
60
60
  view
@@ -65,7 +65,7 @@ interface ArbGasInfo {
65
65
  );
66
66
 
67
67
  /// @notice Get prices in ArbGas. Assumes the callers preferred validator, or the default if caller doesn't have a preferred one.
68
- /// @return (per L2 tx, per L1 calldata unit, per storage allocation)
68
+ /// @return (per L2 tx, per L1 calldata byte, per storage allocation)
69
69
  function getPricesInArbGas()
70
70
  external
71
71
  view
@@ -109,4 +109,16 @@ interface ArbGasInfo {
109
109
 
110
110
  /// @notice Get the forgivable amount of backlogged gas ArbOS will ignore when raising the basefee
111
111
  function getGasBacklogTolerance() external view returns (uint64);
112
+
113
+ /// @notice Returns the surplus of funds for L1 batch posting payments (may be negative).
114
+ function getL1PricingSurplus() external view returns (int256);
115
+
116
+ /// @notice Returns the base charge (in L1 gas) attributed to each data batch in the calldata pricer
117
+ function getPerBatchGasCharge() external view returns (int64);
118
+
119
+ /// @notice Returns the cost amortization cap in basis points
120
+ function getAmortizedCostCapBips() external view returns (uint64);
121
+
122
+ /// @notice Returns the available funds from L1 fees
123
+ function getL1FeesAvailable() external view returns (uint256);
112
124
  }
@@ -48,9 +48,15 @@ interface ArbOwner {
48
48
  /// @notice Get the network fee collector
49
49
  function getNetworkFeeAccount() external view returns (address);
50
50
 
51
+ /// @notice Get the infrastructure fee collector
52
+ function getInfraFeeAccount() external view returns (address);
53
+
51
54
  /// @notice Set the network fee collector
52
55
  function setNetworkFeeAccount(address newNetworkFeeAccount) external;
53
56
 
57
+ /// @notice Set the infrastructure fee collector
58
+ function setInfraFeeAccount(address newInfraFeeAccount) external;
59
+
54
60
  /// @notice Upgrades ArbOS to the requested version at the requested timestamp
55
61
  function scheduleArbOSUpgrade(uint64 newVersion, uint64 timestamp) external;
56
62
 
@@ -66,6 +72,18 @@ interface ArbOwner {
66
72
  /// @notice Sets reward amount for L1 price adjustment algorithm, in wei per unit
67
73
  function setL1PricingRewardRate(uint64 weiPerUnit) external;
68
74
 
75
+ /// @notice Set how much ArbOS charges per L1 gas spent on transaction data.
76
+ function setL1PricePerUnit(uint256 pricePerUnit) external;
77
+
78
+ /// @notice Sets the base charge (in L1 gas) attributed to each data batch in the calldata pricer
79
+ function setPerBatchGasCharge(int64 cost) external;
80
+
81
+ /// @notice Sets the cost amortization cap in basis points
82
+ function setAmortizedCostCapBips(uint64 cap) external;
83
+
84
+ /// @notice Releases surplus funds from L1PricerFundsPoolAddress for use
85
+ function releaseL1PricerSurplusFunds(uint256 maxWeiToRelease) external returns (uint256);
86
+
69
87
  // Emitted when a successful call is made to this precompile
70
88
  event OwnerActs(bytes4 indexed method, address indexed owner, bytes data);
71
89
  }
@@ -15,4 +15,7 @@ interface ArbOwnerPublic {
15
15
 
16
16
  /// @notice Gets the network fee collector
17
17
  function getNetworkFeeAccount() external view returns (address);
18
+
19
+ /// @notice Get the infrastructure fee collector
20
+ function getInfraFeeAccount() external view returns (address);
18
21
  }
@@ -36,13 +36,14 @@ interface ArbSys {
36
36
 
37
37
  /**
38
38
  * @notice Returns 0 since Nitro has no concept of storage gas
39
- * @return int 0
39
+ * @return uint 0
40
40
  */
41
41
  function getStorageGasAvailable() external view returns (uint256);
42
42
 
43
43
  /**
44
- * @notice check if current call is coming from l1
45
- * @return true if the caller of this was called directly from L1
44
+ * @notice (deprecated) check if current call is top level (meaning it was triggered by an EoA or a L1 contract)
45
+ * @dev this call has been deprecated and may be removed in a future release
46
+ * @return true if current execution frame is not a call by another L2 contract
46
47
  */
47
48
  function isTopLevelCall() external view returns (bool);
48
49
 
@@ -79,6 +80,8 @@ interface ArbSys {
79
80
 
80
81
  /**
81
82
  * @notice Send a transaction to L1
83
+ * @dev it is not possible to execute on the L1 any L2-to-L1 transaction which contains data
84
+ * to a contract address without any code (as enforced by the Bridge contract).
82
85
  * @param destination recipient address on L1
83
86
  * @param data (optional) calldata for L1 contract call
84
87
  * @return a unique identifier for this L2-to-L1 transaction.
@@ -134,7 +137,7 @@ interface ArbSys {
134
137
  );
135
138
 
136
139
  /**
137
- * @notice logs a merkle branch for proof sythesis
140
+ * @notice logs a merkle branch for proof synthesis
138
141
  * @param reserved an index meant only to align the 4th index with L2ToL1Transaction's 4th event
139
142
  * @param hash the merkle hash
140
143
  * @param position = (level << 192) + leaf
@@ -77,6 +77,8 @@ interface IRollupCore {
77
77
 
78
78
  function isValidator(address) external view returns (bool);
79
79
 
80
+ function validatorWhitelistDisabled() external view returns (bool);
81
+
80
82
  /**
81
83
  * @notice Get the Node for the given index.
82
84
  */
@@ -15,6 +15,10 @@ interface IRollupUserAbs is IRollupCore, IOwnable {
15
15
  /// this allows the admin logic to ensure consistency on parameters.
16
16
  function initialize(address stakeToken) external view;
17
17
 
18
+ function removeWhitelistAfterFork() external;
19
+
20
+ function removeWhitelistAfterValidatorAfk() external;
21
+
18
22
  function isERC20Enabled() external view returns (bool);
19
23
 
20
24
  function rejectNextNode(address stakerAddress) external;
@@ -215,4 +219,10 @@ interface IRollupAdmin {
215
219
  * @param _sequencerInbox new address of sequencer inbox
216
220
  */
217
221
  function setSequencerInbox(address _sequencerInbox) external;
222
+
223
+ /**
224
+ * @notice set the validatorWhitelistDisabled flag
225
+ * @param _validatorWhitelistDisabled new value of validatorWhitelistDisabled, i.e. true = disabled
226
+ */
227
+ function setValidatorWhitelistDisabled(bool _validatorWhitelistDisabled) external;
218
228
  }
@@ -9,12 +9,12 @@ import "./RollupCore.sol";
9
9
  import "../bridge/IOutbox.sol";
10
10
  import "../bridge/ISequencerInbox.sol";
11
11
  import "../challenge/IChallengeManager.sol";
12
- import "../libraries/SecondaryLogicUUPSUpgradeable.sol";
12
+ import "../libraries/DoubleLogicUUPSUpgradeable.sol";
13
13
  import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
14
14
 
15
15
  import {NO_CHAL_INDEX} from "../libraries/Constants.sol";
16
16
 
17
- contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgradeable {
17
+ contract RollupAdminLogic is RollupCore, IRollupAdmin, DoubleLogicUUPSUpgradeable {
18
18
  function initialize(Config calldata config, ContractDependencies calldata connectedContracts)
19
19
  external
20
20
  override
@@ -37,7 +37,14 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgrade
37
37
  );
38
38
 
39
39
  connectedContracts.rollupEventInbox.rollupInitialized(config.chainId);
40
- connectedContracts.sequencerInbox.addSequencerL2Batch(0, "", 1, IGasRefunder(address(0)));
40
+ connectedContracts.sequencerInbox.addSequencerL2Batch(
41
+ 0,
42
+ "",
43
+ 1,
44
+ IGasRefunder(address(0)),
45
+ 0,
46
+ 1
47
+ );
41
48
 
42
49
  validatorUtils = connectedContracts.validatorUtils;
43
50
  validatorWalletCreator = connectedContracts.validatorWalletCreator;
@@ -121,6 +128,9 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgrade
121
128
  /**
122
129
  * @notice Pause interaction with the rollup contract.
123
130
  * The time spent paused is not incremented in the rollup's timing for node validation.
131
+ * @dev this function may be frontrun by a validator (ie to create a node before the system is paused).
132
+ * The pause should be called atomically with required checks to be sure the system is paused in a consistent state.
133
+ * The RollupAdmin may execute a check against the Rollup's latest node num or the ChallengeManager, then execute this function atomically with it.
124
134
  */
125
135
  function pause() external override {
126
136
  _pause();
@@ -153,6 +163,7 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgrade
153
163
  * @param _val value to set in the whitelist for corresponding address
154
164
  */
155
165
  function setValidator(address[] calldata _validator, bool[] calldata _val) external override {
166
+ require(_validator.length > 0, "EMPTY_ARRAY");
156
167
  require(_validator.length == _val.length, "WRONG_LENGTH");
157
168
 
158
169
  for (uint256 i = 0; i < _validator.length; i++) {
@@ -185,6 +196,7 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgrade
185
196
  * @param newConfirmPeriod new number of blocks
186
197
  */
187
198
  function setConfirmPeriodBlocks(uint64 newConfirmPeriod) external override {
199
+ require(newConfirmPeriod > 0, "INVALID_CONFIRM_PERIOD");
188
200
  confirmPeriodBlocks = newConfirmPeriod;
189
201
  emit OwnerFunctionCalled(9);
190
202
  }
@@ -247,6 +259,7 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgrade
247
259
  override
248
260
  whenPaused
249
261
  {
262
+ require(stakerA.length > 0, "EMPTY_ARRAY");
250
263
  require(stakerA.length == stakerB.length, "WRONG_LENGTH");
251
264
  for (uint256 i = 0; i < stakerA.length; i++) {
252
265
  uint64 chall = inChallenge(stakerA[i], stakerB[i]);
@@ -260,7 +273,9 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgrade
260
273
  }
261
274
 
262
275
  function forceRefundStaker(address[] calldata staker) external override whenPaused {
276
+ require(staker.length > 0, "EMPTY_ARRAY");
263
277
  for (uint256 i = 0; i < staker.length; i++) {
278
+ require(_stakerMap[staker[i]].currentChallenge == NO_CHAL_INDEX, "STAKER_IN_CHALL");
264
279
  reduceStakeTo(staker[i], 0);
265
280
  turnIntoZombie(staker[i]);
266
281
  }
@@ -315,4 +330,55 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgrade
315
330
  bridge.setSequencerInbox(_sequencerInbox);
316
331
  emit OwnerFunctionCalled(27);
317
332
  }
333
+
334
+ /**
335
+ * @notice sets the rollup's inbox reference. Does not update the bridge's view.
336
+ * @param newInbox new address of inbox
337
+ */
338
+ function setInbox(IInbox newInbox) external {
339
+ inbox = newInbox;
340
+ emit OwnerFunctionCalled(28);
341
+ }
342
+
343
+ function createNitroMigrationGenesis(RollupLib.Assertion calldata assertion)
344
+ external
345
+ whenPaused
346
+ {
347
+ bytes32 expectedSendRoot = bytes32(0);
348
+ uint64 expectedInboxCount = 1;
349
+
350
+ require(latestNodeCreated() == 0, "NON_GENESIS_NODES_EXIST");
351
+ require(GlobalStateLib.isEmpty(assertion.beforeState.globalState), "NOT_EMPTY_BEFORE");
352
+ require(
353
+ assertion.beforeState.machineStatus == MachineStatus.FINISHED,
354
+ "BEFORE_MACHINE_NOT_FINISHED"
355
+ );
356
+ // accessors such as state.getSendRoot not available for calldata structs, only memory
357
+ require(
358
+ assertion.afterState.globalState.bytes32Vals[1] == expectedSendRoot,
359
+ "NOT_ZERO_SENDROOT"
360
+ );
361
+ require(
362
+ assertion.afterState.globalState.u64Vals[0] == expectedInboxCount,
363
+ "INBOX_NOT_AT_ONE"
364
+ );
365
+ require(assertion.afterState.globalState.u64Vals[1] == 0, "POSITION_IN_MESSAGE_NOT_ZERO");
366
+ require(
367
+ assertion.afterState.machineStatus == MachineStatus.FINISHED,
368
+ "AFTER_MACHINE_NOT_FINISHED"
369
+ );
370
+ bytes32 genesisBlockHash = assertion.afterState.globalState.bytes32Vals[0];
371
+ createNewNode(assertion, 0, expectedInboxCount, bytes32(0));
372
+ confirmNode(1, genesisBlockHash, expectedSendRoot);
373
+ emit OwnerFunctionCalled(29);
374
+ }
375
+
376
+ /**
377
+ * @notice set the validatorWhitelistDisabled flag
378
+ * @param _validatorWhitelistDisabled new value of validatorWhitelistDisabled, i.e. true = disabled
379
+ */
380
+ function setValidatorWhitelistDisabled(bool _validatorWhitelistDisabled) external {
381
+ validatorWhitelistDisabled = _validatorWhitelistDisabled;
382
+ emit OwnerFunctionCalled(30);
383
+ }
318
384
  }
@@ -74,6 +74,8 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
74
74
  // The node number of the initial node
75
75
  uint64 internal constant GENESIS_NODE = 0;
76
76
 
77
+ bool public validatorWhitelistDisabled;
78
+
77
79
  /**
78
80
  * @notice Get a storage reference to the Node for the given node index
79
81
  * @param nodeNum Index of the node
@@ -502,6 +504,7 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
502
504
  */
503
505
  function deleteStaker(address stakerAddress) private {
504
506
  Staker storage staker = _stakerMap[stakerAddress];
507
+ require(staker.isStaked, "NOT_STAKED");
505
508
  uint64 stakerIndex = staker.index;
506
509
  _stakerList[stakerIndex] = _stakerList[_stakerList.length - 1];
507
510
  _stakerMap[_stakerList[stakerIndex]].index = stakerIndex;
@@ -552,7 +555,7 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
552
555
  if (afterInboxCount == prevInboxPosition) {
553
556
  require(
554
557
  assertion.afterState.globalState.getPositionInMessage() >=
555
- assertion.afterState.globalState.getPositionInMessage(),
558
+ assertion.beforeState.globalState.getPositionInMessage(),
556
559
  "INBOX_POS_IN_MSG_BACKWARDS"
557
560
  );
558
561
  }
@@ -592,7 +595,10 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
592
595
  memoryFrame.sequencerBatchAcc,
593
596
  wasmModuleRoot
594
597
  );
595
- require(newNodeHash == expectedNodeHash, "UNEXPECTED_NODE_HASH");
598
+ require(
599
+ newNodeHash == expectedNodeHash || expectedNodeHash == bytes32(0),
600
+ "UNEXPECTED_NODE_HASH"
601
+ );
596
602
 
597
603
  memoryFrame.node = NodeLib.createNode(
598
604
  RollupLib.stateHash(assertion.afterState, memoryFrame.currentInboxSize),