@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.
- package/package.json +13 -2
- package/src/bridge/Bridge.sol +49 -29
- package/src/bridge/IBridge.sol +58 -45
- package/src/bridge/IDelayedMessageProvider.sol +2 -1
- package/src/bridge/IInbox.sol +133 -50
- package/src/bridge/IOutbox.sol +95 -27
- package/src/bridge/IOwnable.sol +2 -1
- package/src/bridge/ISequencerInbox.sol +79 -31
- package/src/bridge/Inbox.sol +171 -108
- package/src/bridge/Outbox.sol +26 -41
- package/src/bridge/SequencerInbox.sol +152 -62
- package/src/challenge/ChallengeManager.sol +0 -9
- package/src/challenge/IChallengeManager.sol +0 -2
- package/src/libraries/AdminFallbackProxy.sol +4 -4
- package/src/libraries/Constants.sol +3 -0
- package/src/libraries/{SecondaryLogicUUPSUpgradeable.sol → DoubleLogicUUPSUpgradeable.sol} +2 -1
- package/src/libraries/Error.sol +119 -0
- package/src/libraries/IGasRefunder.sol +13 -6
- package/src/libraries/MerkleLib.sol +5 -3
- package/src/mocks/BridgeStub.sol +22 -1
- package/src/mocks/BridgeUnproxied.sol +17 -0
- package/src/mocks/InboxStub.sol +49 -2
- package/src/mocks/SequencerInboxStub.sol +13 -3
- package/src/mocks/Simple.sol +69 -0
- package/src/node-interface/NodeInterface.sol +69 -7
- package/src/precompiles/ArbGasInfo.sol +16 -4
- package/src/precompiles/ArbOwner.sol +18 -0
- package/src/precompiles/ArbOwnerPublic.sol +3 -0
- package/src/precompiles/ArbSys.sol +7 -4
- package/src/rollup/IRollupCore.sol +2 -0
- package/src/rollup/IRollupLogic.sol +10 -0
- package/src/rollup/RollupAdminLogic.sol +69 -3
- package/src/rollup/RollupCore.sol +8 -2
- package/src/rollup/RollupCreator.sol +3 -3
- package/src/rollup/RollupEventInbox.sol +3 -6
- package/src/rollup/RollupLib.sol +1 -0
- package/src/{libraries/ArbitrumProxy.sol → rollup/RollupProxy.sol} +3 -3
- package/src/rollup/RollupUserLogic.sol +47 -10
- package/src/state/GlobalState.sol +7 -0
- package/src/test-helpers/BridgeTester.sol +17 -1
- package/src/test-helpers/InterfaceCompatibilityTester.sol +11 -0
- package/src/test-helpers/OutboxWithoutOptTester.sol +33 -7
@@ -10,7 +10,7 @@ import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
|
|
10
10
|
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
11
11
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
12
12
|
|
13
|
-
import "
|
13
|
+
import "./RollupProxy.sol";
|
14
14
|
|
15
15
|
contract RollupCreator is Ownable {
|
16
16
|
event RollupCreated(
|
@@ -59,7 +59,7 @@ contract RollupCreator is Ownable {
|
|
59
59
|
IInbox inbox;
|
60
60
|
IRollupEventInbox rollupEventInbox;
|
61
61
|
IOutbox outbox;
|
62
|
-
|
62
|
+
RollupProxy rollup;
|
63
63
|
}
|
64
64
|
|
65
65
|
// After this setup:
|
@@ -104,7 +104,7 @@ contract RollupCreator is Ownable {
|
|
104
104
|
osp
|
105
105
|
);
|
106
106
|
|
107
|
-
frame.rollup = new
|
107
|
+
frame.rollup = new RollupProxy(
|
108
108
|
config,
|
109
109
|
ContractDependencies({
|
110
110
|
bridge: frame.bridge,
|
@@ -9,16 +9,12 @@ import "../bridge/IBridge.sol";
|
|
9
9
|
import "../bridge/IDelayedMessageProvider.sol";
|
10
10
|
import "../libraries/DelegateCallAware.sol";
|
11
11
|
import {INITIALIZATION_MSG_TYPE} from "../libraries/MessageTypes.sol";
|
12
|
+
import {AlreadyInit, HadZeroInit} from "../libraries/Error.sol";
|
12
13
|
|
13
14
|
/**
|
14
15
|
* @title The inbox for rollup protocol events
|
15
16
|
*/
|
16
17
|
contract RollupEventInbox is IRollupEventInbox, IDelayedMessageProvider, DelegateCallAware {
|
17
|
-
uint8 internal constant CREATE_NODE_EVENT = 0;
|
18
|
-
uint8 internal constant CONFIRM_NODE_EVENT = 1;
|
19
|
-
uint8 internal constant REJECT_NODE_EVENT = 2;
|
20
|
-
uint8 internal constant STAKE_CREATED_EVENT = 3;
|
21
|
-
|
22
18
|
IBridge public override bridge;
|
23
19
|
address public override rollup;
|
24
20
|
|
@@ -28,7 +24,8 @@ contract RollupEventInbox is IRollupEventInbox, IDelayedMessageProvider, Delegat
|
|
28
24
|
}
|
29
25
|
|
30
26
|
function initialize(IBridge _bridge) external override onlyDelegated {
|
31
|
-
|
27
|
+
if (address(bridge) != address(0)) revert AlreadyInit();
|
28
|
+
if (address(_bridge) == address(0)) revert HadZeroInit();
|
32
29
|
bridge = _bridge;
|
33
30
|
rollup = address(_bridge.rollup());
|
34
31
|
}
|
package/src/rollup/RollupLib.sol
CHANGED
@@ -4,10 +4,10 @@
|
|
4
4
|
|
5
5
|
pragma solidity ^0.8.0;
|
6
6
|
|
7
|
-
import "
|
8
|
-
import "
|
7
|
+
import "../libraries/AdminFallbackProxy.sol";
|
8
|
+
import "./IRollupLogic.sol";
|
9
9
|
|
10
|
-
contract
|
10
|
+
contract RollupProxy is AdminFallbackProxy {
|
11
11
|
constructor(Config memory config, ContractDependencies memory connectedContracts)
|
12
12
|
AdminFallbackProxy(
|
13
13
|
address(connectedContracts.rollupAdminLogic),
|
@@ -9,6 +9,7 @@ import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
|
|
9
9
|
import {IRollupUser} from "./IRollupLogic.sol";
|
10
10
|
import "../libraries/UUPSNotUpgradeable.sol";
|
11
11
|
import "./RollupCore.sol";
|
12
|
+
import {ETH_POS_BLOCK_TIME} from "../libraries/Constants.sol";
|
12
13
|
|
13
14
|
abstract contract AbsRollupUserLogic is
|
14
15
|
RollupCore,
|
@@ -20,10 +21,43 @@ abstract contract AbsRollupUserLogic is
|
|
20
21
|
using GlobalStateLib for GlobalState;
|
21
22
|
|
22
23
|
modifier onlyValidator() {
|
23
|
-
require(isValidator[msg.sender], "NOT_VALIDATOR");
|
24
|
+
require(isValidator[msg.sender] || validatorWhitelistDisabled, "NOT_VALIDATOR");
|
24
25
|
_;
|
25
26
|
}
|
26
27
|
|
28
|
+
uint256 internal immutable deployTimeChainId = block.chainid;
|
29
|
+
|
30
|
+
function _chainIdChanged() internal view returns (bool) {
|
31
|
+
return deployTimeChainId != block.chainid;
|
32
|
+
}
|
33
|
+
|
34
|
+
/**
|
35
|
+
* @notice Extra number of blocks the validator can remain inactive before considered inactive
|
36
|
+
* This is 7 days assuming a 13.2 seconds block time
|
37
|
+
*/
|
38
|
+
uint256 public constant VALIDATOR_AFK_BLOCKS = 45818;
|
39
|
+
|
40
|
+
function _validatorIsAfk() internal view returns (bool) {
|
41
|
+
Node memory latestNode = getNodeStorage(latestNodeCreated());
|
42
|
+
if (latestNode.createdAtBlock == 0) return false;
|
43
|
+
if (latestNode.createdAtBlock + confirmPeriodBlocks + VALIDATOR_AFK_BLOCKS < block.number) {
|
44
|
+
return true;
|
45
|
+
}
|
46
|
+
return false;
|
47
|
+
}
|
48
|
+
|
49
|
+
function removeWhitelistAfterFork() external {
|
50
|
+
require(!validatorWhitelistDisabled, "WHITELIST_DISABLED");
|
51
|
+
require(_chainIdChanged(), "CHAIN_ID_NOT_CHANGED");
|
52
|
+
validatorWhitelistDisabled = true;
|
53
|
+
}
|
54
|
+
|
55
|
+
function removeWhitelistAfterValidatorAfk() external {
|
56
|
+
require(!validatorWhitelistDisabled, "WHITELIST_DISABLED");
|
57
|
+
require(_validatorIsAfk(), "VALIDATOR_NOT_AFK");
|
58
|
+
validatorWhitelistDisabled = true;
|
59
|
+
}
|
60
|
+
|
27
61
|
function isERC20Enabled() public view override returns (bool) {
|
28
62
|
return stakeToken != address(0);
|
29
63
|
}
|
@@ -239,7 +273,7 @@ abstract contract AbsRollupUserLogic is
|
|
239
273
|
* @param globalStates The before and after global state for the first assertion
|
240
274
|
* @param numBlocks The number of L2 blocks contained in the first assertion
|
241
275
|
* @param secondExecutionHash The execution hash of the second assertion
|
242
|
-
* @param
|
276
|
+
* @param proposedBlocks L1 block numbers that the two nodes were proposed at
|
243
277
|
* @param wasmModuleRoots The wasm module roots at the time of the creation of each assertion
|
244
278
|
*/
|
245
279
|
function createChallenge(
|
@@ -249,7 +283,7 @@ abstract contract AbsRollupUserLogic is
|
|
249
283
|
GlobalState[2] calldata globalStates,
|
250
284
|
uint64 numBlocks,
|
251
285
|
bytes32 secondExecutionHash,
|
252
|
-
uint256[2] calldata
|
286
|
+
uint256[2] calldata proposedBlocks,
|
253
287
|
bytes32[2] calldata wasmModuleRoots
|
254
288
|
) external onlyValidator whenNotPaused {
|
255
289
|
require(nodeNums[0] < nodeNums[1], "WRONG_ORDER");
|
@@ -274,7 +308,7 @@ abstract contract AbsRollupUserLogic is
|
|
274
308
|
node1.challengeHash ==
|
275
309
|
RollupLib.challengeRootHash(
|
276
310
|
RollupLib.executionHash(machineStatuses, globalStates, numBlocks),
|
277
|
-
|
311
|
+
proposedBlocks[0],
|
278
312
|
wasmModuleRoots[0]
|
279
313
|
),
|
280
314
|
"CHAL_HASH1"
|
@@ -284,18 +318,18 @@ abstract contract AbsRollupUserLogic is
|
|
284
318
|
node2.challengeHash ==
|
285
319
|
RollupLib.challengeRootHash(
|
286
320
|
secondExecutionHash,
|
287
|
-
|
321
|
+
proposedBlocks[1],
|
288
322
|
wasmModuleRoots[1]
|
289
323
|
),
|
290
324
|
"CHAL_HASH2"
|
291
325
|
);
|
292
326
|
|
293
327
|
// Calculate upper limit for allowed node proposal time:
|
294
|
-
uint256
|
328
|
+
uint256 commonEndBlock = getNodeStorage(node1.prevNum).firstChildBlock +
|
295
329
|
// Dispute start: dispute timer for a node starts when its first child is created
|
296
|
-
(node1.deadlineBlock -
|
330
|
+
(node1.deadlineBlock - proposedBlocks[0]) +
|
297
331
|
extraChallengeTimeBlocks; // add dispute window to dispute start time
|
298
|
-
if (
|
332
|
+
if (commonEndBlock < proposedBlocks[1]) {
|
299
333
|
// The 2nd node was created too late; loses challenge automatically.
|
300
334
|
completeChallengeImpl(stakers[0], stakers[1]);
|
301
335
|
return;
|
@@ -307,8 +341,9 @@ abstract contract AbsRollupUserLogic is
|
|
307
341
|
globalStates,
|
308
342
|
numBlocks,
|
309
343
|
wasmModuleRoots,
|
310
|
-
|
311
|
-
|
344
|
+
// convert from block counts to real second based timestamps
|
345
|
+
(commonEndBlock - proposedBlocks[0]) * ETH_POS_BLOCK_TIME,
|
346
|
+
(commonEndBlock - proposedBlocks[1]) * ETH_POS_BLOCK_TIME
|
312
347
|
); // trusted external call
|
313
348
|
|
314
349
|
challengeStarted(stakers[0], stakers[1], challengeIndex);
|
@@ -366,6 +401,8 @@ abstract contract AbsRollupUserLogic is
|
|
366
401
|
uint256 amountWon = remainingLoserStake / 2;
|
367
402
|
increaseStakeBy(winningStaker, amountWon);
|
368
403
|
remainingLoserStake -= amountWon;
|
404
|
+
// We deliberately leave loser in challenge state to prevent them from
|
405
|
+
// doing certain thing that are allowed only to parties not in a challenge
|
369
406
|
clearChallenge(winningStaker);
|
370
407
|
// Credit the other half to the loserStakeEscrow address
|
371
408
|
increaseWithdrawableFunds(loserStakeEscrow, remainingLoserStake);
|
@@ -41,4 +41,11 @@ library GlobalStateLib {
|
|
41
41
|
function getPositionInMessage(GlobalState memory state) internal pure returns (uint64) {
|
42
42
|
return state.u64Vals[1];
|
43
43
|
}
|
44
|
+
|
45
|
+
function isEmpty(GlobalState calldata state) internal pure returns (bool) {
|
46
|
+
return (state.bytes32Vals[0] == bytes32(0) &&
|
47
|
+
state.bytes32Vals[1] == bytes32(0) &&
|
48
|
+
state.u64Vals[0] == 0 &&
|
49
|
+
state.u64Vals[1] == 0);
|
50
|
+
}
|
44
51
|
}
|
@@ -7,6 +7,14 @@ pragma solidity ^0.8.4;
|
|
7
7
|
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
8
8
|
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
|
9
9
|
|
10
|
+
import {
|
11
|
+
NotContract,
|
12
|
+
NotRollupOrOwner,
|
13
|
+
NotDelayedInbox,
|
14
|
+
NotSequencerInbox,
|
15
|
+
NotOutbox,
|
16
|
+
InvalidOutboxSet
|
17
|
+
} from "../libraries/Error.sol";
|
10
18
|
import "../bridge/IBridge.sol";
|
11
19
|
import "../bridge/Messages.sol";
|
12
20
|
import "../libraries/DelegateCallAware.sol";
|
@@ -56,6 +64,7 @@ contract BridgeTester is Initializable, DelegateCallAware, IBridge {
|
|
56
64
|
bytes32[] public override delayedInboxAccs;
|
57
65
|
|
58
66
|
bytes32[] public override sequencerInboxAccs;
|
67
|
+
uint256 public override sequencerReportedSubMessageCount;
|
59
68
|
|
60
69
|
address private constant EMPTY_ACTIVEOUTBOX = address(type(uint160).max);
|
61
70
|
|
@@ -77,7 +86,12 @@ contract BridgeTester is Initializable, DelegateCallAware, IBridge {
|
|
77
86
|
return allowedOutboxesMap[outbox].allowed;
|
78
87
|
}
|
79
88
|
|
80
|
-
function enqueueSequencerMessage(
|
89
|
+
function enqueueSequencerMessage(
|
90
|
+
bytes32 dataHash,
|
91
|
+
uint256 afterDelayedMessagesRead,
|
92
|
+
uint256 prevMessageCount,
|
93
|
+
uint256 newMessageCount
|
94
|
+
)
|
81
95
|
external
|
82
96
|
returns (
|
83
97
|
uint256 seqMessageIndex,
|
@@ -220,4 +234,6 @@ contract BridgeTester is Initializable, DelegateCallAware, IBridge {
|
|
220
234
|
}
|
221
235
|
|
222
236
|
receive() external payable {}
|
237
|
+
|
238
|
+
function acceptFundsFromOldBridge() external payable {}
|
223
239
|
}
|
@@ -0,0 +1,11 @@
|
|
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
|
+
// solhint-disable-next-line compiler-version
|
6
|
+
pragma solidity >=0.6.9 <0.9.0;
|
7
|
+
|
8
|
+
import "../bridge/IBridge.sol";
|
9
|
+
import "../bridge/IOutbox.sol";
|
10
|
+
import "../bridge/IInbox.sol";
|
11
|
+
import "../bridge/ISequencerInbox.sol";
|
@@ -4,6 +4,15 @@
|
|
4
4
|
|
5
5
|
pragma solidity ^0.8.4;
|
6
6
|
|
7
|
+
import {
|
8
|
+
AlreadyInit,
|
9
|
+
NotRollup,
|
10
|
+
ProofTooLong,
|
11
|
+
PathNotMinimal,
|
12
|
+
UnknownRoot,
|
13
|
+
AlreadySpent,
|
14
|
+
BridgeCallFailed
|
15
|
+
} from "../libraries/Error.sol";
|
7
16
|
import "../bridge/IBridge.sol";
|
8
17
|
import "../bridge/IOutbox.sol";
|
9
18
|
import "../libraries/MerkleLib.sol";
|
@@ -13,7 +22,11 @@ contract OutboxWithoutOptTester is DelegateCallAware, IOutbox {
|
|
13
22
|
address public rollup; // the rollup contract
|
14
23
|
IBridge public bridge; // the bridge contract
|
15
24
|
|
16
|
-
|
25
|
+
function spent(uint256) external pure override returns (bytes32) {
|
26
|
+
revert("NOT_IMPLEMETED");
|
27
|
+
}
|
28
|
+
|
29
|
+
mapping(uint256 => bool) public isSpent; // maps leaf number => if spent
|
17
30
|
mapping(bytes32 => bytes32) public roots; // maps root hashes => L2 block hash
|
18
31
|
|
19
32
|
struct L2ToL1Context {
|
@@ -61,7 +74,7 @@ contract OutboxWithoutOptTester is DelegateCallAware, IOutbox {
|
|
61
74
|
}
|
62
75
|
|
63
76
|
// @deprecated batch number is now always 0
|
64
|
-
function l2ToL1BatchNum() external pure
|
77
|
+
function l2ToL1BatchNum() external pure returns (uint256) {
|
65
78
|
return 0;
|
66
79
|
}
|
67
80
|
|
@@ -93,7 +106,7 @@ contract OutboxWithoutOptTester is DelegateCallAware, IOutbox {
|
|
93
106
|
uint256 l2Timestamp,
|
94
107
|
uint256 value,
|
95
108
|
bytes calldata data
|
96
|
-
) external virtual {
|
109
|
+
) external virtual override {
|
97
110
|
bytes32 outputId;
|
98
111
|
{
|
99
112
|
bytes32 userTx = calculateItemHash(
|
@@ -128,6 +141,19 @@ contract OutboxWithoutOptTester is DelegateCallAware, IOutbox {
|
|
128
141
|
context = prevContext;
|
129
142
|
}
|
130
143
|
|
144
|
+
function executeTransactionSimulation(
|
145
|
+
uint256,
|
146
|
+
address,
|
147
|
+
address,
|
148
|
+
uint256,
|
149
|
+
uint256,
|
150
|
+
uint256,
|
151
|
+
uint256,
|
152
|
+
bytes calldata
|
153
|
+
) external pure override {
|
154
|
+
revert("Not implemented");
|
155
|
+
}
|
156
|
+
|
131
157
|
function recordOutputAsSpent(
|
132
158
|
bytes32[] memory proof,
|
133
159
|
uint256 index,
|
@@ -140,8 +166,8 @@ contract OutboxWithoutOptTester is DelegateCallAware, IOutbox {
|
|
140
166
|
bytes32 calcRoot = calculateMerkleRoot(proof, index, item);
|
141
167
|
if (roots[calcRoot] == bytes32(0)) revert UnknownRoot(calcRoot);
|
142
168
|
|
143
|
-
if (
|
144
|
-
|
169
|
+
if (isSpent[index]) revert AlreadySpent(index);
|
170
|
+
isSpent[index] = true;
|
145
171
|
|
146
172
|
return bytes32(index);
|
147
173
|
}
|
@@ -173,7 +199,7 @@ contract OutboxWithoutOptTester is DelegateCallAware, IOutbox {
|
|
173
199
|
uint256 l2Timestamp,
|
174
200
|
uint256 value,
|
175
201
|
bytes calldata data
|
176
|
-
) public pure returns (bytes32) {
|
202
|
+
) public pure override returns (bytes32) {
|
177
203
|
return
|
178
204
|
keccak256(abi.encodePacked(l2Sender, to, l2Block, l1Block, l2Timestamp, value, data));
|
179
205
|
}
|
@@ -182,7 +208,7 @@ contract OutboxWithoutOptTester is DelegateCallAware, IOutbox {
|
|
182
208
|
bytes32[] memory proof,
|
183
209
|
uint256 path,
|
184
210
|
bytes32 item
|
185
|
-
) public pure returns (bytes32) {
|
211
|
+
) public pure override returns (bytes32) {
|
186
212
|
return MerkleLib.calculateRoot(proof, path, keccak256(abi.encodePacked(item)));
|
187
213
|
}
|
188
214
|
}
|