@arbitrum/nitro-contracts 1.0.0-beta.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }