@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.
- 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;
|