@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.
- package/.prettierrc +5 -0
- package/.solhint.json +18 -0
- package/deploy/BridgeStubCreator.js +10 -0
- package/deploy/HashProofHelper.js +13 -0
- package/deploy/InboxStubCreator.js +17 -0
- package/deploy/OneStepProofEntryCreator.js +19 -0
- package/deploy/OneStepProver0Creator.js +14 -0
- package/deploy/OneStepProverHostIoCreator.js +14 -0
- package/deploy/OneStepProverMathCreator.js +14 -0
- package/deploy/OneStepProverMemoryCreator.js +14 -0
- package/deploy/SequencerInboxStubCreator.js +13 -0
- package/deploy/ValueArrayTesterCreator.js +13 -0
- package/hardhat.config.ts +47 -0
- package/hardhat.prod-config.js +18 -0
- package/package.json +49 -0
- package/scripts/build.bash +5 -0
- package/src/bridge/Bridge.sol +168 -0
- package/src/bridge/IBridge.sol +68 -0
- package/src/bridge/IInbox.sol +80 -0
- package/src/bridge/IMessageProvider.sol +11 -0
- package/src/bridge/IOutbox.sol +52 -0
- package/src/bridge/ISequencerInbox.sol +85 -0
- package/src/bridge/Inbox.sol +414 -0
- package/src/bridge/Messages.sol +38 -0
- package/src/bridge/Outbox.sol +188 -0
- package/src/bridge/SequencerInbox.sol +274 -0
- package/src/challenge/ChallengeLib.sol +135 -0
- package/src/challenge/ChallengeManager.sol +367 -0
- package/src/challenge/IChallengeManager.sol +75 -0
- package/src/challenge/IChallengeResultReceiver.sol +13 -0
- package/src/libraries/AddressAliasHelper.sol +29 -0
- package/src/libraries/AdminFallbackProxy.sol +153 -0
- package/src/libraries/ArbitrumProxy.sol +20 -0
- package/src/libraries/Constants.sol +10 -0
- package/src/libraries/CryptographyPrimitives.sol +323 -0
- package/src/libraries/DelegateCallAware.sol +44 -0
- package/src/libraries/Error.sol +38 -0
- package/src/libraries/IGasRefunder.sol +35 -0
- package/src/libraries/MerkleLib.sol +46 -0
- package/src/libraries/MessageTypes.sol +14 -0
- package/src/libraries/SecondaryLogicUUPSUpgradeable.sol +58 -0
- package/src/libraries/UUPSNotUpgradeable.sol +56 -0
- package/src/mocks/BridgeStub.sol +115 -0
- package/src/mocks/Counter.sol +13 -0
- package/src/mocks/ExecutionManager.sol +41 -0
- package/src/mocks/InboxStub.sol +131 -0
- package/src/mocks/MockResultReceiver.sol +59 -0
- package/src/mocks/SequencerInboxStub.sol +42 -0
- package/src/mocks/SimpleProxy.sol +19 -0
- package/src/node-interface/NodeInterface.sol +50 -0
- package/src/osp/HashProofHelper.sol +154 -0
- package/src/osp/IOneStepProofEntry.sol +20 -0
- package/src/osp/IOneStepProver.sol +27 -0
- package/src/osp/OneStepProofEntry.sol +129 -0
- package/src/osp/OneStepProver0.sol +566 -0
- package/src/osp/OneStepProverHostIo.sol +357 -0
- package/src/osp/OneStepProverMath.sol +514 -0
- package/src/osp/OneStepProverMemory.sol +313 -0
- package/src/precompiles/ArbAddressTable.sol +60 -0
- package/src/precompiles/ArbAggregator.sol +62 -0
- package/src/precompiles/ArbBLS.sol +53 -0
- package/src/precompiles/ArbDebug.sol +39 -0
- package/src/precompiles/ArbFunctionTable.sol +29 -0
- package/src/precompiles/ArbGasInfo.sol +121 -0
- package/src/precompiles/ArbInfo.sol +15 -0
- package/src/precompiles/ArbOwner.sol +65 -0
- package/src/precompiles/ArbOwnerPublic.sol +18 -0
- package/src/precompiles/ArbRetryableTx.sol +89 -0
- package/src/precompiles/ArbStatistics.sol +29 -0
- package/src/precompiles/ArbSys.sol +134 -0
- package/src/precompiles/ArbosActs.sol +41 -0
- package/src/precompiles/ArbosTest.sol +14 -0
- package/src/rollup/BridgeCreator.sol +120 -0
- package/src/rollup/IRollupCore.sol +152 -0
- package/src/rollup/IRollupLogic.sol +183 -0
- package/src/rollup/Node.sol +99 -0
- package/src/rollup/RollupAdminLogic.sol +322 -0
- package/src/rollup/RollupCore.sol +627 -0
- package/src/rollup/RollupCreator.sol +133 -0
- package/src/rollup/RollupEventBridge.sol +46 -0
- package/src/rollup/RollupLib.sol +135 -0
- package/src/rollup/RollupUserLogic.sol +712 -0
- package/src/rollup/ValidatorUtils.sol +243 -0
- package/src/rollup/ValidatorWallet.sol +76 -0
- package/src/rollup/ValidatorWalletCreator.sol +43 -0
- package/src/state/Deserialize.sol +321 -0
- package/src/state/GlobalState.sol +44 -0
- package/src/state/Instructions.sol +159 -0
- package/src/state/Machine.sol +65 -0
- package/src/state/MerkleProof.sol +99 -0
- package/src/state/Module.sol +33 -0
- package/src/state/ModuleMemory.sol +42 -0
- package/src/state/PcArray.sol +45 -0
- package/src/state/PcStack.sol +32 -0
- package/src/state/StackFrame.sol +63 -0
- package/src/state/Value.sol +65 -0
- package/src/state/ValueArray.sol +47 -0
- package/src/state/ValueStack.sol +39 -0
- package/src/test-helpers/CryptographyPrimitivesTester.sol +27 -0
- package/src/test-helpers/MessageTester.sol +34 -0
- package/src/test-helpers/ValueArrayTester.sol +34 -0
- package/test/contract/arbRollup.spec.ts +869 -0
- package/test/contract/common/challengeLib.ts +43 -0
- package/test/contract/common/globalStateLib.ts +17 -0
- package/test/contract/common/rolluplib.ts +259 -0
- package/test/contract/cryptographyPrimitives.spec.ts +82 -0
- package/test/contract/sequencerInboxForceInclude.spec.ts +516 -0
- package/test/contract/utils.ts +40 -0
- package/test/prover/hash-proofs.ts +75 -0
- package/test/prover/one-step-proof.ts +93 -0
- package/test/prover/proofs/.gitkeep +0 -0
- package/test/prover/value-arrays.ts +11 -0
- package/tsconfig.json +13 -0
|
@@ -0,0 +1,243 @@
|
|
|
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
|
+
pragma experimental ABIEncoderV2;
|
|
8
|
+
|
|
9
|
+
import "../rollup/IRollupCore.sol";
|
|
10
|
+
import "../rollup/IRollupLogic.sol";
|
|
11
|
+
import "../challenge/IChallengeManager.sol";
|
|
12
|
+
|
|
13
|
+
import {NO_CHAL_INDEX} from "../libraries/Constants.sol";
|
|
14
|
+
|
|
15
|
+
contract ValidatorUtils {
|
|
16
|
+
using NodeLib for Node;
|
|
17
|
+
|
|
18
|
+
enum ConfirmType {
|
|
19
|
+
NONE,
|
|
20
|
+
VALID,
|
|
21
|
+
INVALID
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
enum NodeConflictType {
|
|
25
|
+
NONE,
|
|
26
|
+
FOUND,
|
|
27
|
+
INDETERMINATE,
|
|
28
|
+
INCOMPLETE
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
struct NodeConflict {
|
|
32
|
+
NodeConflictType ty;
|
|
33
|
+
uint64 node1;
|
|
34
|
+
uint64 node2;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function findStakerConflict(
|
|
38
|
+
IRollupCore rollup,
|
|
39
|
+
address staker1,
|
|
40
|
+
address staker2,
|
|
41
|
+
uint256 maxDepth
|
|
42
|
+
) external view returns (NodeConflict memory) {
|
|
43
|
+
uint64 staker1NodeNum = rollup.latestStakedNode(staker1);
|
|
44
|
+
uint64 staker2NodeNum = rollup.latestStakedNode(staker2);
|
|
45
|
+
return findNodeConflict(rollup, staker1NodeNum, staker2NodeNum, maxDepth);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function checkDecidableNextNode(IRollupUserAbs rollup) external view returns (ConfirmType) {
|
|
49
|
+
try ValidatorUtils(address(this)).requireConfirmable(rollup) {
|
|
50
|
+
return ConfirmType.VALID;
|
|
51
|
+
} catch {}
|
|
52
|
+
|
|
53
|
+
try ValidatorUtils(address(this)).requireRejectable(rollup) {
|
|
54
|
+
return ConfirmType.INVALID;
|
|
55
|
+
} catch {
|
|
56
|
+
return ConfirmType.NONE;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function requireRejectable(IRollupCore rollup) external view {
|
|
61
|
+
IRollupUser(address(rollup)).requireUnresolvedExists();
|
|
62
|
+
uint64 firstUnresolvedNode = rollup.firstUnresolvedNode();
|
|
63
|
+
Node memory node = rollup.getNode(firstUnresolvedNode);
|
|
64
|
+
if (node.prevNum == rollup.latestConfirmed()) {
|
|
65
|
+
// Verify the block's deadline has passed
|
|
66
|
+
require(block.number >= node.deadlineBlock, "BEFORE_DEADLINE");
|
|
67
|
+
rollup.getNode(node.prevNum).requirePastChildConfirmDeadline();
|
|
68
|
+
|
|
69
|
+
// Verify that no staker is staked on this node
|
|
70
|
+
require(
|
|
71
|
+
node.stakerCount ==
|
|
72
|
+
IRollupUser(address(rollup)).countStakedZombies(firstUnresolvedNode),
|
|
73
|
+
"HAS_STAKERS"
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function requireConfirmable(IRollupUserAbs rollup) external view {
|
|
79
|
+
rollup.requireUnresolvedExists();
|
|
80
|
+
|
|
81
|
+
uint256 stakerCount = rollup.stakerCount();
|
|
82
|
+
// There is at least one non-zombie staker
|
|
83
|
+
require(stakerCount > 0, "NO_STAKERS");
|
|
84
|
+
|
|
85
|
+
uint64 firstUnresolved = rollup.firstUnresolvedNode();
|
|
86
|
+
Node memory node = rollup.getNode(firstUnresolved);
|
|
87
|
+
|
|
88
|
+
// Verify the block's deadline has passed
|
|
89
|
+
node.requirePastDeadline();
|
|
90
|
+
|
|
91
|
+
// Check that prev is latest confirmed
|
|
92
|
+
assert(node.prevNum == rollup.latestConfirmed());
|
|
93
|
+
|
|
94
|
+
Node memory prevNode = rollup.getNode(node.prevNum);
|
|
95
|
+
prevNode.requirePastChildConfirmDeadline();
|
|
96
|
+
|
|
97
|
+
uint256 zombiesStakedOnOtherChildren = rollup.countZombiesStakedOnChildren(node.prevNum) -
|
|
98
|
+
rollup.countStakedZombies(firstUnresolved);
|
|
99
|
+
require(
|
|
100
|
+
prevNode.childStakerCount == node.stakerCount + zombiesStakedOnOtherChildren,
|
|
101
|
+
"NOT_ALL_STAKED"
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function refundableStakers(IRollupCore rollup) external view returns (address[] memory) {
|
|
106
|
+
uint256 stakerCount = rollup.stakerCount();
|
|
107
|
+
address[] memory stakers = new address[](stakerCount);
|
|
108
|
+
uint256 latestConfirmed = rollup.latestConfirmed();
|
|
109
|
+
uint256 index = 0;
|
|
110
|
+
for (uint64 i = 0; i < stakerCount; i++) {
|
|
111
|
+
address staker = rollup.getStakerAddress(i);
|
|
112
|
+
uint256 latestStakedNode = rollup.latestStakedNode(staker);
|
|
113
|
+
if (latestStakedNode <= latestConfirmed && rollup.currentChallenge(staker) == 0) {
|
|
114
|
+
stakers[index] = staker;
|
|
115
|
+
index++;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
assembly {
|
|
119
|
+
mstore(stakers, index)
|
|
120
|
+
}
|
|
121
|
+
return stakers;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function latestStaked(IRollupCore rollup, address staker)
|
|
125
|
+
external
|
|
126
|
+
view
|
|
127
|
+
returns (uint64, Node memory)
|
|
128
|
+
{
|
|
129
|
+
uint64 num = rollup.latestStakedNode(staker);
|
|
130
|
+
if (num == 0) {
|
|
131
|
+
num = rollup.latestConfirmed();
|
|
132
|
+
}
|
|
133
|
+
Node memory node = rollup.getNode(num);
|
|
134
|
+
return (num, node);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function stakedNodes(IRollupCore rollup, address staker)
|
|
138
|
+
external
|
|
139
|
+
view
|
|
140
|
+
returns (uint64[] memory)
|
|
141
|
+
{
|
|
142
|
+
uint64[] memory nodes = new uint64[](100000);
|
|
143
|
+
uint256 index = 0;
|
|
144
|
+
for (uint64 i = rollup.latestConfirmed(); i <= rollup.latestNodeCreated(); i++) {
|
|
145
|
+
if (rollup.nodeHasStaker(i, staker)) {
|
|
146
|
+
nodes[index] = i;
|
|
147
|
+
index++;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Shrink array down to real size
|
|
151
|
+
assembly {
|
|
152
|
+
mstore(nodes, index)
|
|
153
|
+
}
|
|
154
|
+
return nodes;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function findNodeConflict(
|
|
158
|
+
IRollupCore rollup,
|
|
159
|
+
uint64 node1,
|
|
160
|
+
uint64 node2,
|
|
161
|
+
uint256 maxDepth
|
|
162
|
+
) public view returns (NodeConflict memory) {
|
|
163
|
+
uint64 firstUnresolvedNode = rollup.firstUnresolvedNode();
|
|
164
|
+
uint64 node1Prev = rollup.getNode(node1).prevNum;
|
|
165
|
+
uint64 node2Prev = rollup.getNode(node2).prevNum;
|
|
166
|
+
|
|
167
|
+
for (uint256 i = 0; i < maxDepth; i++) {
|
|
168
|
+
if (node1 == node2) {
|
|
169
|
+
return NodeConflict(NodeConflictType.NONE, node1, node2);
|
|
170
|
+
}
|
|
171
|
+
if (node1Prev == node2Prev) {
|
|
172
|
+
return NodeConflict(NodeConflictType.FOUND, node1, node2);
|
|
173
|
+
}
|
|
174
|
+
if (node1Prev < firstUnresolvedNode && node2Prev < firstUnresolvedNode) {
|
|
175
|
+
return NodeConflict(NodeConflictType.INDETERMINATE, 0, 0);
|
|
176
|
+
}
|
|
177
|
+
if (node1Prev < node2Prev) {
|
|
178
|
+
node2 = node2Prev;
|
|
179
|
+
node2Prev = rollup.getNode(node2).prevNum;
|
|
180
|
+
} else {
|
|
181
|
+
node1 = node1Prev;
|
|
182
|
+
node1Prev = rollup.getNode(node1).prevNum;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return NodeConflict(NodeConflictType.INCOMPLETE, 0, 0);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function getStakers(
|
|
189
|
+
IRollupCore rollup,
|
|
190
|
+
uint64 startIndex,
|
|
191
|
+
uint64 max
|
|
192
|
+
) public view returns (address[] memory, bool hasMore) {
|
|
193
|
+
uint256 maxStakers = rollup.stakerCount();
|
|
194
|
+
if (startIndex + max <= maxStakers) {
|
|
195
|
+
maxStakers = startIndex + max;
|
|
196
|
+
hasMore = true;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
address[] memory stakers = new address[](maxStakers);
|
|
200
|
+
for (uint64 i = 0; i < maxStakers; i++) {
|
|
201
|
+
stakers[i] = rollup.getStakerAddress(startIndex + i);
|
|
202
|
+
}
|
|
203
|
+
return (stakers, hasMore);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function timedOutChallenges(
|
|
207
|
+
IRollupCore rollup,
|
|
208
|
+
uint64 startIndex,
|
|
209
|
+
uint64 max
|
|
210
|
+
) external view returns (uint64[] memory, bool hasMore) {
|
|
211
|
+
(address[] memory stakers, bool hasMoreStakers) = getStakers(rollup, startIndex, max);
|
|
212
|
+
uint64[] memory challenges = new uint64[](stakers.length);
|
|
213
|
+
uint256 index = 0;
|
|
214
|
+
IChallengeManager challengeManager = rollup.challengeManager();
|
|
215
|
+
for (uint256 i = 0; i < stakers.length; i++) {
|
|
216
|
+
address staker = stakers[i];
|
|
217
|
+
uint64 challengeIndex = rollup.currentChallenge(staker);
|
|
218
|
+
if (
|
|
219
|
+
challengeIndex != NO_CHAL_INDEX &&
|
|
220
|
+
challengeManager.isTimedOut(challengeIndex) &&
|
|
221
|
+
challengeManager.currentResponder(challengeIndex) == staker
|
|
222
|
+
) {
|
|
223
|
+
challenges[index++] = challengeIndex;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// Shrink array down to real size
|
|
227
|
+
assembly {
|
|
228
|
+
mstore(challenges, index)
|
|
229
|
+
}
|
|
230
|
+
return (challenges, hasMoreStakers);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Worst case runtime of O(depth), as it terminates if it switches paths.
|
|
234
|
+
function areUnresolvedNodesLinear(IRollupCore rollup) external view returns (bool) {
|
|
235
|
+
uint256 end = rollup.latestNodeCreated();
|
|
236
|
+
for (uint64 i = rollup.firstUnresolvedNode(); i <= end; i++) {
|
|
237
|
+
if (i > 0 && rollup.getNode(i).prevNum != i - 1) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
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 "./IRollupLogic.sol";
|
|
8
|
+
import "../challenge/IChallengeManager.sol";
|
|
9
|
+
import "../libraries/DelegateCallAware.sol";
|
|
10
|
+
import "@openzeppelin/contracts/utils/Address.sol";
|
|
11
|
+
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
|
12
|
+
|
|
13
|
+
contract ValidatorWallet is OwnableUpgradeable, DelegateCallAware {
|
|
14
|
+
using Address for address;
|
|
15
|
+
|
|
16
|
+
function initialize() external initializer onlyDelegated {
|
|
17
|
+
__Ownable_init();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function executeTransactions(
|
|
21
|
+
bytes[] calldata data,
|
|
22
|
+
address[] calldata destination,
|
|
23
|
+
uint256[] calldata amount
|
|
24
|
+
) external payable onlyOwner {
|
|
25
|
+
uint256 numTxes = data.length;
|
|
26
|
+
for (uint256 i = 0; i < numTxes; i++) {
|
|
27
|
+
if (data[i].length > 0) require(destination[i].isContract(), "NO_CODE_AT_ADDR");
|
|
28
|
+
// We use a low level call here to allow for contract and non-contract calls
|
|
29
|
+
// solhint-disable-next-line avoid-low-level-calls
|
|
30
|
+
(bool success, ) = address(destination[i]).call{value: amount[i]}(data[i]);
|
|
31
|
+
if (!success) {
|
|
32
|
+
assembly {
|
|
33
|
+
let ptr := mload(0x40)
|
|
34
|
+
let size := returndatasize()
|
|
35
|
+
returndatacopy(ptr, 0, size)
|
|
36
|
+
revert(ptr, size)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function executeTransaction(
|
|
43
|
+
bytes calldata data,
|
|
44
|
+
address destination,
|
|
45
|
+
uint256 amount
|
|
46
|
+
) external payable onlyOwner {
|
|
47
|
+
if (data.length > 0) require(destination.isContract(), "NO_CODE_AT_ADDR");
|
|
48
|
+
// We use a low level call here to allow for contract and non-contract calls
|
|
49
|
+
// solhint-disable-next-line avoid-low-level-calls
|
|
50
|
+
(bool success, ) = destination.call{value: amount}(data);
|
|
51
|
+
if (!success) {
|
|
52
|
+
assembly {
|
|
53
|
+
let ptr := mload(0x40)
|
|
54
|
+
let size := returndatasize()
|
|
55
|
+
returndatacopy(ptr, 0, size)
|
|
56
|
+
revert(ptr, size)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function timeoutChallenges(IChallengeManager manager, uint64[] calldata challenges)
|
|
62
|
+
external
|
|
63
|
+
onlyOwner
|
|
64
|
+
{
|
|
65
|
+
uint256 challengesCount = challenges.length;
|
|
66
|
+
for (uint256 i = 0; i < challengesCount; i++) {
|
|
67
|
+
try manager.timeout(challenges[i]) {} catch (bytes memory error) {
|
|
68
|
+
if (error.length == 0) {
|
|
69
|
+
// Assume out of gas
|
|
70
|
+
// We need to revert here so gas estimation works
|
|
71
|
+
require(false, "GAS");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
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/proxy/transparent/ProxyAdmin.sol";
|
|
8
|
+
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
|
9
|
+
import "@openzeppelin/contracts/access/Ownable.sol";
|
|
10
|
+
|
|
11
|
+
import "./ValidatorWallet.sol";
|
|
12
|
+
|
|
13
|
+
contract ValidatorWalletCreator is Ownable {
|
|
14
|
+
event WalletCreated(
|
|
15
|
+
address indexed walletAddress,
|
|
16
|
+
address indexed userAddress,
|
|
17
|
+
address adminProxy
|
|
18
|
+
);
|
|
19
|
+
event TemplateUpdated();
|
|
20
|
+
|
|
21
|
+
address public template;
|
|
22
|
+
|
|
23
|
+
constructor() Ownable() {
|
|
24
|
+
template = address(new ValidatorWallet());
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function setTemplate(address _template) external onlyOwner {
|
|
28
|
+
template = _template;
|
|
29
|
+
emit TemplateUpdated();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function createWallet() external returns (address) {
|
|
33
|
+
ProxyAdmin admin = new ProxyAdmin();
|
|
34
|
+
address proxy = address(
|
|
35
|
+
new TransparentUpgradeableProxy(address(template), address(admin), "")
|
|
36
|
+
);
|
|
37
|
+
admin.transferOwnership(msg.sender);
|
|
38
|
+
ValidatorWallet(proxy).initialize();
|
|
39
|
+
ValidatorWallet(proxy).transferOwnership(msg.sender);
|
|
40
|
+
emit WalletCreated(proxy, msg.sender, address(admin));
|
|
41
|
+
return proxy;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,321 @@
|
|
|
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 "./Value.sol";
|
|
8
|
+
import "./ValueStack.sol";
|
|
9
|
+
import "./PcStack.sol";
|
|
10
|
+
import "./Machine.sol";
|
|
11
|
+
import "./Instructions.sol";
|
|
12
|
+
import "./StackFrame.sol";
|
|
13
|
+
import "./MerkleProof.sol";
|
|
14
|
+
import "./ModuleMemory.sol";
|
|
15
|
+
import "./Module.sol";
|
|
16
|
+
import "./GlobalState.sol";
|
|
17
|
+
|
|
18
|
+
library Deserialize {
|
|
19
|
+
function u8(bytes calldata proof, uint256 startOffset)
|
|
20
|
+
internal
|
|
21
|
+
pure
|
|
22
|
+
returns (uint8 ret, uint256 offset)
|
|
23
|
+
{
|
|
24
|
+
offset = startOffset;
|
|
25
|
+
ret = uint8(proof[offset]);
|
|
26
|
+
offset++;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function u16(bytes calldata proof, uint256 startOffset)
|
|
30
|
+
internal
|
|
31
|
+
pure
|
|
32
|
+
returns (uint16 ret, uint256 offset)
|
|
33
|
+
{
|
|
34
|
+
offset = startOffset;
|
|
35
|
+
for (uint256 i = 0; i < 16 / 8; i++) {
|
|
36
|
+
ret <<= 8;
|
|
37
|
+
ret |= uint8(proof[offset]);
|
|
38
|
+
offset++;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function u32(bytes calldata proof, uint256 startOffset)
|
|
43
|
+
internal
|
|
44
|
+
pure
|
|
45
|
+
returns (uint32 ret, uint256 offset)
|
|
46
|
+
{
|
|
47
|
+
offset = startOffset;
|
|
48
|
+
for (uint256 i = 0; i < 32 / 8; i++) {
|
|
49
|
+
ret <<= 8;
|
|
50
|
+
ret |= uint8(proof[offset]);
|
|
51
|
+
offset++;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function u64(bytes calldata proof, uint256 startOffset)
|
|
56
|
+
internal
|
|
57
|
+
pure
|
|
58
|
+
returns (uint64 ret, uint256 offset)
|
|
59
|
+
{
|
|
60
|
+
offset = startOffset;
|
|
61
|
+
for (uint256 i = 0; i < 64 / 8; i++) {
|
|
62
|
+
ret <<= 8;
|
|
63
|
+
ret |= uint8(proof[offset]);
|
|
64
|
+
offset++;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function u256(bytes calldata proof, uint256 startOffset)
|
|
69
|
+
internal
|
|
70
|
+
pure
|
|
71
|
+
returns (uint256 ret, uint256 offset)
|
|
72
|
+
{
|
|
73
|
+
offset = startOffset;
|
|
74
|
+
for (uint256 i = 0; i < 256 / 8; i++) {
|
|
75
|
+
ret <<= 8;
|
|
76
|
+
ret |= uint8(proof[offset]);
|
|
77
|
+
offset++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function b32(bytes calldata proof, uint256 startOffset)
|
|
82
|
+
internal
|
|
83
|
+
pure
|
|
84
|
+
returns (bytes32 ret, uint256 offset)
|
|
85
|
+
{
|
|
86
|
+
offset = startOffset;
|
|
87
|
+
uint256 retInt;
|
|
88
|
+
(retInt, offset) = u256(proof, offset);
|
|
89
|
+
ret = bytes32(retInt);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function value(bytes calldata proof, uint256 startOffset)
|
|
93
|
+
internal
|
|
94
|
+
pure
|
|
95
|
+
returns (Value memory val, uint256 offset)
|
|
96
|
+
{
|
|
97
|
+
offset = startOffset;
|
|
98
|
+
uint8 typeInt = uint8(proof[offset]);
|
|
99
|
+
offset++;
|
|
100
|
+
require(typeInt <= uint8(ValueLib.maxValueType()), "BAD_VALUE_TYPE");
|
|
101
|
+
uint256 contents;
|
|
102
|
+
(contents, offset) = u256(proof, offset);
|
|
103
|
+
val = Value({valueType: ValueType(typeInt), contents: contents});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function valueStack(bytes calldata proof, uint256 startOffset)
|
|
107
|
+
internal
|
|
108
|
+
pure
|
|
109
|
+
returns (ValueStack memory stack, uint256 offset)
|
|
110
|
+
{
|
|
111
|
+
offset = startOffset;
|
|
112
|
+
bytes32 remainingHash;
|
|
113
|
+
(remainingHash, offset) = b32(proof, offset);
|
|
114
|
+
uint256 provedLength;
|
|
115
|
+
(provedLength, offset) = u256(proof, offset);
|
|
116
|
+
Value[] memory proved = new Value[](provedLength);
|
|
117
|
+
for (uint256 i = 0; i < proved.length; i++) {
|
|
118
|
+
(proved[i], offset) = value(proof, offset);
|
|
119
|
+
}
|
|
120
|
+
stack = ValueStack({proved: ValueArray(proved), remainingHash: remainingHash});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function pcStack(bytes calldata proof, uint256 startOffset)
|
|
124
|
+
internal
|
|
125
|
+
pure
|
|
126
|
+
returns (PcStack memory stack, uint256 offset)
|
|
127
|
+
{
|
|
128
|
+
offset = startOffset;
|
|
129
|
+
bytes32 remainingHash;
|
|
130
|
+
(remainingHash, offset) = b32(proof, offset);
|
|
131
|
+
uint256 provedLength;
|
|
132
|
+
(provedLength, offset) = u256(proof, offset);
|
|
133
|
+
uint32[] memory proved = new uint32[](provedLength);
|
|
134
|
+
for (uint256 i = 0; i < proved.length; i++) {
|
|
135
|
+
(proved[i], offset) = u32(proof, offset);
|
|
136
|
+
}
|
|
137
|
+
stack = PcStack({proved: PcArray(proved), remainingHash: remainingHash});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function instruction(bytes calldata proof, uint256 startOffset)
|
|
141
|
+
internal
|
|
142
|
+
pure
|
|
143
|
+
returns (Instruction memory inst, uint256 offset)
|
|
144
|
+
{
|
|
145
|
+
offset = startOffset;
|
|
146
|
+
uint16 opcode;
|
|
147
|
+
uint256 data;
|
|
148
|
+
(opcode, offset) = u16(proof, offset);
|
|
149
|
+
(data, offset) = u256(proof, offset);
|
|
150
|
+
inst = Instruction({opcode: opcode, argumentData: data});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function stackFrame(bytes calldata proof, uint256 startOffset)
|
|
154
|
+
internal
|
|
155
|
+
pure
|
|
156
|
+
returns (StackFrame memory window, uint256 offset)
|
|
157
|
+
{
|
|
158
|
+
offset = startOffset;
|
|
159
|
+
Value memory returnPc;
|
|
160
|
+
bytes32 localsMerkleRoot;
|
|
161
|
+
uint32 callerModule;
|
|
162
|
+
uint32 callerModuleInternals;
|
|
163
|
+
(returnPc, offset) = value(proof, offset);
|
|
164
|
+
(localsMerkleRoot, offset) = b32(proof, offset);
|
|
165
|
+
(callerModule, offset) = u32(proof, offset);
|
|
166
|
+
(callerModuleInternals, offset) = u32(proof, offset);
|
|
167
|
+
window = StackFrame({
|
|
168
|
+
returnPc: returnPc,
|
|
169
|
+
localsMerkleRoot: localsMerkleRoot,
|
|
170
|
+
callerModule: callerModule,
|
|
171
|
+
callerModuleInternals: callerModuleInternals
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function stackFrameWindow(bytes calldata proof, uint256 startOffset)
|
|
176
|
+
internal
|
|
177
|
+
pure
|
|
178
|
+
returns (StackFrameWindow memory window, uint256 offset)
|
|
179
|
+
{
|
|
180
|
+
offset = startOffset;
|
|
181
|
+
bytes32 remainingHash;
|
|
182
|
+
(remainingHash, offset) = b32(proof, offset);
|
|
183
|
+
StackFrame[] memory proved;
|
|
184
|
+
if (proof[offset] != 0) {
|
|
185
|
+
offset++;
|
|
186
|
+
proved = new StackFrame[](1);
|
|
187
|
+
(proved[0], offset) = stackFrame(proof, offset);
|
|
188
|
+
} else {
|
|
189
|
+
offset++;
|
|
190
|
+
proved = new StackFrame[](0);
|
|
191
|
+
}
|
|
192
|
+
window = StackFrameWindow({proved: proved, remainingHash: remainingHash});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function moduleMemory(bytes calldata proof, uint256 startOffset)
|
|
196
|
+
internal
|
|
197
|
+
pure
|
|
198
|
+
returns (ModuleMemory memory mem, uint256 offset)
|
|
199
|
+
{
|
|
200
|
+
offset = startOffset;
|
|
201
|
+
uint64 size;
|
|
202
|
+
bytes32 root;
|
|
203
|
+
(size, offset) = u64(proof, offset);
|
|
204
|
+
(root, offset) = b32(proof, offset);
|
|
205
|
+
mem = ModuleMemory({size: size, merkleRoot: root});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function module(bytes calldata proof, uint256 startOffset)
|
|
209
|
+
internal
|
|
210
|
+
pure
|
|
211
|
+
returns (Module memory mod, uint256 offset)
|
|
212
|
+
{
|
|
213
|
+
offset = startOffset;
|
|
214
|
+
bytes32 globalsMerkleRoot;
|
|
215
|
+
ModuleMemory memory mem;
|
|
216
|
+
bytes32 tablesMerkleRoot;
|
|
217
|
+
bytes32 functionsMerkleRoot;
|
|
218
|
+
uint32 internalsOffset;
|
|
219
|
+
(globalsMerkleRoot, offset) = b32(proof, offset);
|
|
220
|
+
(mem, offset) = moduleMemory(proof, offset);
|
|
221
|
+
(tablesMerkleRoot, offset) = b32(proof, offset);
|
|
222
|
+
(functionsMerkleRoot, offset) = b32(proof, offset);
|
|
223
|
+
(internalsOffset, offset) = u32(proof, offset);
|
|
224
|
+
mod = Module({
|
|
225
|
+
globalsMerkleRoot: globalsMerkleRoot,
|
|
226
|
+
moduleMemory: mem,
|
|
227
|
+
tablesMerkleRoot: tablesMerkleRoot,
|
|
228
|
+
functionsMerkleRoot: functionsMerkleRoot,
|
|
229
|
+
internalsOffset: internalsOffset
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function globalState(bytes calldata proof, uint256 startOffset)
|
|
234
|
+
internal
|
|
235
|
+
pure
|
|
236
|
+
returns (GlobalState memory state, uint256 offset)
|
|
237
|
+
{
|
|
238
|
+
offset = startOffset;
|
|
239
|
+
|
|
240
|
+
// using constant ints for array size requires newer solidity
|
|
241
|
+
bytes32[2] memory bytes32Vals;
|
|
242
|
+
uint64[2] memory u64Vals;
|
|
243
|
+
|
|
244
|
+
for (uint8 i = 0; i < GlobalStateLib.BYTES32_VALS_NUM; i++) {
|
|
245
|
+
(bytes32Vals[i], offset) = b32(proof, offset);
|
|
246
|
+
}
|
|
247
|
+
for (uint8 i = 0; i < GlobalStateLib.U64_VALS_NUM; i++) {
|
|
248
|
+
(u64Vals[i], offset) = u64(proof, offset);
|
|
249
|
+
}
|
|
250
|
+
state = GlobalState({bytes32Vals: bytes32Vals, u64Vals: u64Vals});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function machine(bytes calldata proof, uint256 startOffset)
|
|
254
|
+
internal
|
|
255
|
+
pure
|
|
256
|
+
returns (Machine memory mach, uint256 offset)
|
|
257
|
+
{
|
|
258
|
+
offset = startOffset;
|
|
259
|
+
MachineStatus status;
|
|
260
|
+
{
|
|
261
|
+
uint8 statusU8;
|
|
262
|
+
(statusU8, offset) = u8(proof, offset);
|
|
263
|
+
if (statusU8 == 0) {
|
|
264
|
+
status = MachineStatus.RUNNING;
|
|
265
|
+
} else if (statusU8 == 1) {
|
|
266
|
+
status = MachineStatus.FINISHED;
|
|
267
|
+
} else if (statusU8 == 2) {
|
|
268
|
+
status = MachineStatus.ERRORED;
|
|
269
|
+
} else if (statusU8 == 3) {
|
|
270
|
+
status = MachineStatus.TOO_FAR;
|
|
271
|
+
} else {
|
|
272
|
+
revert("UNKNOWN_MACH_STATUS");
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
ValueStack memory values;
|
|
276
|
+
ValueStack memory internalStack;
|
|
277
|
+
PcStack memory blocks;
|
|
278
|
+
bytes32 globalStateHash;
|
|
279
|
+
uint32 moduleIdx;
|
|
280
|
+
uint32 functionIdx;
|
|
281
|
+
uint32 functionPc;
|
|
282
|
+
StackFrameWindow memory frameStack;
|
|
283
|
+
bytes32 modulesRoot;
|
|
284
|
+
(values, offset) = valueStack(proof, offset);
|
|
285
|
+
(internalStack, offset) = valueStack(proof, offset);
|
|
286
|
+
(blocks, offset) = pcStack(proof, offset);
|
|
287
|
+
(frameStack, offset) = stackFrameWindow(proof, offset);
|
|
288
|
+
(globalStateHash, offset) = b32(proof, offset);
|
|
289
|
+
(moduleIdx, offset) = u32(proof, offset);
|
|
290
|
+
(functionIdx, offset) = u32(proof, offset);
|
|
291
|
+
(functionPc, offset) = u32(proof, offset);
|
|
292
|
+
(modulesRoot, offset) = b32(proof, offset);
|
|
293
|
+
mach = Machine({
|
|
294
|
+
status: status,
|
|
295
|
+
valueStack: values,
|
|
296
|
+
internalStack: internalStack,
|
|
297
|
+
blockStack: blocks,
|
|
298
|
+
frameStack: frameStack,
|
|
299
|
+
globalStateHash: globalStateHash,
|
|
300
|
+
moduleIdx: moduleIdx,
|
|
301
|
+
functionIdx: functionIdx,
|
|
302
|
+
functionPc: functionPc,
|
|
303
|
+
modulesRoot: modulesRoot
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function merkleProof(bytes calldata proof, uint256 startOffset)
|
|
308
|
+
internal
|
|
309
|
+
pure
|
|
310
|
+
returns (MerkleProof memory merkle, uint256 offset)
|
|
311
|
+
{
|
|
312
|
+
offset = startOffset;
|
|
313
|
+
uint8 length;
|
|
314
|
+
(length, offset) = u8(proof, offset);
|
|
315
|
+
bytes32[] memory counterparts = new bytes32[](length);
|
|
316
|
+
for (uint8 i = 0; i < length; i++) {
|
|
317
|
+
(counterparts[i], offset) = b32(proof, offset);
|
|
318
|
+
}
|
|
319
|
+
merkle = MerkleProof(counterparts);
|
|
320
|
+
}
|
|
321
|
+
}
|