@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,129 @@
|
|
|
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 "../state/Deserialize.sol";
|
|
8
|
+
import "../state/Machine.sol";
|
|
9
|
+
import "../state/MerkleProof.sol";
|
|
10
|
+
import "./IOneStepProver.sol";
|
|
11
|
+
import "./IOneStepProofEntry.sol";
|
|
12
|
+
|
|
13
|
+
contract OneStepProofEntry is IOneStepProofEntry {
|
|
14
|
+
using MerkleProofLib for MerkleProof;
|
|
15
|
+
using MachineLib for Machine;
|
|
16
|
+
|
|
17
|
+
IOneStepProver public prover0;
|
|
18
|
+
IOneStepProver public proverMem;
|
|
19
|
+
IOneStepProver public proverMath;
|
|
20
|
+
IOneStepProver public proverHostIo;
|
|
21
|
+
|
|
22
|
+
constructor(
|
|
23
|
+
IOneStepProver prover0_,
|
|
24
|
+
IOneStepProver proverMem_,
|
|
25
|
+
IOneStepProver proverMath_,
|
|
26
|
+
IOneStepProver proverHostIo_
|
|
27
|
+
) {
|
|
28
|
+
prover0 = prover0_;
|
|
29
|
+
proverMem = proverMem_;
|
|
30
|
+
proverMath = proverMath_;
|
|
31
|
+
proverHostIo = proverHostIo_;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function proveOneStep(
|
|
35
|
+
ExecutionContext calldata execCtx,
|
|
36
|
+
uint256 machineStep,
|
|
37
|
+
bytes32 beforeHash,
|
|
38
|
+
bytes calldata proof
|
|
39
|
+
) external view override returns (bytes32 afterHash) {
|
|
40
|
+
Machine memory mach;
|
|
41
|
+
Module memory mod;
|
|
42
|
+
MerkleProof memory modProof;
|
|
43
|
+
Instruction memory inst;
|
|
44
|
+
|
|
45
|
+
{
|
|
46
|
+
uint256 offset = 0;
|
|
47
|
+
(mach, offset) = Deserialize.machine(proof, offset);
|
|
48
|
+
require(mach.hash() == beforeHash, "MACHINE_BEFORE_HASH");
|
|
49
|
+
if (mach.status != MachineStatus.RUNNING) {
|
|
50
|
+
// Machine is halted.
|
|
51
|
+
// WARNING: at this point, most machine fields are unconstrained.
|
|
52
|
+
return mach.hash();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (machineStep + 1 == OneStepProofEntryLib.MAX_STEPS) {
|
|
56
|
+
mach.status = MachineStatus.ERRORED;
|
|
57
|
+
return mach.hash();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
(mod, offset) = Deserialize.module(proof, offset);
|
|
61
|
+
(modProof, offset) = Deserialize.merkleProof(proof, offset);
|
|
62
|
+
require(
|
|
63
|
+
modProof.computeRootFromModule(mach.moduleIdx, mod) == mach.modulesRoot,
|
|
64
|
+
"MODULES_ROOT"
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
{
|
|
68
|
+
MerkleProof memory instProof;
|
|
69
|
+
MerkleProof memory funcProof;
|
|
70
|
+
(inst, offset) = Deserialize.instruction(proof, offset);
|
|
71
|
+
(instProof, offset) = Deserialize.merkleProof(proof, offset);
|
|
72
|
+
(funcProof, offset) = Deserialize.merkleProof(proof, offset);
|
|
73
|
+
bytes32 codeHash = instProof.computeRootFromInstruction(mach.functionPc, inst);
|
|
74
|
+
bytes32 recomputedRoot = funcProof.computeRootFromFunction(
|
|
75
|
+
mach.functionIdx,
|
|
76
|
+
codeHash
|
|
77
|
+
);
|
|
78
|
+
require(recomputedRoot == mod.functionsMerkleRoot, "BAD_FUNCTIONS_ROOT");
|
|
79
|
+
}
|
|
80
|
+
proof = proof[offset:];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
uint256 oldModIdx = mach.moduleIdx;
|
|
84
|
+
mach.functionPc += 1;
|
|
85
|
+
uint16 opcode = inst.opcode;
|
|
86
|
+
IOneStepProver prover;
|
|
87
|
+
if (
|
|
88
|
+
(opcode >= Instructions.I32_LOAD && opcode <= Instructions.I64_LOAD32_U) ||
|
|
89
|
+
(opcode >= Instructions.I32_STORE && opcode <= Instructions.I64_STORE32) ||
|
|
90
|
+
opcode == Instructions.MEMORY_SIZE ||
|
|
91
|
+
opcode == Instructions.MEMORY_GROW
|
|
92
|
+
) {
|
|
93
|
+
prover = proverMem;
|
|
94
|
+
} else if (
|
|
95
|
+
(opcode == Instructions.I32_EQZ || opcode == Instructions.I64_EQZ) ||
|
|
96
|
+
(opcode >= Instructions.I32_RELOP_BASE &&
|
|
97
|
+
opcode <= Instructions.I32_RELOP_BASE + Instructions.IRELOP_LAST) ||
|
|
98
|
+
(opcode >= Instructions.I32_UNOP_BASE &&
|
|
99
|
+
opcode <= Instructions.I32_UNOP_BASE + Instructions.IUNOP_LAST) ||
|
|
100
|
+
(opcode >= Instructions.I32_ADD && opcode <= Instructions.I32_ROTR) ||
|
|
101
|
+
(opcode >= Instructions.I64_RELOP_BASE &&
|
|
102
|
+
opcode <= Instructions.I64_RELOP_BASE + Instructions.IRELOP_LAST) ||
|
|
103
|
+
(opcode >= Instructions.I64_UNOP_BASE &&
|
|
104
|
+
opcode <= Instructions.I64_UNOP_BASE + Instructions.IUNOP_LAST) ||
|
|
105
|
+
(opcode >= Instructions.I64_ADD && opcode <= Instructions.I64_ROTR) ||
|
|
106
|
+
(opcode == Instructions.I32_WRAP_I64) ||
|
|
107
|
+
(opcode == Instructions.I64_EXTEND_I32_S || opcode == Instructions.I64_EXTEND_I32_U) ||
|
|
108
|
+
(opcode >= Instructions.I32_EXTEND_8S && opcode <= Instructions.I64_EXTEND_32S) ||
|
|
109
|
+
(opcode >= Instructions.I32_REINTERPRET_F32 &&
|
|
110
|
+
opcode <= Instructions.F64_REINTERPRET_I64)
|
|
111
|
+
) {
|
|
112
|
+
prover = proverMath;
|
|
113
|
+
} else if (
|
|
114
|
+
(opcode >= Instructions.GET_GLOBAL_STATE_BYTES32 &&
|
|
115
|
+
opcode <= Instructions.SET_GLOBAL_STATE_U64) ||
|
|
116
|
+
(opcode >= Instructions.READ_PRE_IMAGE && opcode <= Instructions.HALT_AND_SET_FINISHED)
|
|
117
|
+
) {
|
|
118
|
+
prover = proverHostIo;
|
|
119
|
+
} else {
|
|
120
|
+
prover = prover0;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
(mach, mod) = prover.executeOneStep(execCtx, mach, mod, inst, proof);
|
|
124
|
+
|
|
125
|
+
mach.modulesRoot = modProof.computeRootFromModule(oldModIdx, mod);
|
|
126
|
+
|
|
127
|
+
return mach.hash();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,566 @@
|
|
|
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 "../state/Value.sol";
|
|
8
|
+
import "../state/Machine.sol";
|
|
9
|
+
import "../state/Module.sol";
|
|
10
|
+
import "../state/Deserialize.sol";
|
|
11
|
+
import "./IOneStepProver.sol";
|
|
12
|
+
|
|
13
|
+
contract OneStepProver0 is IOneStepProver {
|
|
14
|
+
using MerkleProofLib for MerkleProof;
|
|
15
|
+
using PcStackLib for PcStack;
|
|
16
|
+
using StackFrameLib for StackFrameWindow;
|
|
17
|
+
using ValueLib for Value;
|
|
18
|
+
using ValueStackLib for ValueStack;
|
|
19
|
+
|
|
20
|
+
function executeUnreachable(
|
|
21
|
+
Machine memory mach,
|
|
22
|
+
Module memory,
|
|
23
|
+
Instruction calldata,
|
|
24
|
+
bytes calldata
|
|
25
|
+
) internal pure {
|
|
26
|
+
mach.status = MachineStatus.ERRORED;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function executeNop(
|
|
30
|
+
Machine memory mach,
|
|
31
|
+
Module memory,
|
|
32
|
+
Instruction calldata,
|
|
33
|
+
bytes calldata
|
|
34
|
+
) internal pure {
|
|
35
|
+
// :)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function executeConstPush(
|
|
39
|
+
Machine memory mach,
|
|
40
|
+
Module memory,
|
|
41
|
+
Instruction calldata inst,
|
|
42
|
+
bytes calldata
|
|
43
|
+
) internal pure {
|
|
44
|
+
uint16 opcode = inst.opcode;
|
|
45
|
+
ValueType ty;
|
|
46
|
+
if (opcode == Instructions.I32_CONST) {
|
|
47
|
+
ty = ValueType.I32;
|
|
48
|
+
} else if (opcode == Instructions.I64_CONST) {
|
|
49
|
+
ty = ValueType.I64;
|
|
50
|
+
} else if (opcode == Instructions.F32_CONST) {
|
|
51
|
+
ty = ValueType.F32;
|
|
52
|
+
} else if (opcode == Instructions.F64_CONST) {
|
|
53
|
+
ty = ValueType.F64;
|
|
54
|
+
} else if (opcode == Instructions.PUSH_STACK_BOUNDARY) {
|
|
55
|
+
ty = ValueType.STACK_BOUNDARY;
|
|
56
|
+
} else {
|
|
57
|
+
revert("CONST_PUSH_INVALID_OPCODE");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
mach.valueStack.push(Value({valueType: ty, contents: uint64(inst.argumentData)}));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function executeDrop(
|
|
64
|
+
Machine memory mach,
|
|
65
|
+
Module memory,
|
|
66
|
+
Instruction calldata,
|
|
67
|
+
bytes calldata
|
|
68
|
+
) internal pure {
|
|
69
|
+
mach.valueStack.pop();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function executeSelect(
|
|
73
|
+
Machine memory mach,
|
|
74
|
+
Module memory,
|
|
75
|
+
Instruction calldata,
|
|
76
|
+
bytes calldata
|
|
77
|
+
) internal pure {
|
|
78
|
+
uint32 selector = mach.valueStack.pop().assumeI32();
|
|
79
|
+
Value memory b = mach.valueStack.pop();
|
|
80
|
+
Value memory a = mach.valueStack.pop();
|
|
81
|
+
|
|
82
|
+
if (selector != 0) {
|
|
83
|
+
mach.valueStack.push(a);
|
|
84
|
+
} else {
|
|
85
|
+
mach.valueStack.push(b);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function executeBlock(
|
|
90
|
+
Machine memory mach,
|
|
91
|
+
Module memory,
|
|
92
|
+
Instruction calldata inst,
|
|
93
|
+
bytes calldata
|
|
94
|
+
) internal pure {
|
|
95
|
+
uint32 targetPc = uint32(inst.argumentData);
|
|
96
|
+
require(targetPc == inst.argumentData, "BAD_BLOCK_PC");
|
|
97
|
+
mach.blockStack.push(targetPc);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function executeBranch(
|
|
101
|
+
Machine memory mach,
|
|
102
|
+
Module memory,
|
|
103
|
+
Instruction calldata,
|
|
104
|
+
bytes calldata
|
|
105
|
+
) internal pure {
|
|
106
|
+
mach.functionPc = mach.blockStack.pop();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function executeBranchIf(
|
|
110
|
+
Machine memory mach,
|
|
111
|
+
Module memory,
|
|
112
|
+
Instruction calldata,
|
|
113
|
+
bytes calldata
|
|
114
|
+
) internal pure {
|
|
115
|
+
uint32 cond = mach.valueStack.pop().assumeI32();
|
|
116
|
+
if (cond != 0) {
|
|
117
|
+
// Jump to target
|
|
118
|
+
mach.functionPc = mach.blockStack.pop();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function executeReturn(
|
|
123
|
+
Machine memory mach,
|
|
124
|
+
Module memory,
|
|
125
|
+
Instruction calldata,
|
|
126
|
+
bytes calldata
|
|
127
|
+
) internal pure {
|
|
128
|
+
StackFrame memory frame = mach.frameStack.pop();
|
|
129
|
+
if (frame.returnPc.valueType == ValueType.REF_NULL) {
|
|
130
|
+
mach.status = MachineStatus.ERRORED;
|
|
131
|
+
return;
|
|
132
|
+
} else if (frame.returnPc.valueType != ValueType.INTERNAL_REF) {
|
|
133
|
+
revert("INVALID_RETURN_PC_TYPE");
|
|
134
|
+
}
|
|
135
|
+
uint256 data = frame.returnPc.contents;
|
|
136
|
+
uint32 pc = uint32(data);
|
|
137
|
+
uint32 func = uint32(data >> 32);
|
|
138
|
+
uint32 mod = uint32(data >> 64);
|
|
139
|
+
require(data >> 96 == 0, "INVALID_RETURN_PC_DATA");
|
|
140
|
+
mach.functionPc = pc;
|
|
141
|
+
mach.functionIdx = func;
|
|
142
|
+
mach.moduleIdx = mod;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function createReturnValue(Machine memory mach) internal pure returns (Value memory) {
|
|
146
|
+
uint256 returnData = 0;
|
|
147
|
+
returnData |= mach.functionPc;
|
|
148
|
+
returnData |= uint256(mach.functionIdx) << 32;
|
|
149
|
+
returnData |= uint256(mach.moduleIdx) << 64;
|
|
150
|
+
return Value({valueType: ValueType.INTERNAL_REF, contents: returnData});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function executeCall(
|
|
154
|
+
Machine memory mach,
|
|
155
|
+
Module memory,
|
|
156
|
+
Instruction calldata inst,
|
|
157
|
+
bytes calldata
|
|
158
|
+
) internal pure {
|
|
159
|
+
// Push the return pc to the stack
|
|
160
|
+
mach.valueStack.push(createReturnValue(mach));
|
|
161
|
+
|
|
162
|
+
// Push caller module info to the stack
|
|
163
|
+
StackFrame memory frame = mach.frameStack.peek();
|
|
164
|
+
mach.valueStack.push(ValueLib.newI32(frame.callerModule));
|
|
165
|
+
mach.valueStack.push(ValueLib.newI32(frame.callerModuleInternals));
|
|
166
|
+
|
|
167
|
+
// Jump to the target
|
|
168
|
+
uint32 idx = uint32(inst.argumentData);
|
|
169
|
+
require(idx == inst.argumentData, "BAD_CALL_DATA");
|
|
170
|
+
mach.functionIdx = idx;
|
|
171
|
+
mach.functionPc = 0;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function executeCrossModuleCall(
|
|
175
|
+
Machine memory mach,
|
|
176
|
+
Module memory mod,
|
|
177
|
+
Instruction calldata inst,
|
|
178
|
+
bytes calldata
|
|
179
|
+
) internal pure {
|
|
180
|
+
// Push the return pc to the stack
|
|
181
|
+
mach.valueStack.push(createReturnValue(mach));
|
|
182
|
+
|
|
183
|
+
// Push caller module info to the stack
|
|
184
|
+
mach.valueStack.push(ValueLib.newI32(mach.moduleIdx));
|
|
185
|
+
mach.valueStack.push(ValueLib.newI32(mod.internalsOffset));
|
|
186
|
+
|
|
187
|
+
// Jump to the target
|
|
188
|
+
uint32 func = uint32(inst.argumentData);
|
|
189
|
+
uint32 module = uint32(inst.argumentData >> 32);
|
|
190
|
+
require(inst.argumentData >> 64 == 0, "BAD_CROSS_MODULE_CALL_DATA");
|
|
191
|
+
mach.moduleIdx = module;
|
|
192
|
+
mach.functionIdx = func;
|
|
193
|
+
mach.functionPc = 0;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function executeCallerModuleInternalCall(
|
|
197
|
+
Machine memory mach,
|
|
198
|
+
Module memory mod,
|
|
199
|
+
Instruction calldata inst,
|
|
200
|
+
bytes calldata
|
|
201
|
+
) internal pure {
|
|
202
|
+
// Push the return pc to the stack
|
|
203
|
+
mach.valueStack.push(createReturnValue(mach));
|
|
204
|
+
|
|
205
|
+
// Push caller module info to the stack
|
|
206
|
+
mach.valueStack.push(ValueLib.newI32(mach.moduleIdx));
|
|
207
|
+
mach.valueStack.push(ValueLib.newI32(mod.internalsOffset));
|
|
208
|
+
|
|
209
|
+
StackFrame memory frame = mach.frameStack.peek();
|
|
210
|
+
if (frame.callerModuleInternals == 0) {
|
|
211
|
+
// The caller module has no internals
|
|
212
|
+
mach.status = MachineStatus.ERRORED;
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Jump to the target
|
|
217
|
+
uint32 offset = uint32(inst.argumentData);
|
|
218
|
+
require(offset == inst.argumentData, "BAD_CALLER_INTERNAL_CALL_DATA");
|
|
219
|
+
mach.moduleIdx = frame.callerModule;
|
|
220
|
+
mach.functionIdx = frame.callerModuleInternals + offset;
|
|
221
|
+
mach.functionPc = 0;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function executeCallIndirect(
|
|
225
|
+
Machine memory mach,
|
|
226
|
+
Module memory mod,
|
|
227
|
+
Instruction calldata inst,
|
|
228
|
+
bytes calldata proof
|
|
229
|
+
) internal pure {
|
|
230
|
+
uint32 funcIdx;
|
|
231
|
+
{
|
|
232
|
+
uint32 elementIdx = mach.valueStack.pop().assumeI32();
|
|
233
|
+
|
|
234
|
+
// Prove metadata about the instruction and tables
|
|
235
|
+
bytes32 elemsRoot;
|
|
236
|
+
bytes32 wantedFuncTypeHash;
|
|
237
|
+
uint256 offset = 0;
|
|
238
|
+
{
|
|
239
|
+
uint64 tableIdx;
|
|
240
|
+
uint8 tableType;
|
|
241
|
+
uint64 tableSize;
|
|
242
|
+
MerkleProof memory tableMerkleProof;
|
|
243
|
+
(tableIdx, offset) = Deserialize.u64(proof, offset);
|
|
244
|
+
(wantedFuncTypeHash, offset) = Deserialize.b32(proof, offset);
|
|
245
|
+
(tableType, offset) = Deserialize.u8(proof, offset);
|
|
246
|
+
(tableSize, offset) = Deserialize.u64(proof, offset);
|
|
247
|
+
(elemsRoot, offset) = Deserialize.b32(proof, offset);
|
|
248
|
+
(tableMerkleProof, offset) = Deserialize.merkleProof(proof, offset);
|
|
249
|
+
|
|
250
|
+
// Validate the information by recomputing known hashes
|
|
251
|
+
bytes32 recomputed = keccak256(
|
|
252
|
+
abi.encodePacked("Call indirect:", tableIdx, wantedFuncTypeHash)
|
|
253
|
+
);
|
|
254
|
+
require(recomputed == bytes32(inst.argumentData), "BAD_CALL_INDIRECT_DATA");
|
|
255
|
+
recomputed = tableMerkleProof.computeRootFromTable(
|
|
256
|
+
tableIdx,
|
|
257
|
+
tableType,
|
|
258
|
+
tableSize,
|
|
259
|
+
elemsRoot
|
|
260
|
+
);
|
|
261
|
+
require(recomputed == mod.tablesMerkleRoot, "BAD_TABLES_ROOT");
|
|
262
|
+
|
|
263
|
+
// Check if the table access is out of bounds
|
|
264
|
+
if (elementIdx >= tableSize) {
|
|
265
|
+
mach.status = MachineStatus.ERRORED;
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
bytes32 elemFuncTypeHash;
|
|
271
|
+
Value memory functionPointer;
|
|
272
|
+
MerkleProof memory elementMerkleProof;
|
|
273
|
+
(elemFuncTypeHash, offset) = Deserialize.b32(proof, offset);
|
|
274
|
+
(functionPointer, offset) = Deserialize.value(proof, offset);
|
|
275
|
+
(elementMerkleProof, offset) = Deserialize.merkleProof(proof, offset);
|
|
276
|
+
bytes32 recomputedElemRoot = elementMerkleProof.computeRootFromElement(
|
|
277
|
+
elementIdx,
|
|
278
|
+
elemFuncTypeHash,
|
|
279
|
+
functionPointer
|
|
280
|
+
);
|
|
281
|
+
require(recomputedElemRoot == elemsRoot, "BAD_ELEMENTS_ROOT");
|
|
282
|
+
|
|
283
|
+
if (elemFuncTypeHash != wantedFuncTypeHash) {
|
|
284
|
+
mach.status = MachineStatus.ERRORED;
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (functionPointer.valueType == ValueType.REF_NULL) {
|
|
289
|
+
mach.status = MachineStatus.ERRORED;
|
|
290
|
+
return;
|
|
291
|
+
} else if (functionPointer.valueType == ValueType.FUNC_REF) {
|
|
292
|
+
funcIdx = uint32(functionPointer.contents);
|
|
293
|
+
require(funcIdx == functionPointer.contents, "BAD_FUNC_REF_CONTENTS");
|
|
294
|
+
} else {
|
|
295
|
+
revert("BAD_ELEM_TYPE");
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Push the return pc to the stack
|
|
300
|
+
mach.valueStack.push(createReturnValue(mach));
|
|
301
|
+
|
|
302
|
+
// Push caller module info to the stack
|
|
303
|
+
StackFrame memory frame = mach.frameStack.peek();
|
|
304
|
+
mach.valueStack.push(ValueLib.newI32(frame.callerModule));
|
|
305
|
+
mach.valueStack.push(ValueLib.newI32(frame.callerModuleInternals));
|
|
306
|
+
|
|
307
|
+
// Jump to the target
|
|
308
|
+
mach.functionIdx = funcIdx;
|
|
309
|
+
mach.functionPc = 0;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function executeArbitraryJumpIf(
|
|
313
|
+
Machine memory mach,
|
|
314
|
+
Module memory,
|
|
315
|
+
Instruction calldata inst,
|
|
316
|
+
bytes calldata
|
|
317
|
+
) internal pure {
|
|
318
|
+
uint32 cond = mach.valueStack.pop().assumeI32();
|
|
319
|
+
if (cond != 0) {
|
|
320
|
+
// Jump to target
|
|
321
|
+
uint32 pc = uint32(inst.argumentData);
|
|
322
|
+
require(pc == inst.argumentData, "BAD_CALL_DATA");
|
|
323
|
+
mach.functionPc = pc;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function merkleProveGetValue(
|
|
328
|
+
bytes32 merkleRoot,
|
|
329
|
+
uint256 index,
|
|
330
|
+
bytes calldata proof
|
|
331
|
+
) internal pure returns (Value memory) {
|
|
332
|
+
uint256 offset = 0;
|
|
333
|
+
Value memory proposedVal;
|
|
334
|
+
MerkleProof memory merkle;
|
|
335
|
+
(proposedVal, offset) = Deserialize.value(proof, offset);
|
|
336
|
+
(merkle, offset) = Deserialize.merkleProof(proof, offset);
|
|
337
|
+
bytes32 recomputedRoot = merkle.computeRootFromValue(index, proposedVal);
|
|
338
|
+
require(recomputedRoot == merkleRoot, "WRONG_MERKLE_ROOT");
|
|
339
|
+
return proposedVal;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function merkleProveSetValue(
|
|
343
|
+
bytes32 merkleRoot,
|
|
344
|
+
uint256 index,
|
|
345
|
+
Value memory newVal,
|
|
346
|
+
bytes calldata proof
|
|
347
|
+
) internal pure returns (bytes32) {
|
|
348
|
+
Value memory oldVal;
|
|
349
|
+
uint256 offset = 0;
|
|
350
|
+
MerkleProof memory merkle;
|
|
351
|
+
(oldVal, offset) = Deserialize.value(proof, offset);
|
|
352
|
+
(merkle, offset) = Deserialize.merkleProof(proof, offset);
|
|
353
|
+
bytes32 recomputedRoot = merkle.computeRootFromValue(index, oldVal);
|
|
354
|
+
require(recomputedRoot == merkleRoot, "WRONG_MERKLE_ROOT");
|
|
355
|
+
return merkle.computeRootFromValue(index, newVal);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function executeLocalGet(
|
|
359
|
+
Machine memory mach,
|
|
360
|
+
Module memory,
|
|
361
|
+
Instruction calldata inst,
|
|
362
|
+
bytes calldata proof
|
|
363
|
+
) internal pure {
|
|
364
|
+
StackFrame memory frame = mach.frameStack.peek();
|
|
365
|
+
Value memory val = merkleProveGetValue(frame.localsMerkleRoot, inst.argumentData, proof);
|
|
366
|
+
mach.valueStack.push(val);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function executeLocalSet(
|
|
370
|
+
Machine memory mach,
|
|
371
|
+
Module memory,
|
|
372
|
+
Instruction calldata inst,
|
|
373
|
+
bytes calldata proof
|
|
374
|
+
) internal pure {
|
|
375
|
+
Value memory newVal = mach.valueStack.pop();
|
|
376
|
+
StackFrame memory frame = mach.frameStack.peek();
|
|
377
|
+
frame.localsMerkleRoot = merkleProveSetValue(
|
|
378
|
+
frame.localsMerkleRoot,
|
|
379
|
+
inst.argumentData,
|
|
380
|
+
newVal,
|
|
381
|
+
proof
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function executeGlobalGet(
|
|
386
|
+
Machine memory mach,
|
|
387
|
+
Module memory mod,
|
|
388
|
+
Instruction calldata inst,
|
|
389
|
+
bytes calldata proof
|
|
390
|
+
) internal pure {
|
|
391
|
+
Value memory val = merkleProveGetValue(mod.globalsMerkleRoot, inst.argumentData, proof);
|
|
392
|
+
mach.valueStack.push(val);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function executeGlobalSet(
|
|
396
|
+
Machine memory mach,
|
|
397
|
+
Module memory mod,
|
|
398
|
+
Instruction calldata inst,
|
|
399
|
+
bytes calldata proof
|
|
400
|
+
) internal pure {
|
|
401
|
+
Value memory newVal = mach.valueStack.pop();
|
|
402
|
+
mod.globalsMerkleRoot = merkleProveSetValue(
|
|
403
|
+
mod.globalsMerkleRoot,
|
|
404
|
+
inst.argumentData,
|
|
405
|
+
newVal,
|
|
406
|
+
proof
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function executeEndBlock(
|
|
411
|
+
Machine memory mach,
|
|
412
|
+
Module memory,
|
|
413
|
+
Instruction calldata,
|
|
414
|
+
bytes calldata
|
|
415
|
+
) internal pure {
|
|
416
|
+
mach.blockStack.pop();
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function executeEndBlockIf(
|
|
420
|
+
Machine memory mach,
|
|
421
|
+
Module memory,
|
|
422
|
+
Instruction calldata,
|
|
423
|
+
bytes calldata
|
|
424
|
+
) internal pure {
|
|
425
|
+
uint32 cond = mach.valueStack.peek().assumeI32();
|
|
426
|
+
if (cond != 0) {
|
|
427
|
+
mach.blockStack.pop();
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function executeInitFrame(
|
|
432
|
+
Machine memory mach,
|
|
433
|
+
Module memory,
|
|
434
|
+
Instruction calldata inst,
|
|
435
|
+
bytes calldata
|
|
436
|
+
) internal pure {
|
|
437
|
+
Value memory callerModuleInternals = mach.valueStack.pop();
|
|
438
|
+
Value memory callerModule = mach.valueStack.pop();
|
|
439
|
+
Value memory returnPc = mach.valueStack.pop();
|
|
440
|
+
StackFrame memory newFrame = StackFrame({
|
|
441
|
+
returnPc: returnPc,
|
|
442
|
+
localsMerkleRoot: bytes32(inst.argumentData),
|
|
443
|
+
callerModule: callerModule.assumeI32(),
|
|
444
|
+
callerModuleInternals: callerModuleInternals.assumeI32()
|
|
445
|
+
});
|
|
446
|
+
mach.frameStack.push(newFrame);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function executeMoveInternal(
|
|
450
|
+
Machine memory mach,
|
|
451
|
+
Module memory,
|
|
452
|
+
Instruction calldata inst,
|
|
453
|
+
bytes calldata
|
|
454
|
+
) internal pure {
|
|
455
|
+
Value memory val;
|
|
456
|
+
if (inst.opcode == Instructions.MOVE_FROM_STACK_TO_INTERNAL) {
|
|
457
|
+
val = mach.valueStack.pop();
|
|
458
|
+
mach.internalStack.push(val);
|
|
459
|
+
} else if (inst.opcode == Instructions.MOVE_FROM_INTERNAL_TO_STACK) {
|
|
460
|
+
val = mach.internalStack.pop();
|
|
461
|
+
mach.valueStack.push(val);
|
|
462
|
+
} else {
|
|
463
|
+
revert("MOVE_INTERNAL_INVALID_OPCODE");
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function executeIsStackBoundary(
|
|
468
|
+
Machine memory mach,
|
|
469
|
+
Module memory,
|
|
470
|
+
Instruction calldata,
|
|
471
|
+
bytes calldata
|
|
472
|
+
) internal pure {
|
|
473
|
+
Value memory val = mach.valueStack.pop();
|
|
474
|
+
uint32 newContents = 0;
|
|
475
|
+
if (val.valueType == ValueType.STACK_BOUNDARY) {
|
|
476
|
+
newContents = 1;
|
|
477
|
+
}
|
|
478
|
+
mach.valueStack.push(ValueLib.newI32(newContents));
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function executeDup(
|
|
482
|
+
Machine memory mach,
|
|
483
|
+
Module memory,
|
|
484
|
+
Instruction calldata,
|
|
485
|
+
bytes calldata
|
|
486
|
+
) internal pure {
|
|
487
|
+
Value memory val = mach.valueStack.peek();
|
|
488
|
+
mach.valueStack.push(val);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function executeOneStep(
|
|
492
|
+
ExecutionContext calldata,
|
|
493
|
+
Machine calldata startMach,
|
|
494
|
+
Module calldata startMod,
|
|
495
|
+
Instruction calldata inst,
|
|
496
|
+
bytes calldata proof
|
|
497
|
+
) external pure override returns (Machine memory mach, Module memory mod) {
|
|
498
|
+
mach = startMach;
|
|
499
|
+
mod = startMod;
|
|
500
|
+
|
|
501
|
+
uint16 opcode = inst.opcode;
|
|
502
|
+
|
|
503
|
+
function(Machine memory, Module memory, Instruction calldata, bytes calldata)
|
|
504
|
+
internal
|
|
505
|
+
pure impl;
|
|
506
|
+
if (opcode == Instructions.UNREACHABLE) {
|
|
507
|
+
impl = executeUnreachable;
|
|
508
|
+
} else if (opcode == Instructions.NOP) {
|
|
509
|
+
impl = executeNop;
|
|
510
|
+
} else if (opcode == Instructions.BLOCK) {
|
|
511
|
+
impl = executeBlock;
|
|
512
|
+
} else if (opcode == Instructions.BRANCH) {
|
|
513
|
+
impl = executeBranch;
|
|
514
|
+
} else if (opcode == Instructions.BRANCH_IF) {
|
|
515
|
+
impl = executeBranchIf;
|
|
516
|
+
} else if (opcode == Instructions.RETURN) {
|
|
517
|
+
impl = executeReturn;
|
|
518
|
+
} else if (opcode == Instructions.CALL) {
|
|
519
|
+
impl = executeCall;
|
|
520
|
+
} else if (opcode == Instructions.CROSS_MODULE_CALL) {
|
|
521
|
+
impl = executeCrossModuleCall;
|
|
522
|
+
} else if (opcode == Instructions.CALLER_MODULE_INTERNAL_CALL) {
|
|
523
|
+
impl = executeCallerModuleInternalCall;
|
|
524
|
+
} else if (opcode == Instructions.CALL_INDIRECT) {
|
|
525
|
+
impl = executeCallIndirect;
|
|
526
|
+
} else if (opcode == Instructions.END_BLOCK) {
|
|
527
|
+
impl = executeEndBlock;
|
|
528
|
+
} else if (opcode == Instructions.END_BLOCK_IF) {
|
|
529
|
+
impl = executeEndBlockIf;
|
|
530
|
+
} else if (opcode == Instructions.ARBITRARY_JUMP_IF) {
|
|
531
|
+
impl = executeArbitraryJumpIf;
|
|
532
|
+
} else if (opcode == Instructions.LOCAL_GET) {
|
|
533
|
+
impl = executeLocalGet;
|
|
534
|
+
} else if (opcode == Instructions.LOCAL_SET) {
|
|
535
|
+
impl = executeLocalSet;
|
|
536
|
+
} else if (opcode == Instructions.GLOBAL_GET) {
|
|
537
|
+
impl = executeGlobalGet;
|
|
538
|
+
} else if (opcode == Instructions.GLOBAL_SET) {
|
|
539
|
+
impl = executeGlobalSet;
|
|
540
|
+
} else if (opcode == Instructions.INIT_FRAME) {
|
|
541
|
+
impl = executeInitFrame;
|
|
542
|
+
} else if (opcode == Instructions.DROP) {
|
|
543
|
+
impl = executeDrop;
|
|
544
|
+
} else if (opcode == Instructions.SELECT) {
|
|
545
|
+
impl = executeSelect;
|
|
546
|
+
} else if (
|
|
547
|
+
(opcode >= Instructions.I32_CONST && opcode <= Instructions.F64_CONST) ||
|
|
548
|
+
opcode == Instructions.PUSH_STACK_BOUNDARY
|
|
549
|
+
) {
|
|
550
|
+
impl = executeConstPush;
|
|
551
|
+
} else if (
|
|
552
|
+
opcode == Instructions.MOVE_FROM_STACK_TO_INTERNAL ||
|
|
553
|
+
opcode == Instructions.MOVE_FROM_INTERNAL_TO_STACK
|
|
554
|
+
) {
|
|
555
|
+
impl = executeMoveInternal;
|
|
556
|
+
} else if (opcode == Instructions.IS_STACK_BOUNDARY) {
|
|
557
|
+
impl = executeIsStackBoundary;
|
|
558
|
+
} else if (opcode == Instructions.DUP) {
|
|
559
|
+
impl = executeDup;
|
|
560
|
+
} else {
|
|
561
|
+
revert("INVALID_OPCODE");
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
impl(mach, mod, inst, proof);
|
|
565
|
+
}
|
|
566
|
+
}
|