@bradthomasbrown/evm-single-context 1.0.0
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/README.md +91 -0
- package/dist/lib.d.ts +26 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +129 -0
- package/dist/machine.d.ts +40 -0
- package/dist/machine.d.ts.map +1 -0
- package/dist/machine.js +166 -0
- package/dist/opsets/9db704/opcodes/ADD.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/ADD.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/ADD.js +13 -0
- package/dist/opsets/9db704/opcodes/ADDRESS.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/ADDRESS.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/ADDRESS.js +11 -0
- package/dist/opsets/9db704/opcodes/AND.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/AND.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/AND.js +13 -0
- package/dist/opsets/9db704/opcodes/BYTE.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/BYTE.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/BYTE.js +13 -0
- package/dist/opsets/9db704/opcodes/CALLDATACOPY.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/CALLDATACOPY.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/CALLDATACOPY.js +14 -0
- package/dist/opsets/9db704/opcodes/CALLDATALOAD.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/CALLDATALOAD.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/CALLDATALOAD.js +17 -0
- package/dist/opsets/9db704/opcodes/CALLDATASIZE.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/CALLDATASIZE.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/CALLDATASIZE.js +11 -0
- package/dist/opsets/9db704/opcodes/CALLER.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/CALLER.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/CALLER.js +11 -0
- package/dist/opsets/9db704/opcodes/CALLVALUE.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/CALLVALUE.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/CALLVALUE.js +11 -0
- package/dist/opsets/9db704/opcodes/CHAINID.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/CHAINID.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/CHAINID.js +12 -0
- package/dist/opsets/9db704/opcodes/CODECOPY.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/CODECOPY.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/CODECOPY.js +13 -0
- package/dist/opsets/9db704/opcodes/CREATE.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/CREATE.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/CREATE.js +49 -0
- package/dist/opsets/9db704/opcodes/CREATE2.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/CREATE2.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/CREATE2.js +50 -0
- package/dist/opsets/9db704/opcodes/DIV.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/DIV.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/DIV.js +16 -0
- package/dist/opsets/9db704/opcodes/DUP.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/DUP.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/DUP.js +11 -0
- package/dist/opsets/9db704/opcodes/EQ.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/EQ.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/EQ.js +13 -0
- package/dist/opsets/9db704/opcodes/EXTCODECOPY.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/EXTCODECOPY.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/EXTCODECOPY.js +20 -0
- package/dist/opsets/9db704/opcodes/EXTCODESIZE.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/EXTCODESIZE.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/EXTCODESIZE.js +20 -0
- package/dist/opsets/9db704/opcodes/GAS.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/GAS.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/GAS.js +11 -0
- package/dist/opsets/9db704/opcodes/GT.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/GT.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/GT.js +13 -0
- package/dist/opsets/9db704/opcodes/ISZERO.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/ISZERO.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/ISZERO.js +13 -0
- package/dist/opsets/9db704/opcodes/JUMP.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/JUMP.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/JUMP.js +16 -0
- package/dist/opsets/9db704/opcodes/JUMPDEST.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/JUMPDEST.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/JUMPDEST.js +10 -0
- package/dist/opsets/9db704/opcodes/JUMPI.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/JUMPI.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/JUMPI.js +20 -0
- package/dist/opsets/9db704/opcodes/KECCAK256.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/KECCAK256.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/KECCAK256.js +14 -0
- package/dist/opsets/9db704/opcodes/LOG.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/LOG.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/LOG.js +14 -0
- package/dist/opsets/9db704/opcodes/LT.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/LT.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/LT.js +13 -0
- package/dist/opsets/9db704/opcodes/MLOAD.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/MLOAD.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/MLOAD.js +14 -0
- package/dist/opsets/9db704/opcodes/MSIZE.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/MSIZE.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/MSIZE.js +11 -0
- package/dist/opsets/9db704/opcodes/MSTORE.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/MSTORE.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/MSTORE.js +14 -0
- package/dist/opsets/9db704/opcodes/MSTORE8.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/MSTORE8.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/MSTORE8.js +14 -0
- package/dist/opsets/9db704/opcodes/MUL.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/MUL.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/MUL.js +13 -0
- package/dist/opsets/9db704/opcodes/NOT.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/NOT.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/NOT.js +13 -0
- package/dist/opsets/9db704/opcodes/OR.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/OR.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/OR.js +13 -0
- package/dist/opsets/9db704/opcodes/PC.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/PC.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/PC.js +11 -0
- package/dist/opsets/9db704/opcodes/POP.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/POP.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/POP.js +11 -0
- package/dist/opsets/9db704/opcodes/PUSH.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/PUSH.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/PUSH.js +11 -0
- package/dist/opsets/9db704/opcodes/RETURN.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/RETURN.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/RETURN.js +15 -0
- package/dist/opsets/9db704/opcodes/RETURNDATACOPY.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/RETURNDATACOPY.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/RETURNDATACOPY.js +13 -0
- package/dist/opsets/9db704/opcodes/RETURNDATASIZE.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/RETURNDATASIZE.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/RETURNDATASIZE.js +11 -0
- package/dist/opsets/9db704/opcodes/REVERT.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/REVERT.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/REVERT.js +15 -0
- package/dist/opsets/9db704/opcodes/SGT.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/SGT.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/SGT.js +15 -0
- package/dist/opsets/9db704/opcodes/SHL.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/SHL.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/SHL.js +13 -0
- package/dist/opsets/9db704/opcodes/SHR.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/SHR.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/SHR.js +13 -0
- package/dist/opsets/9db704/opcodes/SLOAD.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/SLOAD.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/SLOAD.js +21 -0
- package/dist/opsets/9db704/opcodes/SLT.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/SLT.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/SLT.js +15 -0
- package/dist/opsets/9db704/opcodes/SSTORE.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/SSTORE.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/SSTORE.js +50 -0
- package/dist/opsets/9db704/opcodes/STATICCALL.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/STATICCALL.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/STATICCALL.js +104 -0
- package/dist/opsets/9db704/opcodes/STOP.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/STOP.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/STOP.js +9 -0
- package/dist/opsets/9db704/opcodes/SUB.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/SUB.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/SUB.js +13 -0
- package/dist/opsets/9db704/opcodes/SWAP.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/SWAP.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/SWAP.js +15 -0
- package/dist/opsets/9db704/opcodes/TIMESTAMP.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/TIMESTAMP.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/TIMESTAMP.js +13 -0
- package/dist/opsets/9db704/opcodes/TLOAD.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/TLOAD.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/TLOAD.js +14 -0
- package/dist/opsets/9db704/opcodes/TSTORE.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/TSTORE.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/TSTORE.js +18 -0
- package/dist/opsets/9db704/opcodes/XOR.d.ts +8 -0
- package/dist/opsets/9db704/opcodes/XOR.d.ts.map +1 -0
- package/dist/opsets/9db704/opcodes/XOR.js +13 -0
- package/dist/opsets/9db704/opset.d.ts +53 -0
- package/dist/opsets/9db704/opset.d.ts.map +1 -0
- package/dist/opsets/9db704/opset.js +52 -0
- package/dist/types.d.ts +49 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# evm-single-context
|
|
2
|
+
This is an implementation of a "single-context machine" partial interpretation of an Ethereum Virtual Machine (EVM).
|
|
3
|
+
By "single-context machine", we mean that an instance of one of these machines will run until the point where most EVM implementations would recurse into a new execution context, like on any CALL-type or CREATE-type opcode.
|
|
4
|
+
This kind of machine will be different in that instances will simply block when these opcodes are reached and will wait for a higher machine or coordinator to do what is necessary and then unblock the machine.
|
|
5
|
+
|
|
6
|
+
## Why?
|
|
7
|
+
For local testing, we found quickly that Anvil has execution consensus divergences (bugs) with go-ethereum (`geth`). If we want to deploy a contract on Ethereum Mainnet, we should not use Anvil.
|
|
8
|
+
`geth` itself is very inflexible and not friendly for local development work and testing. If you want to test handling chain reorganizations, this will end up being a lot of work. Anvil allows easy testing of this, but has the aformentioned bugs.
|
|
9
|
+
Both require spinning up a node with an external application/binary and probably some form of container runtime.
|
|
10
|
+
The official JS/TS implementation is just as inflexible since it is designed to closely mirror `geth` and contains a lot of complexity and bloat since it aims to be as close to full EVM functionality as possible.
|
|
11
|
+
This will be the first of a set of light, simple, and flexible implementations designed to be easy to work with and use for developing/testing/verification.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
```sh
|
|
15
|
+
npm i @bradthomasbrown/evm-single-context
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
```js
|
|
20
|
+
import type { Context } from "@bradthomasbrown/evm-single-context/types";
|
|
21
|
+
import { EvmEntity } from "@bradthomasbrown/entity/evm";
|
|
22
|
+
import { createContext } from "@bradthomasbrown/evm-single-context/lib";
|
|
23
|
+
import { SingleContextMachine, traceObjects } from "@bradthomasbrown/evm-single-context";
|
|
24
|
+
|
|
25
|
+
// set up some test parameters
|
|
26
|
+
const parameters = {
|
|
27
|
+
from: "0x45c3bde5d2cc59a626bee55ac8e494cf128e866e",
|
|
28
|
+
gas: 217590n,
|
|
29
|
+
value: 111360000000000000n,
|
|
30
|
+
input: await Bun.file("testinput.hex").text(), // or any other way to set the input/data/calldata, which should appear as `0x<hex>...`
|
|
31
|
+
code: await Bun.file("testcode.hex").text(), // or any other way to set the code, which should appear as `0x<hex>...`
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// assign a random address for a contract
|
|
35
|
+
const contract = EvmEntity.random();
|
|
36
|
+
|
|
37
|
+
// get the code as a uint8array
|
|
38
|
+
const code = parameters.code === null
|
|
39
|
+
? Uint8Array.fromHex(parameters.input.slice(2)).buffer
|
|
40
|
+
: Uint8Array.fromHex(parameters.code.slice(2)).buffer;
|
|
41
|
+
|
|
42
|
+
// create state
|
|
43
|
+
const accounts:Context["states"][number]["accounts"] = new Map([ [contract.address, { nonce: 1n, balance: 0n, code }] ]);
|
|
44
|
+
const states:Context["states"] = [{ accounts, transientStorage: null, storage: null }];
|
|
45
|
+
|
|
46
|
+
// create a context
|
|
47
|
+
const context = createContext({
|
|
48
|
+
origin:parameters.from,
|
|
49
|
+
sender:parameters.from,
|
|
50
|
+
value:parameters.value,
|
|
51
|
+
to:contract.address,
|
|
52
|
+
gas:parameters.gas,
|
|
53
|
+
calldata:Uint8Array.fromHex(parameters.input.slice(2)).buffer,
|
|
54
|
+
code,
|
|
55
|
+
states
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// do some initial context handling (more related to transactions, not single-contexts),
|
|
59
|
+
// like initial transaction cost and pre-warming precompile addresses
|
|
60
|
+
let g0_data = 0n;
|
|
61
|
+
if (context.calldata !== null)
|
|
62
|
+
for (const byte of new Uint8Array(context.calldata))
|
|
63
|
+
g0_data += byte === 0 ? 4n : 16n;
|
|
64
|
+
let g0_create = 0n;
|
|
65
|
+
if (context.to === null) {
|
|
66
|
+
const codeArray = new Uint8Array(context.calldata!);
|
|
67
|
+
g0_create += 32000n;
|
|
68
|
+
g0_create += 2n * BigInt((codeArray.byteLength + 0x1f & ~0x1f) >> 5);
|
|
69
|
+
}
|
|
70
|
+
const g0_transaction = 21000n;
|
|
71
|
+
const g0 = g0_data + g0_create + g0_transaction;
|
|
72
|
+
context.gas -= g0;
|
|
73
|
+
context.accountAccessSet.add(`0x${"1".padStart(40, '0')}`);
|
|
74
|
+
|
|
75
|
+
// create a single-context machine from this context, initialize and run it, then log trace objects
|
|
76
|
+
// should replicate go-ethereum's traces
|
|
77
|
+
const machine = new SingleContextMachine(context);
|
|
78
|
+
machine.initializeAndRun();
|
|
79
|
+
console.log(traceObjects);
|
|
80
|
+
/* ..., {
|
|
81
|
+
pc: 409,
|
|
82
|
+
op: "JUMP",
|
|
83
|
+
gas: 189836,
|
|
84
|
+
gasCost: 8,
|
|
85
|
+
depth: 1,
|
|
86
|
+
stack: [ "0x0", "0x19a", "0x36c", "0x13c" ],
|
|
87
|
+
memory: [ "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000",
|
|
88
|
+
"0000000000000000000000000000000000000000000000000000000000000080"
|
|
89
|
+
],
|
|
90
|
+
}, ... */
|
|
91
|
+
```
|
package/dist/lib.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { MapComponents, Context, PartialContext } from "./types.js";
|
|
2
|
+
import { keccak256 } from "@bradthomasbrown/keccak/keccak256";
|
|
3
|
+
declare function byteSliceToBigInt_be(bytes: Uint8Array, offset: number, size: number, permitOobZeroes: boolean): bigint;
|
|
4
|
+
declare function numberToHex(value: number | bigint, padding: number): string;
|
|
5
|
+
declare const F: {
|
|
6
|
+
p: bigint;
|
|
7
|
+
sqrt: (a: number | bigint) => bigint;
|
|
8
|
+
add(a: bigint | number, b: bigint | number): bigint;
|
|
9
|
+
multiply(a: bigint | number, b: bigint | number): bigint;
|
|
10
|
+
inverse(a: bigint | number): bigint;
|
|
11
|
+
subtract(a: bigint | number, b: bigint | number): bigint;
|
|
12
|
+
reciprocal(a: bigint | number): bigint;
|
|
13
|
+
divide(a: bigint | number, b: bigint | number): bigint;
|
|
14
|
+
power(b: bigint | number, e: bigint | number): bigint;
|
|
15
|
+
};
|
|
16
|
+
declare function pop(stack: Array<bigint>, count: number): bigint[];
|
|
17
|
+
declare function peek(stack: Array<bigint>, count: number): bigint[];
|
|
18
|
+
declare function copy(destinationBuffer: ArrayBuffer, sourceBuffer: null | ArrayBuffer, destinationOffset: number, sourceOffset: number, size: number, permitOobZeroes: boolean): void;
|
|
19
|
+
declare function memoryExpand(context: Context, size: number): void;
|
|
20
|
+
declare function getStateValue<I extends keyof Context["states"][number], M extends Context["states"][number][I], C extends MapComponents<NonNullable<M>>, K extends C["keyPath"], V extends C["value"]>(states: Context["states"], maxIndex: null | number, mapIdentifier: I, keyPath: K): null | V;
|
|
21
|
+
declare function createContext(partialContext: PartialContext): Context;
|
|
22
|
+
declare function deriveAddress(context: Context): string;
|
|
23
|
+
declare function deriveAddress2(sender: string, salt: bigint, code: ArrayBuffer): string;
|
|
24
|
+
declare function write(destination: ArrayBuffer, value: bigint, offset: number, size: number): void;
|
|
25
|
+
export { byteSliceToBigInt_be, numberToHex, F, keccak256, pop, peek, copy, memoryExpand, getStateValue, write, createContext, deriveAddress, deriveAddress2 };
|
|
26
|
+
//# sourceMappingURL=lib.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEzE,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAG9D,iBAAS,oBAAoB,CAAC,KAAK,EAAC,UAAU,EAAE,MAAM,EAAC,MAAM,EAAE,IAAI,EAAC,MAAM,EAAE,eAAe,EAAC,OAAO,UAOlG;AAED,iBAAS,WAAW,CAAC,KAAK,EAAC,MAAM,GAAC,MAAM,EAAE,OAAO,EAAC,MAAM,UAEvD;AAMD,QAAA,MAAM,CAAC;;;;;;;;;;CAAqB,CAAC;AAE7B,iBAAS,GAAG,CAAC,KAAK,EAAC,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAC,MAAM,YAK7C;AAED,iBAAS,IAAI,CAAC,KAAK,EAAC,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAC,MAAM,YAK9C;AAED,iBAAS,IAAI,CAAC,iBAAiB,EAAC,WAAW,EAAE,YAAY,EAAC,IAAI,GAAC,WAAW,EAAE,iBAAiB,EAAC,MAAM,EAAE,YAAY,EAAC,MAAM,EAAE,IAAI,EAAC,MAAM,EAAE,eAAe,EAAC,OAAO,QAa9J;AAED,iBAAS,YAAY,CAAC,OAAO,EAAC,OAAO,EAAE,IAAI,EAAC,MAAM,QAWjD;AAED,iBAAS,aAAa,CAClB,CAAC,SAAS,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EACzC,CAAC,SAAS,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EACtC,CAAC,SAAS,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EACvC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,EACtB,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EACtB,MAAM,EAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAC,IAAI,GAAC,MAAM,EAAE,aAAa,EAAC,CAAC,EAAE,OAAO,EAAC,CAAC,GAAE,IAAI,GAAC,CAAC,CAenF;AAED,iBAAS,aAAa,CAAC,cAAc,EAAC,cAAc,GAAE,OAAO,CA0B5D;AAED,iBAAS,aAAa,CAAC,OAAO,EAAC,OAAO,UAIrC;AAED,iBAAS,cAAc,CAAC,MAAM,EAAC,MAAM,EAAE,IAAI,EAAC,MAAM,EAAE,IAAI,EAAC,WAAW,UAOnE;AAED,iBAAS,KAAK,CAAC,WAAW,EAAC,WAAW,EAAE,KAAK,EAAC,MAAM,EAAE,MAAM,EAAC,MAAM,EAAE,IAAI,EAAC,MAAM,QAI/E;AAED,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC"}
|
package/dist/lib.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { _7c3dda_ } from "@bradthomasbrown/finite-field";
|
|
2
|
+
import { keccak256 } from "@bradthomasbrown/keccak/keccak256";
|
|
3
|
+
import { encode } from "@bradthomasbrown/rlp";
|
|
4
|
+
function byteSliceToBigInt_be(bytes, offset, size, permitOobZeroes) {
|
|
5
|
+
if ((permitOobZeroes === false) && (offset + size > bytes.byteLength))
|
|
6
|
+
throw new Error("out of bounds", { cause: { bytes, offset, size } });
|
|
7
|
+
let value = 0n;
|
|
8
|
+
for (let i = offset; i < offset + size; i++)
|
|
9
|
+
value = (value << 8n) + (i >= bytes.byteLength ? 0n : BigInt(bytes[i]));
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
function numberToHex(value, padding) {
|
|
13
|
+
return value.toString(16).padStart(padding, '0');
|
|
14
|
+
}
|
|
15
|
+
// shouldn't use p3mod4 field implementation here, so we make our own field implementation
|
|
16
|
+
function sqrt() { throw new Error("sqrt unsupported"); return 0n; }
|
|
17
|
+
const FiniteField = _7c3dda_(sqrt);
|
|
18
|
+
const p = (1n << 256n);
|
|
19
|
+
const F = new FiniteField(p);
|
|
20
|
+
function pop(stack, count) {
|
|
21
|
+
const array = new Array(count);
|
|
22
|
+
for (let j = 0; j < count; j++)
|
|
23
|
+
array[j] = stack.pop();
|
|
24
|
+
return array;
|
|
25
|
+
}
|
|
26
|
+
function peek(stack, count) {
|
|
27
|
+
const array = new Array(count);
|
|
28
|
+
for (let j = 0; j < count; j++)
|
|
29
|
+
array[j] = stack.at(0 - (j + 1));
|
|
30
|
+
return array;
|
|
31
|
+
}
|
|
32
|
+
function copy(destinationBuffer, sourceBuffer, destinationOffset, sourceOffset, size, permitOobZeroes) {
|
|
33
|
+
if (size == 0)
|
|
34
|
+
return;
|
|
35
|
+
let sourceBytesAvailable = 0;
|
|
36
|
+
if (sourceBuffer !== null && sourceOffset < sourceBuffer.byteLength)
|
|
37
|
+
sourceBytesAvailable = Math.min(sourceBuffer.byteLength - sourceOffset, size);
|
|
38
|
+
const destinationArray = new Uint8Array(destinationBuffer);
|
|
39
|
+
if (sourceBytesAvailable > 0) {
|
|
40
|
+
const sourceArray = new Uint8Array(sourceBuffer.slice(sourceOffset, sourceOffset + sourceBytesAvailable));
|
|
41
|
+
destinationArray.set(sourceArray, destinationOffset);
|
|
42
|
+
}
|
|
43
|
+
const bytesRemaining = size - sourceBytesAvailable;
|
|
44
|
+
if (bytesRemaining == 0)
|
|
45
|
+
return;
|
|
46
|
+
if (permitOobZeroes === false)
|
|
47
|
+
throw new Error(`outOfBoundsCopy`, { cause: { destinationBuffer, sourceBuffer, destinationOffset, sourceOffset, size } });
|
|
48
|
+
destinationArray.fill(0, destinationOffset + sourceBytesAvailable, bytesRemaining);
|
|
49
|
+
}
|
|
50
|
+
function memoryExpand(context, size) {
|
|
51
|
+
if (size == 0)
|
|
52
|
+
return;
|
|
53
|
+
if (context.memory === null)
|
|
54
|
+
context.memory = new ArrayBuffer(1);
|
|
55
|
+
const memoryWords = (size + 0x1f) >> 5;
|
|
56
|
+
if (context.memoryWords >= memoryWords)
|
|
57
|
+
return;
|
|
58
|
+
const C_mem = 3n * BigInt(memoryWords) + BigInt(memoryWords) ** 2n / 512n;
|
|
59
|
+
context.gas -= C_mem - context.C_mem_prev;
|
|
60
|
+
context.memoryWords = memoryWords;
|
|
61
|
+
context.C_mem_prev = C_mem;
|
|
62
|
+
while (context.memory.byteLength < size)
|
|
63
|
+
context.memory = context.memory.transfer(context.memory.byteLength << 1);
|
|
64
|
+
}
|
|
65
|
+
function getStateValue(states, maxIndex, mapIdentifier, keyPath) {
|
|
66
|
+
let value = null;
|
|
67
|
+
l0: for (let i = Math.min(maxIndex ?? states.length - 1, states.length - 1); i >= 0; i--) {
|
|
68
|
+
let map = states[i][mapIdentifier];
|
|
69
|
+
if (map === null)
|
|
70
|
+
continue;
|
|
71
|
+
for (let j = 0; j < keyPath.length - 1; j++) {
|
|
72
|
+
if (map.has(keyPath[j]) === false)
|
|
73
|
+
continue l0;
|
|
74
|
+
map = map.get(keyPath[j]);
|
|
75
|
+
}
|
|
76
|
+
const lastKeyComponent = keyPath[keyPath.length - 1];
|
|
77
|
+
if (map.has(lastKeyComponent) === false)
|
|
78
|
+
continue;
|
|
79
|
+
value = map.get(lastKeyComponent);
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
function createContext(partialContext) {
|
|
85
|
+
return {
|
|
86
|
+
origin: partialContext.origin,
|
|
87
|
+
sender: partialContext.sender,
|
|
88
|
+
to: partialContext.to ?? null,
|
|
89
|
+
address: partialContext.address ?? null,
|
|
90
|
+
value: partialContext.value ?? 0n,
|
|
91
|
+
pc: partialContext.pc ?? 0,
|
|
92
|
+
gas: partialContext.gas ?? 0n,
|
|
93
|
+
stack: partialContext.stack ?? [],
|
|
94
|
+
memory: partialContext.memory ?? null,
|
|
95
|
+
C_mem_prev: partialContext.C_mem_prev ?? 0n,
|
|
96
|
+
returndata: partialContext.returndata ?? null,
|
|
97
|
+
accountAccessSet: partialContext.accountAccessSet ?? new Set(),
|
|
98
|
+
storageAccessSet: partialContext.storageAccessSet ?? new Map(),
|
|
99
|
+
depth: partialContext.depth ?? 1,
|
|
100
|
+
calldata: partialContext.calldata ?? null,
|
|
101
|
+
subcontext: partialContext.subcontext ?? null,
|
|
102
|
+
blocked: partialContext.blocked ?? false,
|
|
103
|
+
reverted: partialContext.reverted ?? null,
|
|
104
|
+
states: partialContext.states ?? [{ accounts: null, transientStorage: null, storage: null }],
|
|
105
|
+
refund: partialContext.refund ?? 0n,
|
|
106
|
+
code: partialContext.code ?? null,
|
|
107
|
+
memoryWords: 0,
|
|
108
|
+
L: null
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function deriveAddress(context) {
|
|
112
|
+
const account = getStateValue(context.states, null, "accounts", [context.sender]);
|
|
113
|
+
const addressBytes = Uint8Array.fromHex(context.sender.slice(2));
|
|
114
|
+
return `0x${keccak256(encode([addressBytes, account.nonce])).slice(12).toHex()}`;
|
|
115
|
+
}
|
|
116
|
+
function deriveAddress2(sender, salt, code) {
|
|
117
|
+
const bytes = new Uint8Array(1 + 20 + 32 + 32);
|
|
118
|
+
bytes[0] = 0xff;
|
|
119
|
+
bytes.set(Uint8Array.fromHex(sender.slice(2)), 1);
|
|
120
|
+
write(bytes.buffer, salt, 1 + 20, 0x20);
|
|
121
|
+
bytes.set(keccak256(new Uint8Array(code)), 1 + 20 + 0x20);
|
|
122
|
+
return `0x${keccak256(bytes).slice(12).toHex()}`;
|
|
123
|
+
}
|
|
124
|
+
function write(destination, value, offset, size) {
|
|
125
|
+
const array = new Uint8Array(destination);
|
|
126
|
+
for (let i = offset + size - 1; i >= offset; i--, value >>= 8n)
|
|
127
|
+
array[i] = Number(value & 0xffn);
|
|
128
|
+
}
|
|
129
|
+
export { byteSliceToBigInt_be, numberToHex, F, keccak256, pop, peek, copy, memoryExpand, getStateValue, write, createContext, deriveAddress, deriveAddress2 };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Context } from "./types.js";
|
|
2
|
+
declare let traceHelper: {
|
|
3
|
+
instruction: null | number;
|
|
4
|
+
pc: null | number;
|
|
5
|
+
op: null | string;
|
|
6
|
+
gas: null | number;
|
|
7
|
+
depth: null | number;
|
|
8
|
+
stack: null | Array<string>;
|
|
9
|
+
returnData: null | string;
|
|
10
|
+
memoryWords: null | Array<string>;
|
|
11
|
+
storage: null | {
|
|
12
|
+
[key: string]: string;
|
|
13
|
+
};
|
|
14
|
+
stop: null | boolean;
|
|
15
|
+
};
|
|
16
|
+
declare function buildTraceObject(context: Context): {
|
|
17
|
+
pc: number;
|
|
18
|
+
op: string;
|
|
19
|
+
gas: number;
|
|
20
|
+
gasCost: number;
|
|
21
|
+
depth: number;
|
|
22
|
+
stack: Array<string>;
|
|
23
|
+
returnData?: string;
|
|
24
|
+
memory?: Array<string>;
|
|
25
|
+
storage?: {
|
|
26
|
+
[key: string]: string;
|
|
27
|
+
};
|
|
28
|
+
refund?: number;
|
|
29
|
+
};
|
|
30
|
+
declare const traceObjects: Array<ReturnType<typeof buildTraceObject>>;
|
|
31
|
+
declare const SingleContextMachine: new (context: Context) => {
|
|
32
|
+
context: Context;
|
|
33
|
+
continue(): boolean;
|
|
34
|
+
step(): void;
|
|
35
|
+
initialize(): void;
|
|
36
|
+
run(): void;
|
|
37
|
+
initializeAndRun(): void;
|
|
38
|
+
};
|
|
39
|
+
export { SingleContextMachine, traceObjects, traceHelper };
|
|
40
|
+
//# sourceMappingURL=machine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../src/machine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAY,MAAM,YAAY,CAAC;AA2EpD,QAAA,IAAI,WAAW,EAAC;IACZ,WAAW,EAAC,IAAI,GAAC,MAAM,CAAC;IACxB,EAAE,EAAC,IAAI,GAAC,MAAM,CAAC;IACf,EAAE,EAAC,IAAI,GAAC,MAAM,CAAC;IACf,GAAG,EAAC,IAAI,GAAC,MAAM,CAAA;IACf,KAAK,EAAC,IAAI,GAAC,MAAM,CAAC;IAClB,KAAK,EAAC,IAAI,GAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACzB,UAAU,EAAC,IAAI,GAAC,MAAM,CAAC;IACvB,WAAW,EAAC,IAAI,GAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,OAAO,EAAC,IAAI,GAAC;QAAE,CAAC,GAAG,EAAC,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACtC,IAAI,EAAC,IAAI,GAAC,OAAO,CAAA;CACmH,CAAC;AAmDzI,iBAAS,gBAAgB,CAAC,OAAO,EAAC,OAAO;QAK9B,MAAM;QACN,MAAM;SACL,MAAM;aACF,MAAM;WACR,MAAM;WACN,KAAK,CAAC,MAAM,CAAC;iBACP,MAAM;aACV,KAAK,CAAC,MAAM,CAAC;cACZ;QAAE,CAAC,GAAG,EAAC,MAAM,GAAG,MAAM,CAAA;KAAE;aACzB,MAAM;EAcrB;AAED,QAAA,MAAM,YAAY,EAAC,KAAK,CAAC,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAM,CAAA;AA6BlE,QAAA,MAAM,oBAAoB;;;;;;;CAOzB,CAAC;AAEF,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/machine.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { createMachine } from "@bradthomasbrown/machine/6873f5";
|
|
2
|
+
import { byteSliceToBigInt_be, numberToHex, peek, copy, getStateValue, deriveAddress } from "./lib.js";
|
|
3
|
+
import * as opset from "./opsets/9db704/opset.js";
|
|
4
|
+
function continuePredicate(context) {
|
|
5
|
+
// if revert is known (true or false, not null), don't continue
|
|
6
|
+
if (context.reverted !== null)
|
|
7
|
+
return false;
|
|
8
|
+
// if there is no code, don't continue
|
|
9
|
+
if (context.code === null)
|
|
10
|
+
return false;
|
|
11
|
+
// if the program counter is beyond the code length, don't continue
|
|
12
|
+
if (context.pc >= context.code.byteLength)
|
|
13
|
+
return false;
|
|
14
|
+
// if there is an incomplete subcontext, don't continue
|
|
15
|
+
if (context.subcontext !== null && context.subcontext.reverted === null)
|
|
16
|
+
return false;
|
|
17
|
+
// otherwise, continue
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
function parseInstruction(context) {
|
|
21
|
+
const codeArray = new Uint8Array(context.code);
|
|
22
|
+
const instruction = codeArray[context.pc];
|
|
23
|
+
// PUSH handling
|
|
24
|
+
if (instruction >= 0x5f && instruction < 0x80) {
|
|
25
|
+
const variant = instruction - 0x5f;
|
|
26
|
+
const width = variant + 1;
|
|
27
|
+
const literal = byteSliceToBigInt_be(codeArray, context.pc + 1, variant, true);
|
|
28
|
+
return [0x60, { variant, width, literal }];
|
|
29
|
+
}
|
|
30
|
+
// DUP handling
|
|
31
|
+
if (instruction >= 0x80 && instruction < 0x90) {
|
|
32
|
+
const variant = instruction - 0x80;
|
|
33
|
+
const width = 1;
|
|
34
|
+
const literal = null;
|
|
35
|
+
return [0x80, { variant, width, literal }];
|
|
36
|
+
}
|
|
37
|
+
// SWAP handling
|
|
38
|
+
if (instruction >= 0x90 && instruction < 0xa0) {
|
|
39
|
+
const variant = instruction - 0x90;
|
|
40
|
+
const width = 1;
|
|
41
|
+
const literal = null;
|
|
42
|
+
return [0x90, { variant, width, literal }];
|
|
43
|
+
}
|
|
44
|
+
// LOG handling
|
|
45
|
+
if (instruction >= 0xa0 && instruction < 0xa5) {
|
|
46
|
+
const variant = instruction - 0xa0;
|
|
47
|
+
const width = 1;
|
|
48
|
+
const literal = null;
|
|
49
|
+
return [0xa0, { variant, width, literal }];
|
|
50
|
+
}
|
|
51
|
+
// default handling
|
|
52
|
+
const variant = null;
|
|
53
|
+
const width = 1;
|
|
54
|
+
const literal = null;
|
|
55
|
+
return [instruction, { variant, width, literal }];
|
|
56
|
+
}
|
|
57
|
+
const debug = true;
|
|
58
|
+
const identifierToString = new Map();
|
|
59
|
+
for (const opcode of Object.values(opset))
|
|
60
|
+
identifierToString.set(opcode.identifier, (instruction) => opcode.instructionToString(instruction));
|
|
61
|
+
let traceHelper = { instruction: null, gas: null, pc: null, op: null, depth: null, stack: null, returnData: null, memoryWords: null, storage: null, stop: null };
|
|
62
|
+
// NOTE: the entirety of this is just debug-related as of now
|
|
63
|
+
function preExecute(context) {
|
|
64
|
+
if (debug === false)
|
|
65
|
+
return;
|
|
66
|
+
const instruction = new Uint8Array(context.code)[context.pc];
|
|
67
|
+
let identifier = instruction;
|
|
68
|
+
if (instruction >= 0x5f && instruction < 0x80)
|
|
69
|
+
identifier = 0x60; // PUSH
|
|
70
|
+
if (instruction >= 0x80 && instruction < 0x90)
|
|
71
|
+
identifier = 0x80; // DUP
|
|
72
|
+
if (instruction >= 0x90 && instruction < 0xa0)
|
|
73
|
+
identifier = 0x90; // SWAP
|
|
74
|
+
if (instruction >= 0xa0 && instruction < 0xa5)
|
|
75
|
+
identifier = 0xa0; // LOG
|
|
76
|
+
if (identifierToString.has(identifier) === false)
|
|
77
|
+
throw new Error(`missing identiferToString.get(${numberToHex(identifier, 2)})`);
|
|
78
|
+
traceHelper.instruction = instruction;
|
|
79
|
+
traceHelper.pc = context.pc;
|
|
80
|
+
traceHelper.op = identifierToString.get(identifier)(instruction);
|
|
81
|
+
traceHelper.gas = Number(context.gas);
|
|
82
|
+
traceHelper.depth = context.depth;
|
|
83
|
+
traceHelper.stack = context.stack.map(value => `0x${value.toString(16)}`);
|
|
84
|
+
if (context.subcontext !== null && context.subcontext.to !== null && context.subcontext.returndata !== null)
|
|
85
|
+
traceHelper.returnData = `0x${new Uint8Array(context.subcontext.returndata).toHex()}`;
|
|
86
|
+
else
|
|
87
|
+
traceHelper.returnData = null;
|
|
88
|
+
if (context.memory !== null) {
|
|
89
|
+
traceHelper.memoryWords = [];
|
|
90
|
+
for (let i = 0; i < context.memoryWords << 5; i += 0x20) {
|
|
91
|
+
const wordBytes = new ArrayBuffer(32);
|
|
92
|
+
copy(wordBytes, context.memory, 0, i, 0x20, true);
|
|
93
|
+
traceHelper.memoryWords.push(new Uint8Array(wordBytes).toHex());
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (instruction == 0x54) {
|
|
97
|
+
const [key] = peek(context.stack, 1);
|
|
98
|
+
const value = getStateValue(context.states, null, "storage", [context.address, key]) ?? 0n;
|
|
99
|
+
if (traceHelper.storage === null)
|
|
100
|
+
traceHelper.storage = {};
|
|
101
|
+
traceHelper.storage[numberToHex(key, 64)] = numberToHex(value, 64);
|
|
102
|
+
}
|
|
103
|
+
else if (instruction == 0x55) {
|
|
104
|
+
const [key, value] = peek(context.stack, 2);
|
|
105
|
+
if (traceHelper.storage === null)
|
|
106
|
+
traceHelper.storage = {};
|
|
107
|
+
traceHelper.storage[numberToHex(key, 64)] = numberToHex(value, 64);
|
|
108
|
+
}
|
|
109
|
+
traceHelper.stop = instruction == 0x00;
|
|
110
|
+
}
|
|
111
|
+
const dispatch = new Map();
|
|
112
|
+
for (const opcode of Object.values(opset))
|
|
113
|
+
dispatch.set(opcode.identifier, opcode.executor);
|
|
114
|
+
function getExecutor(identifier) {
|
|
115
|
+
if (dispatch.has(identifier))
|
|
116
|
+
return dispatch.get(identifier);
|
|
117
|
+
throw new Error(`no executor found for identifier ${numberToHex(identifier, 2)}`);
|
|
118
|
+
}
|
|
119
|
+
function buildTraceObject(context) {
|
|
120
|
+
let gasCost = null;
|
|
121
|
+
if ([0xf0, 0xf5].includes(traceHelper.instruction))
|
|
122
|
+
gasCost = traceHelper.gas - Number(context.gas) - Number(context.L);
|
|
123
|
+
else
|
|
124
|
+
gasCost = traceHelper.gas - Number(context.gas);
|
|
125
|
+
const traceObject = {
|
|
126
|
+
pc: traceHelper.pc,
|
|
127
|
+
op: traceHelper.op,
|
|
128
|
+
gas: traceHelper.gas,
|
|
129
|
+
gasCost,
|
|
130
|
+
depth: traceHelper.depth,
|
|
131
|
+
stack: traceHelper.stack
|
|
132
|
+
};
|
|
133
|
+
if (traceHelper.returnData !== null)
|
|
134
|
+
traceObject.returnData = traceHelper.returnData;
|
|
135
|
+
if (traceHelper.memoryWords !== null)
|
|
136
|
+
traceObject.memory = traceHelper.memoryWords;
|
|
137
|
+
if (traceHelper.op == "SLOAD" || traceHelper.op == "SSTORE")
|
|
138
|
+
traceObject.storage = traceHelper.storage;
|
|
139
|
+
if (context.refund != 0n)
|
|
140
|
+
traceObject.refund = Number(context.refund);
|
|
141
|
+
return traceObject;
|
|
142
|
+
}
|
|
143
|
+
const traceObjects = [];
|
|
144
|
+
function postExecute(context) {
|
|
145
|
+
if (debug === true)
|
|
146
|
+
traceObjects.push(buildTraceObject(context));
|
|
147
|
+
if (context.pc < context.code.byteLength)
|
|
148
|
+
return;
|
|
149
|
+
if (context.reverted !== null)
|
|
150
|
+
return;
|
|
151
|
+
// if program counter is past code and we haven't yet decided on reverted
|
|
152
|
+
// reverted is false
|
|
153
|
+
// this detects end of execution if no STOP, REVERT, RETURN, etc. was provided in code
|
|
154
|
+
context.reverted = false;
|
|
155
|
+
}
|
|
156
|
+
function initialize(context) {
|
|
157
|
+
if (context.address === null && context.to !== null)
|
|
158
|
+
context.address = context.to;
|
|
159
|
+
// for EoA deployments, address is null, but we'll need it in execution
|
|
160
|
+
if (context.address === null && context.to === null) {
|
|
161
|
+
context.address = deriveAddress(context);
|
|
162
|
+
context.code = context.calldata;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const SingleContextMachine = createMachine(continuePredicate, parseInstruction, preExecute, getExecutor, postExecute, initialize);
|
|
166
|
+
export { SingleContextMachine, traceObjects, traceHelper };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ADD.d.ts","sourceRoot":"","sources":["../../../../src/opsets/9db704/opcodes/ADD.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;;;sBAO5B,OAAO;;;AAJ5B,wBAeE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { pop, F } from "../../../lib.js";
|
|
2
|
+
export default {
|
|
3
|
+
identifier: 0x01,
|
|
4
|
+
executor(context) {
|
|
5
|
+
const [a, b] = pop(context.stack, 2);
|
|
6
|
+
context.stack.push(F.add(a, b));
|
|
7
|
+
context.gas -= 3n;
|
|
8
|
+
context.pc++;
|
|
9
|
+
},
|
|
10
|
+
instructionToString() {
|
|
11
|
+
return "ADD";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ADDRESS.d.ts","sourceRoot":"","sources":["../../../../src/opsets/9db704/opcodes/ADDRESS.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;;;sBAM5B,OAAO;;;AAJ5B,wBAcE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AND.d.ts","sourceRoot":"","sources":["../../../../src/opsets/9db704/opcodes/AND.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;;;sBAO5B,OAAO;;;AAJ5B,wBAeE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { pop } from "../../../lib.js";
|
|
2
|
+
export default {
|
|
3
|
+
identifier: 0x16,
|
|
4
|
+
executor(context) {
|
|
5
|
+
const [a, b] = pop(context.stack, 2);
|
|
6
|
+
context.stack.push(a & b);
|
|
7
|
+
context.gas -= 3n;
|
|
8
|
+
context.pc++;
|
|
9
|
+
},
|
|
10
|
+
instructionToString() {
|
|
11
|
+
return "AND";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BYTE.d.ts","sourceRoot":"","sources":["../../../../src/opsets/9db704/opcodes/BYTE.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;;;sBAO5B,OAAO;;;AAJ5B,wBAeE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { pop } from "../../../lib.js";
|
|
2
|
+
export default {
|
|
3
|
+
identifier: 0x1a,
|
|
4
|
+
executor(context) {
|
|
5
|
+
const [i, x] = pop(context.stack, 2);
|
|
6
|
+
context.stack.push(x >> (0x1fn - i << 3n) & 0xffn);
|
|
7
|
+
context.gas -= 3n;
|
|
8
|
+
context.pc++;
|
|
9
|
+
},
|
|
10
|
+
instructionToString() {
|
|
11
|
+
return "BYTE";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CALLDATACOPY.d.ts","sourceRoot":"","sources":["../../../../src/opsets/9db704/opcodes/CALLDATACOPY.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;;;sBAO5B,OAAO;;;AAJ5B,wBAgBE"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { pop, copy, memoryExpand } from "../../../lib.js";
|
|
2
|
+
export default {
|
|
3
|
+
identifier: 0x37,
|
|
4
|
+
executor(context) {
|
|
5
|
+
const [destOffset, offset, size] = pop(context.stack, 3);
|
|
6
|
+
context.gas -= 3n + 3n * (size + 0x1fn >> 5n);
|
|
7
|
+
memoryExpand(context, Number(destOffset) + Number(size));
|
|
8
|
+
copy(context.memory, context.calldata, Number(destOffset), Number(offset), Number(size), true);
|
|
9
|
+
context.pc++;
|
|
10
|
+
},
|
|
11
|
+
instructionToString() {
|
|
12
|
+
return "CALLDATACOPY";
|
|
13
|
+
}
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CALLDATALOAD.d.ts","sourceRoot":"","sources":["../../../../src/opsets/9db704/opcodes/CALLDATALOAD.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;;;sBAO5B,OAAO;;;AAJ5B,wBAmBE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { byteSliceToBigInt_be, pop } from "../../../lib.js";
|
|
2
|
+
export default {
|
|
3
|
+
identifier: 0x35,
|
|
4
|
+
executor(context) {
|
|
5
|
+
const [i] = pop(context.stack, 1);
|
|
6
|
+
context.gas -= 3n;
|
|
7
|
+
if (context.calldata === null) {
|
|
8
|
+
context.stack.push(0n);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
context.stack.push(byteSliceToBigInt_be(new Uint8Array(context.calldata), Number(i), 0x20, true));
|
|
12
|
+
context.pc++;
|
|
13
|
+
},
|
|
14
|
+
instructionToString() {
|
|
15
|
+
return "CALLDATALOAD";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CALLDATASIZE.d.ts","sourceRoot":"","sources":["../../../../src/opsets/9db704/opcodes/CALLDATASIZE.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;;;sBAM5B,OAAO;;;AAJ5B,wBAcE"}
|