@arbitrum/nitro-contracts 1.0.0-beta.1

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 (113) hide show
  1. package/.prettierrc +5 -0
  2. package/.solhint.json +18 -0
  3. package/deploy/BridgeStubCreator.js +10 -0
  4. package/deploy/HashProofHelper.js +13 -0
  5. package/deploy/InboxStubCreator.js +17 -0
  6. package/deploy/OneStepProofEntryCreator.js +19 -0
  7. package/deploy/OneStepProver0Creator.js +14 -0
  8. package/deploy/OneStepProverHostIoCreator.js +14 -0
  9. package/deploy/OneStepProverMathCreator.js +14 -0
  10. package/deploy/OneStepProverMemoryCreator.js +14 -0
  11. package/deploy/SequencerInboxStubCreator.js +13 -0
  12. package/deploy/ValueArrayTesterCreator.js +13 -0
  13. package/hardhat.config.ts +47 -0
  14. package/hardhat.prod-config.js +18 -0
  15. package/package.json +49 -0
  16. package/scripts/build.bash +5 -0
  17. package/src/bridge/Bridge.sol +168 -0
  18. package/src/bridge/IBridge.sol +68 -0
  19. package/src/bridge/IInbox.sol +80 -0
  20. package/src/bridge/IMessageProvider.sol +11 -0
  21. package/src/bridge/IOutbox.sol +52 -0
  22. package/src/bridge/ISequencerInbox.sol +85 -0
  23. package/src/bridge/Inbox.sol +414 -0
  24. package/src/bridge/Messages.sol +38 -0
  25. package/src/bridge/Outbox.sol +188 -0
  26. package/src/bridge/SequencerInbox.sol +274 -0
  27. package/src/challenge/ChallengeLib.sol +135 -0
  28. package/src/challenge/ChallengeManager.sol +367 -0
  29. package/src/challenge/IChallengeManager.sol +75 -0
  30. package/src/challenge/IChallengeResultReceiver.sol +13 -0
  31. package/src/libraries/AddressAliasHelper.sol +29 -0
  32. package/src/libraries/AdminFallbackProxy.sol +153 -0
  33. package/src/libraries/ArbitrumProxy.sol +20 -0
  34. package/src/libraries/Constants.sol +10 -0
  35. package/src/libraries/CryptographyPrimitives.sol +323 -0
  36. package/src/libraries/DelegateCallAware.sol +44 -0
  37. package/src/libraries/Error.sol +38 -0
  38. package/src/libraries/IGasRefunder.sol +35 -0
  39. package/src/libraries/MerkleLib.sol +46 -0
  40. package/src/libraries/MessageTypes.sol +14 -0
  41. package/src/libraries/SecondaryLogicUUPSUpgradeable.sol +58 -0
  42. package/src/libraries/UUPSNotUpgradeable.sol +56 -0
  43. package/src/mocks/BridgeStub.sol +115 -0
  44. package/src/mocks/Counter.sol +13 -0
  45. package/src/mocks/ExecutionManager.sol +41 -0
  46. package/src/mocks/InboxStub.sol +131 -0
  47. package/src/mocks/MockResultReceiver.sol +59 -0
  48. package/src/mocks/SequencerInboxStub.sol +42 -0
  49. package/src/mocks/SimpleProxy.sol +19 -0
  50. package/src/node-interface/NodeInterface.sol +50 -0
  51. package/src/osp/HashProofHelper.sol +154 -0
  52. package/src/osp/IOneStepProofEntry.sol +20 -0
  53. package/src/osp/IOneStepProver.sol +27 -0
  54. package/src/osp/OneStepProofEntry.sol +129 -0
  55. package/src/osp/OneStepProver0.sol +566 -0
  56. package/src/osp/OneStepProverHostIo.sol +357 -0
  57. package/src/osp/OneStepProverMath.sol +514 -0
  58. package/src/osp/OneStepProverMemory.sol +313 -0
  59. package/src/precompiles/ArbAddressTable.sol +60 -0
  60. package/src/precompiles/ArbAggregator.sol +62 -0
  61. package/src/precompiles/ArbBLS.sol +53 -0
  62. package/src/precompiles/ArbDebug.sol +39 -0
  63. package/src/precompiles/ArbFunctionTable.sol +29 -0
  64. package/src/precompiles/ArbGasInfo.sol +121 -0
  65. package/src/precompiles/ArbInfo.sol +15 -0
  66. package/src/precompiles/ArbOwner.sol +65 -0
  67. package/src/precompiles/ArbOwnerPublic.sol +18 -0
  68. package/src/precompiles/ArbRetryableTx.sol +89 -0
  69. package/src/precompiles/ArbStatistics.sol +29 -0
  70. package/src/precompiles/ArbSys.sol +134 -0
  71. package/src/precompiles/ArbosActs.sol +41 -0
  72. package/src/precompiles/ArbosTest.sol +14 -0
  73. package/src/rollup/BridgeCreator.sol +120 -0
  74. package/src/rollup/IRollupCore.sol +152 -0
  75. package/src/rollup/IRollupLogic.sol +183 -0
  76. package/src/rollup/Node.sol +99 -0
  77. package/src/rollup/RollupAdminLogic.sol +322 -0
  78. package/src/rollup/RollupCore.sol +627 -0
  79. package/src/rollup/RollupCreator.sol +133 -0
  80. package/src/rollup/RollupEventBridge.sol +46 -0
  81. package/src/rollup/RollupLib.sol +135 -0
  82. package/src/rollup/RollupUserLogic.sol +712 -0
  83. package/src/rollup/ValidatorUtils.sol +243 -0
  84. package/src/rollup/ValidatorWallet.sol +76 -0
  85. package/src/rollup/ValidatorWalletCreator.sol +43 -0
  86. package/src/state/Deserialize.sol +321 -0
  87. package/src/state/GlobalState.sol +44 -0
  88. package/src/state/Instructions.sol +159 -0
  89. package/src/state/Machine.sol +65 -0
  90. package/src/state/MerkleProof.sol +99 -0
  91. package/src/state/Module.sol +33 -0
  92. package/src/state/ModuleMemory.sol +42 -0
  93. package/src/state/PcArray.sol +45 -0
  94. package/src/state/PcStack.sol +32 -0
  95. package/src/state/StackFrame.sol +63 -0
  96. package/src/state/Value.sol +65 -0
  97. package/src/state/ValueArray.sol +47 -0
  98. package/src/state/ValueStack.sol +39 -0
  99. package/src/test-helpers/CryptographyPrimitivesTester.sol +27 -0
  100. package/src/test-helpers/MessageTester.sol +34 -0
  101. package/src/test-helpers/ValueArrayTester.sol +34 -0
  102. package/test/contract/arbRollup.spec.ts +869 -0
  103. package/test/contract/common/challengeLib.ts +43 -0
  104. package/test/contract/common/globalStateLib.ts +17 -0
  105. package/test/contract/common/rolluplib.ts +259 -0
  106. package/test/contract/cryptographyPrimitives.spec.ts +82 -0
  107. package/test/contract/sequencerInboxForceInclude.spec.ts +516 -0
  108. package/test/contract/utils.ts +40 -0
  109. package/test/prover/hash-proofs.ts +75 -0
  110. package/test/prover/one-step-proof.ts +93 -0
  111. package/test/prover/proofs/.gitkeep +0 -0
  112. package/test/prover/value-arrays.ts +11 -0
  113. package/tsconfig.json +13 -0
@@ -0,0 +1,627 @@
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 "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
8
+
9
+ import "./Node.sol";
10
+ import "./IRollupCore.sol";
11
+ import "./RollupLib.sol";
12
+ import "./RollupEventBridge.sol";
13
+ import "./IRollupCore.sol";
14
+
15
+ import "../challenge/IChallengeManager.sol";
16
+
17
+ import "../bridge/ISequencerInbox.sol";
18
+ import "../bridge/IBridge.sol";
19
+ import "../bridge/IOutbox.sol";
20
+
21
+ import {NO_CHAL_INDEX} from "../libraries/Constants.sol";
22
+
23
+ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
24
+ using NodeLib for Node;
25
+ using GlobalStateLib for GlobalState;
26
+
27
+ // Rollup Config
28
+ uint64 public confirmPeriodBlocks;
29
+ uint64 public extraChallengeTimeBlocks;
30
+ uint256 public chainId;
31
+ uint256 public baseStake;
32
+ bytes32 public wasmModuleRoot;
33
+
34
+ IBridge public delayedBridge;
35
+ ISequencerInbox public sequencerBridge;
36
+ IOutbox public outbox;
37
+ RollupEventBridge public rollupEventBridge;
38
+ IChallengeManager public override challengeManager;
39
+ // when a staker loses a challenge, half of their funds get escrowed in this address
40
+ address public loserStakeEscrow;
41
+ address public stakeToken;
42
+ uint256 public minimumAssertionPeriod;
43
+
44
+ mapping(address => bool) public isValidator;
45
+
46
+ // Stakers become Zombies after losing a challenge
47
+ struct Zombie {
48
+ address stakerAddress;
49
+ uint64 latestStakedNode;
50
+ }
51
+
52
+ uint64 private _latestConfirmed;
53
+ uint64 private _firstUnresolvedNode;
54
+ uint64 private _latestNodeCreated;
55
+ uint64 private _lastStakeBlock;
56
+ mapping(uint64 => Node) private _nodes;
57
+ mapping(uint64 => mapping(address => bool)) private _nodeStakers;
58
+
59
+ address[] private _stakerList;
60
+ mapping(address => Staker) public _stakerMap;
61
+
62
+ Zombie[] private _zombies;
63
+
64
+ mapping(address => uint256) private _withdrawableFunds;
65
+ uint256 public totalWithdrawableFunds;
66
+
67
+ // The node number of the initial node
68
+ uint64 internal constant GENESIS_NODE = 0;
69
+
70
+ /**
71
+ * @notice Get a storage reference to the Node for the given node index
72
+ * @param nodeNum Index of the node
73
+ * @return Node struct
74
+ */
75
+ function getNodeStorage(uint64 nodeNum) internal view returns (Node storage) {
76
+ return _nodes[nodeNum];
77
+ }
78
+
79
+ /**
80
+ * @notice Get the Node for the given index.
81
+ */
82
+ function getNode(uint64 nodeNum) public view override returns (Node memory) {
83
+ return getNodeStorage(nodeNum);
84
+ }
85
+
86
+ /**
87
+ * @notice Check if the specified node has been staked on by the provided staker.
88
+ * Only accurate at the latest confirmed node and afterwards.
89
+ */
90
+ function nodeHasStaker(uint64 nodeNum, address staker) public view override returns (bool) {
91
+ return _nodeStakers[nodeNum][staker];
92
+ }
93
+
94
+ /**
95
+ * @notice Get the address of the staker at the given index
96
+ * @param stakerNum Index of the staker
97
+ * @return Address of the staker
98
+ */
99
+ function getStakerAddress(uint64 stakerNum) external view override returns (address) {
100
+ return _stakerList[stakerNum];
101
+ }
102
+
103
+ /**
104
+ * @notice Check whether the given staker is staked
105
+ * @param staker Staker address to check
106
+ * @return True or False for whether the staker was staked
107
+ */
108
+ function isStaked(address staker) public view override returns (bool) {
109
+ return _stakerMap[staker].isStaked;
110
+ }
111
+
112
+ /**
113
+ * @notice Check whether the given staker is staked on the latest confirmed node,
114
+ * which includes if the staker is staked on a descendent of the latest confirmed node.
115
+ * @param staker Staker address to check
116
+ * @return True or False for whether the staker was staked
117
+ */
118
+ function isStakedOnLatestConfirmed(address staker) public view returns (bool) {
119
+ return _stakerMap[staker].isStaked && nodeHasStaker(_latestConfirmed, staker);
120
+ }
121
+
122
+ /**
123
+ * @notice Get the latest staked node of the given staker
124
+ * @param staker Staker address to lookup
125
+ * @return Latest node staked of the staker
126
+ */
127
+ function latestStakedNode(address staker) public view override returns (uint64) {
128
+ return _stakerMap[staker].latestStakedNode;
129
+ }
130
+
131
+ /**
132
+ * @notice Get the current challenge of the given staker
133
+ * @param staker Staker address to lookup
134
+ * @return Current challenge of the staker
135
+ */
136
+ function currentChallenge(address staker) public view override returns (uint64) {
137
+ return _stakerMap[staker].currentChallenge;
138
+ }
139
+
140
+ /**
141
+ * @notice Get the amount staked of the given staker
142
+ * @param staker Staker address to lookup
143
+ * @return Amount staked of the staker
144
+ */
145
+ function amountStaked(address staker) public view override returns (uint256) {
146
+ return _stakerMap[staker].amountStaked;
147
+ }
148
+
149
+ /**
150
+ * @notice Retrieves stored information about a requested staker
151
+ * @param staker Staker address to retrieve
152
+ * @return A structure with information about the requested staker
153
+ */
154
+ function getStaker(address staker) external view override returns (Staker memory) {
155
+ return _stakerMap[staker];
156
+ }
157
+
158
+ /**
159
+ * @notice Get the original staker address of the zombie at the given index
160
+ * @param zombieNum Index of the zombie to lookup
161
+ * @return Original staker address of the zombie
162
+ */
163
+ function zombieAddress(uint256 zombieNum) public view override returns (address) {
164
+ return _zombies[zombieNum].stakerAddress;
165
+ }
166
+
167
+ /**
168
+ * @notice Get Latest node that the given zombie at the given index is staked on
169
+ * @param zombieNum Index of the zombie to lookup
170
+ * @return Latest node that the given zombie is staked on
171
+ */
172
+ function zombieLatestStakedNode(uint256 zombieNum) public view override returns (uint64) {
173
+ return _zombies[zombieNum].latestStakedNode;
174
+ }
175
+
176
+ /**
177
+ * @notice Retrieves stored information about a requested zombie
178
+ * @param zombieNum Index of the zombie to lookup
179
+ * @return A structure with information about the requested staker
180
+ */
181
+ function getZombieStorage(uint256 zombieNum) internal view returns (Zombie storage) {
182
+ return _zombies[zombieNum];
183
+ }
184
+
185
+ /// @return Current number of un-removed zombies
186
+ function zombieCount() public view override returns (uint256) {
187
+ return _zombies.length;
188
+ }
189
+
190
+ function isZombie(address staker) public view override returns (bool) {
191
+ for (uint256 i = 0; i < _zombies.length; i++) {
192
+ if (staker == _zombies[i].stakerAddress) {
193
+ return true;
194
+ }
195
+ }
196
+ return false;
197
+ }
198
+
199
+ /**
200
+ * @notice Get the amount of funds withdrawable by the given address
201
+ * @param user Address to check the funds of
202
+ * @return Amount of funds withdrawable by user
203
+ */
204
+ function withdrawableFunds(address user) external view override returns (uint256) {
205
+ return _withdrawableFunds[user];
206
+ }
207
+
208
+ /**
209
+ * @return Index of the first unresolved node
210
+ * @dev If all nodes have been resolved, this will be latestNodeCreated + 1
211
+ */
212
+ function firstUnresolvedNode() public view override returns (uint64) {
213
+ return _firstUnresolvedNode;
214
+ }
215
+
216
+ /// @return Index of the latest confirmed node
217
+ function latestConfirmed() public view override returns (uint64) {
218
+ return _latestConfirmed;
219
+ }
220
+
221
+ /// @return Index of the latest rollup node created
222
+ function latestNodeCreated() public view override returns (uint64) {
223
+ return _latestNodeCreated;
224
+ }
225
+
226
+ /// @return Ethereum block that the most recent stake was created
227
+ function lastStakeBlock() external view override returns (uint64) {
228
+ return _lastStakeBlock;
229
+ }
230
+
231
+ /// @return Number of active stakers currently staked
232
+ function stakerCount() public view override returns (uint64) {
233
+ return uint64(_stakerList.length);
234
+ }
235
+
236
+ /**
237
+ * @notice Initialize the core with an initial node
238
+ * @param initialNode Initial node to start the chain with
239
+ */
240
+ function initializeCore(Node memory initialNode) internal {
241
+ __Pausable_init();
242
+ _nodes[GENESIS_NODE] = initialNode;
243
+ _firstUnresolvedNode = GENESIS_NODE + 1;
244
+ }
245
+
246
+ /**
247
+ * @notice React to a new node being created by storing it an incrementing the latest node counter
248
+ * @param node Node that was newly created
249
+ */
250
+ function nodeCreated(Node memory node) internal {
251
+ _latestNodeCreated++;
252
+ _nodes[_latestNodeCreated] = node;
253
+ }
254
+
255
+ /// @notice Reject the next unresolved node
256
+ function _rejectNextNode() internal {
257
+ _firstUnresolvedNode++;
258
+ }
259
+
260
+ function confirmNode(
261
+ uint64 nodeNum,
262
+ bytes32 blockHash,
263
+ bytes32 sendRoot
264
+ ) internal {
265
+ Node storage node = getNodeStorage(nodeNum);
266
+ // Authenticate data against node's confirm data pre-image
267
+ require(node.confirmData == RollupLib.confirmHash(blockHash, sendRoot), "CONFIRM_DATA");
268
+
269
+ // trusted external call to outbox
270
+ outbox.updateSendRoot(sendRoot, blockHash);
271
+
272
+ _latestConfirmed = nodeNum;
273
+ _firstUnresolvedNode = nodeNum + 1;
274
+
275
+ emit NodeConfirmed(nodeNum, blockHash, sendRoot);
276
+ }
277
+
278
+ /**
279
+ * @notice Create a new stake at latest confirmed node
280
+ * @param stakerAddress Address of the new staker
281
+ * @param depositAmount Stake amount of the new staker
282
+ */
283
+ function createNewStake(address stakerAddress, uint256 depositAmount) internal {
284
+ uint64 stakerIndex = uint64(_stakerList.length);
285
+ _stakerList.push(stakerAddress);
286
+ _stakerMap[stakerAddress] = Staker(
287
+ depositAmount,
288
+ stakerIndex,
289
+ _latestConfirmed,
290
+ NO_CHAL_INDEX, // new staker is not in challenge
291
+ true
292
+ );
293
+ _nodeStakers[_latestConfirmed][stakerAddress] = true;
294
+ _lastStakeBlock = uint64(block.number);
295
+ emit UserStakeUpdated(stakerAddress, 0, depositAmount);
296
+ }
297
+
298
+ /**
299
+ * @notice Check to see whether the two stakers are in the same challenge
300
+ * @param stakerAddress1 Address of the first staker
301
+ * @param stakerAddress2 Address of the second staker
302
+ * @return Address of the challenge that the two stakers are in
303
+ */
304
+ function inChallenge(address stakerAddress1, address stakerAddress2)
305
+ internal
306
+ view
307
+ returns (uint64)
308
+ {
309
+ Staker storage staker1 = _stakerMap[stakerAddress1];
310
+ Staker storage staker2 = _stakerMap[stakerAddress2];
311
+ uint64 challenge = staker1.currentChallenge;
312
+ require(challenge != NO_CHAL_INDEX, "NO_CHAL");
313
+ require(challenge == staker2.currentChallenge, "DIFF_IN_CHAL");
314
+ return challenge;
315
+ }
316
+
317
+ /**
318
+ * @notice Make the given staker as not being in a challenge
319
+ * @param stakerAddress Address of the staker to remove from a challenge
320
+ */
321
+ function clearChallenge(address stakerAddress) internal {
322
+ Staker storage staker = _stakerMap[stakerAddress];
323
+ staker.currentChallenge = NO_CHAL_INDEX;
324
+ }
325
+
326
+ /**
327
+ * @notice Mark both the given stakers as engaged in the challenge
328
+ * @param staker1 Address of the first staker
329
+ * @param staker2 Address of the second staker
330
+ * @param challenge Address of the challenge both stakers are now in
331
+ */
332
+ function challengeStarted(
333
+ address staker1,
334
+ address staker2,
335
+ uint64 challenge
336
+ ) internal {
337
+ _stakerMap[staker1].currentChallenge = challenge;
338
+ _stakerMap[staker2].currentChallenge = challenge;
339
+ }
340
+
341
+ /**
342
+ * @notice Add to the stake of the given staker by the given amount
343
+ * @param stakerAddress Address of the staker to increase the stake of
344
+ * @param amountAdded Amount of stake to add to the staker
345
+ */
346
+ function increaseStakeBy(address stakerAddress, uint256 amountAdded) internal {
347
+ Staker storage staker = _stakerMap[stakerAddress];
348
+ uint256 initialStaked = staker.amountStaked;
349
+ uint256 finalStaked = initialStaked + amountAdded;
350
+ staker.amountStaked = finalStaked;
351
+ emit UserStakeUpdated(stakerAddress, initialStaked, finalStaked);
352
+ }
353
+
354
+ /**
355
+ * @notice Reduce the stake of the given staker to the given target
356
+ * @param stakerAddress Address of the staker to reduce the stake of
357
+ * @param target Amount of stake to leave with the staker
358
+ * @return Amount of value released from the stake
359
+ */
360
+ function reduceStakeTo(address stakerAddress, uint256 target) internal returns (uint256) {
361
+ Staker storage staker = _stakerMap[stakerAddress];
362
+ uint256 current = staker.amountStaked;
363
+ require(target <= current, "TOO_LITTLE_STAKE");
364
+ uint256 amountWithdrawn = current - target;
365
+ staker.amountStaked = target;
366
+ increaseWithdrawableFunds(stakerAddress, amountWithdrawn);
367
+ emit UserStakeUpdated(stakerAddress, current, target);
368
+ return amountWithdrawn;
369
+ }
370
+
371
+ /**
372
+ * @notice Remove the given staker and turn them into a zombie
373
+ * @param stakerAddress Address of the staker to remove
374
+ */
375
+ function turnIntoZombie(address stakerAddress) internal {
376
+ Staker storage staker = _stakerMap[stakerAddress];
377
+ _zombies.push(Zombie(stakerAddress, staker.latestStakedNode));
378
+ deleteStaker(stakerAddress);
379
+ }
380
+
381
+ /**
382
+ * @notice Update the latest staked node of the zombie at the given index
383
+ * @param zombieNum Index of the zombie to move
384
+ * @param latest New latest node the zombie is staked on
385
+ */
386
+ function zombieUpdateLatestStakedNode(uint256 zombieNum, uint64 latest) internal {
387
+ _zombies[zombieNum].latestStakedNode = latest;
388
+ }
389
+
390
+ /**
391
+ * @notice Remove the zombie at the given index
392
+ * @param zombieNum Index of the zombie to remove
393
+ */
394
+ function removeZombie(uint256 zombieNum) internal {
395
+ _zombies[zombieNum] = _zombies[_zombies.length - 1];
396
+ _zombies.pop();
397
+ }
398
+
399
+ /**
400
+ * @notice Mark the given staker as staked on this node
401
+ * @param staker Address of the staker to mark
402
+ */
403
+ function addStaker(uint64 nodeNum, address staker) internal {
404
+ require(!_nodeStakers[nodeNum][staker], "ALREADY_STAKED");
405
+ _nodeStakers[nodeNum][staker] = true;
406
+ Node storage node = getNodeStorage(nodeNum);
407
+ require(node.deadlineBlock != 0, "NO_NODE");
408
+
409
+ uint64 prevCount = node.stakerCount;
410
+ node.stakerCount = prevCount + 1;
411
+
412
+ if (nodeNum > GENESIS_NODE) {
413
+ Node storage parent = getNodeStorage(node.prevNum);
414
+ parent.childStakerCount++;
415
+ if (prevCount == 0) {
416
+ parent.newChildConfirmDeadline(uint64(block.number) + confirmPeriodBlocks);
417
+ }
418
+ }
419
+ }
420
+
421
+ /**
422
+ * @notice Remove the given staker from this node
423
+ * @param staker Address of the staker to remove
424
+ */
425
+ function removeStaker(uint64 nodeNum, address staker) internal {
426
+ require(_nodeStakers[nodeNum][staker], "NOT_STAKED");
427
+ _nodeStakers[nodeNum][staker] = false;
428
+
429
+ Node storage node = getNodeStorage(nodeNum);
430
+ node.stakerCount--;
431
+
432
+ if (nodeNum > GENESIS_NODE) {
433
+ getNodeStorage(node.prevNum).childStakerCount--;
434
+ }
435
+ }
436
+
437
+ /**
438
+ * @notice Remove the given staker and return their stake
439
+ * This should not be called if the staker is staked on a descendent of the latest confirmed node
440
+ * @param stakerAddress Address of the staker withdrawing their stake
441
+ */
442
+ function withdrawStaker(address stakerAddress) internal {
443
+ Staker storage staker = _stakerMap[stakerAddress];
444
+ uint64 latestConfirmedNum = latestConfirmed();
445
+ if (nodeHasStaker(latestConfirmedNum, stakerAddress)) {
446
+ // Withdrawing a staker whose latest staked node isn't resolved should be impossible
447
+ assert(staker.latestStakedNode == latestConfirmedNum);
448
+ removeStaker(latestConfirmedNum, stakerAddress);
449
+ }
450
+ uint256 initialStaked = staker.amountStaked;
451
+ increaseWithdrawableFunds(stakerAddress, initialStaked);
452
+ deleteStaker(stakerAddress);
453
+ emit UserStakeUpdated(stakerAddress, initialStaked, 0);
454
+ }
455
+
456
+ /**
457
+ * @notice Advance the given staker to the given node
458
+ * @param stakerAddress Address of the staker adding their stake
459
+ * @param nodeNum Index of the node to stake on
460
+ */
461
+ function stakeOnNode(address stakerAddress, uint64 nodeNum) internal {
462
+ Staker storage staker = _stakerMap[stakerAddress];
463
+ addStaker(nodeNum, stakerAddress);
464
+ staker.latestStakedNode = nodeNum;
465
+ }
466
+
467
+ /**
468
+ * @notice Clear the withdrawable funds for the given address
469
+ * @param account Address of the account to remove funds from
470
+ * @return Amount of funds removed from account
471
+ */
472
+ function withdrawFunds(address account) internal returns (uint256) {
473
+ uint256 amount = _withdrawableFunds[account];
474
+ _withdrawableFunds[account] = 0;
475
+ totalWithdrawableFunds -= amount;
476
+ emit UserWithdrawableFundsUpdated(account, amount, 0);
477
+ return amount;
478
+ }
479
+
480
+ /**
481
+ * @notice Increase the withdrawable funds for the given address
482
+ * @param account Address of the account to add withdrawable funds to
483
+ */
484
+ function increaseWithdrawableFunds(address account, uint256 amount) internal {
485
+ uint256 initialWithdrawable = _withdrawableFunds[account];
486
+ uint256 finalWithdrawable = initialWithdrawable + amount;
487
+ _withdrawableFunds[account] = finalWithdrawable;
488
+ totalWithdrawableFunds += amount;
489
+ emit UserWithdrawableFundsUpdated(account, initialWithdrawable, finalWithdrawable);
490
+ }
491
+
492
+ /**
493
+ * @notice Remove the given staker
494
+ * @param stakerAddress Address of the staker to remove
495
+ */
496
+ function deleteStaker(address stakerAddress) private {
497
+ Staker storage staker = _stakerMap[stakerAddress];
498
+ uint64 stakerIndex = staker.index;
499
+ _stakerList[stakerIndex] = _stakerList[_stakerList.length - 1];
500
+ _stakerMap[_stakerList[stakerIndex]].index = stakerIndex;
501
+ _stakerList.pop();
502
+ delete _stakerMap[stakerAddress];
503
+ }
504
+
505
+ struct StakeOnNewNodeFrame {
506
+ uint256 currentInboxSize;
507
+ Node node;
508
+ bytes32 executionHash;
509
+ Node prevNode;
510
+ bytes32 lastHash;
511
+ bool hasSibling;
512
+ uint64 deadlineBlock;
513
+ bytes32 sequencerBatchAcc;
514
+ }
515
+
516
+ function createNewNode(
517
+ RollupLib.Assertion calldata assertion,
518
+ uint64 prevNodeNum,
519
+ uint256 prevNodeInboxMaxCount,
520
+ bytes32 expectedNodeHash
521
+ ) internal returns (bytes32 newNodeHash) {
522
+ require(
523
+ assertion.afterState.machineStatus == MachineStatus.FINISHED ||
524
+ assertion.afterState.machineStatus == MachineStatus.ERRORED,
525
+ "BAD_AFTER_STATUS"
526
+ );
527
+
528
+ StakeOnNewNodeFrame memory memoryFrame;
529
+ {
530
+ // validate data
531
+ memoryFrame.prevNode = getNode(prevNodeNum);
532
+ memoryFrame.currentInboxSize = sequencerBridge.batchCount();
533
+
534
+ // Make sure the previous state is correct against the node being built on
535
+ require(
536
+ RollupLib.stateHash(assertion.beforeState, prevNodeInboxMaxCount) ==
537
+ memoryFrame.prevNode.stateHash,
538
+ "PREV_STATE_HASH"
539
+ );
540
+
541
+ // Ensure that the assertion doesn't read past the end of the current inbox
542
+ uint64 afterInboxCount = assertion.afterState.globalState.getInboxPosition();
543
+ uint64 prevInboxPosition = assertion.beforeState.globalState.getInboxPosition();
544
+ require(afterInboxCount >= prevInboxPosition, "INBOX_BACKWARDS");
545
+ if (afterInboxCount == prevInboxPosition) {
546
+ require(
547
+ assertion.afterState.globalState.getPositionInMessage() >=
548
+ assertion.afterState.globalState.getPositionInMessage(),
549
+ "INBOX_POS_IN_MSG_BACKWARDS"
550
+ );
551
+ }
552
+ // See validator/assertion.go ExecutionState RequiredBatches() for reasoning
553
+ if (
554
+ assertion.afterState.machineStatus == MachineStatus.ERRORED ||
555
+ assertion.afterState.globalState.getPositionInMessage() > 0
556
+ ) {
557
+ // The current inbox message was read
558
+ afterInboxCount++;
559
+ }
560
+ require(afterInboxCount <= memoryFrame.currentInboxSize, "INBOX_PAST_END");
561
+ // This gives replay protection against the state of the inbox
562
+ if (afterInboxCount > 0) {
563
+ memoryFrame.sequencerBatchAcc = sequencerBridge.inboxAccs(afterInboxCount - 1);
564
+ }
565
+ }
566
+
567
+ {
568
+ memoryFrame.executionHash = RollupLib.executionHash(assertion);
569
+
570
+ memoryFrame.deadlineBlock = uint64(block.number) + confirmPeriodBlocks;
571
+
572
+ memoryFrame.hasSibling = memoryFrame.prevNode.latestChildNumber > 0;
573
+ // here we don't use ternacy operator to remain compatible with slither
574
+ if (memoryFrame.hasSibling) {
575
+ memoryFrame.lastHash = getNodeStorage(memoryFrame.prevNode.latestChildNumber)
576
+ .nodeHash;
577
+ } else {
578
+ memoryFrame.lastHash = memoryFrame.prevNode.nodeHash;
579
+ }
580
+
581
+ newNodeHash = RollupLib.nodeHash(
582
+ memoryFrame.hasSibling,
583
+ memoryFrame.lastHash,
584
+ memoryFrame.executionHash,
585
+ memoryFrame.sequencerBatchAcc
586
+ );
587
+ require(newNodeHash == expectedNodeHash, "UNEXPECTED_NODE_HASH");
588
+
589
+ memoryFrame.node = NodeLib.createNode(
590
+ RollupLib.stateHash(assertion.afterState, memoryFrame.currentInboxSize),
591
+ RollupLib.challengeRootHash(
592
+ memoryFrame.executionHash,
593
+ block.number,
594
+ wasmModuleRoot
595
+ ),
596
+ RollupLib.confirmHash(assertion),
597
+ prevNodeNum,
598
+ memoryFrame.deadlineBlock,
599
+ newNodeHash
600
+ );
601
+ }
602
+
603
+ {
604
+ uint64 nodeNum = latestNodeCreated() + 1;
605
+
606
+ // Fetch a storage reference to prevNode since we copied our other one into memory
607
+ // and we don't have enough stack available to keep to keep the previous storage reference around
608
+ Node storage prevNode = getNodeStorage(prevNodeNum);
609
+ prevNode.childCreated(nodeNum);
610
+
611
+ nodeCreated(memoryFrame.node);
612
+ }
613
+
614
+ emit NodeCreated(
615
+ latestNodeCreated(),
616
+ memoryFrame.prevNode.nodeHash,
617
+ newNodeHash,
618
+ memoryFrame.executionHash,
619
+ assertion,
620
+ memoryFrame.sequencerBatchAcc,
621
+ wasmModuleRoot,
622
+ memoryFrame.currentInboxSize
623
+ );
624
+
625
+ return newNodeHash;
626
+ }
627
+ }