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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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),