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;
}
