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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. package/package.json +2 -1
  2. package/src/bridge/Bridge.sol +127 -32
  3. package/src/bridge/IBridge.sol +40 -6
  4. package/src/bridge/{IMessageProvider.sol → IDelayedMessageProvider.sol} +4 -1
  5. package/src/bridge/IInbox.sol +23 -2
  6. package/src/bridge/IOwnable.sol +9 -0
  7. package/src/bridge/ISequencerInbox.sol +36 -9
  8. package/src/bridge/Inbox.sol +131 -34
  9. package/src/bridge/Outbox.sol +134 -31
  10. package/src/bridge/SequencerInbox.sol +159 -60
  11. package/src/challenge/ChallengeLib.sol +0 -2
  12. package/src/challenge/ChallengeManager.sol +4 -8
  13. package/src/challenge/IChallengeManager.sol +1 -1
  14. package/src/libraries/Error.sol +6 -0
  15. package/src/libraries/IGasRefunder.sol +13 -13
  16. package/src/libraries/MerkleLib.sol +11 -2
  17. package/src/libraries/MessageTypes.sol +1 -0
  18. package/src/mocks/BridgeStub.sol +67 -21
  19. package/src/mocks/SequencerInboxStub.sol +10 -8
  20. package/src/mocks/Simple.sol +8 -0
  21. package/src/node-interface/NodeInterface.sol +32 -5
  22. package/src/osp/IOneStepProver.sol +1 -2
  23. package/src/osp/OneStepProver0.sol +1 -87
  24. package/src/osp/OneStepProverHostIo.sol +5 -6
  25. package/src/osp/OneStepProverMath.sol +37 -27
  26. package/src/osp/OneStepProverMemory.sol +3 -4
  27. package/src/precompiles/ArbAggregator.sol +23 -33
  28. package/src/precompiles/ArbBLS.sol +1 -43
  29. package/src/precompiles/ArbGasInfo.sol +9 -18
  30. package/src/precompiles/ArbOwner.sol +18 -15
  31. package/src/precompiles/ArbRetryableTx.sol +13 -1
  32. package/src/precompiles/ArbSys.sol +15 -2
  33. package/src/precompiles/ArbosActs.sol +9 -2
  34. package/src/rollup/BridgeCreator.sol +23 -28
  35. package/src/rollup/IRollupCore.sol +3 -3
  36. package/src/rollup/{IRollupEventBridge.sol → IRollupEventInbox.sol} +2 -2
  37. package/src/rollup/IRollupLogic.sol +21 -18
  38. package/src/rollup/RollupAdminLogic.sol +30 -34
  39. package/src/rollup/RollupCore.sol +15 -7
  40. package/src/rollup/RollupCreator.sol +21 -11
  41. package/src/rollup/{RollupEventBridge.sol → RollupEventInbox.sol} +10 -10
  42. package/src/rollup/RollupLib.sol +20 -5
  43. package/src/rollup/RollupUserLogic.sol +10 -18
  44. package/src/rollup/ValidatorWallet.sol +125 -8
  45. package/src/rollup/ValidatorWalletCreator.sol +11 -6
  46. package/src/state/Deserialize.sol +3 -22
  47. package/src/state/Instructions.sol +2 -10
  48. package/src/state/Machine.sol +0 -4
  49. package/src/state/ModuleMemory.sol +2 -1
  50. package/src/state/Value.sol +2 -3
  51. package/src/test-helpers/BridgeTester.sol +223 -0
  52. package/src/test-helpers/OutboxWithoutOptTester.sol +188 -0
  53. package/src/test-helpers/RollupMock.sol +21 -0
  54. package/src/state/PcStack.sol +0 -32
@@ -0,0 +1,223 @@
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.4;
6
+
7
+ import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
8
+ import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
9
+
10
+ import "../bridge/IBridge.sol";
11
+ import "../bridge/Messages.sol";
12
+ import "../libraries/DelegateCallAware.sol";
13
+
14
+ /**
15
+ * @title Staging ground for incoming and outgoing messages
16
+ * @notice Holds the inbox accumulator for delayed messages, and is the ETH escrow
17
+ * for value sent with these messages.
18
+ * Since the escrow is held here, this contract also contains a list of allowed
19
+ * outboxes that can make calls from here and withdraw this escrow.
20
+ */
21
+ contract BridgeTester is Initializable, DelegateCallAware, IBridge {
22
+ using AddressUpgradeable for address;
23
+
24
+ struct InOutInfo {
25
+ uint256 index;
26
+ bool allowed;
27
+ }
28
+
29
+ mapping(address => InOutInfo) private allowedInboxesMap;
30
+ mapping(address => InOutInfo) private allowedOutboxesMap;
31
+
32
+ address[] public allowedDelayedInboxList;
33
+ address[] public allowedOutboxList;
34
+
35
+ address private _activeOutbox;
36
+
37
+ IOwnable public rollup;
38
+ address public sequencerInbox;
39
+
40
+ modifier onlyRollupOrOwner() {
41
+ if (msg.sender != address(rollup)) {
42
+ address rollupOwner = rollup.owner();
43
+ if (msg.sender != rollupOwner) {
44
+ revert NotRollupOrOwner(msg.sender, address(rollup), rollupOwner);
45
+ }
46
+ }
47
+ _;
48
+ }
49
+
50
+ function setSequencerInbox(address _sequencerInbox) external override onlyRollupOrOwner {
51
+ sequencerInbox = _sequencerInbox;
52
+ emit SequencerInboxUpdated(_sequencerInbox);
53
+ }
54
+
55
+ /// @dev Accumulator for delayed inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
56
+ bytes32[] public override delayedInboxAccs;
57
+
58
+ bytes32[] public override sequencerInboxAccs;
59
+
60
+ address private constant EMPTY_ACTIVEOUTBOX = address(type(uint160).max);
61
+
62
+ function initialize(IOwnable rollup_) external initializer {
63
+ _activeOutbox = EMPTY_ACTIVEOUTBOX;
64
+ rollup = rollup_;
65
+ }
66
+
67
+ function activeOutbox() public view returns (address) {
68
+ if (_activeOutbox == EMPTY_ACTIVEOUTBOX) return address(uint160(0));
69
+ return _activeOutbox;
70
+ }
71
+
72
+ function allowedDelayedInboxes(address inbox) external view override returns (bool) {
73
+ return allowedInboxesMap[inbox].allowed;
74
+ }
75
+
76
+ function allowedOutboxes(address outbox) external view override returns (bool) {
77
+ return allowedOutboxesMap[outbox].allowed;
78
+ }
79
+
80
+ function enqueueSequencerMessage(bytes32 dataHash, uint256 afterDelayedMessagesRead)
81
+ external
82
+ returns (
83
+ uint256 seqMessageIndex,
84
+ bytes32 beforeAcc,
85
+ bytes32 delayedAcc,
86
+ bytes32 acc
87
+ )
88
+ {
89
+ // TODO: implement stub logic
90
+ }
91
+
92
+ function submitBatchSpendingReport(address batchPoster, bytes32 dataHash)
93
+ external
94
+ returns (uint256)
95
+ {
96
+ // TODO: implement stub
97
+ }
98
+
99
+ /**
100
+ * @dev Enqueue a message in the delayed inbox accumulator.
101
+ * These messages are later sequenced in the SequencerInbox, either by the sequencer as
102
+ * part of a normal batch, or by force inclusion.
103
+ */
104
+ function enqueueDelayedMessage(
105
+ uint8 kind,
106
+ address sender,
107
+ bytes32 messageDataHash
108
+ ) external payable override returns (uint256) {
109
+ if (!allowedInboxesMap[msg.sender].allowed) revert NotDelayedInbox(msg.sender);
110
+ return
111
+ addMessageToDelayedAccumulator(
112
+ kind,
113
+ sender,
114
+ uint64(block.number),
115
+ uint64(block.timestamp), // solhint-disable-line not-rely-on-time
116
+ block.basefee,
117
+ messageDataHash
118
+ );
119
+ }
120
+
121
+ function addMessageToDelayedAccumulator(
122
+ uint8 kind,
123
+ address sender,
124
+ uint64 blockNumber,
125
+ uint64 blockTimestamp,
126
+ uint256 baseFeeL1,
127
+ bytes32 messageDataHash
128
+ ) internal returns (uint256) {
129
+ uint256 count = delayedInboxAccs.length;
130
+ bytes32 messageHash = Messages.messageHash(
131
+ kind,
132
+ sender,
133
+ blockNumber,
134
+ blockTimestamp,
135
+ count,
136
+ baseFeeL1,
137
+ messageDataHash
138
+ );
139
+ bytes32 prevAcc = 0;
140
+ if (count > 0) {
141
+ prevAcc = delayedInboxAccs[count - 1];
142
+ }
143
+ delayedInboxAccs.push(Messages.accumulateInboxMessage(prevAcc, messageHash));
144
+ emit MessageDelivered(
145
+ count,
146
+ prevAcc,
147
+ msg.sender,
148
+ kind,
149
+ sender,
150
+ messageDataHash,
151
+ baseFeeL1,
152
+ blockTimestamp
153
+ );
154
+ return count;
155
+ }
156
+
157
+ function executeCall(
158
+ address to,
159
+ uint256 value,
160
+ bytes calldata data
161
+ ) external override returns (bool success, bytes memory returnData) {
162
+ if (!allowedOutboxesMap[msg.sender].allowed) revert NotOutbox(msg.sender);
163
+ if (data.length > 0 && !to.isContract()) revert NotContract(to);
164
+ address prevOutbox = _activeOutbox;
165
+ _activeOutbox = msg.sender;
166
+ // We set and reset active outbox around external call so activeOutbox remains valid during call
167
+
168
+ // We use a low level call here since we want to bubble up whether it succeeded or failed to the caller
169
+ // rather than reverting on failure as well as allow contract and non-contract calls
170
+ // solhint-disable-next-line avoid-low-level-calls
171
+ (success, returnData) = to.call{value: value}(data);
172
+ _activeOutbox = prevOutbox;
173
+ emit BridgeCallTriggered(msg.sender, to, value, data);
174
+ }
175
+
176
+ function setDelayedInbox(address inbox, bool enabled) external override onlyRollupOrOwner {
177
+ InOutInfo storage info = allowedInboxesMap[inbox];
178
+ bool alreadyEnabled = info.allowed;
179
+ emit InboxToggle(inbox, enabled);
180
+ if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) {
181
+ return;
182
+ }
183
+ if (enabled) {
184
+ allowedInboxesMap[inbox] = InOutInfo(allowedDelayedInboxList.length, true);
185
+ allowedDelayedInboxList.push(inbox);
186
+ } else {
187
+ allowedDelayedInboxList[info.index] = allowedDelayedInboxList[
188
+ allowedDelayedInboxList.length - 1
189
+ ];
190
+ allowedInboxesMap[allowedDelayedInboxList[info.index]].index = info.index;
191
+ allowedDelayedInboxList.pop();
192
+ delete allowedInboxesMap[inbox];
193
+ }
194
+ }
195
+
196
+ function setOutbox(address outbox, bool enabled) external override onlyRollupOrOwner {
197
+ InOutInfo storage info = allowedOutboxesMap[outbox];
198
+ bool alreadyEnabled = info.allowed;
199
+ emit OutboxToggle(outbox, enabled);
200
+ if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) {
201
+ return;
202
+ }
203
+ if (enabled) {
204
+ allowedOutboxesMap[outbox] = InOutInfo(allowedOutboxList.length, true);
205
+ allowedOutboxList.push(outbox);
206
+ } else {
207
+ allowedOutboxList[info.index] = allowedOutboxList[allowedOutboxList.length - 1];
208
+ allowedOutboxesMap[allowedOutboxList[info.index]].index = info.index;
209
+ allowedOutboxList.pop();
210
+ delete allowedOutboxesMap[outbox];
211
+ }
212
+ }
213
+
214
+ function delayedMessageCount() external view override returns (uint256) {
215
+ return delayedInboxAccs.length;
216
+ }
217
+
218
+ function sequencerMessageCount() external view override returns (uint256) {
219
+ return sequencerInboxAccs.length;
220
+ }
221
+
222
+ receive() external payable {}
223
+ }
@@ -0,0 +1,188 @@
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.4;
6
+
7
+ import "../bridge/IBridge.sol";
8
+ import "../bridge/IOutbox.sol";
9
+ import "../libraries/MerkleLib.sol";
10
+ import "../libraries/DelegateCallAware.sol";
11
+
12
+ contract OutboxWithoutOptTester is DelegateCallAware, IOutbox {
13
+ address public rollup; // the rollup contract
14
+ IBridge public bridge; // the bridge contract
15
+
16
+ mapping(uint256 => bool) public spent; // maps leaf number => if spent
17
+ mapping(bytes32 => bytes32) public roots; // maps root hashes => L2 block hash
18
+
19
+ struct L2ToL1Context {
20
+ uint128 l2Block;
21
+ uint128 l1Block;
22
+ uint128 timestamp;
23
+ bytes32 outputId;
24
+ address sender;
25
+ }
26
+ // Note, these variables are set and then wiped during a single transaction.
27
+ // Therefore their values don't need to be maintained, and their slots will
28
+ // be empty outside of transactions
29
+ L2ToL1Context internal context;
30
+ uint128 public constant OUTBOX_VERSION = 2;
31
+
32
+ function initialize(IBridge _bridge) external {
33
+ if (address(bridge) != address(0)) revert AlreadyInit();
34
+ bridge = _bridge;
35
+ rollup = address(_bridge.rollup());
36
+ }
37
+
38
+ function updateSendRoot(bytes32 root, bytes32 l2BlockHash) external override {
39
+ //if (msg.sender != rollup) revert NotRollup(msg.sender, rollup); //test only!!!
40
+ roots[root] = l2BlockHash;
41
+ emit SendRootUpdated(root, l2BlockHash);
42
+ }
43
+
44
+ /// @notice When l2ToL1Sender returns a nonzero address, the message was originated by an L2 account
45
+ /// When the return value is zero, that means this is a system message
46
+ /// @dev the l2ToL1Sender behaves as the tx.origin, the msg.sender should be validated to protect against reentrancies
47
+ function l2ToL1Sender() external view override returns (address) {
48
+ return context.sender;
49
+ }
50
+
51
+ function l2ToL1Block() external view override returns (uint256) {
52
+ return uint256(context.l2Block);
53
+ }
54
+
55
+ function l2ToL1EthBlock() external view override returns (uint256) {
56
+ return uint256(context.l1Block);
57
+ }
58
+
59
+ function l2ToL1Timestamp() external view override returns (uint256) {
60
+ return uint256(context.timestamp);
61
+ }
62
+
63
+ // @deprecated batch number is now always 0
64
+ function l2ToL1BatchNum() external pure override returns (uint256) {
65
+ return 0;
66
+ }
67
+
68
+ function l2ToL1OutputId() external view override returns (bytes32) {
69
+ return context.outputId;
70
+ }
71
+
72
+ /**
73
+ * @notice Executes a messages in an Outbox entry.
74
+ * @dev Reverts if dispute period hasn't expired, since the outbox entry
75
+ * is only created once the rollup confirms the respective assertion.
76
+ * @param proof Merkle proof of message inclusion in send root
77
+ * @param index Merkle path to message
78
+ * @param l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1)
79
+ * @param to destination address for L1 contract call
80
+ * @param l2Block l2 block number at which sendTxToL1 call was made
81
+ * @param l1Block l1 block number at which sendTxToL1 call was made
82
+ * @param l2Timestamp l2 Timestamp at which sendTxToL1 call was made
83
+ * @param value wei in L1 message
84
+ * @param data abi-encoded L1 message data
85
+ */
86
+ function executeTransaction(
87
+ bytes32[] calldata proof,
88
+ uint256 index,
89
+ address l2Sender,
90
+ address to,
91
+ uint256 l2Block,
92
+ uint256 l1Block,
93
+ uint256 l2Timestamp,
94
+ uint256 value,
95
+ bytes calldata data
96
+ ) external virtual {
97
+ bytes32 outputId;
98
+ {
99
+ bytes32 userTx = calculateItemHash(
100
+ l2Sender,
101
+ to,
102
+ l2Block,
103
+ l1Block,
104
+ l2Timestamp,
105
+ value,
106
+ data
107
+ );
108
+
109
+ outputId = recordOutputAsSpent(proof, index, userTx);
110
+ emit OutBoxTransactionExecuted(to, l2Sender, 0, index);
111
+ }
112
+
113
+ // we temporarily store the previous values so the outbox can naturally
114
+ // unwind itself when there are nested calls to `executeTransaction`
115
+ L2ToL1Context memory prevContext = context;
116
+
117
+ context = L2ToL1Context({
118
+ sender: l2Sender,
119
+ l2Block: uint128(l2Block),
120
+ l1Block: uint128(l1Block),
121
+ timestamp: uint128(l2Timestamp),
122
+ outputId: outputId
123
+ });
124
+
125
+ // set and reset vars around execution so they remain valid during call
126
+ executeBridgeCall(to, value, data);
127
+
128
+ context = prevContext;
129
+ }
130
+
131
+ function recordOutputAsSpent(
132
+ bytes32[] memory proof,
133
+ uint256 index,
134
+ bytes32 item
135
+ ) internal returns (bytes32) {
136
+ if (proof.length >= 256) revert ProofTooLong(proof.length);
137
+ if (index >= 2**proof.length) revert PathNotMinimal(index, 2**proof.length);
138
+
139
+ // Hash the leaf an extra time to prove it's a leaf
140
+ bytes32 calcRoot = calculateMerkleRoot(proof, index, item);
141
+ if (roots[calcRoot] == bytes32(0)) revert UnknownRoot(calcRoot);
142
+
143
+ if (spent[index]) revert AlreadySpent(index);
144
+ spent[index] = true;
145
+
146
+ return bytes32(index);
147
+ }
148
+
149
+ function executeBridgeCall(
150
+ address to,
151
+ uint256 value,
152
+ bytes memory data
153
+ ) internal {
154
+ (bool success, bytes memory returndata) = bridge.executeCall(to, value, data);
155
+ if (!success) {
156
+ if (returndata.length > 0) {
157
+ // solhint-disable-next-line no-inline-assembly
158
+ assembly {
159
+ let returndata_size := mload(returndata)
160
+ revert(add(32, returndata), returndata_size)
161
+ }
162
+ } else {
163
+ revert BridgeCallFailed();
164
+ }
165
+ }
166
+ }
167
+
168
+ function calculateItemHash(
169
+ address l2Sender,
170
+ address to,
171
+ uint256 l2Block,
172
+ uint256 l1Block,
173
+ uint256 l2Timestamp,
174
+ uint256 value,
175
+ bytes calldata data
176
+ ) public pure returns (bytes32) {
177
+ return
178
+ keccak256(abi.encodePacked(l2Sender, to, l2Block, l1Block, l2Timestamp, value, data));
179
+ }
180
+
181
+ function calculateMerkleRoot(
182
+ bytes32[] memory proof,
183
+ uint256 path,
184
+ bytes32 item
185
+ ) public pure returns (bytes32) {
186
+ return MerkleLib.calculateRoot(proof, path, keccak256(abi.encodePacked(item)));
187
+ }
188
+ }
@@ -0,0 +1,21 @@
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.4;
6
+
7
+ contract RollupMock {
8
+ event WithdrawTriggered();
9
+ event ZombieTriggered();
10
+
11
+ function withdrawStakerFunds() external returns (uint256) {
12
+ emit WithdrawTriggered();
13
+ return 0;
14
+ }
15
+
16
+ function removeOldZombies(
17
+ uint256 /* startIndex */
18
+ ) external {
19
+ emit ZombieTriggered();
20
+ }
21
+ }
@@ -1,32 +0,0 @@
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 "./PcArray.sol";
8
-
9
- struct PcStack {
10
- PcArray proved;
11
- bytes32 remainingHash;
12
- }
13
-
14
- library PcStackLib {
15
- using PcArrayLib for PcArray;
16
-
17
- function hash(PcStack memory stack) internal pure returns (bytes32 h) {
18
- h = stack.remainingHash;
19
- uint256 len = stack.proved.length();
20
- for (uint256 i = 0; i < len; i++) {
21
- h = keccak256(abi.encodePacked("Program counter stack:", stack.proved.get(i), h));
22
- }
23
- }
24
-
25
- function pop(PcStack memory stack) internal pure returns (uint32) {
26
- return stack.proved.pop();
27
- }
28
-
29
- function push(PcStack memory stack, uint32 val) internal pure {
30
- return stack.proved.push(val);
31
- }
32
- }