sevm
Version:
A Symbolic Ethereum Virtual Machine (EVM) bytecode decompiler & analyzer library & CLI
127 lines (126 loc) • 5.43 kB
TypeScript
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;
}