@arbitrum/nitro-contracts 1.0.0-beta.5 → 1.0.0-beta.6

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} +2 -3
  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 -45
  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 +12 -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/InboxStub.sol +3 -9
  20. package/src/mocks/SequencerInboxStub.sol +10 -8
  21. package/src/mocks/Simple.sol +8 -0
  22. package/src/node-interface/NodeInterface.sol +32 -5
  23. package/src/osp/IOneStepProver.sol +1 -2
  24. package/src/osp/OneStepProver0.sol +1 -87
  25. package/src/osp/OneStepProverHostIo.sol +5 -6
  26. package/src/osp/OneStepProverMath.sol +37 -27
  27. package/src/osp/OneStepProverMemory.sol +3 -4
  28. package/src/precompiles/ArbAggregator.sol +23 -33
  29. package/src/precompiles/ArbBLS.sol +1 -43
  30. package/src/precompiles/ArbGasInfo.sol +1 -19
  31. package/src/precompiles/ArbOwner.sol +12 -15
  32. package/src/precompiles/ArbRetryableTx.sol +10 -1
  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 +9 -18
  44. package/src/rollup/ValidatorWallet.sol +124 -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
@@ -5,9 +5,12 @@
5
5
  pragma solidity ^0.8.0;
6
6
 
7
7
  import "./IBridge.sol";
8
+ import "./IInbox.sol";
8
9
  import "./ISequencerInbox.sol";
10
+ import "../rollup/IRollupLogic.sol";
9
11
  import "./Messages.sol";
10
12
 
13
+ import {L1MessageType_batchPostingReport} from "../libraries/MessageTypes.sol";
11
14
  import {GasRefundEnabled, IGasRefunder} from "../libraries/IGasRefunder.sol";
12
15
  import "../libraries/DelegateCallAware.sol";
13
16
  import {MAX_DATA_SIZE} from "../libraries/Constants.sol";
@@ -20,10 +23,9 @@ import {MAX_DATA_SIZE} from "../libraries/Constants.sol";
20
23
  * sequencer within a time limit they can be force included into the rollup inbox by anyone.
21
24
  */
22
25
  contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox {
23
- bytes32[] public override inboxAccs;
24
26
  uint256 public totalDelayedMessagesRead;
25
27
 
26
- IBridge public delayedBridge;
28
+ IBridge public bridge;
27
29
 
28
30
  /// @dev The size of the batch header
29
31
  uint256 public constant HEADER_LENGTH = 40;
@@ -31,19 +33,29 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
31
33
  /// the sequencer inbox has authenticated the data. Currently not used.
32
34
  bytes1 public constant DATA_AUTHENTICATED_FLAG = 0x40;
33
35
 
34
- address public rollup;
36
+ IOwnable public rollup;
35
37
  mapping(address => bool) public isBatchPoster;
36
38
  ISequencerInbox.MaxTimeVariation public maxTimeVariation;
37
39
 
40
+ struct DasKeySetInfo {
41
+ bool isValidKeyset;
42
+ uint64 creationBlock;
43
+ }
44
+ mapping(bytes32 => DasKeySetInfo) public dasKeySetInfo;
45
+
46
+ modifier onlyRollupOwner() {
47
+ if (msg.sender != rollup.owner()) revert NotOwner(msg.sender, address(rollup));
48
+ _;
49
+ }
50
+
38
51
  function initialize(
39
- IBridge delayedBridge_,
40
- address rollup_,
52
+ IBridge bridge_,
41
53
  ISequencerInbox.MaxTimeVariation calldata maxTimeVariation_
42
54
  ) external onlyDelegated {
43
- if (delayedBridge != IBridge(address(0))) revert AlreadyInit();
44
- if (delayedBridge_ == IBridge(address(0))) revert HadZeroInit();
45
- delayedBridge = delayedBridge_;
46
- rollup = rollup_;
55
+ if (bridge != IBridge(address(0))) revert AlreadyInit();
56
+ if (bridge_ == IBridge(address(0))) revert HadZeroInit();
57
+ bridge = bridge_;
58
+ rollup = bridge_.rollup();
47
59
  maxTimeVariation = maxTimeVariation_;
48
60
  }
49
61
 
@@ -98,22 +110,24 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
98
110
  // Verify that message hash represents the last message sequence of delayed message to be included
99
111
  bytes32 prevDelayedAcc = 0;
100
112
  if (_totalDelayedMessagesRead > 1) {
101
- prevDelayedAcc = delayedBridge.inboxAccs(_totalDelayedMessagesRead - 2);
113
+ prevDelayedAcc = bridge.delayedInboxAccs(_totalDelayedMessagesRead - 2);
102
114
  }
103
115
  if (
104
- delayedBridge.inboxAccs(_totalDelayedMessagesRead - 1) !=
116
+ bridge.delayedInboxAccs(_totalDelayedMessagesRead - 1) !=
105
117
  Messages.accumulateInboxMessage(prevDelayedAcc, messageHash)
106
118
  ) revert IncorrectMessagePreimage();
107
119
 
108
120
  (bytes32 dataHash, TimeBounds memory timeBounds) = formEmptyDataHash(
109
121
  _totalDelayedMessagesRead
110
122
  );
111
- (bytes32 beforeAcc, bytes32 delayedAcc, bytes32 afterAcc) = addSequencerL2BatchImpl(
112
- dataHash,
113
- _totalDelayedMessagesRead
114
- );
123
+ (
124
+ uint256 seqMessageIndex,
125
+ bytes32 beforeAcc,
126
+ bytes32 delayedAcc,
127
+ bytes32 afterAcc
128
+ ) = addSequencerL2BatchImpl(dataHash, _totalDelayedMessagesRead, 0);
115
129
  emit SequencerBatchDelivered(
116
- inboxAccs.length - 1,
130
+ seqMessageIndex,
117
131
  beforeAcc,
118
132
  afterAcc,
119
133
  delayedAcc,
@@ -128,21 +142,24 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
128
142
  bytes calldata data,
129
143
  uint256 afterDelayedMessagesRead,
130
144
  IGasRefunder gasRefunder
131
- ) external refundsGasWithCalldata(gasRefunder, payable(msg.sender)) {
145
+ ) external refundsGas(gasRefunder) {
132
146
  // solhint-disable-next-line avoid-tx-origin
133
147
  if (msg.sender != tx.origin) revert NotOrigin();
134
148
  if (!isBatchPoster[msg.sender]) revert NotBatchPoster();
135
- if (inboxAccs.length != sequenceNumber) revert BadSequencerNumber();
136
149
  (bytes32 dataHash, TimeBounds memory timeBounds) = formDataHash(
137
150
  data,
138
151
  afterDelayedMessagesRead
139
152
  );
140
- (bytes32 beforeAcc, bytes32 delayedAcc, bytes32 afterAcc) = addSequencerL2BatchImpl(
141
- dataHash,
142
- afterDelayedMessagesRead
143
- );
153
+ (
154
+ uint256 seqMessageIndex,
155
+ bytes32 beforeAcc,
156
+ bytes32 delayedAcc,
157
+ bytes32 afterAcc
158
+ ) = addSequencerL2BatchImpl(dataHash, afterDelayedMessagesRead, data.length);
159
+ if (seqMessageIndex != sequenceNumber)
160
+ revert BadSequencerNumber(seqMessageIndex, sequenceNumber);
144
161
  emit SequencerBatchDelivered(
145
- inboxAccs.length - 1,
162
+ sequenceNumber,
146
163
  beforeAcc,
147
164
  afterAcc,
148
165
  delayedAcc,
@@ -157,18 +174,23 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
157
174
  bytes calldata data,
158
175
  uint256 afterDelayedMessagesRead,
159
176
  IGasRefunder gasRefunder
160
- ) external override refundsGasNoCalldata(gasRefunder, payable(msg.sender)) {
161
- if (!isBatchPoster[msg.sender] && msg.sender != rollup) revert NotBatchPoster();
162
- if (inboxAccs.length != sequenceNumber) revert BadSequencerNumber();
177
+ ) external override refundsGas(gasRefunder) {
178
+ if (!isBatchPoster[msg.sender] && msg.sender != address(rollup)) revert NotBatchPoster();
163
179
 
164
180
  (bytes32 dataHash, TimeBounds memory timeBounds) = formDataHash(
165
181
  data,
166
182
  afterDelayedMessagesRead
167
183
  );
168
- (bytes32 beforeAcc, bytes32 delayedAcc, bytes32 afterAcc) = addSequencerL2BatchImpl(
169
- dataHash,
170
- afterDelayedMessagesRead
171
- );
184
+ // we set the calldata length posted to 0 here since the caller isn't the origin
185
+ // of the tx, so they might have not paid tx input cost for the calldata
186
+ (
187
+ uint256 seqMessageIndex,
188
+ bytes32 beforeAcc,
189
+ bytes32 delayedAcc,
190
+ bytes32 afterAcc
191
+ ) = addSequencerL2BatchImpl(dataHash, afterDelayedMessagesRead, 0);
192
+ if (seqMessageIndex != sequenceNumber)
193
+ revert BadSequencerNumber(seqMessageIndex, sequenceNumber);
172
194
  emit SequencerBatchDelivered(
173
195
  sequenceNumber,
174
196
  beforeAcc,
@@ -181,6 +203,22 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
181
203
  emit SequencerBatchData(sequenceNumber, data);
182
204
  }
183
205
 
206
+ modifier validateBatchData(bytes calldata data) {
207
+ uint256 fullDataLen = HEADER_LENGTH + data.length;
208
+ if (fullDataLen > MAX_DATA_SIZE) revert DataTooLarge(fullDataLen, MAX_DATA_SIZE);
209
+ if (data.length > 0 && (data[0] & DATA_AUTHENTICATED_FLAG) == DATA_AUTHENTICATED_FLAG) {
210
+ revert DataNotAuthenticated();
211
+ }
212
+ // the first byte is used to identify the type of batch data
213
+ // das batches expect to have the type byte set, followed by the keyset (so they should have at least 33 bytes)
214
+ if (data.length >= 33 && data[0] & 0x80 != 0) {
215
+ // we skip the first byte, then read the next 32 bytes for the keyset
216
+ bytes32 dasKeysetHash = bytes32(data[1:33]);
217
+ if (!dasKeySetInfo[dasKeysetHash].isValidKeyset) revert NoSuchKeyset(dasKeysetHash);
218
+ }
219
+ _;
220
+ }
221
+
184
222
  function packHeader(uint256 afterDelayedMessagesRead)
185
223
  internal
186
224
  view
@@ -202,25 +240,12 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
202
240
  function formDataHash(bytes calldata data, uint256 afterDelayedMessagesRead)
203
241
  internal
204
242
  view
243
+ validateBatchData(data)
205
244
  returns (bytes32, TimeBounds memory)
206
245
  {
207
- uint256 fullDataLen = HEADER_LENGTH + data.length;
208
- if (fullDataLen < HEADER_LENGTH) revert DataLengthOverflow();
209
- if (fullDataLen > MAX_DATA_SIZE) revert DataTooLarge(fullDataLen, MAX_DATA_SIZE);
210
- bytes memory fullData = new bytes(fullDataLen);
211
246
  (bytes memory header, TimeBounds memory timeBounds) = packHeader(afterDelayedMessagesRead);
212
-
213
- for (uint256 i = 0; i < HEADER_LENGTH; i++) {
214
- fullData[i] = header[i];
215
- }
216
- if (data.length > 0 && (data[0] & DATA_AUTHENTICATED_FLAG) == DATA_AUTHENTICATED_FLAG) {
217
- revert DataNotAuthenticated();
218
- }
219
- // copy data into fullData at offset of HEADER_LENGTH (the extra 32 offset is because solidity puts the array len first)
220
- assembly {
221
- calldatacopy(add(fullData, add(HEADER_LENGTH, 32)), data.offset, data.length)
222
- }
223
- return (keccak256(fullData), timeBounds);
247
+ bytes32 dataHash = keccak256(bytes.concat(header, data));
248
+ return (dataHash, timeBounds);
224
249
  }
225
250
 
226
251
  function formEmptyDataHash(uint256 afterDelayedMessagesRead)
@@ -232,43 +257,117 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
232
257
  return (keccak256(header), timeBounds);
233
258
  }
234
259
 
235
- function addSequencerL2BatchImpl(bytes32 dataHash, uint256 afterDelayedMessagesRead)
260
+ function addSequencerL2BatchImpl(
261
+ bytes32 dataHash,
262
+ uint256 afterDelayedMessagesRead,
263
+ uint256 calldataLengthPosted
264
+ )
236
265
  internal
237
266
  returns (
267
+ uint256 seqMessageIndex,
238
268
  bytes32 beforeAcc,
239
269
  bytes32 delayedAcc,
240
270
  bytes32 acc
241
271
  )
242
272
  {
243
273
  if (afterDelayedMessagesRead < totalDelayedMessagesRead) revert DelayedBackwards();
244
- if (afterDelayedMessagesRead > delayedBridge.messageCount()) revert DelayedTooFar();
274
+ if (afterDelayedMessagesRead > bridge.delayedMessageCount()) revert DelayedTooFar();
245
275
 
246
- if (inboxAccs.length > 0) {
247
- beforeAcc = inboxAccs[inboxAccs.length - 1];
248
- }
249
- if (afterDelayedMessagesRead > 0) {
250
- delayedAcc = delayedBridge.inboxAccs(afterDelayedMessagesRead - 1);
251
- }
276
+ (seqMessageIndex, beforeAcc, delayedAcc, acc) = bridge.enqueueSequencerMessage(
277
+ dataHash,
278
+ afterDelayedMessagesRead
279
+ );
252
280
 
253
- acc = keccak256(abi.encodePacked(beforeAcc, dataHash, delayedAcc));
254
- inboxAccs.push(acc);
255
281
  totalDelayedMessagesRead = afterDelayedMessagesRead;
282
+
283
+ if (calldataLengthPosted > 0) {
284
+ // this msg isn't included in the current sequencer batch, but instead added to
285
+ // the delayed messages queue that is yet to be included
286
+ address batchPoster = msg.sender;
287
+ bytes memory spendingReportMsg = abi.encodePacked(
288
+ block.timestamp,
289
+ batchPoster,
290
+ dataHash,
291
+ seqMessageIndex,
292
+ block.basefee
293
+ );
294
+ uint256 msgNum = bridge.submitBatchSpendingReport(
295
+ batchPoster,
296
+ keccak256(spendingReportMsg)
297
+ );
298
+ // this is the same event used by Inbox.sol after including a message to the delayed message accumulator
299
+ emit InboxMessageDelivered(msgNum, spendingReportMsg);
300
+ }
301
+ }
302
+
303
+ function inboxAccs(uint256 index) external view override returns (bytes32) {
304
+ return bridge.sequencerInboxAccs(index);
256
305
  }
257
306
 
258
307
  function batchCount() external view override returns (uint256) {
259
- return inboxAccs.length;
308
+ return bridge.sequencerMessageCount();
260
309
  }
261
310
 
311
+ /**
312
+ * @notice Set max delay for sequencer inbox
313
+ * @param maxTimeVariation_ the maximum time variation parameters
314
+ */
262
315
  function setMaxTimeVariation(ISequencerInbox.MaxTimeVariation memory maxTimeVariation_)
263
316
  external
264
317
  override
318
+ onlyRollupOwner
265
319
  {
266
- if (msg.sender != rollup) revert NotRollup(msg.sender, rollup);
267
320
  maxTimeVariation = maxTimeVariation_;
321
+ emit OwnerFunctionCalled(0);
268
322
  }
269
323
 
270
- function setIsBatchPoster(address addr, bool isBatchPoster_) external override {
271
- if (msg.sender != rollup) revert NotRollup(msg.sender, rollup);
324
+ /**
325
+ * @notice Updates whether an address is authorized to be a batch poster at the sequencer inbox
326
+ * @param addr the address
327
+ * @param isBatchPoster_ if the specified address should be authorized as a batch poster
328
+ */
329
+ function setIsBatchPoster(address addr, bool isBatchPoster_) external override onlyRollupOwner {
272
330
  isBatchPoster[addr] = isBatchPoster_;
331
+ emit OwnerFunctionCalled(1);
332
+ }
333
+
334
+ /**
335
+ * @notice Makes Data Availability Service keyset valid
336
+ * @param keysetBytes bytes of the serialized keyset
337
+ */
338
+ function setValidKeyset(bytes calldata keysetBytes) external override onlyRollupOwner {
339
+ bytes32 ksHash = keccak256(keysetBytes);
340
+ if (dasKeySetInfo[ksHash].isValidKeyset) revert AlreadyValidDASKeyset(ksHash);
341
+ dasKeySetInfo[ksHash] = DasKeySetInfo({
342
+ isValidKeyset: true,
343
+ creationBlock: uint64(block.number)
344
+ });
345
+ emit SetValidKeyset(ksHash, keysetBytes);
346
+ emit OwnerFunctionCalled(2);
347
+ }
348
+
349
+ /**
350
+ * @notice Invalidates a Data Availability Service keyset
351
+ * @param ksHash hash of the keyset
352
+ */
353
+ function invalidateKeysetHash(bytes32 ksHash) external override onlyRollupOwner {
354
+ if (!dasKeySetInfo[ksHash].isValidKeyset) revert NoSuchKeyset(ksHash);
355
+ // we don't delete the block creation value since its used to fetch the SetValidKeyset
356
+ // event efficiently. The event provides the hash preimage of the key.
357
+ // this is still needed when syncing the chain after a keyset is invalidated.
358
+ dasKeySetInfo[ksHash].isValidKeyset = false;
359
+ emit InvalidateKeyset(ksHash);
360
+ emit OwnerFunctionCalled(3);
361
+ }
362
+
363
+ function isValidKeysetHash(bytes32 ksHash) external view returns (bool) {
364
+ return dasKeySetInfo[ksHash].isValidKeyset;
365
+ }
366
+
367
+ /// @notice the creation block is intended to still be available after a keyset is deleted
368
+ function getKeysetCreationBlock(bytes32 ksHash) external view returns (uint256) {
369
+ DasKeySetInfo memory ksInfo = dasKeySetInfo[ksHash];
370
+ if (ksInfo.creationBlock == 0) revert NoSuchKeyset(ksHash);
371
+ return uint256(ksInfo.creationBlock);
273
372
  }
274
373
  }
@@ -61,14 +61,12 @@ library ChallengeLib {
61
61
  ValueArray memory valuesArray = ValueArray({inner: startingValues});
62
62
  ValueStack memory values = ValueStack({proved: valuesArray, remainingHash: 0});
63
63
  ValueStack memory internalStack;
64
- PcStack memory blocks;
65
64
  StackFrameWindow memory frameStack;
66
65
 
67
66
  Machine memory mach = Machine({
68
67
  status: MachineStatus.RUNNING,
69
68
  valueStack: values,
70
69
  internalStack: internalStack,
71
- blockStack: blocks,
72
70
  frameStack: frameStack,
73
71
  globalStateHash: globalStateHash,
74
72
  moduleIdx: 0,
@@ -33,7 +33,7 @@ contract ChallengeManager is DelegateCallAware, IChallengeManager {
33
33
  IChallengeResultReceiver public resultReceiver;
34
34
 
35
35
  ISequencerInbox public sequencerInbox;
36
- IBridge public delayedBridge;
36
+ IBridge public bridge;
37
37
  IOneStepProofEntry public osp;
38
38
 
39
39
  function challengeInfo(uint64 challengeIndex)
@@ -99,14 +99,14 @@ contract ChallengeManager is DelegateCallAware, IChallengeManager {
99
99
  function initialize(
100
100
  IChallengeResultReceiver resultReceiver_,
101
101
  ISequencerInbox sequencerInbox_,
102
- IBridge delayedBridge_,
102
+ IBridge bridge_,
103
103
  IOneStepProofEntry osp_
104
104
  ) external override onlyDelegated {
105
105
  require(address(resultReceiver) == address(0), "ALREADY_INIT");
106
106
  require(address(resultReceiver_) != address(0), "NO_RESULT_RECEIVER");
107
107
  resultReceiver = resultReceiver_;
108
108
  sequencerInbox = sequencerInbox_;
109
- delayedBridge = delayedBridge_;
109
+ bridge = bridge_;
110
110
  osp = osp_;
111
111
  }
112
112
 
@@ -254,11 +254,7 @@ contract ChallengeManager is DelegateCallAware, IChallengeManager {
254
254
  }
255
255
 
256
256
  bytes32 afterHash = osp.proveOneStep(
257
- ExecutionContext({
258
- maxInboxMessagesRead: challenge.maxInboxMessages,
259
- sequencerInbox: sequencerInbox,
260
- delayedBridge: delayedBridge
261
- }),
257
+ ExecutionContext({maxInboxMessagesRead: challenge.maxInboxMessages, bridge: bridge}),
262
258
  challengeStart,
263
259
  selection.oldSegments[selection.challengePosition],
264
260
  proof
@@ -43,7 +43,7 @@ interface IChallengeManager {
43
43
  function initialize(
44
44
  IChallengeResultReceiver resultReceiver_,
45
45
  ISequencerInbox sequencerInbox_,
46
- IBridge delayedBridge_,
46
+ IBridge bridge_,
47
47
  IOneStepProofEntry osp_
48
48
  ) external;
49
49
 
@@ -36,3 +36,9 @@ error NotContract(address addr);
36
36
  /// @param actualLength The length of the merkle proof provided
37
37
  /// @param maxProofLength The max length a merkle proof can have
38
38
  error MerkleProofTooLong(uint256 actualLength, uint256 maxProofLength);
39
+
40
+ /// @dev Thrown when an un-authorized address tries to access an admin function
41
+ /// @param sender The un-authorized sender
42
+ /// @param rollup The rollup, which would be authorized
43
+ /// @param owner The rollup's owner, which would be authorized
44
+ error NotRollupOrOwner(address sender, address rollup, address owner);
@@ -13,23 +13,22 @@ interface IGasRefunder {
13
13
  }
14
14
 
15
15
  abstract contract GasRefundEnabled {
16
- modifier refundsGasWithCalldata(IGasRefunder gasRefunder, address payable spender) {
16
+ /// @dev this refunds the sender for execution costs of the tx
17
+ /// calldata costs are only refunded if `msg.sender == tx.origin` to guarantee the value refunded relates to charging
18
+ /// for the `tx.input`. this avoids a possible attack where you generate large calldata from a contract and get over-refunded
19
+ modifier refundsGas(IGasRefunder gasRefunder) {
17
20
  uint256 startGasLeft = gasleft();
18
21
  _;
19
22
  if (address(gasRefunder) != address(0)) {
20
- uint256 calldataSize;
21
- assembly {
22
- calldataSize := calldatasize()
23
+ uint256 calldataSize = 0;
24
+ // if triggered in a contract call, the spender may be overrefunded by appending dummy data to the call
25
+ // so we check if it is a top level call, which would mean the sender paid calldata as part of tx.input
26
+ if (msg.sender == tx.origin) {
27
+ assembly {
28
+ calldataSize := calldatasize()
29
+ }
23
30
  }
24
- gasRefunder.onGasSpent(spender, startGasLeft - gasleft(), calldataSize);
25
- }
26
- }
27
-
28
- modifier refundsGasNoCalldata(IGasRefunder gasRefunder, address payable spender) {
29
- uint256 startGasLeft = gasleft();
30
- _;
31
- if (address(gasRefunder) != address(0)) {
32
- gasRefunder.onGasSpent(spender, startGasLeft - gasleft(), 0);
31
+ gasRefunder.onGasSpent(payable(msg.sender), startGasLeft - gasleft(), calldataSize);
33
32
  }
34
33
  }
35
34
  }
@@ -34,10 +34,19 @@ library MerkleLib {
34
34
  if (proofItems > 256) revert MerkleProofTooLong(proofItems, 256);
35
35
  bytes32 h = item;
36
36
  for (uint256 i = 0; i < proofItems; i++) {
37
+ bytes32 node = nodes[i];
37
38
  if (route % 2 == 0) {
38
- h = keccak256(abi.encodePacked(h, nodes[i]));
39
+ assembly {
40
+ mstore(0x00, h)
41
+ mstore(0x20, node)
42
+ h := keccak256(0x00, 0x40)
43
+ }
39
44
  } else {
40
- h = keccak256(abi.encodePacked(nodes[i], h));
45
+ assembly {
46
+ mstore(0x00, node)
47
+ mstore(0x20, h)
48
+ h := keccak256(0x00, 0x40)
49
+ }
41
50
  }
42
51
  route /= 2;
43
52
  }
@@ -8,6 +8,7 @@ uint8 constant L2_MSG = 3;
8
8
  uint8 constant L1MessageType_L2FundedByL1 = 7;
9
9
  uint8 constant L1MessageType_submitRetryableTx = 9;
10
10
  uint8 constant L1MessageType_ethDeposit = 12;
11
+ uint8 constant L1MessageType_batchPostingReport = 13;
11
12
  uint8 constant L2MessageType_unsignedEOATx = 0;
12
13
  uint8 constant L2MessageType_unsignedContractTx = 1;
13
14
 
@@ -14,19 +14,28 @@ contract BridgeStub is IBridge {
14
14
  bool allowed;
15
15
  }
16
16
 
17
- mapping(address => InOutInfo) private allowedInboxesMap;
17
+ mapping(address => InOutInfo) private allowedDelayedInboxesMap;
18
18
  //mapping(address => InOutInfo) private allowedOutboxesMap;
19
19
 
20
- address[] public allowedInboxList;
20
+ address[] public allowedDelayedInboxList;
21
21
  address[] public allowedOutboxList;
22
22
 
23
23
  address public override activeOutbox;
24
24
 
25
25
  // Accumulator for delayed inbox; tail represents hash of the current state; each element represents the inclusion of a new message.
26
- bytes32[] public override inboxAccs;
26
+ bytes32[] public override delayedInboxAccs;
27
27
 
28
- function allowedInboxes(address inbox) external view override returns (bool) {
29
- return allowedInboxesMap[inbox].allowed;
28
+ bytes32[] public override sequencerInboxAccs;
29
+
30
+ address public sequencerInbox;
31
+
32
+ function setSequencerInbox(address _sequencerInbox) external override {
33
+ sequencerInbox = _sequencerInbox;
34
+ emit SequencerInboxUpdated(_sequencerInbox);
35
+ }
36
+
37
+ function allowedDelayedInboxes(address inbox) external view override returns (bool) {
38
+ return allowedDelayedInboxesMap[inbox].allowed;
30
39
  }
31
40
 
32
41
  function allowedOutboxes(address) external pure override returns (bool) {
@@ -38,9 +47,9 @@ contract BridgeStub is IBridge {
38
47
  address sender,
39
48
  bytes32 messageDataHash
40
49
  ) external payable override returns (uint256) {
41
- require(allowedInboxesMap[msg.sender].allowed, "NOT_FROM_INBOX");
50
+ require(allowedDelayedInboxesMap[msg.sender].allowed, "NOT_FROM_INBOX");
42
51
  return
43
- addMessageToAccumulator(
52
+ addMessageToDelayedAccumulator(
44
53
  kind,
45
54
  sender,
46
55
  block.number,
@@ -50,7 +59,34 @@ contract BridgeStub is IBridge {
50
59
  );
51
60
  }
52
61
 
53
- function addMessageToAccumulator(
62
+ function enqueueSequencerMessage(bytes32 dataHash, uint256 afterDelayedMessagesRead)
63
+ external
64
+ returns (
65
+ uint256 seqMessageIndex,
66
+ bytes32 beforeAcc,
67
+ bytes32 delayedAcc,
68
+ bytes32 acc
69
+ )
70
+ {
71
+ seqMessageIndex = sequencerInboxAccs.length;
72
+ if (sequencerInboxAccs.length > 0) {
73
+ beforeAcc = sequencerInboxAccs[sequencerInboxAccs.length - 1];
74
+ }
75
+ if (afterDelayedMessagesRead > 0) {
76
+ delayedAcc = delayedInboxAccs[afterDelayedMessagesRead - 1];
77
+ }
78
+ acc = keccak256(abi.encodePacked(beforeAcc, dataHash, delayedAcc));
79
+ sequencerInboxAccs.push(acc);
80
+ }
81
+
82
+ function submitBatchSpendingReport(address batchPoster, bytes32 dataHash)
83
+ external
84
+ returns (uint256)
85
+ {
86
+ // TODO: implement stub
87
+ }
88
+
89
+ function addMessageToDelayedAccumulator(
54
90
  uint8,
55
91
  address,
56
92
  uint256,
@@ -58,7 +94,7 @@ contract BridgeStub is IBridge {
58
94
  uint256,
59
95
  bytes32 messageDataHash
60
96
  ) internal returns (uint256) {
61
- uint256 count = inboxAccs.length;
97
+ uint256 count = delayedInboxAccs.length;
62
98
  bytes32 messageHash = Messages.messageHash(
63
99
  0,
64
100
  address(uint160(0)),
@@ -70,9 +106,9 @@ contract BridgeStub is IBridge {
70
106
  );
71
107
  bytes32 prevAcc = 0;
72
108
  if (count > 0) {
73
- prevAcc = inboxAccs[count - 1];
109
+ prevAcc = delayedInboxAccs[count - 1];
74
110
  }
75
- inboxAccs.push(Messages.accumulateInboxMessage(prevAcc, messageHash));
111
+ delayedInboxAccs.push(Messages.accumulateInboxMessage(prevAcc, messageHash));
76
112
  return count;
77
113
  }
78
114
 
@@ -84,21 +120,23 @@ contract BridgeStub is IBridge {
84
120
  revert("NOT_IMPLEMENTED");
85
121
  }
86
122
 
87
- function setInbox(address inbox, bool enabled) external override {
88
- InOutInfo storage info = allowedInboxesMap[inbox];
123
+ function setDelayedInbox(address inbox, bool enabled) external override {
124
+ InOutInfo storage info = allowedDelayedInboxesMap[inbox];
89
125
  bool alreadyEnabled = info.allowed;
90
126
  emit InboxToggle(inbox, enabled);
91
127
  if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) {
92
128
  return;
93
129
  }
94
130
  if (enabled) {
95
- allowedInboxesMap[inbox] = InOutInfo(allowedInboxList.length, true);
96
- allowedInboxList.push(inbox);
131
+ allowedDelayedInboxesMap[inbox] = InOutInfo(allowedDelayedInboxList.length, true);
132
+ allowedDelayedInboxList.push(inbox);
97
133
  } else {
98
- allowedInboxList[info.index] = allowedInboxList[allowedInboxList.length - 1];
99
- allowedInboxesMap[allowedInboxList[info.index]].index = info.index;
100
- allowedInboxList.pop();
101
- delete allowedInboxesMap[inbox];
134
+ allowedDelayedInboxList[info.index] = allowedDelayedInboxList[
135
+ allowedDelayedInboxList.length - 1
136
+ ];
137
+ allowedDelayedInboxesMap[allowedDelayedInboxList[info.index]].index = info.index;
138
+ allowedDelayedInboxList.pop();
139
+ delete allowedDelayedInboxesMap[inbox];
102
140
  }
103
141
  }
104
142
 
@@ -109,7 +147,15 @@ contract BridgeStub is IBridge {
109
147
  revert("NOT_IMPLEMENTED");
110
148
  }
111
149
 
112
- function messageCount() external view override returns (uint256) {
113
- return inboxAccs.length;
150
+ function delayedMessageCount() external view override returns (uint256) {
151
+ return delayedInboxAccs.length;
152
+ }
153
+
154
+ function sequencerMessageCount() external view override returns (uint256) {
155
+ return sequencerInboxAccs.length;
156
+ }
157
+
158
+ function rollup() external pure override returns (IOwnable) {
159
+ revert("NOT_IMPLEMENTED");
114
160
  }
115
161
  }
@@ -28,16 +28,10 @@ contract InboxStub is IInbox {
28
28
  }
29
29
 
30
30
  /**
31
- * @notice Send a generic L2 message to the chain
32
- * @dev This method is an optimization to avoid having to emit the entirety of the messageData in a log. Instead validators are expected to be able to parse the data from the transaction's input
33
- * @param messageData Data of the message being sent
31
+ * @dev DEPRECATED in favor of sendL2Message
34
32
  */
35
33
  function sendL2MessageFromOrigin(bytes calldata messageData) external returns (uint256) {
36
- // solhint-disable-next-line avoid-tx-origin
37
- require(msg.sender == tx.origin, "origin only");
38
- uint256 msgNum = deliverToBridge(L2_MSG, msg.sender, keccak256(messageData));
39
- emit InboxMessageDeliveredFromOrigin(msgNum);
40
- return msgNum;
34
+ return sendL2Message(messageData);
41
35
  }
42
36
 
43
37
  /**
@@ -45,7 +39,7 @@ contract InboxStub is IInbox {
45
39
  * @dev This method can be used to send any type of message that doesn't require L1 validation
46
40
  * @param messageData Data of the message being sent
47
41
  */
48
- function sendL2Message(bytes calldata messageData) external override returns (uint256) {
42
+ function sendL2Message(bytes calldata messageData) public override returns (uint256) {
49
43
  uint256 msgNum = deliverToBridge(L2_MSG, msg.sender, keccak256(messageData));
50
44
  emit InboxMessageDelivered(msgNum, messageData);
51
45
  return msgNum;