Opcode semantics¶
The interpreter interpret dispatches each decoded opcode to a handler that charges its gas, consumes its stack operands, and produces its result or effect. The handlers are grouped by family (arithmetic, bitwise, keccak, environment, block, stack/memory, storage, flow, push/dup/swap, log, system).
Handlers follow the state-passing convention (YP ฮผโฒ = ฮ(ฮผ)): each takes only the carried values it uses and returns the same values in the same order. Decoded instruction data remains explicit where required. The registers behind the state are read and written only at frame boundaries.
Pure compute is done here; every world effect is a kernel syscall
(k_*). All gas and policy stays in the EVM: it marks-and-prices access
via the kernel's returned warm bit (EIP-2929), decides whether an effect
happens, and issues the syscall only for real effects (a no-op SSTORE
charges gas but issues no host write). Memory-touching opcodes pay the
quadratic expansion cost via memory_expansion_gas_cost before acting.
Sub-calls and creates delegate to run_call / run_create, which
install a child frame and save its parent continuation. The non-recursive
opcode bodies are the execute_* functions below.
function opcode_frame_status¶
Converts a non-terminal opcode result into the corresponding frame status.
function opcode_frame_status(result : OpcodeOutcome) -> FrameStatus = match result {
Continue() => Running(),
Failed(kind) => Exceptional(kind),
}Per-frame execution status: running, halted normally, or exceptionally halted.
union FrameStatus = {
/* mid-execution */
Running : unit,
/* halted normally (YP ยง9.4.4) */
Halted : HaltKind,
/* halted exceptionally: all frame gas consumed, effects void */
Exceptional : ExceptionKind
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}Helpers¶
function self_addr¶
The storage owner (YP I_a): SLOAD, SSTORE, LOG, and
SELFDESTRUCT act on this account.
The per-frame call message (YP ยง8, the I tuple): caller, executing address, code owner, value, calldata length, static flag, and call depth.
struct Message = {
/* CALLER (I_s) */
caller : address,
/* account whose code runs (differs under DELEGATECALL/CALLCODE and
EIP-7702 delegation) */
code_address : address,
/* ADDRESS / storage owner = self (I_a) */
address : address,
/* CALLVALUE (I_v) */
value : word,
/* State-gas reservoir available when the frame was entered. */
state_gas_reservoir : state_gas,
/* inside a STATICCALL frame (EIP-214) */
is_static : bool,
/* call depth (YP I_e), bounded by call_depth_limit */
depth : frame_depth,
}A 20-byte account address (YP ยง4.1), in canonical protocol byte order.
type address = vector(20, inc, byte)function guard_static¶
EIP-214 write protection: any state-modifying opcode in a
STATICCALL frame halts exceptionally on the carried gas.
State-changing opcodes call this first; true means already
halted.
function guard_static(g : gas, is_static : bool) -> (gas, OpcodeOutcome) =
if is_static then {
(GAS_ZERO, Failed(WriteProtection))
} else {
(g, Continue())
}let GAS_ZERO : int(0) = 0Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function do_jump¶
JUMP/JUMPI target validity: the destination must be in code range
and land on a JUMPDEST (the precomputed valid-destination set,
YP ยง9.4.3); otherwise an invalid-jump exceptional halt. PUSH-data
bytes that happen to equal 0x5b are not valid. Returns the next
program counter and the carried gas.
function do_jump(
pc_in : code_pointer,
g : gas,
frame_code : Code,
destination_value : word,
) -> (
(code_pointer, gas, OpcodeOutcome)
) = {
let code_length = frame_code_len(frame_code);
if destination_value < code_length then {
let destination : code_pointer = destination_value;
let valid_destination = frame_jumpdest_valid(frame_code, destination);
if valid_destination then {
(destination, g, Continue())
} else {
(pc_in, GAS_ZERO, Failed(InvalidJump))
}
} else {
(pc_in, GAS_ZERO, Failed(InvalidJump))
}
}The frame code length in bytes (CODESIZE).
function frame_code_len(frame_code : Code) -> code_length = {
let code = frame_code;
let length = code.len;
length
}function frame_jumpdest_valid(frame_code, dest) = {
let code = frame_code;
let length = code.len;
jumpdest_ref_contains(code.jumpdests, length, dest)
}let GAS_ZERO : int(0) = 0Existential executable-code value whose concrete byte address and length
remain correlated inside CodeFields.
type Code = {
'off 'len,
code_region_valid_range('off, 'len) & code_valid_length('len).
CodeFields('off, 'len)
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}A contract-code length.
type code_length = range(0, code_region_bound)An absolute byte position in the code arena.
type code_pointer = range(0, code_region_bound)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)The EVM 256-bit machine word (YP ยง9.1). A transparent range keeps the mathematical subtype relation visible: narrower non-negative ranges can be passed as words without a model-level conversion.
type word = range(0, 2 ^ 256 - 1)function guard_stack¶
Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Classifies the carried cursor against one instruction's input and output stack requirements.
function validate_stack(top, inputs, outputs) = {
let height = stack_height(top);
if height < inputs then {
StackUnderflowFailure
} else if STACK_LIMIT < height - inputs + outputs then {
StackOverflowFailure
} else {
StackValid
}
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Checks the Yellow Paper stack precondition for one instruction before it
charges gas or performs side effects. inputs is the instruction's
required stack height (delta) and outputs is the height it contributes
after consuming those inputs (alpha). This is the single stack-bounds
guard: handler bodies consume and produce operands unchecked behind it.
enum StackValidation = { StackValid, StackUnderflowFailure, StackOverflowFailure }The number of words on an operand stack.
type operand_stack_height = range(0, 1024)function pop_log_topics¶
Pops count log topics from the stack into its bounded representation.
function pop_log_topics(count : log_topic_count, sp_in : StackPointer) -> (LogTopics, StackPointer) = {
var sp = sp_in;
match count {
0 => (LogTopics0(), sp),
1 => {
let t0 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
(LogTopics1(t0), sp)
},
2 => {
let t0 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let t1 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
(LogTopics2((t0, t1)), sp)
},
3 => {
let t0 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let t1 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let t2 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
(LogTopics3((t0, t1, t2)), sp)
},
4 => {
let t0 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let t1 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let t2 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let t3 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
(LogTopics4((t0, t1, t2, t3)), sp)
},
_ => (LogTopics0(), sp),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}The bounded topic operands of one LOG0โLOG4 instruction. Keeping the
arity in the constructor avoids allocating a Sail list for at most four
stack words.
union LogTopics = {
/* `LOG0`: no topics */
LogTopics0 : unit,
/* `LOG1`: one topic */
LogTopics1 : word,
/* `LOG2`: two topics in stack-pop order */
LogTopics2 : (word, word),
/* `LOG3`: three topics in stack-pop order */
LogTopics3 : (word, word, word),
/* `LOG4`: four topics in stack-pop order */
LogTopics4 : (word, word, word, word),
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}The number of indexed topics attached to one log.
type log_topic_count = range(0, 4)The opcode bodies¶
Each semantic opcode constructor has a named body. The standard decoder
validates the instruction's stack effect before dispatching its ast to these
functions below, so the bodies consume and produce operands unchecked.
Optimized C applies the same validation at its raw-byte dispatch boundary
before calling a generated body, without materializing an ast.
function execute_add¶
Implements ADD.
function execute_add(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
let result = alu_add(a, b);
write_stack_word(sp, result);
(gas, sp, Continue())
}function alu_add(a, b) = word_add(a, b)Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_mul¶
Implements MUL.
function execute_mul(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_low then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_low;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
let result = alu_mul(a, b);
write_stack_word(sp, result);
(gas, sp, Continue())
}function alu_mul(a, b) = word_mul(a, b)Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_low : gas_constant = 5Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_sub¶
Implements SUB.
function execute_sub(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
let result = alu_sub(a, b);
write_stack_word(sp, result);
(gas, sp, Continue())
}function alu_sub(a : word, b : word) -> word = word_sub(a, b)Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_div¶
Implements unsigned DIV.
function execute_div(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_low then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_low;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
let result = alu_div(a, b);
write_stack_word(sp, result);
(gas, sp, Continue())
}DIV: unsigned Euclidean division; division by zero yields 0
(YP Appendix H).
function alu_div(a : word, b : word) -> word =
word_div(a, b)Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_low : gas_constant = 5Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_sdiv¶
Implements signed SDIV.
function execute_sdiv(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_low then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_low;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
let result = alu_sdiv(a, b);
write_stack_word(sp, result);
(gas, sp, Continue())
}SDIV: signed division, truncating toward zero; division by zero
yields 0.
function alu_sdiv(a : word, b : word) -> word = {
/* SDIV */
let divisor_is_zero = word_is_zero(b);
if divisor_is_zero then {
WORD_ZERO
} else {
let dividend_magnitude = word_abs(a);
let divisor_magnitude = word_abs(b);
let quotient = word_div(dividend_magnitude, divisor_magnitude);
let dividend_sign = word_bit(a, 255);
let divisor_sign = word_bit(b, 255);
if (dividend_sign == bitone) != (divisor_sign == bitone) then {
word_negate(quotient)
} else {
quotient
}
}
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_low : gas_constant = 5Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_mod¶
Implements unsigned MOD.
function execute_mod(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_low then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_low;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
let result = alu_mod(a, b);
write_stack_word(sp, result);
(gas, sp, Continue())
}MOD: unsigned modulus; a zero modulus yields 0.
function alu_mod(a : word, b : word) -> word =
word_mod(a, b)Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_low : gas_constant = 5Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_smod¶
Implements signed SMOD.
function execute_smod(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_low then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_low;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
let result = alu_smod(a, b);
write_stack_word(sp, result);
(gas, sp, Continue())
}SMOD: signed remainder, with the sign of the dividend; a zero modulus
yields 0.
function alu_smod(a : word, b : word) -> word = {
/* SMOD */
let modulus_is_zero = word_is_zero(b);
if modulus_is_zero then {
WORD_ZERO
} else {
let dividend_magnitude = word_abs(a);
let modulus_magnitude = word_abs(b);
let remainder = word_mod(dividend_magnitude, modulus_magnitude);
let dividend_sign = word_bit(a, 255);
if dividend_sign == bitone then {
word_negate(remainder)
} else {
remainder
}
}
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_low : gas_constant = 5Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_addmod¶
Implements ADDMOD.
function execute_addmod(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 3, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_mid then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_mid;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let n = read_stack_word(sp);
let result = alu_addmod(a, b, n);
write_stack_word(sp, result);
(gas, sp, Continue())
}function alu_addmod(a, b, n) = {
/* ADDMOD */
if n == 0 then {
WORD_ZERO
} else {
let remainder = tmod_nat(a + b, n);
u256(remainder)
}
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_mid : gas_constant = 8Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_mulmod¶
Implements MULMOD.
function execute_mulmod(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 3, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_mid then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_mid;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let n = read_stack_word(sp);
let result = alu_mulmod(a, b, n);
write_stack_word(sp, result);
(gas, sp, Continue())
}function alu_mulmod(a, b, n) = {
/* MULMOD */
if n == 0 then {
WORD_ZERO
} else {
let remainder = tmod_nat(a * b, n);
u256(remainder)
}
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_mid : gas_constant = 8Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_exp¶
Implements EXP, including exponent-dependent gas.
function execute_exp(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let e = read_stack_word(sp);
let gas_cost = exp_gas(e);
if carried_gas < gas_cost then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - gas_cost;
let result = alu_exp(a, e);
write_stack_word(sp, result);
(gas, sp, Continue())
}EXP via square-and-multiply over the 256 exponent bits, reduced
modulo 2^256 at every step.
function alu_exp(base : word, exponent : word) -> word = {
var result : word = WORD_ONE;
var b : word = base;
var e : word = exponent;
/* Square-and-multiply over exactly the exponent's significant bits:
every round beyond the bit length multiplies by one and squares a
dead base. The final squaring feeds no later round and is skipped. */
var remaining : word_bit_count = word_bit_length(exponent);
while remaining > 0 termination_measure(remaining) do {
let rounds_left = remaining;
let low_bit = word_bit(e, 0);
if low_bit == bitone then {
result = word_mul(result, b)
};
if rounds_left > 1 then {
b = word_mul(b, b)
};
e = word_shift_right_one(e);
remaining =
if rounds_left > 0 then {
rounds_left - 1
} else {
0
}
};
result
}EXP: base plus G_expbyte per significant exponent byte
(EIP-160).
function exp_gas(exponent : word) -> gas_cost = {
let exponent_bytes = word_byte_length(exponent);
G_expbyte * exponent_bytes + G_exp
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)A transient computed charge after its affordability or structural bound
has been established. Unaffordable larger computations are represented by
GasCharge.affordable = false rather than materialized as a cost.
type gas_cost = range(0, 2 ^ 64 - 1)function execute_signextend¶
Implements SIGNEXTEND.
function execute_signextend(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_low then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_low;
let bi = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let v = read_stack_word(sp);
let result = alu_signextend(bi, v);
write_stack_word(sp, result);
(gas, sp, Continue())
}SIGNEXTEND(byte_index, value): sign-extends value from byte
byte_index (0 = least significant); indices โฅ 31 leave the value
unchanged.
function alu_signextend(byte_index : word, value : word) -> word = {
if byte_index < 32 then {
let index : range(0, 31) = byte_index;
let width : word_bit_count = index * 8 + 8;
let sign_shift : word_bit_count = index * 8 + 7;
let shifted_sign = word_shift_right(value, sign_shift);
let isolated_sign = word_and(shifted_sign, WORD_ONE);
let sign_set = isolated_sign == WORD_ONE;
let low_mask_end = word_shift_left(WORD_ONE, width);
let low_mask = word_sub(low_mask_end, WORD_ONE);
if sign_set then {
let low_value = word_and(value, low_mask);
let high_mask = word_not(low_mask);
word_or(low_value, high_mask)
} else {
word_and(value, low_mask)
}
} else {
value
}
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_low : gas_constant = 5Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_lt¶
Implements unsigned LT.
function execute_lt(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
let result = alu_lt(a, b);
write_stack_word(sp, result);
(gas, sp, Continue())
}LT: 1 when a is strictly below b, unsigned.
function alu_lt(a : word, b : word) -> word = {
let result = word_ult(a, b);
word_of_bool(result)
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_gt¶
Implements unsigned GT.
function execute_gt(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
let result = alu_gt(a, b);
write_stack_word(sp, result);
(gas, sp, Continue())
}GT: 1 when a is strictly above b, unsigned.
function alu_gt(a : word, b : word) -> word = {
let result = word_ult(b, a);
word_of_bool(result)
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_slt¶
Implements signed SLT.
function execute_slt(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
let result = alu_slt(a, b);
write_stack_word(sp, result);
(gas, sp, Continue())
}SLT: 1 when a is strictly below b, two's-complement signed.
function alu_slt(a : word, b : word) -> word = {
let result = word_slt(a, b);
word_of_bool(result)
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_sgt¶
Implements signed SGT.
function execute_sgt(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
let result = alu_sgt(a, b);
write_stack_word(sp, result);
(gas, sp, Continue())
}SGT: 1 when a is strictly above b, two's-complement signed.
function alu_sgt(a : word, b : word) -> word = {
let result = word_slt(b, a);
word_of_bool(result)
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_eq¶
Implements EQ.
function execute_eq(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
let result = alu_eq(a, b);
write_stack_word(sp, result);
(gas, sp, Continue())
}function alu_eq(a : word, b : word) -> word = word_of_bool(a == b)Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_iszero¶
Implements ISZERO.
function execute_iszero(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 1, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
if carried_gas < G_verylow then {
return (GAS_ZERO, carried_sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let a = read_stack_word(carried_sp);
let result = alu_iszero(a);
write_stack_word(carried_sp, result);
(gas, carried_sp, Continue())
}ISZERO: 1 exactly when the operand is zero.
function alu_iszero(a : word) -> word = {
let result = word_is_zero(a);
word_of_bool(result)
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_and¶
Implements bitwise AND.
function execute_and(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
let result = alu_and(a, b);
write_stack_word(sp, result);
(gas, sp, Continue())
}function alu_and(a : word, b : word) -> word = word_and(a, b)Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_or¶
Implements bitwise OR.
function execute_or(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
let result = alu_or(a, b);
write_stack_word(sp, result);
(gas, sp, Continue())
}function alu_or(a : word, b : word) -> word = word_or(a, b)Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_xor¶
Implements bitwise XOR.
function execute_xor(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let a = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let b = read_stack_word(sp);
let result = alu_xor(a, b);
write_stack_word(sp, result);
(gas, sp, Continue())
}function alu_xor(a : word, b : word) -> word = word_xor(a, b)Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_not¶
Implements bitwise NOT.
function execute_not(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 1, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
if carried_gas < G_verylow then {
return (GAS_ZERO, carried_sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let a = read_stack_word(carried_sp);
let result = alu_not(a);
write_stack_word(carried_sp, result);
(gas, carried_sp, Continue())
}function alu_not(a : word) -> word = word_not(a)Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_byte¶
Implements BYTE.
function execute_byte(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let i = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let x = read_stack_word(sp);
let result = alu_byte(i, x);
write_stack_word(sp, result);
(gas, sp, Continue())
}BYTE(i, x): the i-th most-significant byte of x (0 = MSB);
indices โฅ 32 yield 0.
function alu_byte(i : word, x : word) -> word = {
if i < 32 then {
let index : range(0, 31) = i;
let shift : word_bit_count = (31 - index) * 8;
let shifted = word_shift_right(x, shift);
let low_byte = word_low_byte(shifted);
unsigned(low_byte)
} else {
WORD_ZERO
}
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_shl¶
Implements logical left shift SHL (EIP-145).
function execute_shl(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
/* EIP-145 */
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let s = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let v = read_stack_word(sp);
let result = alu_shl(s, v);
write_stack_word(sp, result);
(gas, sp, Continue())
}SHL: logical left shift; amounts โฅ 256 yield 0.
function alu_shl(shift_amt : word, v : word) -> word =
/* SHL */
if shift_amt < 256 then {
word_shift_left(v, shift_amt)
} else {
WORD_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_shr¶
Implements logical right shift SHR (EIP-145).
function execute_shr(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
/* EIP-145 */
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let s = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let v = read_stack_word(sp);
let result = alu_shr(s, v);
write_stack_word(sp, result);
(gas, sp, Continue())
}SHR: logical right shift; amounts โฅ 256 yield 0.
function alu_shr(shift_amt : word, v : word) -> word =
/* SHR */
if shift_amt < 256 then {
word_shift_right(v, shift_amt)
} else {
WORD_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_sar¶
Implements arithmetic right shift SAR (EIP-145).
function execute_sar(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
/* EIP-145 */
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let s = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let v = read_stack_word(sp);
let result = alu_sar(s, v);
write_stack_word(sp, result);
(gas, sp, Continue())
}SAR: arithmetic (sign-propagating) right shift.
function alu_sar(shift_amt : word, v : word) -> word = {
/* SAR */
if shift_amt < 256 then {
word_arithmetic_shift_right(v, shift_amt)
} else {
let sign_bit = word_bit(v, 255);
if sign_bit == bitone then {
WORD_ALL_ONES
} else {
WORD_ZERO
}
}
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_clz¶
Implements count-leading-zeroes CLZ (EIP-7939).
function execute_clz(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 1, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
/* EIP-7939 */
if carried_gas < G_low then {
return (GAS_ZERO, carried_sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_low;
let x = read_stack_word(carried_sp);
let result = alu_clz(x);
write_stack_word(carried_sp, result);
(gas, carried_sp, Continue())
}CLZ: the count of leading zero bits of a 256-bit word (EIP-7939).
function alu_clz(x : word) -> word = {
let bit_length = word_bit_length(x);
u256(256 - bit_length)
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_low : gas_constant = 5Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_keccak256¶
Implements KECCAK256 over an expanded memory range.
function execute_keccak256(
memory_base : memory_base,
carried_gas : gas,
carried_sp : StackPointer,
carried_memory_height : memory_height,
) -> (
(gas, StackPointer, memory_height, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 2, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, carried_memory_height, stack_status)
};
var gas : gas = carried_gas;
var sp : StackPointer = carried_sp;
var memory : memory_height = carried_memory_height;
let offset_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let length_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let keccak_cost = keccak_gas_cost(length_word, gas);
if not_bool(keccak_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, keccak_cost.cost);
let requested_height = memory_requested_height(offset_word, length_word);
let expansion_cost = memory_expansion_gas_cost(memory, requested_height, gas);
if not_bool(expansion_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, expansion_cost.cost);
let access = memory_access(offset_word, length_word);
memory = expand_memory(memory_base, memory, access.requested_height);
let digest = mem_keccak(memory_base, memory, access.range);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, digest);
(gas, sp, memory, Continue())
}Materializes an already-charged memory high-water mark and returns its updated scalar height.
function expand_memory(base : memory_base, height : memory_height, requested_height : memory_length) -> memory_height = {
if requested_height <= sizeof(memory_region_bound) - base then {
if height < requested_height then {
mem_expand(base, height, requested_height);
requested_height
} else {
height
}
} else {
fatal_error(ExecutionInvalid)
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}function keccak_gas_cost(size : word, available : gas) -> GasCharge =
memory_word_gas_cost(G_keccak, G_keccak_word, size, available)KECCAK256 over the already-expanded memory range [off, off+len).
function mem_keccak(base : memory_base, mem : memory_height, range : MemoryRange) -> word = {
let bytes = active_memory_slice(base, mem, range.off, range.len);
let digest = keccak256(bytes);
hash_to_word(digest)
}function memory_access(start, size) =
if size == 0 then {
EMPTY_MEMORY_ACCESS
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let range = memory_range(bounded_start, bounded_size);
let requested_height = bounded_start + bounded_size;
let access = struct { range = range, requested_height = requested_height } :
MemoryAccessFields('bounded_start, 'bounded_size, 'bounded_start + 'bounded_size);
access
} else {
fatal_error(ExecutionInvalid)
}
} else {
fatal_error(ExecutionInvalid)
}function memory_expansion_gas_cost(mem, requested_height, available) =
if requested_height <= sizeof(memory_region_bound) then {
let materialized_size : memory_length = requested_height;
let new_words = memory_word_count(materialized_size);
let old_size = memory_high_water(mem);
let old_words = memory_word_count(old_size);
if new_words <= old_words then {
gas_charge(GAS_COST_ZERO)
} else {
let old_cost = mem_cost(old_words);
let new_cost = mem_cost(new_words);
if old_cost <= new_cost then {
let exact_cost = new_cost - old_cost;
if exact_cost <= available then {
let cost : gas_cost = exact_cost;
gas_charge(cost)
} else {
GAS_CHARGE_UNAFFORDABLE
}
} else {
gas_charge(GAS_COST_ZERO)
}
}
} else {
GAS_CHARGE_UNAFFORDABLE
}function memory_requested_height(start, size) =
if size == 0 then {
0
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let requested_height : memory_required_endpoint = bounded_start + bounded_size;
requested_height
} else {
sizeof(memory_region_bound + 1)
}
} else {
sizeof(memory_region_bound + 1)
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)An absolute byte position in the shared EVM-memory arena.
type memory_base = range(0, memory_region_bound)The active EVM frame's exact relative byte high-water mark. It is carried
beside the frame's absolute memory_base; the host retains no hidden
frame coordinate or lifecycle state.
type memory_height = memory_lengthfunction execute_address¶
Implements ADDRESS.
function execute_address(
carried_address : address,
carried_gas : gas,
carried_sp : StackPointer,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let address_word = address_to_word(carried_address);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, address_word);
(gas, sp, Continue())
}Embeds a canonical-order address into the low 160 bits of an EVM word.
function address_to_word(bytes : address) -> word =
unsigned(
bytes[0]
@ bytes[1]
@ bytes[2]
@ bytes[3]
@ bytes[4]
@ bytes[5]
@ bytes[6]
@ bytes[7]
@ bytes[8]
@ bytes[9]
@ bytes[10]
@ bytes[11]
@ bytes[12]
@ bytes[13]
@ bytes[14]
@ bytes[15]
@ bytes[16]
@ bytes[17]
@ bytes[18]
@ bytes[19],
)Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}A 20-byte account address (YP ยง4.1), in canonical protocol byte order.
type address = vector(20, inc, byte)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_origin¶
Implements ORIGIN.
function execute_origin(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let origin = k_env(F_Origin);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, origin);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}An environment field as the word its opcode pushes.
function k_env(f : EnvField) -> word = {
let active_tx = k_tx;
match f {
F_Number => {
let number = word_of_block_number(k_header.number);
u256(number)
},
F_Timestamp => {
let timestamp = word_of_block_timestamp(k_header.timestamp);
u256(timestamp)
},
F_Coinbase => address_to_word(k_header.fee_recipient),
F_BaseFee => k_header.base_fee,
F_ChainId => {
let chain_id = word_of_chain_identifier(k_chain_id);
u256(chain_id)
},
F_GasLimit => u256(k_header.gas_limit),
F_PrevRandao => k_header.prev_randao,
F_Origin => address_to_word(active_tx.origin),
F_GasPrice => active_tx.gas_price,
F_SlotNumber => {
let slot_number = word_of_slot_number(k_header.slot_number);
u256(slot_number)
},
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2The closed environment-projection algebra interpreted by k_env. Each opcode supplies one constant member, so the shared projection remains explicit and first-order for executable and proof backends.
enum EnvField = {
/* block number (`NUMBER`) */
F_Number,
/* block timestamp (`TIMESTAMP`) */
F_Timestamp,
/* beneficiary address (`COINBASE`) */
F_Coinbase,
/* block base fee (`BASEFEE`, EIP-3198) */
F_BaseFee,
/* chain identifier (`CHAINID`, EIP-1344) */
F_ChainId,
/* block gas limit (`GASLIMIT`) */
F_GasLimit,
/* randomness beacon (`PREVRANDAO`, EIP-4399) */
F_PrevRandao,
/* transaction sender (`ORIGIN`) */
F_Origin,
/* effective gas price (`GASPRICE`) */
F_GasPrice,
/* consensus slot number (`SLOTNUM`, EIP-7843) */
F_SlotNumber,
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_caller¶
Implements CALLER.
function execute_caller(
carried_caller : address,
carried_gas : gas,
carried_sp : StackPointer,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let caller = address_to_word(carried_caller);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, caller);
(gas, sp, Continue())
}Embeds a canonical-order address into the low 160 bits of an EVM word.
function address_to_word(bytes : address) -> word =
unsigned(
bytes[0]
@ bytes[1]
@ bytes[2]
@ bytes[3]
@ bytes[4]
@ bytes[5]
@ bytes[6]
@ bytes[7]
@ bytes[8]
@ bytes[9]
@ bytes[10]
@ bytes[11]
@ bytes[12]
@ bytes[13]
@ bytes[14]
@ bytes[15]
@ bytes[16]
@ bytes[17]
@ bytes[18]
@ bytes[19],
)Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}A 20-byte account address (YP ยง4.1), in canonical protocol byte order.
type address = vector(20, inc, byte)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_callvalue¶
Implements CALLVALUE.
function execute_callvalue(
carried_value : word,
carried_gas : gas,
carried_sp : StackPointer,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
sp = stack_top_advance(sp, 1);
write_stack_word(sp, carried_value);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)The EVM 256-bit machine word (YP ยง9.1). A transparent range keeps the mathematical subtype relation visible: narrower non-negative ranges can be passed as words without a model-level conversion.
type word = range(0, 2 ^ 256 - 1)function execute_gasprice¶
Implements GASPRICE.
function execute_gasprice(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let gas_price = k_env(F_GasPrice);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, gas_price);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}An environment field as the word its opcode pushes.
function k_env(f : EnvField) -> word = {
let active_tx = k_tx;
match f {
F_Number => {
let number = word_of_block_number(k_header.number);
u256(number)
},
F_Timestamp => {
let timestamp = word_of_block_timestamp(k_header.timestamp);
u256(timestamp)
},
F_Coinbase => address_to_word(k_header.fee_recipient),
F_BaseFee => k_header.base_fee,
F_ChainId => {
let chain_id = word_of_chain_identifier(k_chain_id);
u256(chain_id)
},
F_GasLimit => u256(k_header.gas_limit),
F_PrevRandao => k_header.prev_randao,
F_Origin => address_to_word(active_tx.origin),
F_GasPrice => active_tx.gas_price,
F_SlotNumber => {
let slot_number = word_of_slot_number(k_header.slot_number);
u256(slot_number)
},
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2The closed environment-projection algebra interpreted by k_env. Each opcode supplies one constant member, so the shared projection remains explicit and first-order for executable and proof backends.
enum EnvField = {
/* block number (`NUMBER`) */
F_Number,
/* block timestamp (`TIMESTAMP`) */
F_Timestamp,
/* beneficiary address (`COINBASE`) */
F_Coinbase,
/* block base fee (`BASEFEE`, EIP-3198) */
F_BaseFee,
/* chain identifier (`CHAINID`, EIP-1344) */
F_ChainId,
/* block gas limit (`GASLIMIT`) */
F_GasLimit,
/* randomness beacon (`PREVRANDAO`, EIP-4399) */
F_PrevRandao,
/* transaction sender (`ORIGIN`) */
F_Origin,
/* effective gas price (`GASPRICE`) */
F_GasPrice,
/* consensus slot number (`SLOTNUM`, EIP-7843) */
F_SlotNumber,
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_calldatasize¶
Implements CALLDATASIZE.
function execute_calldatasize(
carried_calldata : CalldataSlice,
carried_gas : gas,
carried_sp : StackPointer,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let input = carried_calldata;
let input_length = region_slice_length(input);
let length_word = word_of_byte_count(input_length);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, length_word);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2Calldata is either the immutable top-level transaction input or a frozen range of the suspended caller's memory. The variants state the only two protocol-valid provenances instead of exposing the host's region enum.
union CalldataSlice = {
/* the immutable top-level transaction input */
InputCalldata : StatelessInputSlice,
/* a frozen range of the suspended caller's memory */
MemoryCalldata : EvmMemorySlice,
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_calldataload¶
Implements CALLDATALOAD.
function execute_calldataload(
carried_calldata : CalldataSlice,
carried_gas : gas,
carried_sp : StackPointer,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 1, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let offset_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let value = slice_load_word_offset(carried_calldata, offset_word);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, value);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Calldata is either the immutable top-level transaction input or a frozen range of the suspended caller's memory. The variants state the only two protocol-valid provenances instead of exposing the host's region enum.
union CalldataSlice = {
/* the immutable top-level transaction input */
InputCalldata : StatelessInputSlice,
/* a frozen range of the suspended caller's memory */
MemoryCalldata : EvmMemorySlice,
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_calldatacopy¶
Implements CALLDATACOPY.
function execute_calldatacopy(
carried_calldata : CalldataSlice,
memory_base : memory_base,
carried_gas : gas,
carried_sp : StackPointer,
carried_memory_height : memory_height,
) -> (
(gas, StackPointer, memory_height, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 3, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, carried_memory_height, stack_status)
};
var gas : gas = carried_gas;
var sp : StackPointer = carried_sp;
var memory : memory_height = carried_memory_height;
if gas < G_verylow then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, G_verylow);
let destination_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let source_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let length_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let copy_cost = copy_gas_cost(length_word, gas);
if not_bool(copy_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, copy_cost.cost);
let requested_height = memory_requested_height(destination_word, length_word);
let expansion_cost = memory_expansion_gas_cost(memory, requested_height, gas);
if not_bool(expansion_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, expansion_cost.cost);
let access = memory_access(destination_word, length_word);
memory = expand_memory(memory_base, memory, access.requested_height);
let range = access.range;
let destination = memory_absolute(memory_base, range.off);
slice_copy_word_offset(carried_calldata, destination, source_word, range.len);
(gas, sp, memory, Continue())
}function copy_gas_cost(size : word, available : gas) -> GasCharge =
memory_word_gas_cost(GAS_CONSTANT_ZERO, G_copy_word, size, available)Materializes an already-charged memory high-water mark and returns its updated scalar height.
function expand_memory(base : memory_base, height : memory_height, requested_height : memory_length) -> memory_height = {
if requested_height <= sizeof(memory_region_bound) - base then {
if height < requested_height then {
mem_expand(base, height, requested_height);
requested_height
} else {
height
}
} else {
fatal_error(ExecutionInvalid)
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Converts a frame-relative coordinate to an absolute arena coordinate.
function memory_absolute(base : memory_base, relative : memory_length) -> memory_base =
if relative <= sizeof(memory_region_bound) - base then {
base + relative
} else {
fatal_error(ExecutionInvalid)
}function memory_access(start, size) =
if size == 0 then {
EMPTY_MEMORY_ACCESS
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let range = memory_range(bounded_start, bounded_size);
let requested_height = bounded_start + bounded_size;
let access = struct { range = range, requested_height = requested_height } :
MemoryAccessFields('bounded_start, 'bounded_size, 'bounded_start + 'bounded_size);
access
} else {
fatal_error(ExecutionInvalid)
}
} else {
fatal_error(ExecutionInvalid)
}function memory_expansion_gas_cost(mem, requested_height, available) =
if requested_height <= sizeof(memory_region_bound) then {
let materialized_size : memory_length = requested_height;
let new_words = memory_word_count(materialized_size);
let old_size = memory_high_water(mem);
let old_words = memory_word_count(old_size);
if new_words <= old_words then {
gas_charge(GAS_COST_ZERO)
} else {
let old_cost = mem_cost(old_words);
let new_cost = mem_cost(new_words);
if old_cost <= new_cost then {
let exact_cost = new_cost - old_cost;
if exact_cost <= available then {
let cost : gas_cost = exact_cost;
gas_charge(cost)
} else {
GAS_CHARGE_UNAFFORDABLE
}
} else {
gas_charge(GAS_COST_ZERO)
}
}
} else {
GAS_CHARGE_UNAFFORDABLE
}function memory_requested_height(start, size) =
if size == 0 then {
0
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let requested_height : memory_required_endpoint = bounded_start + bounded_size;
requested_height
} else {
sizeof(memory_region_bound + 1)
}
} else {
sizeof(memory_region_bound + 1)
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Calldata is either the immutable top-level transaction input or a frozen range of the suspended caller's memory. The variants state the only two protocol-valid provenances instead of exposing the host's region enum.
union CalldataSlice = {
/* the immutable top-level transaction input */
InputCalldata : StatelessInputSlice,
/* a frozen range of the suspended caller's memory */
MemoryCalldata : EvmMemorySlice,
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)An absolute byte position in the shared EVM-memory arena.
type memory_base = range(0, memory_region_bound)The active EVM frame's exact relative byte high-water mark. It is carried
beside the frame's absolute memory_base; the host retains no hidden
frame coordinate or lifecycle state.
type memory_height = memory_lengthfunction execute_codesize¶
Implements CODESIZE.
function execute_codesize(
carried_code : Code,
carried_gas : gas,
carried_sp : StackPointer,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let code_length = frame_code_len(carried_code);
let length_word = word_of_byte_count(code_length);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, length_word);
(gas, sp, Continue())
}The frame code length in bytes (CODESIZE).
function frame_code_len(frame_code : Code) -> code_length = {
let code = frame_code;
let length = code.len;
length
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2Existential executable-code value whose concrete byte address and length
remain correlated inside CodeFields.
type Code = {
'off 'len,
code_region_valid_range('off, 'len) & code_valid_length('len).
CodeFields('off, 'len)
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}A contract-code length.
type code_length = range(0, code_region_bound)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_codecopy¶
Implements CODECOPY.
function execute_codecopy(
carried_code : Code,
memory_base : memory_base,
carried_gas : gas,
carried_sp : StackPointer,
carried_memory_height : memory_height,
) -> (
(gas, StackPointer, memory_height, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 3, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, carried_memory_height, stack_status)
};
var gas : gas = carried_gas;
var sp : StackPointer = carried_sp;
var memory : memory_height = carried_memory_height;
if gas < G_verylow then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, G_verylow);
let destination_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let source_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let length_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let copy_cost = copy_gas_cost(length_word, gas);
if not_bool(copy_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, copy_cost.cost);
let requested_height = memory_requested_height(destination_word, length_word);
let expansion_cost = memory_expansion_gas_cost(memory, requested_height, gas);
if not_bool(expansion_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, expansion_cost.cost);
let access = memory_access(destination_word, length_word);
memory = expand_memory(memory_base, memory, access.requested_height);
let range = access.range;
let code = carried_code;
let bytes = code_bytes(code);
let destination = memory_absolute(memory_base, range.off);
slice_copy_word_offset(bytes, destination, source_word, range.len);
(gas, sp, memory, Continue())
}function code_bytes(code) = struct { bytes = code.bytes, len = code.len }function copy_gas_cost(size : word, available : gas) -> GasCharge =
memory_word_gas_cost(GAS_CONSTANT_ZERO, G_copy_word, size, available)Materializes an already-charged memory high-water mark and returns its updated scalar height.
function expand_memory(base : memory_base, height : memory_height, requested_height : memory_length) -> memory_height = {
if requested_height <= sizeof(memory_region_bound) - base then {
if height < requested_height then {
mem_expand(base, height, requested_height);
requested_height
} else {
height
}
} else {
fatal_error(ExecutionInvalid)
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Converts a frame-relative coordinate to an absolute arena coordinate.
function memory_absolute(base : memory_base, relative : memory_length) -> memory_base =
if relative <= sizeof(memory_region_bound) - base then {
base + relative
} else {
fatal_error(ExecutionInvalid)
}function memory_access(start, size) =
if size == 0 then {
EMPTY_MEMORY_ACCESS
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let range = memory_range(bounded_start, bounded_size);
let requested_height = bounded_start + bounded_size;
let access = struct { range = range, requested_height = requested_height } :
MemoryAccessFields('bounded_start, 'bounded_size, 'bounded_start + 'bounded_size);
access
} else {
fatal_error(ExecutionInvalid)
}
} else {
fatal_error(ExecutionInvalid)
}function memory_expansion_gas_cost(mem, requested_height, available) =
if requested_height <= sizeof(memory_region_bound) then {
let materialized_size : memory_length = requested_height;
let new_words = memory_word_count(materialized_size);
let old_size = memory_high_water(mem);
let old_words = memory_word_count(old_size);
if new_words <= old_words then {
gas_charge(GAS_COST_ZERO)
} else {
let old_cost = mem_cost(old_words);
let new_cost = mem_cost(new_words);
if old_cost <= new_cost then {
let exact_cost = new_cost - old_cost;
if exact_cost <= available then {
let cost : gas_cost = exact_cost;
gas_charge(cost)
} else {
GAS_CHARGE_UNAFFORDABLE
}
} else {
gas_charge(GAS_COST_ZERO)
}
}
} else {
GAS_CHARGE_UNAFFORDABLE
}function memory_requested_height(start, size) =
if size == 0 then {
0
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let requested_height : memory_required_endpoint = bounded_start + bounded_size;
requested_height
} else {
sizeof(memory_region_bound + 1)
}
} else {
sizeof(memory_region_bound + 1)
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Existential executable-code value whose concrete byte address and length
remain correlated inside CodeFields.
type Code = {
'off 'len,
code_region_valid_range('off, 'len) & code_valid_length('len).
CodeFields('off, 'len)
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)An absolute byte position in the shared EVM-memory arena.
type memory_base = range(0, memory_region_bound)The active EVM frame's exact relative byte high-water mark. It is carried
beside the frame's absolute memory_base; the host retains no hidden
frame coordinate or lifecycle state.
type memory_height = memory_lengthfunction execute_balance¶
Implements BALANCE, including warm/cold account access.
function execute_balance(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 1, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
let address_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let a = word_to_address(address_word);
let warm = k_account_is_warm(a);
let gas_cost = account_cost(warm);
if carried_gas < gas_cost then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - gas_cost;
k_account_mark_warm(a);
let balance = k_get_balance(a);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, balance);
(gas, sp, Continue())
}The account-access cost for a prior warm bit.
function account_cost(warm : bool) -> gas_constant = {
let execution_profile = k_execution_profile;
let profile = execution_profile.protocol;
if warm then {
G_warm_access
} else if profile.fork >= Amsterdam then {
G_amsterdam_cold_account_access
} else {
G_cold_account
}
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Returns the address's EIP-2929 warm bit without changing state. Active precompiles are warm independently of the BAL-derived account table.
function k_account_is_warm(a : address) -> bool = {
let precompile_id = precompile_id_for_address(a);
if precompile_id != NotPrecompile then {
true
} else {
account_is_warm(a)
}
}Marks an address warm after the caller has established that its access gas is affordable. Active precompiles need no host-table entry.
function k_account_mark_warm(a : address) -> unit = {
let precompile_id = precompile_id_for_address(a);
if precompile_id != NotPrecompile then {
return ()
};
account_mark_warm(a)
}The account balance (BALANCE, SELFBALANCE).
function k_get_balance(a : address) -> word = {
k_aload(a).info.balance
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Converts a word to its low 160-bit address in canonical byte order.
function word_to_address(value : word) -> address = {
let zero_bytes = vector_init(20, 0x00);
var result : address = Address(zero_bytes);
result[0] = get_slice_int(8, value, 152);
result[1] = get_slice_int(8, value, 144);
result[2] = get_slice_int(8, value, 136);
result[3] = get_slice_int(8, value, 128);
result[4] = get_slice_int(8, value, 120);
result[5] = get_slice_int(8, value, 112);
result[6] = get_slice_int(8, value, 104);
result[7] = get_slice_int(8, value, 96);
result[8] = get_slice_int(8, value, 88);
result[9] = get_slice_int(8, value, 80);
result[10] = get_slice_int(8, value, 72);
result[11] = get_slice_int(8, value, 64);
result[12] = get_slice_int(8, value, 56);
result[13] = get_slice_int(8, value, 48);
result[14] = get_slice_int(8, value, 40);
result[15] = get_slice_int(8, value, 32);
result[16] = get_slice_int(8, value, 24);
result[17] = get_slice_int(8, value, 16);
result[18] = get_slice_int(8, value, 8);
result[19] = get_slice_int(8, value, 0);
result
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)A transient computed charge after its affordability or structural bound
has been established. Unaffordable larger computations are represented by
GasCharge.affordable = false rather than materialized as a cost.
type gas_cost = range(0, 2 ^ 64 - 1)function execute_selfbalance¶
Implements SELFBALANCE.
function execute_selfbalance(
carried_address : address,
carried_gas : gas,
carried_sp : StackPointer,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_low then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_low;
let balance = k_get_balance(carried_address);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, balance);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}The account balance (BALANCE, SELFBALANCE).
function k_get_balance(a : address) -> word = {
k_aload(a).info.balance
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_low : gas_constant = 5Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}A 20-byte account address (YP ยง4.1), in canonical protocol byte order.
type address = vector(20, inc, byte)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_extcodesize¶
Implements EXTCODESIZE, including warm/cold account access.
function execute_extcodesize(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 1, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
let address_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let a = word_to_address(address_word);
let warm = k_account_is_warm(a);
let access_cost = account_cost(warm);
let read_cost = external_code_read_cost();
if carried_gas < access_cost + read_cost then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = gas_sub(carried_gas, access_cost + read_cost);
k_account_mark_warm(a);
let code_size = k_get_code_size(a);
let size_word = word_of_byte_count(code_size);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, size_word);
(gas, sp, Continue())
}The account-access cost for a prior warm bit.
function account_cost(warm : bool) -> gas_constant = {
let execution_profile = k_execution_profile;
let profile = execution_profile.protocol;
if warm then {
G_warm_access
} else if profile.fork >= Amsterdam then {
G_amsterdam_cold_account_access
} else {
G_cold_account
}
}The second database read performed by EXTCODESIZE and EXTCODECOPY.
EIP-8038 prices the code-store read as one warm access at Amsterdam.
function external_code_read_cost() -> gas_constant = {
let execution_profile = k_execution_profile;
let profile = execution_profile.protocol;
if profile.fork >= Amsterdam then {
G_warm_access
} else {
G_zero
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Returns the address's EIP-2929 warm bit without changing state. Active precompiles are warm independently of the BAL-derived account table.
function k_account_is_warm(a : address) -> bool = {
let precompile_id = precompile_id_for_address(a);
if precompile_id != NotPrecompile then {
true
} else {
account_is_warm(a)
}
}Marks an address warm after the caller has established that its access gas is affordable. Active precompiles need no host-table entry.
function k_account_mark_warm(a : address) -> unit = {
let precompile_id = precompile_id_for_address(a);
if precompile_id != NotPrecompile then {
return ()
};
account_mark_warm(a)
}EXTCODESIZE: the account's code length in bytes.
function k_get_code_size(a : address) -> code_length = {
let code_key = k_code_key(a);
let code = code_db_resolve(code_key);
code.len
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Converts a word to its low 160-bit address in canonical byte order.
function word_to_address(value : word) -> address = {
let zero_bytes = vector_init(20, 0x00);
var result : address = Address(zero_bytes);
result[0] = get_slice_int(8, value, 152);
result[1] = get_slice_int(8, value, 144);
result[2] = get_slice_int(8, value, 136);
result[3] = get_slice_int(8, value, 128);
result[4] = get_slice_int(8, value, 120);
result[5] = get_slice_int(8, value, 112);
result[6] = get_slice_int(8, value, 104);
result[7] = get_slice_int(8, value, 96);
result[8] = get_slice_int(8, value, 88);
result[9] = get_slice_int(8, value, 80);
result[10] = get_slice_int(8, value, 72);
result[11] = get_slice_int(8, value, 64);
result[12] = get_slice_int(8, value, 56);
result[13] = get_slice_int(8, value, 48);
result[14] = get_slice_int(8, value, 40);
result[15] = get_slice_int(8, value, 32);
result[16] = get_slice_int(8, value, 24);
result[17] = get_slice_int(8, value, 16);
result[18] = get_slice_int(8, value, 8);
result[19] = get_slice_int(8, value, 0);
result
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_extcodecopy¶
Implements EXTCODECOPY, including access and copy gas.
function execute_extcodecopy(
memory_base : memory_base,
carried_gas : gas,
carried_sp : StackPointer,
carried_memory_height : memory_height,
) -> (
(gas, StackPointer, memory_height, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 4, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, carried_memory_height, stack_status)
};
var gas : gas = carried_gas;
var sp : StackPointer = carried_sp;
var memory : memory_height = carried_memory_height;
let address_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let a = word_to_address(address_word);
let destination_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let source_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let length_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let warm = k_account_is_warm(a);
let access_cost = account_cost(warm);
let read_cost = external_code_read_cost();
if gas < access_cost + read_cost then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, access_cost + read_cost);
let copy_cost = copy_gas_cost(length_word, gas);
if not_bool(copy_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, copy_cost.cost);
let requested_height = memory_requested_height(destination_word, length_word);
let expansion_cost = memory_expansion_gas_cost(memory, requested_height, gas);
if not_bool(expansion_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, expansion_cost.cost);
let access = memory_access(destination_word, length_word);
memory = expand_memory(memory_base, memory, access.requested_height);
let range = access.range;
k_account_mark_warm(a);
let destination = memory_absolute(memory_base, range.off);
k_code_copy(a, destination, source_word, range.len);
(gas, sp, memory, Continue())
}The account-access cost for a prior warm bit.
function account_cost(warm : bool) -> gas_constant = {
let execution_profile = k_execution_profile;
let profile = execution_profile.protocol;
if warm then {
G_warm_access
} else if profile.fork >= Amsterdam then {
G_amsterdam_cold_account_access
} else {
G_cold_account
}
}function copy_gas_cost(size : word, available : gas) -> GasCharge =
memory_word_gas_cost(GAS_CONSTANT_ZERO, G_copy_word, size, available)Materializes an already-charged memory high-water mark and returns its updated scalar height.
function expand_memory(base : memory_base, height : memory_height, requested_height : memory_length) -> memory_height = {
if requested_height <= sizeof(memory_region_bound) - base then {
if height < requested_height then {
mem_expand(base, height, requested_height);
requested_height
} else {
height
}
} else {
fatal_error(ExecutionInvalid)
}
}The second database read performed by EXTCODESIZE and EXTCODECOPY.
EIP-8038 prices the code-store read as one warm access at Amsterdam.
function external_code_read_cost() -> gas_constant = {
let execution_profile = k_execution_profile;
let profile = execution_profile.protocol;
if profile.fork >= Amsterdam then {
G_warm_access
} else {
G_zero
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Returns the address's EIP-2929 warm bit without changing state. Active precompiles are warm independently of the BAL-derived account table.
function k_account_is_warm(a : address) -> bool = {
let precompile_id = precompile_id_for_address(a);
if precompile_id != NotPrecompile then {
true
} else {
account_is_warm(a)
}
}Marks an address warm after the caller has established that its access gas is affordable. Active precompiles need no host-table entry.
function k_account_mark_warm(a : address) -> unit = {
let precompile_id = precompile_id_for_address(a);
if precompile_id != NotPrecompile then {
return ()
};
account_mark_warm(a)
}EXTCODECOPY: copies account code into frame memory, zero-padded
past the end.
function k_code_copy(a : address, dst : memory_base, off : word, len : memory_length) -> unit = {
let code_key = k_code_key(a);
let code = code_db_resolve(code_key);
let bytes = code_bytes(code);
slice_copy_word_offset(bytes, dst, off, len)
}Converts a frame-relative coordinate to an absolute arena coordinate.
function memory_absolute(base : memory_base, relative : memory_length) -> memory_base =
if relative <= sizeof(memory_region_bound) - base then {
base + relative
} else {
fatal_error(ExecutionInvalid)
}function memory_access(start, size) =
if size == 0 then {
EMPTY_MEMORY_ACCESS
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let range = memory_range(bounded_start, bounded_size);
let requested_height = bounded_start + bounded_size;
let access = struct { range = range, requested_height = requested_height } :
MemoryAccessFields('bounded_start, 'bounded_size, 'bounded_start + 'bounded_size);
access
} else {
fatal_error(ExecutionInvalid)
}
} else {
fatal_error(ExecutionInvalid)
}function memory_expansion_gas_cost(mem, requested_height, available) =
if requested_height <= sizeof(memory_region_bound) then {
let materialized_size : memory_length = requested_height;
let new_words = memory_word_count(materialized_size);
let old_size = memory_high_water(mem);
let old_words = memory_word_count(old_size);
if new_words <= old_words then {
gas_charge(GAS_COST_ZERO)
} else {
let old_cost = mem_cost(old_words);
let new_cost = mem_cost(new_words);
if old_cost <= new_cost then {
let exact_cost = new_cost - old_cost;
if exact_cost <= available then {
let cost : gas_cost = exact_cost;
gas_charge(cost)
} else {
GAS_CHARGE_UNAFFORDABLE
}
} else {
gas_charge(GAS_COST_ZERO)
}
}
} else {
GAS_CHARGE_UNAFFORDABLE
}function memory_requested_height(start, size) =
if size == 0 then {
0
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let requested_height : memory_required_endpoint = bounded_start + bounded_size;
requested_height
} else {
sizeof(memory_region_bound + 1)
}
} else {
sizeof(memory_region_bound + 1)
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Converts a word to its low 160-bit address in canonical byte order.
function word_to_address(value : word) -> address = {
let zero_bytes = vector_init(20, 0x00);
var result : address = Address(zero_bytes);
result[0] = get_slice_int(8, value, 152);
result[1] = get_slice_int(8, value, 144);
result[2] = get_slice_int(8, value, 136);
result[3] = get_slice_int(8, value, 128);
result[4] = get_slice_int(8, value, 120);
result[5] = get_slice_int(8, value, 112);
result[6] = get_slice_int(8, value, 104);
result[7] = get_slice_int(8, value, 96);
result[8] = get_slice_int(8, value, 88);
result[9] = get_slice_int(8, value, 80);
result[10] = get_slice_int(8, value, 72);
result[11] = get_slice_int(8, value, 64);
result[12] = get_slice_int(8, value, 56);
result[13] = get_slice_int(8, value, 48);
result[14] = get_slice_int(8, value, 40);
result[15] = get_slice_int(8, value, 32);
result[16] = get_slice_int(8, value, 24);
result[17] = get_slice_int(8, value, 16);
result[18] = get_slice_int(8, value, 8);
result[19] = get_slice_int(8, value, 0);
result
}let GAS_ZERO : int(0) = 0Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)An absolute byte position in the shared EVM-memory arena.
type memory_base = range(0, memory_region_bound)The active EVM frame's exact relative byte high-water mark. It is carried
beside the frame's absolute memory_base; the host retains no hidden
frame coordinate or lifecycle state.
type memory_height = memory_lengthfunction execute_extcodehash¶
Implements EXTCODEHASH, including warm/cold account access.
function execute_extcodehash(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 1, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
let address_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let a = word_to_address(address_word);
let warm = k_account_is_warm(a);
let gas_cost = account_cost(warm);
if carried_gas < gas_cost then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - gas_cost;
k_account_mark_warm(a);
let code_hash = k_get_codehash(a);
let hash_word = hash_to_word(code_hash);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, hash_word);
(gas, sp, Continue())
}The account-access cost for a prior warm bit.
function account_cost(warm : bool) -> gas_constant = {
let execution_profile = k_execution_profile;
let profile = execution_profile.protocol;
if warm then {
G_warm_access
} else if profile.fork >= Amsterdam then {
G_amsterdam_cold_account_access
} else {
G_cold_account
}
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Interprets a digest as the corresponding big-endian EVM word.
function hash_to_word(bytes : hash) -> word =
unsigned(
bytes[0]
@ bytes[1]
@ bytes[2]
@ bytes[3]
@ bytes[4]
@ bytes[5]
@ bytes[6]
@ bytes[7]
@ bytes[8]
@ bytes[9]
@ bytes[10]
@ bytes[11]
@ bytes[12]
@ bytes[13]
@ bytes[14]
@ bytes[15]
@ bytes[16]
@ bytes[17]
@ bytes[18]
@ bytes[19]
@ bytes[20]
@ bytes[21]
@ bytes[22]
@ bytes[23]
@ bytes[24]
@ bytes[25]
@ bytes[26]
@ bytes[27]
@ bytes[28]
@ bytes[29]
@ bytes[30]
@ bytes[31],
)Returns the address's EIP-2929 warm bit without changing state. Active precompiles are warm independently of the BAL-derived account table.
function k_account_is_warm(a : address) -> bool = {
let precompile_id = precompile_id_for_address(a);
if precompile_id != NotPrecompile then {
true
} else {
account_is_warm(a)
}
}Marks an address warm after the caller has established that its access gas is affordable. Active precompiles need no host-table entry.
function k_account_mark_warm(a : address) -> unit = {
let precompile_id = precompile_id_for_address(a);
if precompile_id != NotPrecompile then {
return ()
};
account_mark_warm(a)
}EXTCODEHASH (EIP-1052): a truly non-existent account reads as 0,
not KECCAK_EMPTY.
function k_get_codehash(a : address) -> hash = {
let acc = k_aload(a);
let missing = not_bool(acc.present);
if missing then {
ZERO_HASH
} else {
acc.info.code_hash
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Converts a word to its low 160-bit address in canonical byte order.
function word_to_address(value : word) -> address = {
let zero_bytes = vector_init(20, 0x00);
var result : address = Address(zero_bytes);
result[0] = get_slice_int(8, value, 152);
result[1] = get_slice_int(8, value, 144);
result[2] = get_slice_int(8, value, 136);
result[3] = get_slice_int(8, value, 128);
result[4] = get_slice_int(8, value, 120);
result[5] = get_slice_int(8, value, 112);
result[6] = get_slice_int(8, value, 104);
result[7] = get_slice_int(8, value, 96);
result[8] = get_slice_int(8, value, 88);
result[9] = get_slice_int(8, value, 80);
result[10] = get_slice_int(8, value, 72);
result[11] = get_slice_int(8, value, 64);
result[12] = get_slice_int(8, value, 56);
result[13] = get_slice_int(8, value, 48);
result[14] = get_slice_int(8, value, 40);
result[15] = get_slice_int(8, value, 32);
result[16] = get_slice_int(8, value, 24);
result[17] = get_slice_int(8, value, 16);
result[18] = get_slice_int(8, value, 8);
result[19] = get_slice_int(8, value, 0);
result
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)A transient computed charge after its affordability or structural bound
has been established. Unaffordable larger computations are represented by
GasCharge.affordable = false rather than materialized as a cost.
type gas_cost = range(0, 2 ^ 64 - 1)function execute_returndatasize¶
Implements RETURNDATASIZE.
function execute_returndatasize(
carried_returndata : OutputSlice,
carried_gas : gas,
carried_sp : StackPointer,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let return_data_size = returndata_size(carried_returndata);
let size_word = word_of_byte_count(return_data_size);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, size_word);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}RETURNDATASIZE.
function returndata_size(returndata : OutputSlice) -> source_pointer = {
let data = returndata;
data.len
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}A frame-output range with its coordinate and length packed existentially.
type OutputSlice = {
'off 'len,
output_region_valid_range('off, 'len).
OutputSliceFields('off, 'len)
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_returndatacopy¶
Implements bounds-checked RETURNDATACOPY.
function execute_returndatacopy(
carried_returndata : OutputSlice,
memory_base : memory_base,
carried_gas : gas,
carried_sp : StackPointer,
carried_memory_height : memory_height,
) -> (
(gas, StackPointer, memory_height, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 3, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, carried_memory_height, stack_status)
};
var gas : gas = carried_gas;
var sp : StackPointer = carried_sp;
var memory : memory_height = carried_memory_height;
if gas < G_verylow then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, G_verylow);
let destination_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let source_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let length_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let available = returndata_size(carried_returndata);
if source_word <= available then {
let remaining = returndata_remaining(available, source_word);
if length_word <= remaining then {
let bounded_length : memory_length = length_word;
let copy_cost = copy_gas_cost(length_word, gas);
if not_bool(copy_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, copy_cost.cost);
let requested_height = memory_requested_height(destination_word, length_word);
let expansion_cost = memory_expansion_gas_cost(memory, requested_height, gas);
if not_bool(expansion_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, expansion_cost.cost);
let access = memory_access(destination_word, length_word);
memory = expand_memory(memory_base, memory, access.requested_height);
let destination = memory_absolute(memory_base, access.range.off);
let bounded_source_offset : source_pointer = source_word;
returndata_copy(carried_returndata, destination, bounded_source_offset, bounded_length);
(gas, sp, memory, Continue())
} else {
(GAS_ZERO, sp, memory, Failed(InvalidOpcode))
}
} else {
(GAS_ZERO, sp, memory, Failed(InvalidOpcode))
}
}function copy_gas_cost(size : word, available : gas) -> GasCharge =
memory_word_gas_cost(GAS_CONSTANT_ZERO, G_copy_word, size, available)Materializes an already-charged memory high-water mark and returns its updated scalar height.
function expand_memory(base : memory_base, height : memory_height, requested_height : memory_length) -> memory_height = {
if requested_height <= sizeof(memory_region_bound) - base then {
if height < requested_height then {
mem_expand(base, height, requested_height);
requested_height
} else {
height
}
} else {
fatal_error(ExecutionInvalid)
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Converts a frame-relative coordinate to an absolute arena coordinate.
function memory_absolute(base : memory_base, relative : memory_length) -> memory_base =
if relative <= sizeof(memory_region_bound) - base then {
base + relative
} else {
fatal_error(ExecutionInvalid)
}function memory_access(start, size) =
if size == 0 then {
EMPTY_MEMORY_ACCESS
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let range = memory_range(bounded_start, bounded_size);
let requested_height = bounded_start + bounded_size;
let access = struct { range = range, requested_height = requested_height } :
MemoryAccessFields('bounded_start, 'bounded_size, 'bounded_start + 'bounded_size);
access
} else {
fatal_error(ExecutionInvalid)
}
} else {
fatal_error(ExecutionInvalid)
}function memory_expansion_gas_cost(mem, requested_height, available) =
if requested_height <= sizeof(memory_region_bound) then {
let materialized_size : memory_length = requested_height;
let new_words = memory_word_count(materialized_size);
let old_size = memory_high_water(mem);
let old_words = memory_word_count(old_size);
if new_words <= old_words then {
gas_charge(GAS_COST_ZERO)
} else {
let old_cost = mem_cost(old_words);
let new_cost = mem_cost(new_words);
if old_cost <= new_cost then {
let exact_cost = new_cost - old_cost;
if exact_cost <= available then {
let cost : gas_cost = exact_cost;
gas_charge(cost)
} else {
GAS_CHARGE_UNAFFORDABLE
}
} else {
gas_charge(GAS_COST_ZERO)
}
}
} else {
GAS_CHARGE_UNAFFORDABLE
}function memory_requested_height(start, size) =
if size == 0 then {
0
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let requested_height : memory_required_endpoint = bounded_start + bounded_size;
requested_height
} else {
sizeof(memory_region_bound + 1)
}
} else {
sizeof(memory_region_bound + 1)
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)function returndata_copy(returndata, dst, off, len) =
slice_copy(returndata, dst, off, len)function returndata_remaining(available, offset) = available - offsetRETURNDATASIZE.
function returndata_size(returndata : OutputSlice) -> source_pointer = {
let data = returndata;
data.len
}Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}A frame-output range with its coordinate and length packed existentially.
type OutputSlice = {
'off 'len,
output_region_valid_range('off, 'len).
OutputSliceFields('off, 'len)
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)An absolute byte position in the shared EVM-memory arena.
type memory_base = range(0, memory_region_bound)The active EVM frame's exact relative byte high-water mark. It is carried
beside the frame's absolute memory_base; the host retains no hidden
frame coordinate or lifecycle state.
type memory_height = memory_lengthA materialized length or allocation size in the EVM-memory arena.
type memory_length = range(0, memory_region_bound)An absolute byte position in a named source region.
type source_pointer = range(0, default_host_region_bound)function execute_blockhash¶
Implements BLOCKHASH.
function execute_blockhash(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 1, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < 20 then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - 20;
let block_number = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let block_hash = k_blockhash(block_number);
let hash_word = hash_to_word(block_hash);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, hash_word);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Interprets a digest as the corresponding big-endian EVM word.
function hash_to_word(bytes : hash) -> word =
unsigned(
bytes[0]
@ bytes[1]
@ bytes[2]
@ bytes[3]
@ bytes[4]
@ bytes[5]
@ bytes[6]
@ bytes[7]
@ bytes[8]
@ bytes[9]
@ bytes[10]
@ bytes[11]
@ bytes[12]
@ bytes[13]
@ bytes[14]
@ bytes[15]
@ bytes[16]
@ bytes[17]
@ bytes[18]
@ bytes[19]
@ bytes[20]
@ bytes[21]
@ bytes[22]
@ bytes[23]
@ bytes[24]
@ bytes[25]
@ bytes[26]
@ bytes[27]
@ bytes[28]
@ bytes[29]
@ bytes[30]
@ bytes[31],
)BLOCKHASH: the hash of ancestor number, zero outside the 256-block
window; an in-window ancestor missing from the witness is a deficient
witness.
function k_blockhash(number_word : word) -> hash = {
let current = k_header.number;
let current_number = word_of_block_number(current);
let current_word : word = u256(current_number);
if number_word < current_word then {
let distance_word = blockhash_word_distance(current_word, number_word);
if distance_word <= 256 then {
let distance : range(1, 256) = distance_word;
if k_n_headers < distance then {
fatal_error(WitnessDeficient)
} else {
let index : ancestor_index = distance - 1;
ancestor_hash_read(index)
}
} else {
ZERO_HASH
}
} else {
ZERO_HASH
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}An execution block number. Provenance: the execution-payload SSZ schema
declares block_number: uint64. The execution rules do not impose a
tighter supported-fork bound.
type block_number = range(0, ssz_uint_bound)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_coinbase¶
Implements COINBASE.
function execute_coinbase(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let coinbase = k_env(F_Coinbase);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, coinbase);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}An environment field as the word its opcode pushes.
function k_env(f : EnvField) -> word = {
let active_tx = k_tx;
match f {
F_Number => {
let number = word_of_block_number(k_header.number);
u256(number)
},
F_Timestamp => {
let timestamp = word_of_block_timestamp(k_header.timestamp);
u256(timestamp)
},
F_Coinbase => address_to_word(k_header.fee_recipient),
F_BaseFee => k_header.base_fee,
F_ChainId => {
let chain_id = word_of_chain_identifier(k_chain_id);
u256(chain_id)
},
F_GasLimit => u256(k_header.gas_limit),
F_PrevRandao => k_header.prev_randao,
F_Origin => address_to_word(active_tx.origin),
F_GasPrice => active_tx.gas_price,
F_SlotNumber => {
let slot_number = word_of_slot_number(k_header.slot_number);
u256(slot_number)
},
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2The closed environment-projection algebra interpreted by k_env. Each opcode supplies one constant member, so the shared projection remains explicit and first-order for executable and proof backends.
enum EnvField = {
/* block number (`NUMBER`) */
F_Number,
/* block timestamp (`TIMESTAMP`) */
F_Timestamp,
/* beneficiary address (`COINBASE`) */
F_Coinbase,
/* block base fee (`BASEFEE`, EIP-3198) */
F_BaseFee,
/* chain identifier (`CHAINID`, EIP-1344) */
F_ChainId,
/* block gas limit (`GASLIMIT`) */
F_GasLimit,
/* randomness beacon (`PREVRANDAO`, EIP-4399) */
F_PrevRandao,
/* transaction sender (`ORIGIN`) */
F_Origin,
/* effective gas price (`GASPRICE`) */
F_GasPrice,
/* consensus slot number (`SLOTNUM`, EIP-7843) */
F_SlotNumber,
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_timestamp¶
Implements TIMESTAMP.
function execute_timestamp(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let timestamp = k_env(F_Timestamp);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, timestamp);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}An environment field as the word its opcode pushes.
function k_env(f : EnvField) -> word = {
let active_tx = k_tx;
match f {
F_Number => {
let number = word_of_block_number(k_header.number);
u256(number)
},
F_Timestamp => {
let timestamp = word_of_block_timestamp(k_header.timestamp);
u256(timestamp)
},
F_Coinbase => address_to_word(k_header.fee_recipient),
F_BaseFee => k_header.base_fee,
F_ChainId => {
let chain_id = word_of_chain_identifier(k_chain_id);
u256(chain_id)
},
F_GasLimit => u256(k_header.gas_limit),
F_PrevRandao => k_header.prev_randao,
F_Origin => address_to_word(active_tx.origin),
F_GasPrice => active_tx.gas_price,
F_SlotNumber => {
let slot_number = word_of_slot_number(k_header.slot_number);
u256(slot_number)
},
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2The closed environment-projection algebra interpreted by k_env. Each opcode supplies one constant member, so the shared projection remains explicit and first-order for executable and proof backends.
enum EnvField = {
/* block number (`NUMBER`) */
F_Number,
/* block timestamp (`TIMESTAMP`) */
F_Timestamp,
/* beneficiary address (`COINBASE`) */
F_Coinbase,
/* block base fee (`BASEFEE`, EIP-3198) */
F_BaseFee,
/* chain identifier (`CHAINID`, EIP-1344) */
F_ChainId,
/* block gas limit (`GASLIMIT`) */
F_GasLimit,
/* randomness beacon (`PREVRANDAO`, EIP-4399) */
F_PrevRandao,
/* transaction sender (`ORIGIN`) */
F_Origin,
/* effective gas price (`GASPRICE`) */
F_GasPrice,
/* consensus slot number (`SLOTNUM`, EIP-7843) */
F_SlotNumber,
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_number¶
Implements NUMBER.
function execute_number(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let block_number = k_env(F_Number);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, block_number);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}An environment field as the word its opcode pushes.
function k_env(f : EnvField) -> word = {
let active_tx = k_tx;
match f {
F_Number => {
let number = word_of_block_number(k_header.number);
u256(number)
},
F_Timestamp => {
let timestamp = word_of_block_timestamp(k_header.timestamp);
u256(timestamp)
},
F_Coinbase => address_to_word(k_header.fee_recipient),
F_BaseFee => k_header.base_fee,
F_ChainId => {
let chain_id = word_of_chain_identifier(k_chain_id);
u256(chain_id)
},
F_GasLimit => u256(k_header.gas_limit),
F_PrevRandao => k_header.prev_randao,
F_Origin => address_to_word(active_tx.origin),
F_GasPrice => active_tx.gas_price,
F_SlotNumber => {
let slot_number = word_of_slot_number(k_header.slot_number);
u256(slot_number)
},
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2The closed environment-projection algebra interpreted by k_env. Each opcode supplies one constant member, so the shared projection remains explicit and first-order for executable and proof backends.
enum EnvField = {
/* block number (`NUMBER`) */
F_Number,
/* block timestamp (`TIMESTAMP`) */
F_Timestamp,
/* beneficiary address (`COINBASE`) */
F_Coinbase,
/* block base fee (`BASEFEE`, EIP-3198) */
F_BaseFee,
/* chain identifier (`CHAINID`, EIP-1344) */
F_ChainId,
/* block gas limit (`GASLIMIT`) */
F_GasLimit,
/* randomness beacon (`PREVRANDAO`, EIP-4399) */
F_PrevRandao,
/* transaction sender (`ORIGIN`) */
F_Origin,
/* effective gas price (`GASPRICE`) */
F_GasPrice,
/* consensus slot number (`SLOTNUM`, EIP-7843) */
F_SlotNumber,
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}An execution block number. Provenance: the execution-payload SSZ schema
declares block_number: uint64. The execution rules do not impose a
tighter supported-fork bound.
type block_number = range(0, ssz_uint_bound)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_slotnum¶
Implements SLOTNUM.
function execute_slotnum(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let slot_number = k_env(F_SlotNumber);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, slot_number);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}An environment field as the word its opcode pushes.
function k_env(f : EnvField) -> word = {
let active_tx = k_tx;
match f {
F_Number => {
let number = word_of_block_number(k_header.number);
u256(number)
},
F_Timestamp => {
let timestamp = word_of_block_timestamp(k_header.timestamp);
u256(timestamp)
},
F_Coinbase => address_to_word(k_header.fee_recipient),
F_BaseFee => k_header.base_fee,
F_ChainId => {
let chain_id = word_of_chain_identifier(k_chain_id);
u256(chain_id)
},
F_GasLimit => u256(k_header.gas_limit),
F_PrevRandao => k_header.prev_randao,
F_Origin => address_to_word(active_tx.origin),
F_GasPrice => active_tx.gas_price,
F_SlotNumber => {
let slot_number = word_of_slot_number(k_header.slot_number);
u256(slot_number)
},
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2The closed environment-projection algebra interpreted by k_env. Each opcode supplies one constant member, so the shared projection remains explicit and first-order for executable and proof backends.
enum EnvField = {
/* block number (`NUMBER`) */
F_Number,
/* block timestamp (`TIMESTAMP`) */
F_Timestamp,
/* beneficiary address (`COINBASE`) */
F_Coinbase,
/* block base fee (`BASEFEE`, EIP-3198) */
F_BaseFee,
/* chain identifier (`CHAINID`, EIP-1344) */
F_ChainId,
/* block gas limit (`GASLIMIT`) */
F_GasLimit,
/* randomness beacon (`PREVRANDAO`, EIP-4399) */
F_PrevRandao,
/* transaction sender (`ORIGIN`) */
F_Origin,
/* effective gas price (`GASPRICE`) */
F_GasPrice,
/* consensus slot number (`SLOTNUM`, EIP-7843) */
F_SlotNumber,
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)A beacon-chain slot number. Provenance: EIP-7843 and Amsterdam's
stateless SSZ payload declare this field as uint64.
type slot_number = range(0, ssz_uint_bound)function execute_prevrandao¶
Implements PREVRANDAO.
function execute_prevrandao(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let prev_randao = k_env(F_PrevRandao);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, prev_randao);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}An environment field as the word its opcode pushes.
function k_env(f : EnvField) -> word = {
let active_tx = k_tx;
match f {
F_Number => {
let number = word_of_block_number(k_header.number);
u256(number)
},
F_Timestamp => {
let timestamp = word_of_block_timestamp(k_header.timestamp);
u256(timestamp)
},
F_Coinbase => address_to_word(k_header.fee_recipient),
F_BaseFee => k_header.base_fee,
F_ChainId => {
let chain_id = word_of_chain_identifier(k_chain_id);
u256(chain_id)
},
F_GasLimit => u256(k_header.gas_limit),
F_PrevRandao => k_header.prev_randao,
F_Origin => address_to_word(active_tx.origin),
F_GasPrice => active_tx.gas_price,
F_SlotNumber => {
let slot_number = word_of_slot_number(k_header.slot_number);
u256(slot_number)
},
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2The closed environment-projection algebra interpreted by k_env. Each opcode supplies one constant member, so the shared projection remains explicit and first-order for executable and proof backends.
enum EnvField = {
/* block number (`NUMBER`) */
F_Number,
/* block timestamp (`TIMESTAMP`) */
F_Timestamp,
/* beneficiary address (`COINBASE`) */
F_Coinbase,
/* block base fee (`BASEFEE`, EIP-3198) */
F_BaseFee,
/* chain identifier (`CHAINID`, EIP-1344) */
F_ChainId,
/* block gas limit (`GASLIMIT`) */
F_GasLimit,
/* randomness beacon (`PREVRANDAO`, EIP-4399) */
F_PrevRandao,
/* transaction sender (`ORIGIN`) */
F_Origin,
/* effective gas price (`GASPRICE`) */
F_GasPrice,
/* consensus slot number (`SLOTNUM`, EIP-7843) */
F_SlotNumber,
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_gaslimit¶
Implements GASLIMIT.
function execute_gaslimit(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let gas_limit = k_env(F_GasLimit);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, gas_limit);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}An environment field as the word its opcode pushes.
function k_env(f : EnvField) -> word = {
let active_tx = k_tx;
match f {
F_Number => {
let number = word_of_block_number(k_header.number);
u256(number)
},
F_Timestamp => {
let timestamp = word_of_block_timestamp(k_header.timestamp);
u256(timestamp)
},
F_Coinbase => address_to_word(k_header.fee_recipient),
F_BaseFee => k_header.base_fee,
F_ChainId => {
let chain_id = word_of_chain_identifier(k_chain_id);
u256(chain_id)
},
F_GasLimit => u256(k_header.gas_limit),
F_PrevRandao => k_header.prev_randao,
F_Origin => address_to_word(active_tx.origin),
F_GasPrice => active_tx.gas_price,
F_SlotNumber => {
let slot_number = word_of_slot_number(k_header.slot_number);
u256(slot_number)
},
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2The closed environment-projection algebra interpreted by k_env. Each opcode supplies one constant member, so the shared projection remains explicit and first-order for executable and proof backends.
enum EnvField = {
/* block number (`NUMBER`) */
F_Number,
/* block timestamp (`TIMESTAMP`) */
F_Timestamp,
/* beneficiary address (`COINBASE`) */
F_Coinbase,
/* block base fee (`BASEFEE`, EIP-3198) */
F_BaseFee,
/* chain identifier (`CHAINID`, EIP-1344) */
F_ChainId,
/* block gas limit (`GASLIMIT`) */
F_GasLimit,
/* randomness beacon (`PREVRANDAO`, EIP-4399) */
F_PrevRandao,
/* transaction sender (`ORIGIN`) */
F_Origin,
/* effective gas price (`GASPRICE`) */
F_GasPrice,
/* consensus slot number (`SLOTNUM`, EIP-7843) */
F_SlotNumber,
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_chainid¶
Implements CHAINID.
function execute_chainid(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let chain_id = k_env(F_ChainId);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, chain_id);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}An environment field as the word its opcode pushes.
function k_env(f : EnvField) -> word = {
let active_tx = k_tx;
match f {
F_Number => {
let number = word_of_block_number(k_header.number);
u256(number)
},
F_Timestamp => {
let timestamp = word_of_block_timestamp(k_header.timestamp);
u256(timestamp)
},
F_Coinbase => address_to_word(k_header.fee_recipient),
F_BaseFee => k_header.base_fee,
F_ChainId => {
let chain_id = word_of_chain_identifier(k_chain_id);
u256(chain_id)
},
F_GasLimit => u256(k_header.gas_limit),
F_PrevRandao => k_header.prev_randao,
F_Origin => address_to_word(active_tx.origin),
F_GasPrice => active_tx.gas_price,
F_SlotNumber => {
let slot_number = word_of_slot_number(k_header.slot_number);
u256(slot_number)
},
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2The closed environment-projection algebra interpreted by k_env. Each opcode supplies one constant member, so the shared projection remains explicit and first-order for executable and proof backends.
enum EnvField = {
/* block number (`NUMBER`) */
F_Number,
/* block timestamp (`TIMESTAMP`) */
F_Timestamp,
/* beneficiary address (`COINBASE`) */
F_Coinbase,
/* block base fee (`BASEFEE`, EIP-3198) */
F_BaseFee,
/* chain identifier (`CHAINID`, EIP-1344) */
F_ChainId,
/* block gas limit (`GASLIMIT`) */
F_GasLimit,
/* randomness beacon (`PREVRANDAO`, EIP-4399) */
F_PrevRandao,
/* transaction sender (`ORIGIN`) */
F_Origin,
/* effective gas price (`GASPRICE`) */
F_GasPrice,
/* consensus slot number (`SLOTNUM`, EIP-7843) */
F_SlotNumber,
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_basefee¶
Implements BASEFEE.
function execute_basefee(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let base_fee = k_env(F_BaseFee);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, base_fee);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}An environment field as the word its opcode pushes.
function k_env(f : EnvField) -> word = {
let active_tx = k_tx;
match f {
F_Number => {
let number = word_of_block_number(k_header.number);
u256(number)
},
F_Timestamp => {
let timestamp = word_of_block_timestamp(k_header.timestamp);
u256(timestamp)
},
F_Coinbase => address_to_word(k_header.fee_recipient),
F_BaseFee => k_header.base_fee,
F_ChainId => {
let chain_id = word_of_chain_identifier(k_chain_id);
u256(chain_id)
},
F_GasLimit => u256(k_header.gas_limit),
F_PrevRandao => k_header.prev_randao,
F_Origin => address_to_word(active_tx.origin),
F_GasPrice => active_tx.gas_price,
F_SlotNumber => {
let slot_number = word_of_slot_number(k_header.slot_number);
u256(slot_number)
},
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2The closed environment-projection algebra interpreted by k_env. Each opcode supplies one constant member, so the shared projection remains explicit and first-order for executable and proof backends.
enum EnvField = {
/* block number (`NUMBER`) */
F_Number,
/* block timestamp (`TIMESTAMP`) */
F_Timestamp,
/* beneficiary address (`COINBASE`) */
F_Coinbase,
/* block base fee (`BASEFEE`, EIP-3198) */
F_BaseFee,
/* chain identifier (`CHAINID`, EIP-1344) */
F_ChainId,
/* block gas limit (`GASLIMIT`) */
F_GasLimit,
/* randomness beacon (`PREVRANDAO`, EIP-4399) */
F_PrevRandao,
/* transaction sender (`ORIGIN`) */
F_Origin,
/* effective gas price (`GASPRICE`) */
F_GasPrice,
/* consensus slot number (`SLOTNUM`, EIP-7843) */
F_SlotNumber,
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_blobbasefee¶
Implements BLOBBASEFEE.
function execute_blobbasefee(
blob_fee : word,
carried_gas : gas,
carried_sp : StackPointer,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
sp = stack_top_advance(sp, 1);
write_stack_word(sp, blob_fee);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)The EVM 256-bit machine word (YP ยง9.1). A transparent range keeps the mathematical subtype relation visible: narrower non-negative ranges can be passed as words without a model-level conversion.
type word = range(0, 2 ^ 256 - 1)function execute_blobhash¶
Implements BLOBHASH.
function execute_blobhash(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 1, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_verylow then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let index = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let blob_hash = k_blobhash(index);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, blob_hash);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}BLOBHASH (EIP-4844): the i-th versioned hash, zero out of
range.
function k_blobhash(index_word : word) -> word = {
let active_tx = k_tx;
let count = active_tx.blob_hashes.count;
if index_word < count then {
let index = index_word;
let offset : source_pointer = 33 * index + 1;
slice_load_n(active_tx.blob_hashes.bytes, offset, WORD_BYTE_LENGTH)
} else {
ZERO_WORD
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_pop¶
Implements POP.
function execute_pop(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 1, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let _ = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_mload¶
Implements MLOAD.
function execute_mload(
memory_base : memory_base,
carried_gas : gas,
carried_sp : StackPointer,
carried_memory_height : memory_height,
) -> (
(gas, StackPointer, memory_height, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 1, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, carried_memory_height, stack_status)
};
var gas : gas = carried_gas;
var sp : StackPointer = carried_sp;
var memory : memory_height = carried_memory_height;
if gas < G_verylow then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, G_verylow);
let offset_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let word_size = u256(32);
let requested_height = memory_requested_height(offset_word, word_size);
let expansion_cost = memory_expansion_gas_cost(memory, requested_height, gas);
if not_bool(expansion_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, expansion_cost.cost);
let access = memory_access(offset_word, word_size);
memory = expand_memory(memory_base, memory, access.requested_height);
let value = mem_load(memory_base, access.range.off);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, value);
(gas, sp, memory, Continue())
}Materializes an already-charged memory high-water mark and returns its updated scalar height.
function expand_memory(base : memory_base, height : memory_height, requested_height : memory_length) -> memory_height = {
if requested_height <= sizeof(memory_region_bound) - base then {
if height < requested_height then {
mem_expand(base, height, requested_height);
requested_height
} else {
height
}
} else {
fatal_error(ExecutionInvalid)
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}MLOAD: the big-endian word at off.
function mem_load(base : memory_base, off : memory_base) -> word = {
let absolute_offset = memory_absolute(base, off);
mem_load_word(absolute_offset)
}function memory_access(start, size) =
if size == 0 then {
EMPTY_MEMORY_ACCESS
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let range = memory_range(bounded_start, bounded_size);
let requested_height = bounded_start + bounded_size;
let access = struct { range = range, requested_height = requested_height } :
MemoryAccessFields('bounded_start, 'bounded_size, 'bounded_start + 'bounded_size);
access
} else {
fatal_error(ExecutionInvalid)
}
} else {
fatal_error(ExecutionInvalid)
}function memory_expansion_gas_cost(mem, requested_height, available) =
if requested_height <= sizeof(memory_region_bound) then {
let materialized_size : memory_length = requested_height;
let new_words = memory_word_count(materialized_size);
let old_size = memory_high_water(mem);
let old_words = memory_word_count(old_size);
if new_words <= old_words then {
gas_charge(GAS_COST_ZERO)
} else {
let old_cost = mem_cost(old_words);
let new_cost = mem_cost(new_words);
if old_cost <= new_cost then {
let exact_cost = new_cost - old_cost;
if exact_cost <= available then {
let cost : gas_cost = exact_cost;
gas_charge(cost)
} else {
GAS_CHARGE_UNAFFORDABLE
}
} else {
gas_charge(GAS_COST_ZERO)
}
}
} else {
GAS_CHARGE_UNAFFORDABLE
}function memory_requested_height(start, size) =
if size == 0 then {
0
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let requested_height : memory_required_endpoint = bounded_start + bounded_size;
requested_height
} else {
sizeof(memory_region_bound + 1)
}
} else {
sizeof(memory_region_bound + 1)
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}function u256(value) = valueWrites the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)An absolute byte position in the shared EVM-memory arena.
type memory_base = range(0, memory_region_bound)The active EVM frame's exact relative byte high-water mark. It is carried
beside the frame's absolute memory_base; the host retains no hidden
frame coordinate or lifecycle state.
type memory_height = memory_lengthfunction execute_mstore¶
Implements MSTORE.
function execute_mstore(
memory_base : memory_base,
carried_gas : gas,
carried_sp : StackPointer,
carried_memory_height : memory_height,
) -> (
(gas, StackPointer, memory_height, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 2, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, carried_memory_height, stack_status)
};
var gas : gas = carried_gas;
var sp : StackPointer = carried_sp;
var memory : memory_height = carried_memory_height;
if gas < G_verylow then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, G_verylow);
let offset_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let v = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let word_size = u256(32);
let requested_height = memory_requested_height(offset_word, word_size);
let expansion_cost = memory_expansion_gas_cost(memory, requested_height, gas);
if not_bool(expansion_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, expansion_cost.cost);
let access = memory_access(offset_word, word_size);
memory = expand_memory(memory_base, memory, access.requested_height);
mem_store(memory_base, access.range.off, v);
(gas, sp, memory, Continue())
}Materializes an already-charged memory high-water mark and returns its updated scalar height.
function expand_memory(base : memory_base, height : memory_height, requested_height : memory_length) -> memory_height = {
if requested_height <= sizeof(memory_region_bound) - base then {
if height < requested_height then {
mem_expand(base, height, requested_height);
requested_height
} else {
height
}
} else {
fatal_error(ExecutionInvalid)
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}MSTORE: writes the big-endian word at off and raises the
high-water mark.
function mem_store(base : memory_base, off : memory_base, w : word) -> unit = {
let absolute_offset = memory_absolute(base, off);
mem_store_word(absolute_offset, w)
}function memory_access(start, size) =
if size == 0 then {
EMPTY_MEMORY_ACCESS
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let range = memory_range(bounded_start, bounded_size);
let requested_height = bounded_start + bounded_size;
let access = struct { range = range, requested_height = requested_height } :
MemoryAccessFields('bounded_start, 'bounded_size, 'bounded_start + 'bounded_size);
access
} else {
fatal_error(ExecutionInvalid)
}
} else {
fatal_error(ExecutionInvalid)
}function memory_expansion_gas_cost(mem, requested_height, available) =
if requested_height <= sizeof(memory_region_bound) then {
let materialized_size : memory_length = requested_height;
let new_words = memory_word_count(materialized_size);
let old_size = memory_high_water(mem);
let old_words = memory_word_count(old_size);
if new_words <= old_words then {
gas_charge(GAS_COST_ZERO)
} else {
let old_cost = mem_cost(old_words);
let new_cost = mem_cost(new_words);
if old_cost <= new_cost then {
let exact_cost = new_cost - old_cost;
if exact_cost <= available then {
let cost : gas_cost = exact_cost;
gas_charge(cost)
} else {
GAS_CHARGE_UNAFFORDABLE
}
} else {
gas_charge(GAS_COST_ZERO)
}
}
} else {
GAS_CHARGE_UNAFFORDABLE
}function memory_requested_height(start, size) =
if size == 0 then {
0
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let requested_height : memory_required_endpoint = bounded_start + bounded_size;
requested_height
} else {
sizeof(memory_region_bound + 1)
}
} else {
sizeof(memory_region_bound + 1)
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}function u256(value) = valuelet GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)An absolute byte position in the shared EVM-memory arena.
type memory_base = range(0, memory_region_bound)The active EVM frame's exact relative byte high-water mark. It is carried
beside the frame's absolute memory_base; the host retains no hidden
frame coordinate or lifecycle state.
type memory_height = memory_lengthfunction execute_mstore8¶
Implements MSTORE8.
function execute_mstore8(
memory_base : memory_base,
carried_gas : gas,
carried_sp : StackPointer,
carried_memory_height : memory_height,
) -> (
(gas, StackPointer, memory_height, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 2, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, carried_memory_height, stack_status)
};
var gas : gas = carried_gas;
var sp : StackPointer = carried_sp;
var memory : memory_height = carried_memory_height;
if gas < G_verylow then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, G_verylow);
let offset_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let v = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let requested_height = memory_requested_height(offset_word, WORD_ONE);
let expansion_cost = memory_expansion_gas_cost(memory, requested_height, gas);
if not_bool(expansion_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, expansion_cost.cost);
let access = memory_access(offset_word, WORD_ONE);
memory = expand_memory(memory_base, memory, access.requested_height);
mem_store_byte(memory_base, access.range.off, v);
(gas, sp, memory, Continue())
}Materializes an already-charged memory high-water mark and returns its updated scalar height.
function expand_memory(base : memory_base, height : memory_height, requested_height : memory_length) -> memory_height = {
if requested_height <= sizeof(memory_region_bound) - base then {
if height < requested_height then {
mem_expand(base, height, requested_height);
requested_height
} else {
height
}
} else {
fatal_error(ExecutionInvalid)
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}MSTORE8: writes the low byte of w.
function mem_store_byte(base : memory_base, off : memory_base, w : word) -> unit = {
let value = word_low_byte(w);
mem_set_byte(base, off, value)
}function memory_access(start, size) =
if size == 0 then {
EMPTY_MEMORY_ACCESS
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let range = memory_range(bounded_start, bounded_size);
let requested_height = bounded_start + bounded_size;
let access = struct { range = range, requested_height = requested_height } :
MemoryAccessFields('bounded_start, 'bounded_size, 'bounded_start + 'bounded_size);
access
} else {
fatal_error(ExecutionInvalid)
}
} else {
fatal_error(ExecutionInvalid)
}function memory_expansion_gas_cost(mem, requested_height, available) =
if requested_height <= sizeof(memory_region_bound) then {
let materialized_size : memory_length = requested_height;
let new_words = memory_word_count(materialized_size);
let old_size = memory_high_water(mem);
let old_words = memory_word_count(old_size);
if new_words <= old_words then {
gas_charge(GAS_COST_ZERO)
} else {
let old_cost = mem_cost(old_words);
let new_cost = mem_cost(new_words);
if old_cost <= new_cost then {
let exact_cost = new_cost - old_cost;
if exact_cost <= available then {
let cost : gas_cost = exact_cost;
gas_charge(cost)
} else {
GAS_CHARGE_UNAFFORDABLE
}
} else {
gas_charge(GAS_COST_ZERO)
}
}
} else {
GAS_CHARGE_UNAFFORDABLE
}function memory_requested_height(start, size) =
if size == 0 then {
0
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let requested_height : memory_required_endpoint = bounded_start + bounded_size;
requested_height
} else {
sizeof(memory_region_bound + 1)
}
} else {
sizeof(memory_region_bound + 1)
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3let WORD_ONE : word = word_from_bits(0x0000000000000000000000000000000000000000000000000000000000000001)Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)An absolute byte position in the shared EVM-memory arena.
type memory_base = range(0, memory_region_bound)The active EVM frame's exact relative byte high-water mark. It is carried
beside the frame's absolute memory_base; the host retains no hidden
frame coordinate or lifecycle state.
type memory_height = memory_lengthfunction execute_msize¶
Implements MSIZE.
function execute_msize(
carried_gas : gas,
carried_sp : StackPointer,
carried_memory_height : memory_height,
) -> (
(gas, StackPointer, memory_height, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, carried_memory_height, stack_status)
};
var sp : StackPointer = carried_sp;
if carried_gas < G_base then {
return (GAS_ZERO, sp, carried_memory_height, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let high_water = memory_high_water(carried_memory_height);
let words = memory_word_count(high_water);
let size = word_of_nat_byte_count(words * 32);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, size);
(gas, sp, carried_memory_height, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Returns the carried frame's exact byte high-water mark.
function memory_high_water(height : memory_height) -> memory_length = heightfunction memory_word_count(byte_len) = {
let quotient = tdiv_nat(byte_len, 32);
let remainder = tmod_nat(byte_len, 32);
if remainder == 0 then {
quotient
} else {
quotient + 1
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}function word_of_nat_byte_count(value) =
if value < 2 ^ 256 then {
u256(value)
} else {
assert(false);
WORD_ZERO
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)The active EVM frame's exact relative byte high-water mark. It is carried
beside the frame's absolute memory_base; the host retains no hidden
frame coordinate or lifecycle state.
type memory_height = memory_lengthfunction execute_mcopy¶
Implements overlapping memory copy MCOPY (EIP-5656).
function execute_mcopy(
memory_base : memory_base,
carried_gas : gas,
carried_sp : StackPointer,
carried_memory_height : memory_height,
) -> (
(gas, StackPointer, memory_height, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 3, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, carried_memory_height, stack_status)
};
var gas : gas = carried_gas;
var sp : StackPointer = carried_sp;
var memory : memory_height = carried_memory_height;
/* EIP-5656 */
if gas < G_verylow then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, G_verylow);
let destination_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let source_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let length_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let copy_cost = copy_gas_cost(length_word, gas);
if not_bool(copy_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, copy_cost.cost);
let destination_requested_height = memory_requested_height(destination_word, length_word);
let source_requested_height = memory_requested_height(source_word, length_word);
let requested_height =
if destination_requested_height < source_requested_height
then source_requested_height
else destination_requested_height;
let expansion_cost = memory_expansion_gas_cost(memory, requested_height, gas);
if not_bool(expansion_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, expansion_cost.cost);
let destination = memory_access(destination_word, length_word);
let source = memory_access(source_word, length_word);
let materialized_required_size =
if destination.requested_height < source.requested_height
then source.requested_height
else destination.requested_height;
memory = expand_memory(memory_base, memory, materialized_required_size);
mem_mcopy(memory_base, destination.range.off, source.range.off, destination.range.len);
(gas, sp, memory, Continue())
}function copy_gas_cost(size : word, available : gas) -> GasCharge =
memory_word_gas_cost(GAS_CONSTANT_ZERO, G_copy_word, size, available)Materializes an already-charged memory high-water mark and returns its updated scalar height.
function expand_memory(base : memory_base, height : memory_height, requested_height : memory_length) -> memory_height = {
if requested_height <= sizeof(memory_region_bound) - base then {
if height < requested_height then {
mem_expand(base, height, requested_height);
requested_height
} else {
height
}
} else {
fatal_error(ExecutionInvalid)
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}MCOPY (EIP-5656): overlapping-safe memory-to-memory copy.
function mem_mcopy(base : memory_base, dst : memory_base, src : memory_base, len : memory_length) -> unit =
if len != 0 then {
let absolute_dst = memory_absolute(base, dst);
let absolute_src = memory_absolute(base, src);
mem_move(absolute_dst, absolute_src, len)
}function memory_access(start, size) =
if size == 0 then {
EMPTY_MEMORY_ACCESS
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let range = memory_range(bounded_start, bounded_size);
let requested_height = bounded_start + bounded_size;
let access = struct { range = range, requested_height = requested_height } :
MemoryAccessFields('bounded_start, 'bounded_size, 'bounded_start + 'bounded_size);
access
} else {
fatal_error(ExecutionInvalid)
}
} else {
fatal_error(ExecutionInvalid)
}function memory_expansion_gas_cost(mem, requested_height, available) =
if requested_height <= sizeof(memory_region_bound) then {
let materialized_size : memory_length = requested_height;
let new_words = memory_word_count(materialized_size);
let old_size = memory_high_water(mem);
let old_words = memory_word_count(old_size);
if new_words <= old_words then {
gas_charge(GAS_COST_ZERO)
} else {
let old_cost = mem_cost(old_words);
let new_cost = mem_cost(new_words);
if old_cost <= new_cost then {
let exact_cost = new_cost - old_cost;
if exact_cost <= available then {
let cost : gas_cost = exact_cost;
gas_charge(cost)
} else {
GAS_CHARGE_UNAFFORDABLE
}
} else {
gas_charge(GAS_COST_ZERO)
}
}
} else {
GAS_CHARGE_UNAFFORDABLE
}function memory_requested_height(start, size) =
if size == 0 then {
0
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let requested_height : memory_required_endpoint = bounded_start + bounded_size;
requested_height
} else {
sizeof(memory_region_bound + 1)
}
} else {
sizeof(memory_region_bound + 1)
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)An absolute byte position in the shared EVM-memory arena.
type memory_base = range(0, memory_region_bound)The active EVM frame's exact relative byte high-water mark. It is carried
beside the frame's absolute memory_base; the host retains no hidden
frame coordinate or lifecycle state.
type memory_height = memory_lengthtype AccountId¶
The storage-owner identity carried by the interpreter. Canonical backends retain the semantic address; optimized C refines this to the account row and its storage range/generation.
type AccountId = range(0, 2 ^ 32 - 1)type StorageId¶
A stable row identifier in an account's optimized storage table.
type StorageId = range(0, 2 ^ 32 - 1)type StorageCount¶
The number of storage rows belonging to an optimized account row.
type StorageCount = range(0, 2 ^ 32 - 1)type StorageGeneration¶
A generation token that invalidates storage rows after an account clear.
type StorageGeneration = range(0, 2 ^ 32 - 1)type AccountExecutionContext¶
The semantic account identity carried while executing one frame.
A 20-byte account address (YP ยง4.1), in canonical protocol byte order.
type address = vector(20, inc, byte)function account_execution_context¶
function account_execution_context(address : address) -> AccountExecutionContext =
struct { address = address }The semantic account identity carried while executing one frame.
struct AccountExecutionContext = {
address : address,
}A 20-byte account address (YP ยง4.1), in canonical protocol byte order.
type address = vector(20, inc, byte)function refresh_account_execution_context¶
Reuses the carried account context when the frame address is unchanged and rebuilds it when execution enters a different account.
function refresh_account_execution_context(
context : AccountExecutionContext,
previous_address : address,
next_address : address,
) -> (
AccountExecutionContext
) =
if previous_address == next_address then {
context
} else {
account_execution_context(next_address)
}function account_execution_context(address : address) -> AccountExecutionContext =
struct { address = address }The semantic account identity carried while executing one frame.
struct AccountExecutionContext = {
address : address,
}A 20-byte account address (YP ยง4.1), in canonical protocol byte order.
type address = vector(20, inc, byte)function execute_sload¶
Implements SLOAD, including warm/cold access gas.
function execute_sload(
context : AccountExecutionContext,
carried_gas : gas,
carried_sp : StackPointer,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 1, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
/* EIP-2929: cold (2100) vs warm (100) by the slot's accessed-set bit */
let s = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let warm = k_slot_is_warm(context.address, s);
let gas_cost = sload_cost(warm);
if carried_gas < gas_cost then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - gas_cost;
k_slot_mark_warm(context.address, s);
let entry = k_sload(context.address, s);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, entry.curr);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Resolves a slot to its live StorageValue: curr
is the value SLOAD pushes; orig is the EIP-2200 transaction-start
value the SSTORE gas policy compares against. The guarded
SLOAD/SSTORE opcode paths are the only callers, so reaching this
function consults the transaction overlay first. A real row hit was already
recorded when that row was established; misses record the EIP-7928 storage
read before consulting either a transaction-local clear generation or
block-scoped state. A clear generation makes an uncached slot known-zero,
but is not itself a slot-cache hit. BAL reads survive frame rollback (the
encoder removes slots that also have a storage change).
stateless_storage_by_key is the base primitive โ an authenticated MPT
point-get, one walk for both the witness and the harness-built alloc trie;
everything above it (the overlay, the read-through, the journal) is common.
function k_sload(a : address, s : word) -> StorageValue = {
let key = storage_key(a, s);
let tx_value = storage_tx_get(key);
match tx_value {
StorageTxHit(value) => return value,
StorageTxCleared(_) => {
bal_storage_read(a, s);
return struct { curr = ZERO_WORD, orig = ZERO_WORD }
},
StorageTxMiss(_) => bal_storage_read(a, s),
};
let block_value = storage_block_get(key);
if block_value.found then {
return struct { curr = block_value.value.curr, orig = block_value.value.curr }
};
let acc = k_aload(a);
let slot_hash = keccak256_word(s);
let value =
if acc.storage_cleared then ZERO_WORD else stateless_storage_by_key(acc.info.storage_root, slot_hash);
storage_block_cache(key, slot_hash, value);
struct { curr = value, orig = value }
}Returns a storage slot's EIP-2929 warm bit without changing state.
function k_slot_is_warm(a : address, s : word) -> bool = storage_is_warm(a, s)Marks a storage slot warm after the caller has paid its access charge.
function k_slot_mark_warm(a : address, s : word) -> unit = storage_mark_warm(a, s)Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)The SLOAD cost for a prior warm bit (cold = 2100, EIP-2929).
function sload_cost(warm : bool) -> gas_constant = {
let execution_profile = k_execution_profile;
let profile = execution_profile.protocol;
if warm then {
G_warm_access
} else if profile.fork >= Amsterdam then {
G_amsterdam_cold_storage_access
} else {
G_cold_sload
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0The semantic account identity carried while executing one frame.
struct AccountExecutionContext = {
address : address,
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}A 20-byte account address (YP ยง4.1), in canonical protocol byte order.
type address = vector(20, inc, byte)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)A transient computed charge after its affordability or structural bound
has been established. Unaffordable larger computations are represented by
GasCharge.affordable = false rather than materialized as a cost.
type gas_cost = range(0, 2 ^ 64 - 1)function execute_sstore¶
function execute_sstore(
context,
fork,
carried_is_static,
carried_gas,
carried_state_gas,
carried_state_spill,
carried_refund,
carried_sp,
) = {
let stack_status = guard_stack(carried_sp, 2, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_state_gas, carried_state_spill, carried_refund, carried_sp, stack_status)
};
var gas : gas = carried_gas;
var state_gas : state_gas = carried_state_gas;
var state_spill : state_gas_spill = carried_state_spill;
var refund : gas_refund = carried_refund;
var sp : StackPointer = carried_sp;
var halt : bool = false;
var status : OpcodeOutcome = Continue();
(gas, status) = guard_static(gas, carried_is_static);
if match status {
Failed(_) => true,
_ => false,
} then {
return (gas, state_gas, state_spill, refund, sp, status)
};
if (fork < Amsterdam) & (gas <= G_callstipend) then {
return (gas, state_gas, state_spill, refund, sp, Failed(OutOfGas))
};
let s = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let v = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let warm = k_slot_is_warm(context.address, s);
let cold = not_bool(warm);
if fork >= Amsterdam then {
let sentry_cost = sstore_sentry_cost(cold);
if gas < sentry_cost then {
return (GAS_ZERO, state_gas, state_spill, refund, sp, Failed(OutOfGas))
}
};
k_slot_mark_warm(context.address, s);
let entry = k_sload(context.address, s);
let costs = sstore_costs(entry.orig, entry.curr, v, cold);
if costs.state_credit != 0 then {
(gas, state_gas, state_spill) = credit_state_gas_refund(gas, state_gas, state_spill, costs.state_credit)
};
if gas < costs.execution then {
return (GAS_ZERO, state_gas, state_spill, refund, sp, Failed(OutOfGas))
};
gas = gas_sub(gas, costs.execution);
(halt, gas, state_gas, state_spill) = charge_state_gas(gas, state_gas, state_spill, costs.state_charge);
if halt then {
return (gas, state_gas, state_spill, refund, sp, Failed(OutOfGas))
};
if not_bool(costs.refund == GAS_REFUND_ZERO) then {
refund = record_refund(refund, costs.refund)
};
if entry.curr != v then {
k_sstore(context.address, s, struct { curr = v, orig = entry.orig })
};
(gas, state_gas, state_spill, refund, sp, Continue())
}function charge_state_gas(g, state_gas_remaining, state_gas_spilled, amount) = {
if amount == 0 then {
return (false, g, state_gas_remaining, state_gas_spilled)
};
let state_left = state_gas_remaining;
if amount <= state_left then {
(false, g, state_left - amount, state_gas_spilled)
} else {
let remainder = amount - state_left;
if remainder <= g then {
let spilled = state_gas_spilled;
(false, g - remainder, STATE_GAS_ZERO, state_gas_spill_add(spilled, remainder))
} else {
(true, g, state_gas_remaining, state_gas_spilled)
}
}
}function credit_state_gas_refund(g, state_gas_remaining, state_gas_spilled, amount) = {
let spilled = state_gas_spilled;
if amount <= spilled then {
if amount != 0 then {
(conserved_gas_add(g, amount), state_gas_remaining, spilled - amount)
} else {
(g, state_gas_remaining, state_gas_spilled)
}
} else {
let credited =
if spilled != 0 then conserved_gas_add(g, spilled) else g;
let to_state : state_gas_spill = amount - spilled;
(credited, conserved_gas_add(state_gas_remaining, to_state), STATE_GAS_SPILL_ZERO)
}
}function execute_sstore(
context,
fork,
carried_is_static,
carried_gas,
carried_state_gas,
carried_state_spill,
carried_refund,
carried_sp,
) = {
let stack_status = guard_stack(carried_sp, 2, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_state_gas, carried_state_spill, carried_refund, carried_sp, stack_status)
};
var gas : gas = carried_gas;
var state_gas : state_gas = carried_state_gas;
var state_spill : state_gas_spill = carried_state_spill;
var refund : gas_refund = carried_refund;
var sp : StackPointer = carried_sp;
var halt : bool = false;
var status : OpcodeOutcome = Continue();
(gas, status) = guard_static(gas, carried_is_static);
if match status {
Failed(_) => true,
_ => false,
} then {
return (gas, state_gas, state_spill, refund, sp, status)
};
if (fork < Amsterdam) & (gas <= G_callstipend) then {
return (gas, state_gas, state_spill, refund, sp, Failed(OutOfGas))
};
let s = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let v = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let warm = k_slot_is_warm(context.address, s);
let cold = not_bool(warm);
if fork >= Amsterdam then {
let sentry_cost = sstore_sentry_cost(cold);
if gas < sentry_cost then {
return (GAS_ZERO, state_gas, state_spill, refund, sp, Failed(OutOfGas))
}
};
k_slot_mark_warm(context.address, s);
let entry = k_sload(context.address, s);
let costs = sstore_costs(entry.orig, entry.curr, v, cold);
if costs.state_credit != 0 then {
(gas, state_gas, state_spill) = credit_state_gas_refund(gas, state_gas, state_spill, costs.state_credit)
};
if gas < costs.execution then {
return (GAS_ZERO, state_gas, state_spill, refund, sp, Failed(OutOfGas))
};
gas = gas_sub(gas, costs.execution);
(halt, gas, state_gas, state_spill) = charge_state_gas(gas, state_gas, state_spill, costs.state_charge);
if halt then {
return (gas, state_gas, state_spill, refund, sp, Failed(OutOfGas))
};
if not_bool(costs.refund == GAS_REFUND_ZERO) then {
refund = record_refund(refund, costs.refund)
};
if entry.curr != v then {
k_sstore(context.address, s, struct { curr = v, orig = entry.orig })
};
(gas, state_gas, state_spill, refund, sp, Continue())
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}EIP-214 write protection: any state-modifying opcode in a
STATICCALL frame halts exceptionally on the carried gas.
State-changing opcodes call this first; true means already
halted.
function guard_static(g : gas, is_static : bool) -> (gas, OpcodeOutcome) =
if is_static then {
(GAS_ZERO, Failed(WriteProtection))
} else {
(g, Continue())
}Resolves a slot to its live StorageValue: curr
is the value SLOAD pushes; orig is the EIP-2200 transaction-start
value the SSTORE gas policy compares against. The guarded
SLOAD/SSTORE opcode paths are the only callers, so reaching this
function consults the transaction overlay first. A real row hit was already
recorded when that row was established; misses record the EIP-7928 storage
read before consulting either a transaction-local clear generation or
block-scoped state. A clear generation makes an uncached slot known-zero,
but is not itself a slot-cache hit. BAL reads survive frame rollback (the
encoder removes slots that also have a storage change).
stateless_storage_by_key is the base primitive โ an authenticated MPT
point-get, one walk for both the witness and the harness-built alloc trie;
everything above it (the overlay, the read-through, the journal) is common.
function k_sload(a : address, s : word) -> StorageValue = {
let key = storage_key(a, s);
let tx_value = storage_tx_get(key);
match tx_value {
StorageTxHit(value) => return value,
StorageTxCleared(_) => {
bal_storage_read(a, s);
return struct { curr = ZERO_WORD, orig = ZERO_WORD }
},
StorageTxMiss(_) => bal_storage_read(a, s),
};
let block_value = storage_block_get(key);
if block_value.found then {
return struct { curr = block_value.value.curr, orig = block_value.value.curr }
};
let acc = k_aload(a);
let slot_hash = keccak256_word(s);
let value =
if acc.storage_cleared then ZERO_WORD else stateless_storage_by_key(acc.info.storage_root, slot_hash);
storage_block_cache(key, slot_hash, value);
struct { curr = value, orig = value }
}Returns a storage slot's EIP-2929 warm bit without changing state.
function k_slot_is_warm(a : address, s : word) -> bool = storage_is_warm(a, s)Marks a storage slot warm after the caller has paid its access charge.
function k_slot_mark_warm(a : address, s : word) -> unit = storage_mark_warm(a, s)SSTORE: creates or updates the live transaction row. The preceding
k_sload supplies the transaction-original value; the host keeps
clear generations and frame undo history private.
function k_sstore(a : address, s : word, v : StorageValue) -> unit = {
let key = storage_key(a, s);
storage_tx_update(struct { key = key, value = v })
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)function record_refund(refund, delta) =
validated_refund_add(refund, delta)Computes the fork-specific effects of one SSTORE. The refund delta is
accumulated and capped at transaction settlement, not here.
function sstore_costs(original : word, current : word, new_value : word, cold : bool) -> SstoreCosts = {
let execution_profile = k_execution_profile;
let profile = execution_profile.protocol;
if profile.fork >= Amsterdam then {
amsterdam_sstore_costs(original, current, new_value, cold)
} else {
legacy_sstore_costs(original, current, new_value, cold)
}
}Minimum execution gas required before an Amsterdam SSTORE may inspect
or mutate authenticated state.
function sstore_sentry_cost(cold : bool) -> gas = {
let access_cost = amsterdam_storage_access_cost(cold);
if access_cost < G_sstore_sentry then {
G_sstore_sentry
} else {
access_cost
}
}Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}EIP-7954 code/initcode size bump (65536/131072).
let Amsterdam : int(amsterdam_fork_value) = sizeof(amsterdam_fork_value)let GAS_REFUND_ZERO : gas_refund = 0let GAS_ZERO : int(0) = 0let G_callstipend : gas = 2300Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}A 20-byte account address (YP ยง4.1), in canonical protocol byte order.
type address = vector(20, inc, byte)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)The signed transaction refund accumulator before capping.
type gas_refund = range(
-gas_refund_bound,
gas_refund_bound,
)Amsterdam's per-frame state-gas reservoir. The transaction's total gas
allowance remains in the execution payload's uint64 domain; only the
regular-gas portion and state-gas spill into that portion are capped by
EIP-7825.
type state_gas = range(0, 2 ^ 64 - 1)Execution gas temporarily consumed by Amsterdam state charges. EIP-8037 draws spill only from the regular-gas pool, which is capped by EIP-7825.
type state_gas_spill = range(0, transaction_execution_gas_limit_value)function execute_tload¶
Implements transient-storage load TLOAD (EIP-1153).
function execute_tload(
carried_address : address,
carried_gas : gas,
carried_sp : StackPointer,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 1, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var sp : StackPointer = carried_sp;
/* EIP-1153 */
if carried_gas < G_warm_access then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_warm_access;
let s = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let value = k_tload(carried_address, s);
sp = stack_top_advance(sp, 1);
write_stack_word(sp, value);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}TLOAD (EIP-1153): reads per-transaction transient storage, which is
discarded at transaction end and is not part of the state trie.
function k_tload(a : address, s : word) -> word = {
transient_load(a, s)
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_warm_access : gas_constant = 100Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}A 20-byte account address (YP ยง4.1), in canonical protocol byte order.
type address = vector(20, inc, byte)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_tstore¶
Implements transient-storage write TSTORE (EIP-1153).
function execute_tstore(
carried_address : address,
carried_is_static : bool,
carried_gas : gas,
carried_sp : StackPointer,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 2, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
var gas : gas = carried_gas;
var status : OpcodeOutcome = Continue();
var sp : StackPointer = carried_sp;
/* EIP-1153 */
(gas, status) = guard_static(gas, carried_is_static);
if match status {
Failed(_) => true,
_ => false,
} then {
return (gas, sp, status)
};
if gas < G_warm_access then {
return (GAS_ZERO, sp, Failed(OutOfGas))
};
gas = gas_sub(gas, G_warm_access);
let s = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let v = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
k_tstore(carried_address, s, v);
(gas, sp, Continue())
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}EIP-214 write protection: any state-modifying opcode in a
STATICCALL frame halts exceptionally on the carried gas.
State-changing opcodes call this first; true means already
halted.
function guard_static(g : gas, is_static : bool) -> (gas, OpcodeOutcome) =
if is_static then {
(GAS_ZERO, Failed(WriteProtection))
} else {
(g, Continue())
}TSTORE (EIP-1153): writes transient storage. Frame rollback is part
of the host's semantic checkpoint contract.
function k_tstore(a : address, s : word, v : word) -> unit = transient_store(a, s, v)Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}let GAS_ZERO : int(0) = 0let G_warm_access : gas_constant = 100Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}A 20-byte account address (YP ยง4.1), in canonical protocol byte order.
type address = vector(20, inc, byte)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_jump¶
Implements unconditional JUMP.
function execute_jump(
carried_code : Code,
carried_pc : code_pointer,
carried_gas : gas,
carried_sp : StackPointer,
) -> (
(code_pointer, gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 1, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (carried_pc, GAS_ZERO, carried_sp, stack_status)
};
var gas : gas = carried_gas;
var pc : code_pointer = carried_pc;
var status : OpcodeOutcome = Continue();
if gas < G_mid then {
return (pc, GAS_ZERO, carried_sp, Failed(OutOfGas))
};
gas = gas_sub(gas, G_mid);
let dest = read_stack_word(carried_sp);
let sp = stack_top_retreat(carried_sp, 1);
(pc, gas, status) = do_jump(pc, gas, carried_code, dest);
(pc, gas, sp, status)
}JUMP/JUMPI target validity: the destination must be in code range
and land on a JUMPDEST (the precomputed valid-destination set,
YP ยง9.4.3); otherwise an invalid-jump exceptional halt. PUSH-data
bytes that happen to equal 0x5b are not valid. Returns the next
program counter and the carried gas.
function do_jump(
pc_in : code_pointer,
g : gas,
frame_code : Code,
destination_value : word,
) -> (
(code_pointer, gas, OpcodeOutcome)
) = {
let code_length = frame_code_len(frame_code);
if destination_value < code_length then {
let destination : code_pointer = destination_value;
let valid_destination = frame_jumpdest_valid(frame_code, destination);
if valid_destination then {
(destination, g, Continue())
} else {
(pc_in, GAS_ZERO, Failed(InvalidJump))
}
} else {
(pc_in, GAS_ZERO, Failed(InvalidJump))
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}let GAS_ZERO : int(0) = 0let G_mid : gas_constant = 8Existential executable-code value whose concrete byte address and length
remain correlated inside CodeFields.
type Code = {
'off 'len,
code_region_valid_range('off, 'len) & code_valid_length('len).
CodeFields('off, 'len)
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}An absolute byte position in the code arena.
type code_pointer = range(0, code_region_bound)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_jumpi¶
Implements conditional JUMPI.
function execute_jumpi(
carried_code : Code,
carried_pc : code_pointer,
carried_gas : gas,
carried_sp : StackPointer,
) -> (
(code_pointer, gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 2, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (carried_pc, GAS_ZERO, carried_sp, stack_status)
};
var gas : gas = carried_gas;
var pc : code_pointer = carried_pc;
var status : OpcodeOutcome = Continue();
var sp : StackPointer = carried_sp;
if gas < G_high then {
return (pc, GAS_ZERO, sp, Failed(OutOfGas))
};
gas = gas_sub(gas, G_high);
let dest = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let cond = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let condition_is_zero = word_is_zero(cond);
if condition_is_zero then {
return (pc, gas, sp, status)
};
(pc, gas, status) = do_jump(pc, gas, carried_code, dest);
(pc, gas, sp, status)
}JUMP/JUMPI target validity: the destination must be in code range
and land on a JUMPDEST (the precomputed valid-destination set,
YP ยง9.4.3); otherwise an invalid-jump exceptional halt. PUSH-data
bytes that happen to equal 0x5b are not valid. Returns the next
program counter and the carried gas.
function do_jump(
pc_in : code_pointer,
g : gas,
frame_code : Code,
destination_value : word,
) -> (
(code_pointer, gas, OpcodeOutcome)
) = {
let code_length = frame_code_len(frame_code);
if destination_value < code_length then {
let destination : code_pointer = destination_value;
let valid_destination = frame_jumpdest_valid(frame_code, destination);
if valid_destination then {
(destination, g, Continue())
} else {
(pc_in, GAS_ZERO, Failed(InvalidJump))
}
} else {
(pc_in, GAS_ZERO, Failed(InvalidJump))
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}function word_is_zero(w) = w == WORD_ZEROlet GAS_ZERO : int(0) = 0let G_high : gas_constant = 10Existential executable-code value whose concrete byte address and length
remain correlated inside CodeFields.
type Code = {
'off 'len,
code_region_valid_range('off, 'len) & code_valid_length('len).
CodeFields('off, 'len)
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}An absolute byte position in the code arena.
type code_pointer = range(0, code_region_bound)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_pc¶
Implements PC, returning the current opcode position from the
carried, already-advanced program counter.
function execute_pc(
carried_pc : code_pointer,
carried_gas : gas,
carried_sp : StackPointer,
) -> (
(code_pointer, gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (carried_pc, GAS_ZERO, carried_sp, stack_status)
};
if carried_gas < G_base then {
return (carried_pc, GAS_ZERO, carried_sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let next_pc = word_of_byte_count(carried_pc);
let opcode_pc = alu_sub(next_pc, WORD_ONE);
let sp = stack_top_advance(carried_sp, 1);
write_stack_word(sp, opcode_pc);
(carried_pc, gas, sp, Continue())
}function alu_sub(a : word, b : word) -> word = word_sub(a, b)Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2let WORD_ONE : word = word_from_bits(0x0000000000000000000000000000000000000000000000000000000000000001)Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}An absolute byte position in the code arena.
type code_pointer = range(0, code_region_bound)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_gas¶
Implements GAS, returning the carried gas remaining after its own
charge.
function execute_gas(carried_gas : gas, carried_sp : StackPointer) -> (gas, StackPointer, OpcodeOutcome) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
if carried_gas < G_base then {
return (GAS_ZERO, carried_sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_base;
let gas_word = word_of_nat_byte_count(gas);
let sp = stack_top_advance(carried_sp, 1);
write_stack_word(sp, gas_word);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}function word_of_nat_byte_count(value) =
if value < 2 ^ 256 then {
u256(value)
} else {
assert(false);
WORD_ZERO
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_jumpdest¶
Implements JUMPDEST.
function execute_jumpdest(carried_gas : gas) -> (gas, OpcodeOutcome) = {
if carried_gas < G_jumpdest then {
return (GAS_ZERO, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_jumpdest;
(gas, Continue())
}let GAS_ZERO : int(0) = 0let G_jumpdest : gas_constant = 1Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_push¶
Implements the PUSH0 through PUSH32 family.
function execute_push(
carried_gas : gas,
carried_sp : StackPointer,
n : push_width,
v : word,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, 0, 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
let cost =
if n == 0 then G_base else G_verylow;
if carried_gas < cost then {
return (GAS_ZERO, carried_sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - cost;
let sp = stack_top_advance(carried_sp, 1);
write_stack_word(sp, v);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_base : gas_constant = 2let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)The immediate-byte width of a PUSH instruction.
type push_width = range(0, 32)The EVM 256-bit machine word (YP ยง9.1). A transparent range keeps the mathematical subtype relation visible: narrower non-negative ranges can be passed as words without a model-level conversion.
type word = range(0, 2 ^ 256 - 1)function execute_dup¶
Implements the DUP1 through DUP16 family.
function execute_dup(
carried_gas : gas,
carried_sp : StackPointer,
n : stack_operation_index,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, n, n + 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
if carried_gas < G_verylow then {
return (GAS_ZERO, carried_sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let value = stack_slot_read(carried_sp, n - 1);
let sp = stack_top_advance(carried_sp, 1);
write_stack_word(sp, value);
(gas, sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}function stack_slot_read(top : StackPointer, index : stack_index) -> word =
stack_slot_read_host(top.storage, index)Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)A nonzero operand-stack position used by DUP and SWAP.
type stack_operation_index = range(1, 16)function execute_swap¶
Implements the SWAP1 through SWAP16 family.
function execute_swap(
carried_gas : gas,
carried_sp : StackPointer,
n : stack_operation_index,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, n + 1, n + 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
if carried_gas < G_verylow then {
return (GAS_ZERO, carried_sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let top_value = read_stack_word(carried_sp);
let other = stack_slot_read(carried_sp, n);
stack_set(carried_sp, 0, other);
stack_set(carried_sp, n, top_value);
(gas, carried_sp, Continue())
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Overwrites the n-th-from-top operand (SWAP); the cursor is
unchanged.
function stack_set(top : StackPointer, n : stack_index, w : word) -> unit =
stack_slot_write(top, n, w)function stack_slot_read(top : StackPointer, index : stack_index) -> word =
stack_slot_read_host(top.storage, index)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)A nonzero operand-stack position used by DUP and SWAP.
type stack_operation_index = range(1, 16)function execute_dupn¶
Implements immediate deep-stack duplication DUPN.
function execute_dupn(
carried_gas : gas,
carried_sp : StackPointer,
immediate : byte,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let valid_immediate = deep_stack_immediate_valid(immediate);
if not_bool(valid_immediate) then {
return (carried_gas, carried_sp, Failed(InvalidOpcode))
};
let n = decode_single_stack_index(immediate);
let stack_status = guard_stack(carried_sp, n, n + 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
if carried_gas < G_verylow then {
return (GAS_ZERO, carried_sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let value = stack_slot_read(carried_sp, n - 1);
let sp = stack_top_advance(carried_sp, 1);
write_stack_word(sp, value);
(gas, sp, Continue())
}Decodes the immediate shared by EIP-8024 DUPN and SWAPN into
their one-based deep-stack index (17โ235).
function decode_single_stack_index(immediate : byte) -> deep_stack_index = {
let valid = deep_stack_immediate_valid(immediate);
assert(valid);
let value : opcode = unsigned(immediate);
if value <= 90 then {
value + 145
} else {
assert(128 <= value);
value - 111
}
}Whether an EIP-8024 DUPN/SWAPN immediate is valid. Invalid
immediates remain opcode-aligned during JUMPDEST analysis.
function deep_stack_immediate_valid(immediate : byte) -> bool = {
let value : opcode = unsigned(immediate);
value <= 90 | 128 <= value
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))function stack_slot_read(top : StackPointer, index : stack_index) -> word =
stack_slot_read_host(top.storage, index)Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Writes the n=0 slot under a validated cursor.
function write_stack_word(sp : StackPointer, value : word) -> unit =
stack_slot_write(sp, 0, value)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}An 8-bit byte.
type byte = bits(8)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_swapn¶
Implements immediate deep-stack exchange SWAPN.
function execute_swapn(
carried_gas : gas,
carried_sp : StackPointer,
immediate : byte,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let valid_immediate = deep_stack_immediate_valid(immediate);
if not_bool(valid_immediate) then {
return (carried_gas, carried_sp, Failed(InvalidOpcode))
};
let n = decode_single_stack_index(immediate);
let stack_status = guard_stack(carried_sp, n + 1, n + 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
if carried_gas < G_verylow then {
return (GAS_ZERO, carried_sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let top_value = read_stack_word(carried_sp);
let other = stack_slot_read(carried_sp, n);
stack_set(carried_sp, 0, other);
stack_set(carried_sp, n, top_value);
(gas, carried_sp, Continue())
}Decodes the immediate shared by EIP-8024 DUPN and SWAPN into
their one-based deep-stack index (17โ235).
function decode_single_stack_index(immediate : byte) -> deep_stack_index = {
let valid = deep_stack_immediate_valid(immediate);
assert(valid);
let value : opcode = unsigned(immediate);
if value <= 90 then {
value + 145
} else {
assert(128 <= value);
value - 111
}
}Whether an EIP-8024 DUPN/SWAPN immediate is valid. Invalid
immediates remain opcode-aligned during JUMPDEST analysis.
function deep_stack_immediate_valid(immediate : byte) -> bool = {
let value : opcode = unsigned(immediate);
value <= 90 | 128 <= value
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Overwrites the n-th-from-top operand (SWAP); the cursor is
unchanged.
function stack_set(top : StackPointer, n : stack_index, w : word) -> unit =
stack_slot_write(top, n, w)function stack_slot_read(top : StackPointer, index : stack_index) -> word =
stack_slot_read_host(top.storage, index)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}An 8-bit byte.
type byte = bits(8)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_exchange¶
Implements immediate pairwise deep-stack EXCHANGE.
function execute_exchange(
carried_gas : gas,
carried_sp : StackPointer,
immediate : byte,
) -> (
(gas, StackPointer, OpcodeOutcome)
) = {
let valid_immediate = exchange_immediate_valid(immediate);
if not_bool(valid_immediate) then {
return (carried_gas, carried_sp, Failed(InvalidOpcode))
};
let (n, m) = decode_exchange_stack_indices(immediate);
let stack_status = guard_stack(carried_sp, m + 1, m + 1);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, stack_status)
};
if carried_gas < G_verylow then {
return (GAS_ZERO, carried_sp, Failed(OutOfGas))
};
let gas : gas = carried_gas - G_verylow;
let first = stack_slot_read(carried_sp, n);
let second = stack_slot_read(carried_sp, m);
stack_set(carried_sp, n, second);
stack_set(carried_sp, m, first);
(gas, carried_sp, Continue())
}Decodes the EIP-8024 EXCHANGE immediate into the two zero-based
stack depths that it exchanges.
function decode_exchange_stack_indices(immediate : byte) -> (stack_index, stack_index) = {
let valid = exchange_immediate_valid(immediate);
assert(valid);
let shifted : byte = xor_vec(immediate, 0x8f);
let quotient : range(0, 15) = unsigned(shifted[7 .. 4]);
let remainder : range(0, 15) = unsigned(shifted[3 .. 0]);
if quotient < remainder then {
(quotient + 1, remainder + 1)
} else {
(remainder + 1, 29 - quotient)
}
}Whether an EIP-8024 EXCHANGE immediate is valid. Invalid immediates
remain opcode-aligned during JUMPDEST analysis.
function exchange_immediate_valid(immediate : byte) -> bool = {
let value : opcode = unsigned(immediate);
value <= 81 | 128 <= value
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Overwrites the n-th-from-top operand (SWAP); the cursor is
unchanged.
function stack_set(top : StackPointer, n : stack_index, w : word) -> unit =
stack_slot_write(top, n, w)function stack_slot_read(top : StackPointer, index : stack_index) -> word =
stack_slot_read_host(top.storage, index)let GAS_ZERO : int(0) = 0let G_verylow : gas_constant = 3Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}An 8-bit byte.
type byte = bits(8)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_log¶
Implements the LOG0 through LOG4 family.
function execute_log(
carried_address : address,
carried_is_static : bool,
memory_base : memory_base,
n : log_topic_count,
carried_gas : gas,
carried_sp : StackPointer,
carried_memory_height : memory_height,
) -> (
(gas, StackPointer, memory_height, OpcodeOutcome)
) = {
let stack_status = guard_stack(carried_sp, n + 2, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, carried_memory_height, stack_status)
};
var gas : gas = carried_gas;
var status : OpcodeOutcome = Continue();
var sp : StackPointer = carried_sp;
var memory : memory_height = carried_memory_height;
var topics : LogTopics = LogTopics0();
(gas, status) = guard_static(gas, carried_is_static);
if match status {
Failed(_) => true,
_ => false,
} then {
return (gas, sp, memory, status)
};
let offset_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let length_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
(topics, sp) = pop_log_topics(n, sp);
let log_cost = log_gas_cost(n, length_word, gas);
if not_bool(log_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, log_cost.cost);
let requested_height = memory_requested_height(offset_word, length_word);
let expansion_cost = memory_expansion_gas_cost(memory, requested_height, gas);
if not_bool(expansion_cost.affordable) then {
return (GAS_ZERO, sp, memory, Failed(OutOfGas))
};
gas = gas_sub(gas, expansion_cost.cost);
let access = memory_access(offset_word, length_word);
memory = expand_memory(memory_base, memory, access.requested_height);
let range = access.range;
let data = active_memory_slice(memory_base, memory, range.off, range.len);
let memory_slice = evm_memory_slice(data.bytes, data.len);
let log_data = LogDataMemory(memory_slice);
k_log(carried_address, topics, log_data);
(gas, sp, memory, Continue())
}function active_memory_slice(base, mem, off, len) =
if len == 0 then {
EMPTY_EVM_MEMORY_SLICE
} else if mem <= sizeof(memory_region_bound) - base & off + len <= mem then {
let window = mem_view(base, mem, off + len);
sub_slice(window, off, len)
} else {
fatal_error(ExecutionInvalid)
}function evm_memory_slice(off, len) =
struct { bytes = off, len = len }Materializes an already-charged memory high-water mark and returns its updated scalar height.
function expand_memory(base : memory_base, height : memory_height, requested_height : memory_length) -> memory_height = {
if requested_height <= sizeof(memory_region_bound) - base then {
if height < requested_height then {
mem_expand(base, height, requested_height);
requested_height
} else {
height
}
} else {
fatal_error(ExecutionInvalid)
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}EIP-214 write protection: any state-modifying opcode in a
STATICCALL frame halts exceptionally on the carried gas.
State-changing opcodes call this first; true means already
halted.
function guard_static(g : gas, is_static : bool) -> (gas, OpcodeOutcome) =
if is_static then {
(GAS_ZERO, Failed(WriteProtection))
} else {
(g, Continue())
}Appends a log record (YP ยง4.4.1) to the transaction's log series.
function k_log(a : address, topics : LogTopics, data : LogData) -> unit = {
log_begin(a);
k_log_topics(topics);
k_log_data(data)
}Computes the base, topic, and data-byte components of a log operation.
function log_gas_cost(num_topics : log_topic_count, size : word, available : gas) -> GasCharge = {
let topic_cost = G_logtopic * num_topics;
let fixed_cost = G_log + topic_cost;
if fixed_cost > available then {
GAS_CHARGE_UNAFFORDABLE
} else {
let after_fixed : gas = available - fixed_cost;
let variable = word_scaled_gas_cost(G_logdata, size, after_fixed);
if variable.affordable then {
let exact_cost : linear_gas_product = fixed_cost + variable.cost;
if exact_cost <= available then {
let cost : gas_cost = exact_cost;
gas_charge(cost)
} else {
GAS_CHARGE_UNAFFORDABLE
}
} else {
GAS_CHARGE_UNAFFORDABLE
}
}
}function memory_access(start, size) =
if size == 0 then {
EMPTY_MEMORY_ACCESS
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let range = memory_range(bounded_start, bounded_size);
let requested_height = bounded_start + bounded_size;
let access = struct { range = range, requested_height = requested_height } :
MemoryAccessFields('bounded_start, 'bounded_size, 'bounded_start + 'bounded_size);
access
} else {
fatal_error(ExecutionInvalid)
}
} else {
fatal_error(ExecutionInvalid)
}function memory_expansion_gas_cost(mem, requested_height, available) =
if requested_height <= sizeof(memory_region_bound) then {
let materialized_size : memory_length = requested_height;
let new_words = memory_word_count(materialized_size);
let old_size = memory_high_water(mem);
let old_words = memory_word_count(old_size);
if new_words <= old_words then {
gas_charge(GAS_COST_ZERO)
} else {
let old_cost = mem_cost(old_words);
let new_cost = mem_cost(new_words);
if old_cost <= new_cost then {
let exact_cost = new_cost - old_cost;
if exact_cost <= available then {
let cost : gas_cost = exact_cost;
gas_charge(cost)
} else {
GAS_CHARGE_UNAFFORDABLE
}
} else {
gas_charge(GAS_COST_ZERO)
}
}
} else {
GAS_CHARGE_UNAFFORDABLE
}function memory_requested_height(start, size) =
if size == 0 then {
0
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let requested_height : memory_required_endpoint = bounded_start + bounded_size;
requested_height
} else {
sizeof(memory_region_bound + 1)
}
} else {
sizeof(memory_region_bound + 1)
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Pops count log topics from the stack into its bounded representation.
function pop_log_topics(count : log_topic_count, sp_in : StackPointer) -> (LogTopics, StackPointer) = {
var sp = sp_in;
match count {
0 => (LogTopics0(), sp),
1 => {
let t0 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
(LogTopics1(t0), sp)
},
2 => {
let t0 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let t1 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
(LogTopics2((t0, t1)), sp)
},
3 => {
let t0 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let t1 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let t2 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
(LogTopics3((t0, t1, t2)), sp)
},
4 => {
let t0 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let t1 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let t2 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let t3 = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
(LogTopics4((t0, t1, t2, t3)), sp)
},
_ => (LogTopics0(), sp),
}
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}let GAS_ZERO : int(0) = 0Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}The bounded topic operands of one LOG0โLOG4 instruction. Keeping the
arity in the constructor avoids allocating a Sail list for at most four
stack words.
union LogTopics = {
/* `LOG0`: no topics */
LogTopics0 : unit,
/* `LOG1`: one topic */
LogTopics1 : word,
/* `LOG2`: two topics in stack-pop order */
LogTopics2 : (word, word),
/* `LOG3`: three topics in stack-pop order */
LogTopics3 : (word, word, word),
/* `LOG4`: four topics in stack-pop order */
LogTopics4 : (word, word, word, word),
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}A 20-byte account address (YP ยง4.1), in canonical protocol byte order.
type address = vector(20, inc, byte)Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)The number of indexed topics attached to one log.
type log_topic_count = range(0, 4)An absolute byte position in the shared EVM-memory arena.
type memory_base = range(0, memory_region_bound)The active EVM frame's exact relative byte high-water mark. It is carried
beside the frame's absolute memory_base; the host retains no hidden
frame coordinate or lifecycle state.
type memory_height = memory_lengthfunction execute_stop¶
Implements normal STOP.
function execute_stop() -> FrameStatus = {
let reason = HaltStop();
Halted(reason)
}Per-frame execution status: running, halted normally, or exceptionally halted.
union FrameStatus = {
/* mid-execution */
Running : unit,
/* halted normally (YP ยง9.4.4) */
Halted : HaltKind,
/* halted exceptionally: all frame gas consumed, effects void */
Exceptional : ExceptionKind
}function execute_return¶
Implements successful RETURN.
function execute_return(
memory_base : memory_base,
carried_gas : gas,
carried_sp : StackPointer,
carried_memory_height : memory_height,
) -> (
(gas, StackPointer, memory_height, FrameStatus)
) = {
let stack_status = guard_stack(carried_sp, 2, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (GAS_ZERO, carried_sp, carried_memory_height, opcode_frame_status(stack_status))
};
var gas : gas = carried_gas;
var sp : StackPointer = carried_sp;
var memory : memory_height = carried_memory_height;
let offset_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let length_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let requested_height = memory_requested_height(offset_word, length_word);
let expansion_cost = memory_expansion_gas_cost(memory, requested_height, gas);
if not_bool(expansion_cost.affordable) then {
return (GAS_ZERO, sp, memory, Exceptional(OutOfGas))
};
gas = gas_sub(gas, expansion_cost.cost);
let access = memory_access(offset_word, length_word);
memory = expand_memory(memory_base, memory, access.requested_height);
let range = access.range;
let data = active_memory_slice(memory_base, memory, range.off, range.len);
let output = freeze_output(data);
let reason = HaltReturn(output);
(gas, sp, memory, Halted(reason))
}function active_memory_slice(base, mem, off, len) =
if len == 0 then {
EMPTY_EVM_MEMORY_SLICE
} else if mem <= sizeof(memory_region_bound) - base & off + len <= mem then {
let window = mem_view(base, mem, off + len);
sub_slice(window, off, len)
} else {
fatal_error(ExecutionInvalid)
}Materializes an already-charged memory high-water mark and returns its updated scalar height.
function expand_memory(base : memory_base, height : memory_height, requested_height : memory_length) -> memory_height = {
if requested_height <= sizeof(memory_region_bound) - base then {
if height < requested_height then {
mem_expand(base, height, requested_height);
requested_height
} else {
height
}
} else {
fatal_error(ExecutionInvalid)
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}function memory_access(start, size) =
if size == 0 then {
EMPTY_MEMORY_ACCESS
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let range = memory_range(bounded_start, bounded_size);
let requested_height = bounded_start + bounded_size;
let access = struct { range = range, requested_height = requested_height } :
MemoryAccessFields('bounded_start, 'bounded_size, 'bounded_start + 'bounded_size);
access
} else {
fatal_error(ExecutionInvalid)
}
} else {
fatal_error(ExecutionInvalid)
}function memory_expansion_gas_cost(mem, requested_height, available) =
if requested_height <= sizeof(memory_region_bound) then {
let materialized_size : memory_length = requested_height;
let new_words = memory_word_count(materialized_size);
let old_size = memory_high_water(mem);
let old_words = memory_word_count(old_size);
if new_words <= old_words then {
gas_charge(GAS_COST_ZERO)
} else {
let old_cost = mem_cost(old_words);
let new_cost = mem_cost(new_words);
if old_cost <= new_cost then {
let exact_cost = new_cost - old_cost;
if exact_cost <= available then {
let cost : gas_cost = exact_cost;
gas_charge(cost)
} else {
GAS_CHARGE_UNAFFORDABLE
}
} else {
gas_charge(GAS_COST_ZERO)
}
}
} else {
GAS_CHARGE_UNAFFORDABLE
}function memory_requested_height(start, size) =
if size == 0 then {
0
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let requested_height : memory_required_endpoint = bounded_start + bounded_size;
requested_height
} else {
sizeof(memory_region_bound + 1)
}
} else {
sizeof(memory_region_bound + 1)
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Converts a non-terminal opcode result into the corresponding frame status.
function opcode_frame_status(result : OpcodeOutcome) -> FrameStatus = match result {
Continue() => Running(),
Failed(kind) => Exceptional(kind),
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}let GAS_ZERO : int(0) = 0Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Per-frame execution status: running, halted normally, or exceptionally halted.
union FrameStatus = {
/* mid-execution */
Running : unit,
/* halted normally (YP ยง9.4.4) */
Halted : HaltKind,
/* halted exceptionally: all frame gas consumed, effects void */
Exceptional : ExceptionKind
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)An absolute byte position in the shared EVM-memory arena.
type memory_base = range(0, memory_region_bound)The active EVM frame's exact relative byte high-water mark. It is carried
beside the frame's absolute memory_base; the host retains no hidden
frame coordinate or lifecycle state.
type memory_height = memory_lengthfunction execute_revert¶
function execute_revert(
carried_state_gas_reservoir,
memory_base,
carried_gas,
carried_state_gas,
carried_state_spill,
carried_sp,
carried_memory_height,
) = {
let stack_status = guard_stack(carried_sp, 2, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (
GAS_ZERO,
carried_state_gas,
carried_state_spill,
carried_sp,
carried_memory_height,
opcode_frame_status(stack_status),
)
};
var gas : gas = carried_gas;
var state_gas : state_gas = carried_state_gas;
var state_spill : state_gas_spill = carried_state_spill;
var sp : StackPointer = carried_sp;
var memory : memory_height = carried_memory_height;
/* EIP-140 */
let offset_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let length_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let requested_height = memory_requested_height(offset_word, length_word);
let expansion_cost = memory_expansion_gas_cost(memory, requested_height, gas);
if not_bool(expansion_cost.affordable) then {
return (GAS_ZERO, carried_state_gas, carried_state_spill, sp, memory, Exceptional(OutOfGas))
};
gas = gas_sub(gas, expansion_cost.cost);
let access = memory_access(offset_word, length_word);
memory = expand_memory(memory_base, memory, access.requested_height);
let range = access.range;
let execution_profile = k_execution_profile;
let profile = execution_profile.protocol;
if profile.fork >= Amsterdam then {
gas = conserved_gas_add(gas, state_spill);
state_gas = carried_state_gas_reservoir;
state_spill = STATE_GAS_SPILL_ZERO
};
let data = active_memory_slice(memory_base, memory, range.off, range.len);
let output = freeze_output(data);
let reason = HaltRevert(output);
(gas, state_gas, state_spill, sp, memory, Halted(reason))
}function active_memory_slice(base, mem, off, len) =
if len == 0 then {
EMPTY_EVM_MEMORY_SLICE
} else if mem <= sizeof(memory_region_bound) - base & off + len <= mem then {
let window = mem_view(base, mem, off + len);
sub_slice(window, off, len)
} else {
fatal_error(ExecutionInvalid)
}function conserved_gas_add(available, credit) =
if credit <= (2 ^ 64 - 1) - available then {
available + credit
} else {
fatal_error(ExecutionInvalid)
}function execute_revert(
carried_state_gas_reservoir,
memory_base,
carried_gas,
carried_state_gas,
carried_state_spill,
carried_sp,
carried_memory_height,
) = {
let stack_status = guard_stack(carried_sp, 2, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (
GAS_ZERO,
carried_state_gas,
carried_state_spill,
carried_sp,
carried_memory_height,
opcode_frame_status(stack_status),
)
};
var gas : gas = carried_gas;
var state_gas : state_gas = carried_state_gas;
var state_spill : state_gas_spill = carried_state_spill;
var sp : StackPointer = carried_sp;
var memory : memory_height = carried_memory_height;
/* EIP-140 */
let offset_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let length_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let requested_height = memory_requested_height(offset_word, length_word);
let expansion_cost = memory_expansion_gas_cost(memory, requested_height, gas);
if not_bool(expansion_cost.affordable) then {
return (GAS_ZERO, carried_state_gas, carried_state_spill, sp, memory, Exceptional(OutOfGas))
};
gas = gas_sub(gas, expansion_cost.cost);
let access = memory_access(offset_word, length_word);
memory = expand_memory(memory_base, memory, access.requested_height);
let range = access.range;
let execution_profile = k_execution_profile;
let profile = execution_profile.protocol;
if profile.fork >= Amsterdam then {
gas = conserved_gas_add(gas, state_spill);
state_gas = carried_state_gas_reservoir;
state_spill = STATE_GAS_SPILL_ZERO
};
let data = active_memory_slice(memory_base, memory, range.off, range.len);
let output = freeze_output(data);
let reason = HaltRevert(output);
(gas, state_gas, state_spill, sp, memory, Halted(reason))
}Materializes an already-charged memory high-water mark and returns its updated scalar height.
function expand_memory(base : memory_base, height : memory_height, requested_height : memory_length) -> memory_height = {
if requested_height <= sizeof(memory_region_bound) - base then {
if height < requested_height then {
mem_expand(base, height, requested_height);
requested_height
} else {
height
}
} else {
fatal_error(ExecutionInvalid)
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}function memory_access(start, size) =
if size == 0 then {
EMPTY_MEMORY_ACCESS
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let range = memory_range(bounded_start, bounded_size);
let requested_height = bounded_start + bounded_size;
let access = struct { range = range, requested_height = requested_height } :
MemoryAccessFields('bounded_start, 'bounded_size, 'bounded_start + 'bounded_size);
access
} else {
fatal_error(ExecutionInvalid)
}
} else {
fatal_error(ExecutionInvalid)
}function memory_expansion_gas_cost(mem, requested_height, available) =
if requested_height <= sizeof(memory_region_bound) then {
let materialized_size : memory_length = requested_height;
let new_words = memory_word_count(materialized_size);
let old_size = memory_high_water(mem);
let old_words = memory_word_count(old_size);
if new_words <= old_words then {
gas_charge(GAS_COST_ZERO)
} else {
let old_cost = mem_cost(old_words);
let new_cost = mem_cost(new_words);
if old_cost <= new_cost then {
let exact_cost = new_cost - old_cost;
if exact_cost <= available then {
let cost : gas_cost = exact_cost;
gas_charge(cost)
} else {
GAS_CHARGE_UNAFFORDABLE
}
} else {
gas_charge(GAS_COST_ZERO)
}
}
} else {
GAS_CHARGE_UNAFFORDABLE
}function memory_requested_height(start, size) =
if size == 0 then {
0
} else if start <= sizeof(memory_region_bound) then {
let (bounded_start as 'bounded_start) :
{'bounded_start,
'bounded_start == 'start & 0 <= 'bounded_start & 'bounded_start <= memory_region_bound.
int('bounded_start)} = start;
if size <= sizeof(memory_region_bound) - bounded_start then {
let (bounded_size as 'bounded_size) :
{'bounded_size,
'bounded_size == 'size & 0 < 'bounded_size & 'bounded_size <= memory_region_bound - 'bounded_start.
int('bounded_size)} = size;
let requested_height : memory_required_endpoint = bounded_start + bounded_size;
requested_height
} else {
sizeof(memory_region_bound + 1)
}
} else {
sizeof(memory_region_bound + 1)
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Converts a non-terminal opcode result into the corresponding frame status.
function opcode_frame_status(result : OpcodeOutcome) -> FrameStatus = match result {
Continue() => Running(),
Failed(kind) => Exceptional(kind),
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}EIP-7954 code/initcode size bump (65536/131072).
let Amsterdam : int(amsterdam_fork_value) = sizeof(amsterdam_fork_value)let GAS_ZERO : int(0) = 0let STATE_GAS_SPILL_ZERO : int(0) = 0The active protocol policy and all gas limits derived from the executing header, selected together while decoding the stateless input.
register k_execution_profile : ExecutionProfile = DEFAULT_EXECUTION_PROFILEExceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)An absolute byte position in the shared EVM-memory arena.
type memory_base = range(0, memory_region_bound)The active EVM frame's exact relative byte high-water mark. It is carried
beside the frame's absolute memory_base; the host retains no hidden
frame coordinate or lifecycle state.
type memory_height = memory_lengthAmsterdam's per-frame state-gas reservoir. The transaction's total gas
allowance remains in the execution payload's uint64 domain; only the
regular-gas portion and state-gas spill into that portion are capped by
EIP-7825.
type state_gas = range(0, 2 ^ 64 - 1)Execution gas temporarily consumed by Amsterdam state charges. EIP-8037 draws spill only from the regular-gas pool, which is capped by EIP-7825.
type state_gas_spill = range(0, transaction_execution_gas_limit_value)function execute_invalid¶
Reports invalid-opcode termination to the interpreter's exceptional-halt boundary.
function execute_invalid(carried_gas : gas) -> (gas, OpcodeOutcome) = {
(carried_gas, Failed(InvalidOpcode))
}Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)function execute_selfdestruct¶
function execute_selfdestruct(
carried_address,
fork,
carried_is_static,
carried_gas,
carried_state_gas,
carried_state_spill,
carried_refund,
carried_sp,
) = {
let stack_status = guard_stack(carried_sp, 1, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (
GAS_ZERO,
carried_state_gas,
carried_state_spill,
carried_refund,
carried_sp,
opcode_frame_status(stack_status),
)
};
var gas : gas = carried_gas;
var state_gas : state_gas = carried_state_gas;
var state_spill : state_gas_spill = carried_state_spill;
var refund : gas_refund = carried_refund;
var sp : StackPointer = carried_sp;
var halt : bool = false;
var status : OpcodeOutcome = Continue();
(gas, status) = guard_static(gas, carried_is_static);
if match status {
Failed(_) => true,
_ => false,
} then {
return (gas, state_gas, state_spill, refund, sp, opcode_frame_status(status))
};
let beneficiary_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let beneficiary = word_to_address(beneficiary_word);
let halt_reason = HaltSelfDestruct();
let halt_status = Halted(halt_reason);
if fork >= Amsterdam then {
let warm = k_account_is_warm(beneficiary);
let cold_access_cost =
if warm then G_zero else G_amsterdam_cold_account_access;
let access_cost = G_selfdestruct + cold_access_cost;
if gas < access_cost then {
return (GAS_ZERO, state_gas, state_spill, refund, sp, Exceptional(OutOfGas))
};
k_account_mark_warm(beneficiary);
let bal = k_get_balance(carried_address);
let nonzero_balance = word_nonzero(bal);
let beneficiary_empty = k_account_is_empty(beneficiary);
let creates_account = nonzero_balance & beneficiary_empty;
let execution_cost =
if creates_account then access_cost + G_amsterdam_account_write else access_cost;
if gas < execution_cost then {
return (GAS_ZERO, state_gas, state_spill, refund, sp, Exceptional(OutOfGas))
};
gas = gas_sub(gas, execution_cost);
if creates_account then {
(halt, gas, state_gas, state_spill) = charge_state_gas(
gas,
state_gas,
state_spill,
G_amsterdam_state_new_account,
)
};
if halt then {
return (gas, state_gas, state_spill, refund, sp, Exceptional(OutOfGas))
};
k_transfer(carried_address, beneficiary, bal);
let created = k_was_created(carried_address);
if created then {
k_selfdestruct(carried_address)
};
(gas, state_gas, state_spill, refund, sp, halt_status)
} else {
let bal = k_get_balance(carried_address);
let warm = k_account_is_warm(beneficiary);
if gas < G_selfdestruct then {
return (GAS_ZERO, state_gas, state_spill, refund, sp, Exceptional(OutOfGas))
};
gas = gas_sub(gas, G_selfdestruct);
if not_bool(warm) then {
if gas < G_cold_account then {
return (GAS_ZERO, state_gas, state_spill, refund, sp, Exceptional(OutOfGas))
};
gas = gas_sub(gas, G_cold_account)
};
k_account_mark_warm(beneficiary);
let nonzero_balance = word_nonzero(bal);
let beneficiary_empty = k_account_is_empty(beneficiary);
if nonzero_balance & beneficiary_empty then {
if gas < G_newaccount then {
return (GAS_ZERO, state_gas, state_spill, refund, sp, Exceptional(OutOfGas))
};
gas = gas_sub(gas, G_newaccount)
};
let is_selfdestructed = k_is_selfdestructed(carried_address);
let first_selfdestruct = not_bool(is_selfdestructed);
if (fork < London) & first_selfdestruct then {
refund = record_refund(refund, R_selfdestruct_pre_london)
};
k_transfer(carried_address, beneficiary, bal);
if fork < Cancun then {
k_zero_balance(carried_address);
k_selfdestruct(carried_address)
} else {
let created = k_was_created(carried_address);
if created then {
k_zero_balance(carried_address);
k_selfdestruct(carried_address)
}
};
(gas, state_gas, state_spill, refund, sp, halt_status)
}
}function charge_state_gas(g, state_gas_remaining, state_gas_spilled, amount) = {
if amount == 0 then {
return (false, g, state_gas_remaining, state_gas_spilled)
};
let state_left = state_gas_remaining;
if amount <= state_left then {
(false, g, state_left - amount, state_gas_spilled)
} else {
let remainder = amount - state_left;
if remainder <= g then {
let spilled = state_gas_spilled;
(false, g - remainder, STATE_GAS_ZERO, state_gas_spill_add(spilled, remainder))
} else {
(true, g, state_gas_remaining, state_gas_spilled)
}
}
}function execute_selfdestruct(
carried_address,
fork,
carried_is_static,
carried_gas,
carried_state_gas,
carried_state_spill,
carried_refund,
carried_sp,
) = {
let stack_status = guard_stack(carried_sp, 1, 0);
if match stack_status {
Failed(_) => true,
_ => false,
} then {
return (
GAS_ZERO,
carried_state_gas,
carried_state_spill,
carried_refund,
carried_sp,
opcode_frame_status(stack_status),
)
};
var gas : gas = carried_gas;
var state_gas : state_gas = carried_state_gas;
var state_spill : state_gas_spill = carried_state_spill;
var refund : gas_refund = carried_refund;
var sp : StackPointer = carried_sp;
var halt : bool = false;
var status : OpcodeOutcome = Continue();
(gas, status) = guard_static(gas, carried_is_static);
if match status {
Failed(_) => true,
_ => false,
} then {
return (gas, state_gas, state_spill, refund, sp, opcode_frame_status(status))
};
let beneficiary_word = read_stack_word(sp);
sp = stack_top_retreat(sp, 1);
let beneficiary = word_to_address(beneficiary_word);
let halt_reason = HaltSelfDestruct();
let halt_status = Halted(halt_reason);
if fork >= Amsterdam then {
let warm = k_account_is_warm(beneficiary);
let cold_access_cost =
if warm then G_zero else G_amsterdam_cold_account_access;
let access_cost = G_selfdestruct + cold_access_cost;
if gas < access_cost then {
return (GAS_ZERO, state_gas, state_spill, refund, sp, Exceptional(OutOfGas))
};
k_account_mark_warm(beneficiary);
let bal = k_get_balance(carried_address);
let nonzero_balance = word_nonzero(bal);
let beneficiary_empty = k_account_is_empty(beneficiary);
let creates_account = nonzero_balance & beneficiary_empty;
let execution_cost =
if creates_account then access_cost + G_amsterdam_account_write else access_cost;
if gas < execution_cost then {
return (GAS_ZERO, state_gas, state_spill, refund, sp, Exceptional(OutOfGas))
};
gas = gas_sub(gas, execution_cost);
if creates_account then {
(halt, gas, state_gas, state_spill) = charge_state_gas(
gas,
state_gas,
state_spill,
G_amsterdam_state_new_account,
)
};
if halt then {
return (gas, state_gas, state_spill, refund, sp, Exceptional(OutOfGas))
};
k_transfer(carried_address, beneficiary, bal);
let created = k_was_created(carried_address);
if created then {
k_selfdestruct(carried_address)
};
(gas, state_gas, state_spill, refund, sp, halt_status)
} else {
let bal = k_get_balance(carried_address);
let warm = k_account_is_warm(beneficiary);
if gas < G_selfdestruct then {
return (GAS_ZERO, state_gas, state_spill, refund, sp, Exceptional(OutOfGas))
};
gas = gas_sub(gas, G_selfdestruct);
if not_bool(warm) then {
if gas < G_cold_account then {
return (GAS_ZERO, state_gas, state_spill, refund, sp, Exceptional(OutOfGas))
};
gas = gas_sub(gas, G_cold_account)
};
k_account_mark_warm(beneficiary);
let nonzero_balance = word_nonzero(bal);
let beneficiary_empty = k_account_is_empty(beneficiary);
if nonzero_balance & beneficiary_empty then {
if gas < G_newaccount then {
return (GAS_ZERO, state_gas, state_spill, refund, sp, Exceptional(OutOfGas))
};
gas = gas_sub(gas, G_newaccount)
};
let is_selfdestructed = k_is_selfdestructed(carried_address);
let first_selfdestruct = not_bool(is_selfdestructed);
if (fork < London) & first_selfdestruct then {
refund = record_refund(refund, R_selfdestruct_pre_london)
};
k_transfer(carried_address, beneficiary, bal);
if fork < Cancun then {
k_zero_balance(carried_address);
k_selfdestruct(carried_address)
} else {
let created = k_was_created(carried_address);
if created then {
k_zero_balance(carried_address);
k_selfdestruct(carried_address)
}
};
(gas, state_gas, state_spill, refund, sp, halt_status)
}
}Total gas subtraction. Protocol callers establish affordability first; the saturated arm keeps the primitive representation-safe by construction.
function gas_sub(left : gas, right : gas_cost) -> gas =
if right <= left then {
left - right
} else {
GAS_ZERO
}Establishes an opcode's local stack precondition before gas charging or
any instruction side effect. The caller supplies the opcode's constant
Yellow Paper (delta, alpha) values.
function guard_stack(
carried_sp : StackPointer,
inputs : operand_stack_height,
outputs : operand_stack_height,
) -> (
OpcodeOutcome
) = {
let stack_validation = validate_stack(carried_sp, inputs, outputs);
match stack_validation {
StackValid => Continue(),
StackUnderflowFailure => Failed(StackUnderflow),
StackOverflowFailure => Failed(StackOverflow),
}
}EIP-214 write protection: any state-modifying opcode in a
STATICCALL frame halts exceptionally on the carried gas.
State-changing opcodes call this first; true means already
halted.
function guard_static(g : gas, is_static : bool) -> (gas, OpcodeOutcome) =
if is_static then {
(GAS_ZERO, Failed(WriteProtection))
} else {
(g, Continue())
}The EIP-161 "empty" test on the live account: zero nonce, zero balance, no code.
function k_account_is_empty(a : address) -> bool = {
let account = k_aload(a);
account_info_empty(account.info)
}Returns the address's EIP-2929 warm bit without changing state. Active precompiles are warm independently of the BAL-derived account table.
function k_account_is_warm(a : address) -> bool = {
let precompile_id = precompile_id_for_address(a);
if precompile_id != NotPrecompile then {
true
} else {
account_is_warm(a)
}
}Marks an address warm after the caller has established that its access gas is affordable. Active precompiles need no host-table entry.
function k_account_mark_warm(a : address) -> unit = {
let precompile_id = precompile_id_for_address(a);
if precompile_id != NotPrecompile then {
return ()
};
account_mark_warm(a)
}The account balance (BALANCE, SELFBALANCE).
function k_get_balance(a : address) -> word = {
k_aload(a).info.balance
}Whether the account is marked selfdestructed this transaction.
function k_is_selfdestructed(a : address) -> bool = k_aload(a).selfdestructedMarks an account selfdestructed (SELFDESTRUCT; deletion is decided
at transaction end per EIP-6780).
function k_selfdestruct(a : address) -> unit = {
let cur = k_aload(a);
let active = not_bool(cur.selfdestructed);
if active then {
store_account(a, { cur with selfdestructed = true })
}
}Moves v wei from src to dst (both updates recorded for frame
rollback; the EVM checks sufficiency before calling) and emits the
EIP-7708 transfer log.
function k_transfer(src : address, dst : address, v : word) -> unit = {
let src_acc = k_aload(src);
let dst_acc = k_aload(dst);
let value_is_zero = word_is_zero(v);
if value_is_zero | (src == dst) then {
return ()
};
let source_balance = alu_sub(src_acc.info.balance, v);
store_account_info(src, src_acc, { src_acc.info with balance = source_balance });
let destination_balance = alu_add(dst_acc.info.balance, v);
store_account_info(dst, dst_acc, { dst_acc.info with balance = destination_balance });
k_emit_transfer_log(src, dst, v)
}Whether the account was created in this transaction.
function k_was_created(a : address) -> bool = k_aload(a).createdZeroes an account's balance (the SELFDESTRUCT sweep of a
self-beneficiary).
function k_zero_balance(a : address) -> unit = {
let cur = k_aload(a);
let balance_is_zero = word_is_zero(cur.info.balance);
if balance_is_zero then {
return ()
};
store_account_info(a, cur, { cur.info with balance = ZERO_WORD })
}val not_bool = pure {coq: "negb", lean: "_lean_not", _: "not"}: forall ('p : Bool). bool('p) -> bool(not('p))Converts a non-terminal opcode result into the corresponding frame status.
function opcode_frame_status(result : OpcodeOutcome) -> FrameStatus = match result {
Continue() => Running(),
Failed(kind) => Exceptional(kind),
}Reads the n=0 slot under a validated cursor.
function read_stack_word(sp : StackPointer) -> word = stack_slot_read(sp, 0)function record_refund(refund, delta) =
validated_refund_add(refund, delta)Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}function word_nonzero(w) = {
let is_zero = word_is_zero(w);
not_bool(is_zero)
}Converts a word to its low 160-bit address in canonical byte order.
function word_to_address(value : word) -> address = {
let zero_bytes = vector_init(20, 0x00);
var result : address = Address(zero_bytes);
result[0] = get_slice_int(8, value, 152);
result[1] = get_slice_int(8, value, 144);
result[2] = get_slice_int(8, value, 136);
result[3] = get_slice_int(8, value, 128);
result[4] = get_slice_int(8, value, 120);
result[5] = get_slice_int(8, value, 112);
result[6] = get_slice_int(8, value, 104);
result[7] = get_slice_int(8, value, 96);
result[8] = get_slice_int(8, value, 88);
result[9] = get_slice_int(8, value, 80);
result[10] = get_slice_int(8, value, 72);
result[11] = get_slice_int(8, value, 64);
result[12] = get_slice_int(8, value, 56);
result[13] = get_slice_int(8, value, 48);
result[14] = get_slice_int(8, value, 40);
result[15] = get_slice_int(8, value, 32);
result[16] = get_slice_int(8, value, 24);
result[17] = get_slice_int(8, value, 16);
result[18] = get_slice_int(8, value, 8);
result[19] = get_slice_int(8, value, 0);
result
}EIP-7954 code/initcode size bump (65536/131072).
let Amsterdam : int(amsterdam_fork_value) = sizeof(amsterdam_fork_value)EIP-1153/4844; precompiles 0x01-0x0a.
let Cancun : int(first_blob_fork_value) = sizeof(first_blob_fork_value)let GAS_ZERO : int(0) = 0let G_amsterdam_account_write : gas_constant = 8000let G_amsterdam_cold_account_access : gas_constant = 3000let G_amsterdam_state_new_account : state_gas_spill = 183600let G_cold_account : gas_constant = 2600let G_newaccount : gas_constant = 25000let G_selfdestruct : gas_constant = 5000let G_zero : gas_constant = 0EIP-1559 fee market and EIP-3529 refund reduction.
let London : int(london_fork_value) = sizeof(london_fork_value)let R_selfdestruct_pre_london : gas_constant = 24000Exceptional halts (YP ยง9.4.2): each consumes all remaining gas and reverts the frame's state changes.
enum ExceptionKind = {
/* an opcode pops more items than the stack holds */
StackUnderflow,
/* a push would exceed the 1024-item stack limit */
StackOverflow,
/* the operation's cost exceeds the remaining gas */
OutOfGas,
/* an unassigned or fork-inactive opcode, or INVALID (0xfe) */
InvalidOpcode,
/* a jump target that is not a valid JUMPDEST */
InvalidJump,
/* EIP-214: state-changing op inside a STATICCALL */
StaticViolation,
/* a call or create beyond depth 1024 */
CallDepthExceeded,
/* a value transfer exceeding the sender's balance */
InsufficientBalance,
/* EIP-214 write protection */
WriteProtection,
/* EIP-3860 */
InitCodeTooLarge,
/* a nonce at its maximum cannot be bumped (EIP-2681) */
NonceOverflow,
/* EIP-684: CREATE into an occupied account */
AddressCollision,
}Lightweight result of one opcode handler.
union OpcodeOutcome = {
/*! Continue executing the active frame. */
Continue : unit,
/*! Stop the active opcode path with the given exceptional halt. */
Failed : ExceptionKind,
}The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}Available gas in a running EVM frame. Every admitted transaction gas
limit originates in the execution payload's SSZ uint64 gas-limit
domain, and child frames can only receive gas from their parent.
type gas = range(0, 2 ^ 64 - 1)The signed transaction refund accumulator before capping.
type gas_refund = range(
-gas_refund_bound,
gas_refund_bound,
)Amsterdam's per-frame state-gas reservoir. The transaction's total gas
allowance remains in the execution payload's uint64 domain; only the
regular-gas portion and state-gas spill into that portion are capped by
EIP-7825.
type state_gas = range(0, 2 ^ 64 - 1)Execution gas temporarily consumed by Amsterdam state charges. EIP-8037 draws spill only from the regular-gas pool, which is capped by EIP-7825.
type state_gas_spill = range(0, transaction_execution_gas_limit_value)