@arbitrum/nitro-contracts 1.0.0-beta.5 → 1.0.0-beta.6
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.
- package/package.json +2 -1
- package/src/bridge/Bridge.sol +127 -32
- package/src/bridge/IBridge.sol +40 -6
- package/src/bridge/{IMessageProvider.sol → IDelayedMessageProvider.sol} +2 -3
- package/src/bridge/IInbox.sol +23 -2
- package/src/bridge/IOwnable.sol +9 -0
- package/src/bridge/ISequencerInbox.sol +36 -9
- package/src/bridge/Inbox.sol +131 -45
- package/src/bridge/Outbox.sol +134 -31
- package/src/bridge/SequencerInbox.sol +159 -60
- package/src/challenge/ChallengeLib.sol +0 -2
- package/src/challenge/ChallengeManager.sol +4 -8
- package/src/challenge/IChallengeManager.sol +1 -1
- package/src/libraries/Error.sol +6 -0
- package/src/libraries/IGasRefunder.sol +12 -13
- package/src/libraries/MerkleLib.sol +11 -2
- package/src/libraries/MessageTypes.sol +1 -0
- package/src/mocks/BridgeStub.sol +67 -21
- package/src/mocks/InboxStub.sol +3 -9
- package/src/mocks/SequencerInboxStub.sol +10 -8
- package/src/mocks/Simple.sol +8 -0
- package/src/node-interface/NodeInterface.sol +32 -5
- package/src/osp/IOneStepProver.sol +1 -2
- package/src/osp/OneStepProver0.sol +1 -87
- package/src/osp/OneStepProverHostIo.sol +5 -6
- package/src/osp/OneStepProverMath.sol +37 -27
- package/src/osp/OneStepProverMemory.sol +3 -4
- package/src/precompiles/ArbAggregator.sol +23 -33
- package/src/precompiles/ArbBLS.sol +1 -43
- package/src/precompiles/ArbGasInfo.sol +1 -19
- package/src/precompiles/ArbOwner.sol +12 -15
- package/src/precompiles/ArbRetryableTx.sol +10 -1
- package/src/precompiles/ArbosActs.sol +9 -2
- package/src/rollup/BridgeCreator.sol +23 -28
- package/src/rollup/IRollupCore.sol +3 -3
- package/src/rollup/{IRollupEventBridge.sol → IRollupEventInbox.sol} +2 -2
- package/src/rollup/IRollupLogic.sol +21 -18
- package/src/rollup/RollupAdminLogic.sol +30 -34
- package/src/rollup/RollupCore.sol +15 -7
- package/src/rollup/RollupCreator.sol +21 -11
- package/src/rollup/{RollupEventBridge.sol → RollupEventInbox.sol} +10 -10
- package/src/rollup/RollupLib.sol +20 -5
- package/src/rollup/RollupUserLogic.sol +9 -18
- package/src/rollup/ValidatorWallet.sol +124 -8
- package/src/rollup/ValidatorWalletCreator.sol +11 -6
- package/src/state/Deserialize.sol +3 -22
- package/src/state/Instructions.sol +2 -10
- package/src/state/Machine.sol +0 -4
- package/src/state/ModuleMemory.sol +2 -1
- package/src/state/Value.sol +2 -3
- package/src/test-helpers/BridgeTester.sol +223 -0
- package/src/test-helpers/OutboxWithoutOptTester.sol +188 -0
- package/src/test-helpers/RollupMock.sol +21 -0
- 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
|
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
|
-
|
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
|
40
|
-
address rollup_,
|
52
|
+
IBridge bridge_,
|
41
53
|
ISequencerInbox.MaxTimeVariation calldata maxTimeVariation_
|
42
54
|
) external onlyDelegated {
|
43
|
-
if (
|
44
|
-
if (
|
45
|
-
|
46
|
-
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 =
|
113
|
+
prevDelayedAcc = bridge.delayedInboxAccs(_totalDelayedMessagesRead - 2);
|
102
114
|
}
|
103
115
|
if (
|
104
|
-
|
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
|
-
(
|
112
|
-
|
113
|
-
|
114
|
-
|
123
|
+
(
|
124
|
+
uint256 seqMessageIndex,
|
125
|
+
bytes32 beforeAcc,
|
126
|
+
bytes32 delayedAcc,
|
127
|
+
bytes32 afterAcc
|
128
|
+
) = addSequencerL2BatchImpl(dataHash, _totalDelayedMessagesRead, 0);
|
115
129
|
emit SequencerBatchDelivered(
|
116
|
-
|
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
|
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
|
-
(
|
141
|
-
|
142
|
-
|
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
|
-
|
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
|
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
|
-
|
169
|
-
|
170
|
-
|
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
|
-
|
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(
|
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 >
|
274
|
+
if (afterDelayedMessagesRead > bridge.delayedMessageCount()) revert DelayedTooFar();
|
245
275
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
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
|
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
|
-
|
271
|
-
|
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
|
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
|
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
|
-
|
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
|
package/src/libraries/Error.sol
CHANGED
@@ -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
|
-
|
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
|
-
|
22
|
-
|
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(
|
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
|
-
|
39
|
+
assembly {
|
40
|
+
mstore(0x00, h)
|
41
|
+
mstore(0x20, node)
|
42
|
+
h := keccak256(0x00, 0x40)
|
43
|
+
}
|
39
44
|
} else {
|
40
|
-
|
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
|
|
package/src/mocks/BridgeStub.sol
CHANGED
@@ -14,19 +14,28 @@ contract BridgeStub is IBridge {
|
|
14
14
|
bool allowed;
|
15
15
|
}
|
16
16
|
|
17
|
-
mapping(address => InOutInfo) private
|
17
|
+
mapping(address => InOutInfo) private allowedDelayedInboxesMap;
|
18
18
|
//mapping(address => InOutInfo) private allowedOutboxesMap;
|
19
19
|
|
20
|
-
address[] public
|
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
|
26
|
+
bytes32[] public override delayedInboxAccs;
|
27
27
|
|
28
|
-
|
29
|
-
|
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(
|
50
|
+
require(allowedDelayedInboxesMap[msg.sender].allowed, "NOT_FROM_INBOX");
|
42
51
|
return
|
43
|
-
|
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
|
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 =
|
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 =
|
109
|
+
prevAcc = delayedInboxAccs[count - 1];
|
74
110
|
}
|
75
|
-
|
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
|
88
|
-
InOutInfo storage info =
|
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
|
-
|
96
|
-
|
131
|
+
allowedDelayedInboxesMap[inbox] = InOutInfo(allowedDelayedInboxList.length, true);
|
132
|
+
allowedDelayedInboxList.push(inbox);
|
97
133
|
} else {
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
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
|
113
|
-
return
|
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
|
}
|
package/src/mocks/InboxStub.sol
CHANGED
@@ -28,16 +28,10 @@ contract InboxStub is IInbox {
|
|
28
28
|
}
|
29
29
|
|
30
30
|
/**
|
31
|
-
* @
|
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
|
-
|
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)
|
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;
|