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

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 (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
- }