UNPKG

sevm

Version:

A Symbolic Ethereum Virtual Machine (EVM) bytecode decompiler & analyzer library & CLI

127 lines (126 loc) 5.43 kB
import { arrayify } from './.bytes'; import { Branch, Throw, type Expr, type Inst } from './ast'; import { State, type Stack } from './state'; import { type Opcode, type StepFn, type Undef } from './step'; /** * Represent a reacheable basic block. */ export interface Block<M extends string> { /** * Where this block ends, exclusive. */ readonly pcend: number; /** * The `Opcode`s decoded from `bytecode` augmented with its `Stack` trace. */ readonly opcodes: { /** * The `Opcode` decoded and executed from `bytecode`. */ readonly opcode: Opcode<M>; /** * The `Stack` trace **after** executing this `opcode`. */ stack?: Stack<Expr>; }[]; readonly states: State<Inst, Expr>[]; } /** * https://ethereum.github.io/execution-specs/autoapi/ethereum/index.html */ export declare class EVM<M extends string> { /** * The `STEP` function that updates the `State` * after executing the opcode pointed by `pc`. * * Maps `mnemonic` keys of `STEP` to their corresponding `opcode` * in the byte range, _i.e._, `0-255`. * * For elements in the range `0-255` that do not have a corresponding `mnemonic`, * `INVALID` is used instead. */ readonly step: Undef<M> & { readonly [m in M]: StepFn; }; /** * Reacheable `blocks` found in `this.bytecode`. */ readonly blocks: Map<number, Block<M>>; /** * Symbolic execution `errors` found during interpretation of `this.bytecode`. */ readonly errors: { /** * The statement that represents the error triggered during symbolic execution. */ err: Throw; /** * The state in which the error was triggered. * Given this states ends up in error, `this.last` statement will be `this.err`. */ state: State<Inst, Expr>; }[]; /** * The bytecode buffer that represents a Contract or Library. */ readonly bytecode: Uint8Array; /** * */ readonly _ids: { _count: number; push(elem: State): void; }; constructor(bytecode: Parameters<typeof arrayify>[0], /** * The `STEP` function that updates the `State` * after executing the opcode pointed by `pc`. * * Maps `mnemonic` keys of `STEP` to their corresponding `opcode` * in the byte range, _i.e._, `0-255`. * * For elements in the range `0-255` that do not have a corresponding `mnemonic`, * `INVALID` is used instead. */ step: Undef<M> & { readonly [m in M]: StepFn; }); /** * Creates a new `EVM` with the latest defined execution fork. */ static new(bytecode: Parameters<typeof arrayify>[0]): EVM<"ADDMOD" | "MULMOD" | "SIGNEXTEND" | "EQ" | "ISZERO" | "NOT" | "BYTE" | "COINBASE" | "TIMESTAMP" | "NUMBER" | "DIFFICULTY" | "GASLIMIT" | "CALLER" | "CALLDATASIZE" | "ORIGIN" | "GASPRICE" | "ADDRESS" | "CODESIZE" | "RETURNDATASIZE" | "GAS" | "CALLVALUE" | "CALLDATALOAD" | "CALLDATACOPY" | "CODECOPY" | "EXTCODECOPY" | "RETURNDATACOPY" | "SLOAD" | "SSTORE" | "POP" | "PUSH2" | "PUSH1" | "PUSH16" | "PUSH3" | "PUSH8" | "PUSH9" | "PUSH11" | "PUSH20" | "PUSH21" | "PUSH25" | "PUSH26" | "PUSH5" | "PUSH32" | "PUSH4" | "PUSH6" | "PUSH7" | "PUSH10" | "PUSH12" | "PUSH13" | "PUSH14" | "PUSH15" | "PUSH24" | "PUSH17" | "PUSH18" | "PUSH19" | "PUSH22" | "PUSH23" | "PUSH27" | "PUSH28" | "PUSH29" | "PUSH30" | "PUSH31" | "DUP2" | "DUP1" | "DUP16" | "DUP3" | "DUP8" | "DUP9" | "DUP11" | "DUP5" | "DUP4" | "DUP6" | "DUP7" | "DUP10" | "DUP12" | "DUP13" | "DUP14" | "DUP15" | "SWAP2" | "SWAP1" | "SWAP16" | "SWAP3" | "SWAP8" | "SWAP9" | "SWAP11" | "SWAP5" | "SWAP4" | "SWAP6" | "SWAP7" | "SWAP10" | "SWAP12" | "SWAP13" | "SWAP14" | "SWAP15" | "ADD" | "MUL" | "SUB" | "DIV" | "SDIV" | "MOD" | "SMOD" | "EXP" | "LT" | "GT" | "SLT" | "SGT" | "AND" | "OR" | "XOR" | "PC" | "BALANCE" | "EXTCODESIZE" | "EXTCODEHASH" | "BLOCKHASH" | "MLOAD" | "MSTORE" | "MSTORE8" | "MSIZE" | "SHA3" | "STOP" | "CREATE" | "CALL" | "CALLCODE" | "RETURN" | "DELEGATECALL" | "STATICCALL" | "REVERT" | "SELFDESTRUCT" | "INVALID" | "LOG0" | "LOG2" | "LOG1" | "LOG3" | "LOG4" | "JUMPDEST" | "JUMP" | "JUMPI" | "SHL" | "SHR" | "SAR" | "CREATE2" | "CHAINID" | "SELFBALANCE" | "PREVRANDAO" | "BASEFEE" | "PUSH0">; /** * */ chunks(): { /** * Where this `chunk` begins, inclusive. */ pcbegin: number; /** * Where this `chunk` ends, exclusive. */ pcend: number; /** * The content found for this `chunk`. * If `pcbegin` is reacheable, then `content` is the `Opcode` for this block. * Otherwise the uninterpreted slice of the bytecode for this chunk. */ content: Opcode<M>[] | Uint8Array; states?: State<Inst, Expr>[]; }[]; /** * */ start(): State<Inst, Expr>; run(pc0: number, state: State<Inst, Expr>): void; exec(pc0: number, state: State<Inst, Expr>): void; /** * Returns the `opcode`s present in the **reacheable blocks** of `this` EVM's `bytecode`. * * **NOTE**. You must call either the `start`, `run` or `exec` methods first. * This is to populate the `bytecode`'s reacheable `blocks`. */ opcodes(): Opcode<M>[]; gc(b: Branch): State<Inst, Expr> | undefined; }