@bradthomasbrown/evm-multi-context
v1.0.0
Published
An implementation of a multi-context Ethereum virtual machine (EVM) in JavaScript/TypeScript.
Readme
evm-multi-context
This is an implementation of a "multi-context machine" partial interpretation of an Ethereum Virtual Machine (EVM). By "multi-context machine", we mean that an instance of one of these machines will run, create, and destroy multiple single-context machines until a transaction is complete, sort of a "thunk-like" replacement for typical EVM execution recursion.
Why?
It was necessary to extend the single-context machine functionality to handle transactions and doing it this way allows single steps and execution pauses even in deeply recursive situations. Although, I don't know if such things aren't possible in the typical recursive way of doing this, this just happened to be more or less how I found it intuitive to deal with this.
Installation
npm i @bradthomasbrown/evm-multi-contextUsage
import type { Context as _589bc4_ } from "@bradthomasbrown/evm-single-context/types";
import { createContext, getStateValue } from "@bradthomasbrown/evm-single-context/lib";
import { SingleContextMachine, traceObjects } from "@bradthomasbrown/evm-single-context";
import { MultiContextMachine } from "./src/machine";
const states:_589bc4_["states"] = [{ accounts:new Map(), transientStorage:null, storage:null }];
// deterministic deployer transaction
const _63_ = {
hash: "0xeddf9e61fb9d8f5111840daef55e5fde0041f5702856532cdbb5a02998033d26",
blockHash: "0xdaa690a16bc4a2bf2ff8955ff1cf3bc2155bc9c53f5731b6f8706fdc2b33b82c",
blockNumber: 10670819n,
from: "0x3fab184622dc19b6109349b94811493bf2a45362",
gas: 100000n,
gasPrice: 100000000000n,
input: "0x604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3",
nonce: 0n,
to: null,
transactionIndex: 42n,
value: 0n,
v: 27n,
r: 15438945231642159389809464667825054380435997955418741871927677867721750618658n,
s: 15438945231642159389809464667825054380435997955418741871927677867721750618658n,
};
console.log({ _63_ });
states[0].accounts!.set(_63_.from, { nonce: 1n, balance: 0n, code: null });
// deploy the deterministic deployer
const _af_ = createContext({
states,
origin: _63_.from,
sender: _63_.from,
to: _63_.to,
calldata: Uint8Array.fromHex(_63_.input.slice(2)).buffer,
gas: 100_000_000n,
value: _63_.value
});
const _34_ = new SingleContextMachine(_af_);
const _ca_:InstanceType<typeof MultiContextMachine>["context"] = { mstack: [_34_] };
const _29_ = new MultiContextMachine(_ca_);
_29_.initializeAndRun();
const _fa_ = _29_.context.mstack.at(0)!.context;
// console.dir(_fa_, { depth:Infinity });
const deterministicDeployerAddress = _fa_.address!;
traceObjects.splice(0, traceObjects.length);
// -- we think setting code in the context can be done in the initialization of a single context machine
// deploy some code via the deterministic deployer
const _c6_ = createContext({
states,
origin: _63_.from,
sender: _63_.from,
to: deterministicDeployerAddress,
calldata: Uint8Array.fromHex("0".repeat(64) + "604260005260206000f3").buffer,
gas: 100_000_000n,
value: 0n,
code: getStateValue(states, 0, "accounts", [deterministicDeployerAddress])!.code
});
const _11_ = new SingleContextMachine(_c6_);
const _94_:InstanceType<typeof MultiContextMachine>["context"] = { mstack: [_11_] };
const _76_ = new MultiContextMachine(_94_);
_76_.initialize();
while (_76_.continue()) {
_76_.step();
console.log(traceObjects.at(-1)); // logs each step of the deterministic deployment
}
const _57_ = _76_.context.mstack.at(0)!.context;
console.dir(_57_, { depth:Infinity });