Skip to main content

VM

Struct VM 

Source
pub struct VM<'a> {
Show 32 fields pub call_frames: Vec<CallFrame>, pub current_call_frame: CallFrame, pub env: Environment, pub substate: Substate, pub db: &'a mut GeneralizedDatabase, pub tx: &'a Transaction, pub hooks: Vec<Rc<RefCell<dyn Hook>>>, pub storage_original_values: FxHashMap<Address, FxHashMap<H256, U256>>, pub tracer: LevmCallTracer, pub opcode_tracer: LevmOpcodeTracer, pub validation_observer: ValidationObserver, pub debug_mode: DebugMode, pub stack_pool: Vec<Stack>, pub vm_type: VMType, pub frame_tx_context: Option<FrameTxContext>, pub state_gas_used: i64, pub state_gas_reservoir: u64, pub state_gas_reservoir_initial: u64, pub state_gas_spill: u64, pub cost_per_state_byte: u64, pub state_gas_new_account: u64, pub state_gas_storage_set: u64, pub state_gas_auth_base: u64, pub intrinsic_state_gas: u64, pub value_new_account_charged: bool, pub prep_baseline_state_gas: i64, pub prep_baseline_reservoir: u64, pub prep_baseline_state_gas_spill: u64, pub prep_region_backup_marker: PrepareRegionBackupMarker, pub pending_prep_oog: bool, pub crypto: &'a dyn Crypto, pub stateless_validator: Option<&'a dyn StatelessValidator>, /* private fields */
}

Fields§

§call_frames: Vec<CallFrame>

Stack of parent call frames (for nested calls).

§current_call_frame: CallFrame

The currently executing call frame.

§env: Environment

Block and transaction environment.

§substate: Substate

Execution substate (accessed addresses, logs, refunds, etc.).

§db: &'a mut GeneralizedDatabase

Database for reading/writing account state.

§tx: &'a Transaction

The transaction being executed. Borrowed for the VM’s lifetime (the caller owns it for at least that long), avoiding a per-tx deep clone of the access/authorization lists.

§hooks: Vec<Rc<RefCell<dyn Hook>>>

Execution hooks for tracing and debugging.

§storage_original_values: FxHashMap<Address, FxHashMap<H256, U256>>

Original storage values before transaction (for SSTORE gas calculation), keyed first by account to avoid hashing the full tuple on each access.

§tracer: LevmCallTracer

Call tracer for execution tracing.

§opcode_tracer: LevmOpcodeTracer

Opcode (EIP-3155) tracer. Disabled by default; zero overhead when inactive.

§validation_observer: ValidationObserver

EIP-8141 mempool validation-trace observer. Disabled by default; active only during simulate_frame_validation_prefix. Read only behind if self.validation_observer.active, so an inactive observer adds one branch to the dispatch loop and nothing more (mirrors opcode_tracer).

§debug_mode: DebugMode

Debug mode for development diagnostics.

§stack_pool: Vec<Stack>

Pool of reusable stacks to reduce allocations.

§vm_type: VMType

VM type (L1 or L2 with fee config).

§frame_tx_context: Option<FrameTxContext>

Frame transaction context (EIP-8141). Set when executing a frame tx.

§state_gas_used: i64

EIP-8037: Accumulated state gas for this transaction (Amsterdam+). Signed: goes negative when inline refunds exceed gross charges in the local frame (e.g. SSTORE 0→x→0 restoration matching an ancestor’s charge).

§state_gas_reservoir: u64

EIP-8037: State gas reservoir pre-funded from excess gas_limit (Amsterdam+).

§state_gas_reservoir_initial: u64

EIP-8037: Initial reservoir at tx start (before any execution). Captured in add_intrinsic_gas so block-dimensional regular gas can be computed independently of mid-tx reservoir activity (auth refunds, SSTORE credits).

§state_gas_spill: u64

EIP-8037: Cumulative state gas that spilled to regular gas during execution (when reservoir was insufficient). Subtracted when computing dimensional regular gas for block accounting — EELS charge_state_gas spills don’t increment regular_gas_used.

§cost_per_state_byte: u64

EIP-8037: Dynamic cost per state byte (computed from block_gas_limit, Amsterdam+).

§state_gas_new_account: u64

EIP-8037: State gas for new account creation (STATE_BYTES_PER_NEW_ACCOUNT * cost_per_state_byte).

§state_gas_storage_set: u64

EIP-8037: State gas for storage slot creation (STATE_BYTES_PER_STORAGE_SET * cost_per_state_byte).

§state_gas_auth_base: u64

EIP-8037: State gas for the 23-byte EIP-7702 delegation indicator (STATE_BYTES_PER_AUTH_BASE * cost_per_state_byte). Charged in-region by eip7702_set_access_code (EELS set_delegation) once per authority when a net-new delegation indicator is written, and never credited back.

§intrinsic_state_gas: u64

EIP-8037: intrinsic state gas (tx_env.intrinsic_state_gas in EELS). Captured at add_intrinsic_gas time. ethrex lumps intrinsic + execution into state_gas_used, so on top-level error this field is what we leave behind when refunding the execution portion to the reservoir — block accounting then bills the intrinsic (matches EELS tx_state_gas = intrinsic_state_gas + tx_output.state_gas_used).

§value_new_account_charged: bool

EIP-8037: set by prepare_execution when the in-region value-to-not-alive NEW_ACCOUNT charge fires (a value-bearing call to a not-yet-alive recipient). Consumed once, at the top of run_execution, to decide whether an Amsterdam precompile-halt must roll the charge back (the recipient never materializes on halt).

§prep_baseline_state_gas: i64

EIP-8037: current_call_frame.state_gas_used_at_entry captured by enter_prepare_region right before the atomic prepare region (EIP-7702 auth + prepare-dispatch charges) begins. fail_prepare_region rewinds the frame’s state_gas_used back to this pre-region baseline on an internal OOG, mirroring EELS restore_tx_state(prep_snapshot).

§prep_baseline_reservoir: u64

EIP-8037: state_gas_reservoir captured by enter_prepare_region. The set_delegation auth lock-in zeroes the frame spill, so fail_prepare_region cannot reconstruct the pre-region reservoir from refill_frame_state_gas arithmetic; it restores this captured value directly (EELS message.state_gas_reservoir = prep_reservoir).

§prep_baseline_state_gas_spill: u64

EIP-8037: cumulative state_gas_spill captured by enter_prepare_region, so fail_prepare_region restores block-accounting spill to its pre-region value (the region’s spilled state gas is fully rolled back / burned as regular).

§prep_region_backup_marker: PrepareRegionBackupMarker

EIP-8037: pre-region key-space snapshot of call_frame_backup, recorded by enter_prepare_region. Lets fail_prepare_region revert only region-added writes, leaving the sender nonce-bump / fee-deduction entries intact.

§pending_prep_oog: bool

EIP-8037: set by fail_prepare_region when an internal OOG rolls back the atomic prepare region. Consumed by run_execution, which turns it into a full-gas revert ContextResult (mirrors EELS depth-0 except ExceptionalHalt: evm.regular_gas_used += evm.gas_left; evm.gas_left = 0) instead of a tx-level rejection Err that would wrongly invalidate the block.

§crypto: &'a dyn Crypto

Crypto provider for cryptographic operations.

§stateless_validator: Option<&'a dyn StatelessValidator>

Optional stateless validator for the EXECUTE precompile. None on VMs that never dispatch EXECUTE (guest program, witness generation, the stateless validator itself) — those paths can’t supply one without a dependency cycle or recursion.

Implementations§

Source§

impl<'a> VM<'a>

Source

pub fn add_callframe(&mut self, new_call_frame: CallFrame)

Adds current calframe to call_frames, sets current call frame to the passed callframe.

Source

pub fn pop_call_frame(&mut self) -> Result<CallFrame, InternalError>

Source

pub fn is_initial_call_frame(&self) -> bool

Source

pub fn restore_cache_state(&mut self) -> Result<(), VMError>

Restores the cache state to the state before changes made during a callframe.

Source

pub fn restore_cache_state_consuming(&mut self) -> Result<(), VMError>

Like Self::restore_cache_state but moves the current frame’s backup out instead of cloning it. Only sound when nothing reads call_frame_backup afterward: the inner-call revert in handle_return (the frame is popped right after, so its backup is dead), and the top-level / invalid-tx revert when no BackupHook is installed (normal L1 block execution, gated on VM::preserve_top_level_backup).

When a BackupHook IS present (L2 / stateless) the top-level paths must keep cloning, because BackupHook::finalize reads the backup to build the tx-level undo snapshot.

Source

pub fn merge_call_frame_backup_with_parent( &mut self, child_call_frame_backup: &CallFrameBackup, ) -> Result<(), VMError>

Source

pub fn advance_pc(&mut self)

Source§

impl<'a> VM<'a>

Source

pub fn get_account_mut( &mut self, address: Address, ) -> Result<&mut LevmAccount, InternalError>

Source

pub fn increase_account_balance( &mut self, address: Address, increase: U256, ) -> Result<(), InternalError>

Source

pub fn decrease_account_balance( &mut self, address: Address, decrease: U256, ) -> Result<(), InternalError>

Source

pub fn transfer( &mut self, from: Address, to: Address, value: U256, ) -> Result<(), InternalError>

Source

pub fn update_account_bytecode( &mut self, address: Address, new_bytecode: Code, ) -> Result<(), InternalError>

Updates bytecode of given account.

Source

pub fn increment_account_nonce( &mut self, address: Address, ) -> Result<u64, InternalError>

Increments the nonce of the given account. Per EIP-7928, nonce changes are recorded for:

  • EOA senders
  • Contracts performing CREATE/CREATE2
  • Deployed contracts
  • EIP-7702 authorities
Source

pub fn access_storage_slot_for_sstore( &mut self, address: Address, key: H256, ) -> Result<(U256, U256, bool), InternalError>

SSTORE-specialized storage access path that returns current and original values together. This keeps the SSTORE hot path tighter by avoiding extra method-level plumbing.

Source

pub fn record_storage_slot_to_bal(&mut self, address: Address, key: U256)

Records a storage slot read to BAL after gas checks have passed. Per EIP-7928: “If pre-state validation fails, the target is never accessed and must not appear in BAL.” This function should be called AFTER the gas check succeeds.

Source

pub fn get_storage_value( &mut self, address: Address, key: H256, ) -> Result<U256, InternalError>

Gets storage value of an account, caching it if not already cached.

Source

pub fn update_account_storage( &mut self, address: Address, key: H256, slot_key: U256, new_value: U256, current_value: U256, ) -> Result<(), InternalError>

Updates storage of an account, caching it if not already cached.

Source

pub fn backup_storage_slot( &mut self, address: Address, key: H256, current_value: U256, ) -> Result<(), InternalError>

Source§

impl<'a> VM<'a>

Source

pub fn handle_precompile_result( precompile_result: Result<Bytes, VMError>, gas_limit: u64, gas_remaining: u64, ) -> Result<ContextResult, VMError>

Source

pub fn handle_opcode_result(&mut self) -> Result<ContextResult, VMError>

Source

pub fn handle_opcode_error( &mut self, error: VMError, ) -> Result<ContextResult, VMError>

Source

pub fn handle_create_transaction( &mut self, ) -> Result<Option<ContextResult>, VMError>

Handles external create transaction.

Source§

impl<'a> VM<'a>

Source

pub fn generic_create( &mut self, value: U256, code_offset_in_memory: usize, code_size_in_memory: usize, salt: Option<U256>, ) -> Result<OpcodeResult, VMError>

Common behavior for CREATE and CREATE2 opcodes

Source

pub fn generic_call( &mut self, gas_limit: u64, value: U256, msg_sender: Address, to: Address, code_address: Address, should_transfer_value: bool, is_static: bool, calldata: Bytes, ret_offset: usize, ret_size: usize, bytecode: Code, is_delegation_7702: bool, new_account_charged: bool, ) -> Result<OpcodeResult, VMError>

This (should) be the only function where gas is used as a U256. This is because we have to use the values that are pushed to the stack.

Source

pub fn handle_state_backup( &mut self, ctx_result: &ContextResult, consume_backup: bool, ) -> Result<(), VMError>

Pop backup from stack and restore substate and cache if transaction reverted.

consume_backup lets the caller move the frame’s backup out (no clone) on the revert path when nothing reads it afterward; see VM::restore_cache_state_consuming. The top-level call passes true for normal L1 execution and false when a BackupHook is installed (L2 / stateless), since that hook reads the backup in finalize_execution (gated on VM::preserve_top_level_backup).

Source

pub fn handle_return( &mut self, ctx_result: &ContextResult, ) -> Result<(), VMError>

Handles case in which callframe was initiated by another callframe (with CALL or CREATE family opcodes)

Returns the pc increment.

Source

pub fn handle_return_call( &mut self, executed_call_frame: CallFrame, ctx_result: &ContextResult, ) -> Result<(), VMError>

Source

pub fn handle_return_create( &mut self, executed_call_frame: CallFrame, ctx_result: &ContextResult, ) -> Result<(), VMError>

Source§

impl<'a> VM<'a>

Source

pub fn get_trace_result(&mut self) -> Result<CallTraceFrame, VMError>

This method is intended to be accessed after transaction execution

Source§

impl<'a> VM<'a>

Source

pub fn eip7702_set_access_code(&mut self) -> Result<(), VMError>

Applies the EIP-7702 authorizations and charges their state-dependent costs at the top frame, mirroring EELS set_delegation (amsterdam/vm/eoa_delegation.py::set_delegation).

Amsterdam+ (EIP-8037/8038): the per-auth intrinsic regular charge is only REGULAR_PER_AUTH_BASE_COST; the state-dependent charges are levied here, in the atomic prepare region (so an OOG rolls the whole region back and burns all gas rather than rejecting the tx). Per valid authorization, in EELS order:

  • NEW_ACCOUNT (state) when the authority’s account leaf does not yet exist;
  • ACCOUNT_WRITE (regular) when this is the transaction’s first write to the authority’s leaf (the sender’s leaf was written at inclusion, and the recipient’s when value > 0, so those pay nothing here — a self-sponsored authority and repeated authorizations on one authority pay ACCOUNT_WRITE at most once);
  • AUTH_BASE (state) when a net-new delegation indicator is written (the authority was not delegated before the tx and none was set for it earlier in the tx). Charged at most once per authority and never credited back.

On any OutOfGas from a charge, fail_prepare_region rolls back the region and this returns Ok (the full-gas revert is emitted by run_execution); it never propagates an Err (that would wrongly invalidate the block).

Pre-Amsterdam keeps the legacy per-auth model: PER_EMPTY_ACCOUNT_COST was charged at intrinsic and REFUND_AUTH_PER_EXISTING_ACCOUNT is credited here for an authority that already exists in the trie.

Source

pub fn add_intrinsic_gas( &mut self, intrinsic: &IntrinsicGas, ) -> Result<(), VMError>

Source

pub fn get_intrinsic_gas(&self) -> Result<IntrinsicGas, VMError>

Returns (regular_gas, state_gas) intrinsic gas for the transaction. For Amsterdam+, state_gas is the EIP-8037 state portion. For pre-Amsterdam, state_gas is always 0.

Source

pub fn get_min_gas_used(&self) -> Result<u64, VMError>

Calculates the minimum gas to be consumed in the transaction.

Source

pub fn get_tx_callee( tx: &Transaction, db: &mut GeneralizedDatabase, env: &Environment, substate: &mut Substate, ) -> Result<(Address, bool), VMError>

Gets transaction callee, calculating create address if it’s a “Create” transaction. Bool indicates whether it is a create transaction or not.

Source§

impl<'a> VM<'a>

Source

pub fn new( env: Environment, db: &'a mut GeneralizedDatabase, tx: &'a Transaction, tracer: LevmCallTracer, vm_type: VMType, crypto: &'a dyn Crypto, stateless_validator: Option<&'a dyn StatelessValidator>, ) -> Result<Self, VMError>

Constructs a VM, allocating a fresh 32 KB root call-frame stack.

Hot block execution should prefer VM::new_pooled, which draws the root stack from a reusable pool instead of allocating + zeroing one per transaction.

Source

pub fn new_pooled( env: Environment, db: &'a mut GeneralizedDatabase, tx: &'a Transaction, tracer: LevmCallTracer, vm_type: VMType, crypto: &'a dyn Crypto, stateless_validator: Option<&'a dyn StatelessValidator>, stack_pool: &mut Vec<Stack>, memory_pool: &mut Vec<Memory>, ) -> Result<Self, VMError>

Like VM::new, but draws the root call-frame stack from stack_pool (falling back to a fresh Stack::default() only when the pool is empty) and adopts the remaining pooled stacks for sub-call frames. This avoids the per-tx 32 KB stack alloc+zero on a warm pool — the dominant allocation for transfer-heavy blocks, where the root frame is the only frame.

Pair with VM::reclaim_into after execution to return every stack (root + sub-frame) to stack_pool and the root memory buffer to memory_pool so the next tx reuses them.

Source

pub fn reclaim_into( self, stack_pool: &mut Vec<Stack>, memory_pool: &mut Vec<Memory>, )

Returns this VM’s reusable buffers to the caller’s pools so the next transaction reuses them instead of allocating: every stack (root call-frame stack plus any sub-frame stacks still pooled internally) to stack_pool, and the root memory buffer to memory_pool. Must run on both the success and error paths of VM::execute.

Source

pub fn increase_state_gas(&mut self, gas: u64) -> Result<(), VMError>

EIP-8037: Charge state gas, drawing from reservoir first, spilling to gas_remaining if exhausted.

Must only be called for Amsterdam+ forks. All call sites must guard with fork >= Fork::Amsterdam before invoking this method.

Source

pub fn credit_state_gas_refund(&mut self, amount: u64) -> Result<(), VMError>

EIP-8037 credit_state_gas_refund: refund amount LIFO, mirroring EELS. The portion spilled past the reservoir into this frame’s gas_remaining (frame_state_gas_spilled) is returned to gas_remaining first; only the remainder flows to the shared reservoir. state_gas_used drops by the full amount (may go negative when the matching charge lives in an ancestor frame). Block accounting: both spill counters drop by the gas_remaining-credited portion only, never the full amount. Amsterdam+ only.

Source

pub fn refund_new_account_state_gas( &mut self, charged: bool, ) -> Result<(), VMError>

Refund the EIP-8037 new-account state gas when charged is true. Used by the CALL paths where a value-bearing call to an empty account charged the new-account state gas but no account ends up created (insufficient balance, max depth, child revert / failed precompile).

Source

pub fn refill_frame_state_gas(&mut self, entry: i64) -> Result<(), VMError>

EIP-8037 refill_frame_state_gas: roll back this frame’s state gas in LIFO order on revert or exceptional halt, mirroring EELS refill_frame_state_gas.

entry is the value of state_gas_used when this frame began executing (current_call_frame.state_gas_used_at_entry). The frame’s net charge is frame_used = state_gas_used - entry. Of that, frame_state_gas_spilled was drawn from gas_remaining (spilled past the reservoir) and the remainder came from the reservoir. LIFO refill returns the spilled portion to gas_remaining first and the rest to the reservoir, restoring the exact pools the charges drew from. state_gas_used is rolled back to entry and the per-frame spill counter is cleared.

Revert-vs-halt equivalence (load-bearing): on revert, the spilled gas returns to gas_remaining (raising the sender refund / lowering raw_consumed) while state_gas_spill drops by the same amount, so the regular dimension in refund_sender (default_hook) drops by exactly the refilled spill. On exceptional halt the caller subsequently sets gas_remaining = 0 and burns it to the regular dimension — but state_gas_spill was already decremented here, so the spilled gas stays counted as regular. Both paths are correct.

Must only be called for Amsterdam+ forks.

Source

pub fn enter_prepare_region(&mut self)

EIP-8037: enters the atomic prepare region (EELS interpreter.py’s depth-0 try around set_delegation + prepare_dispatch, interpreter.py:353-375). Must be called in prepare_execution, after the sender nonce bump and fee deduction (those survive a region rollback) but before the type-4 auth handling (the first region charge). Captures the pre-region state-gas baseline and the call_frame_backup key-space so fail_prepare_region can later undo exactly the region’s writes.

Source

pub fn fail_prepare_region(&mut self)

EIP-8037: rolls back the atomic prepare region on an internal OOG from any of its charges (7702 auth, CREATE/value NEW_ACCOUNT, recipient delegation-resolve). Restores every call_frame_backup entry added since enter_prepare_region (leaving the earlier sender nonce-bump / fee-deduction entries untouched), refills the frame’s state gas back to the pre-region baseline, and sets pending_prep_oog so run_execution turns this into a full-gas revert instead of a tx-level rejection Err (which would wrongly invalidate the block). Mirrors EELS restore_tx_state(prep_snapshot) + refill_frame_state_gas (interpreter.py:366-374).

Source

pub fn execute(&mut self) -> Result<ExecutionReport, VMError>

Executes a whole external transaction. Performing validations at the beginning.

Source

pub fn run_frame_validation_prefix( &mut self, frame_indices: &[usize], deploy_index: Option<usize>, canonical_paymaster_pay_frame: Option<usize>, ) -> Result<PrefixSimResult, VMError>

EIP-8141 mempool entry point: set up the frame-tx context and observer, then simulate the validation prefix.

Performs the frame-tx preamble (static constraints, nonce, fee sanity, FrameTxContext init, outer-signature validation) — the same checks execute_frame_tx runs before any frame — then activates the ValidationObserver for sender with the prefix’s deploy_index, runs the prefix via VM::simulate_validation_prefix, and returns the raw simulation result. Does NOT charge or refund gas. canonical_paymaster_pay_frame is the index of a canonical paymaster’s pay frame (always None today, OQ1); when set, the access-restriction skip fires for that frame.

Source

pub fn simulate_validation_prefix( &mut self, frame_indices: &[usize], ) -> Result<PrefixSimResult, VMError>

EIP-8141 mempool validation-prefix simulation (local peer policy).

Runs ONLY the validation-prefix frames (the verify/pay/deploy frames that must execute before the transaction’s payer is established) of a frame transaction, under an active ValidationObserver, then stops as soon as the payer has been set. Reuses the real frame execution primitives (eip7702_get_code, execute_default_code, run_execution, substate backups, value transfer) over the DEFAULT/VERIFY subset that prefixes are restricted to (Phase 1 structural rules forbid SENDER and atomic-batch frames in the prefix), so it dispatches real opcodes through the real handlers — not a separate mini-EVM.

frame_indices are the prefix frame indices (in order), as identified by FrameTransaction::validation_prefix; expiry-verifier frames interleaved in the prefix are run too (they may appear between prefix frames). The caller must have set frame_tx_context and activated the observer.

Returns PrefixSimResult describing the outcome. Does NOT charge fees or refund gas (mempool simulation only); state changes accumulate in the shared db and are discarded by the caller (a fresh simulation database).

Source

pub fn run_execution(&mut self) -> Result<ContextResult, VMError>

Main execution loop.

Source

pub fn check_validation_banned_opcode(&mut self, opcode: u8)

EIP-8141 validation-trace banned-opcode check (mempool simulation only).

Called once per dispatch-loop iteration, AFTER the opcode is fetched and BEFORE the handler runs, gated by self.validation_observer.active. Byte values are pinned against opcodes.rs.

Static bans: ORIGIN, GASPRICE, BLOCKHASH, COINBASE, TIMESTAMP (except when the current frame’s target is EXPIRY_VERIFIER), NUMBER, PREVRANDAO, GASLIMIT, BASEFEE, BLOBHASH, BLOBBASEFEE, INVALID, SELFDESTRUCT, BALANCE, SELFBALANCE, TLOAD, TSTORE, and CALLCODE in non-deploy prefix frames (ERC-7562 bans CALLCODE in validation; DELEGATECALL is allowed subject to the CALL-family trace rules in the handlers). SSTORE/CREATE/CREATE2 are allowed only inside the deploy frame and are enforced in their handlers (state-write rules), not here.

Sequential GAS rule: GAS is allowed only immediately before a *CALL (CALL/CALLCODE/DELEGATECALL/STATICCALL). We detect this by remembering last_opcode: if the previous iteration was GAS and this opcode is NOT a *CALL, the prior GAS was illegal.

Source

pub fn validation_check_sload(&mut self, address: Address, slot: H256)

EIP-8141 validation-trace SLOAD check (mempool simulation only).

SLOAD is allowed only when the storage owner (address, the executing frame’s to) is the transaction sender. Records the touched slot for the admission-time revalidation affected-set.

Source

pub fn validation_check_sstore(&mut self, address: Address, slot: H256)

EIP-8141 validation-trace SSTORE check (mempool simulation only).

SSTORE is allowed only inside the deploy frame AND only when the storage owner (address, the executing frame’s to) is the transaction sender.

Source

pub fn validation_check_create(&mut self)

EIP-8141 validation-trace state-creation check for CREATE/CREATE2 (mempool simulation only). Contract creation is a state write permitted only inside the deploy frame.

Source

pub fn validation_check_call_target( &mut self, target: Address, is_delegation_7702: bool, ) -> Result<(), VMError>

EIP-8141 validation-trace CALL*/EXTCODE* target check (mempool simulation only).

The target must be an existing account or a precompile and must NOT be EIP-7702-delegated, except the sender running its own default code (the sender is exempt — its existence is a transaction precondition and it may have no code). is_delegation_7702 is the flag already computed by eip7702_get_code in the CALL-family handlers, threaded in to avoid a second delegation resolution (and the &mut VM / &mut db borrow conflict a dispatch-loop stack-peek would create).

Source

pub fn validation_check_extcode_target( &mut self, target: Address, ) -> Result<(), VMError>

EIP-8141 validation-trace EXTCODE* target check (mempool simulation only). Like VM::validation_check_call_target, but resolves the EIP-7702 delegation flag itself (the EXTCODE handlers do not call eip7702_get_code). The substate.add_accessed_address warming the EXTCODE gas already performed has happened; resolving here only follows a delegation indicator to read its flag, mirroring the CALL-family path.

Source

pub fn execute_precompile( code_address: H160, calldata: &Bytes, gas_limit: u64, gas_remaining: &mut u64, fork: Fork, cache: Option<&PrecompileCache>, crypto: &dyn Crypto, stateless_validator: Option<&dyn StatelessValidator>, ) -> Result<ContextResult, VMError>

Executes precompile and handles the output that it returns, generating a report.

Source

pub fn is_create(&self) -> Result<bool, InternalError>

True if external transaction is a contract creation

Source

pub fn stateless_execute(&mut self) -> Result<ExecutionReport, VMError>

Executes without making changes to the cache.

Source

pub fn collect_stack_for_trace(&self) -> Vec<U256>

Collects the current stack in bottom-first order for struct-log emission.

LEVM stack is top-first in memory (values[offset] = top), so we reverse the active slice to produce the bottom-first wire format geth uses. Returns an empty Vec when cfg.disable_stack is true.

Source

pub fn collect_memory_for_trace(&self) -> Vec<u8> ⓘ

Collects the live memory bytes for the current frame.

Returns an empty Vec when cfg.enable_memory is false or memory is empty.

Source

pub fn read_storage_for_trace(&mut self, opcode: u8) -> Option<(H256, H256)>

Pre-reads the storage key/value for the current SLOAD or SSTORE opcode.

Returns None when:

  • cfg.disable_storage is set, or
  • opcode is not SLOAD (0x54) or SSTORE (0x55), or
  • the stack is empty (guard against underflow before the handler runs), or
  • the storage read fails for any reason (including AccountNotFound — the trace omits the entry rather than emitting an ambiguous zero).

For SLOAD: key = stack.top; value = the current stored value read from the DB. For SSTORE: key = stack.top, value = stack[top-1] (the new value being written).

Auto Trait Implementations§

§

impl<'a> !Freeze for VM<'a>

§

impl<'a> !RefUnwindSafe for VM<'a>

§

impl<'a> !Send for VM<'a>

§

impl<'a> !Sync for VM<'a>

§

impl<'a> !UnwindSafe for VM<'a>

§

impl<'a> Unpin for VM<'a>

§

impl<'a> UnsafeUnpin for VM<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> ArchivePointee for T

Source§

type ArchivedMetadata = ()

The archived version of the pointer metadata for this type.
Source§

fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata

Converts some archived metadata to the pointer metadata for itself.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T, U> ExactFrom<T> for U
where U: TryFrom<T>,

Source§

fn exact_from(value: T) -> U

Source§

impl<T, U> ExactInto<U> for T
where U: ExactFrom<T>,

Source§

fn exact_into(self) -> U

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> LayoutRaw for T

Source§

fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>

Returns the layout of the type.
Source§

impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
where T: SharedNiching<N1, N2>, N1: Niching<T>, N2: Niching<T>,

Source§

unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool

Returns whether the given value has been niched. Read more
Source§

fn resolve_niched(out: Place<NichedOption<T, N1>>)

Writes data to out indicating that a T is niched.
Source§

impl<T, U> OverflowingInto<U> for T
where U: OverflowingFrom<T>,

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Pointee for T

Source§

type Metadata = ()

The metadata type for pointers and references to this type.
Source§

impl<T, U> RoundingInto<U> for T
where U: RoundingFrom<T>,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> SaturatingInto<U> for T
where U: SaturatingFrom<T>,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T, U> WrappingInto<U> for T
where U: WrappingFrom<T>,

Source§

fn wrapping_into(self) -> U