Code¶
Executable code and its PUSH-aware JUMPDEST analysis (YP ยง9.4.3).
type jump_table_index¶
A reference to a code's completed JUMPDEST analysis; zero denotes
the empty bitmap.
type jump_table_index = range(0, 2 ^ 64 - 1)Constants¶
EMPTY_JUMP_TABLE denotes empty analysis; EMPTY_CODE_SLICE and EMPTY_CODE
are the canonical executable-code placeholders.
let EMPTY_JUMP_TABLE¶
let EMPTY_JUMP_TABLE : jump_table_index = 0A reference to a code's completed JUMPDEST analysis; zero denotes
the empty bitmap.
type jump_table_index = range(0, 2 ^ 64 - 1)type CodeSlice¶
A source-backed executable byte span. Its length carries the separate representation invariant needed by program-counter arithmetic; this is not a protocol deployment-size limit.
type CodeSlice = {
'off 'len,
code_region_valid_range('off, 'len) & code_valid_length('len).
CodeRegionSliceFields('off, 'len)
}A range in the content-addressed executable-code arena.
struct CodeRegionSliceFields('off : Int, 'len : Int), code_region_valid_range('off, 'len) = {
bytes : int('off),
len : int('len),
}Whether an offset/length pair is contained by the executable-code arena.
type code_region_valid_range('off : Int, 'len : Int) -> Bool =
0 <= 'off & 0 <= 'len & 'off + 'len <= code_region_boundThe representation invariant required of executable code, including enough cursor headroom for a complete PUSH32 immediate.
type code_valid_length('len : Int) -> Bool =
0 <= 'len & 'len + 32 <= code_region_boundfunction validated_code_slice¶
Converts a source span whose producer guarantees executable cursor headroom. The explicit check re-establishes the proof after the length has crossed a non-dependent host boundary.
function validated_code_slice(bytes : CodeRegionSlice) -> CodeSlice =
if bytes.len <= sizeof(code_region_bound) - 32 then {
code_slice(bytes)
} else {
assert(false, "executable code cursor headroom");
code_slice(EMPTY_CODE_REGION_SLICE)
}function code_slice(bytes) = byteslet EMPTY_CODE_REGION_SLICE : CodeRegionSliceFields(0, 0) = code_region_slice(0, 0)A code-region range with its coordinate and length packed existentially.
type CodeRegionSlice = {
'off 'len,
code_region_valid_range('off, 'len).
CodeRegionSliceFields('off, 'len)
}A source-backed executable byte span. Its length carries the separate representation invariant needed by program-counter arithmetic; this is not a protocol deployment-size limit.
type CodeSlice = {
'off 'len,
code_region_valid_range('off, 'len) & code_valid_length('len).
CodeRegionSliceFields('off, 'len)
}Content-addressed executable-code arena capacity.
type code_region_bound : Int = default_host_region_boundlet EMPTY_CODE_SLICE¶
Canonical empty executable code.
let EMPTY_CODE_SLICE : CodeSlice = code_slice(EMPTY_CODE_REGION_SLICE)function code_slice(bytes) = byteslet EMPTY_CODE_REGION_SLICE : CodeRegionSliceFields(0, 0) = code_region_slice(0, 0)A source-backed executable byte span. Its length carries the separate representation invariant needed by program-counter arithmetic; this is not a protocol deployment-size limit.
type CodeSlice = {
'off 'len,
code_region_valid_range('off, 'len) & code_valid_length('len).
CodeRegionSliceFields('off, 'len)
}type DeepStackOperation¶
The closed family of Amsterdam opcodes whose instruction encoding carries one validity-sensitive immediate byte. Keeping this classification in the specification lets instruction fetch and PUSH-aware code analysis share one dispatch without introducing a function-valued decoder.
enum DeepStackOperation = { DeepStackDuplicate, DeepStackSwap, DeepStackExchange, NotDeepStackOperation }function deep_stack_operation¶
Classifies an opcode against Amsterdam's immediate deep-stack operations; every other opcode maps to the non-member.
function deep_stack_operation(opcode : opcode) -> DeepStackOperation =
match opcode {
230 => DeepStackDuplicate,
231 => DeepStackSwap,
232 => DeepStackExchange,
_ => NotDeepStackOperation,
}The closed family of Amsterdam opcodes whose instruction encoding carries one validity-sensitive immediate byte. Keeping this classification in the specification lets instruction fetch and PUSH-aware code analysis share one dispatch without introducing a function-valued decoder.
enum DeepStackOperation = { DeepStackDuplicate, DeepStackSwap, DeepStackExchange, NotDeepStackOperation }An EVM instruction byte.
type opcode = range(0, 255)function deep_stack_immediate_valid¶
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
}converts a bit vector of length $n$ to an integer in the range $0$ to $2^n - 1$.
val unsigned = pure {ocaml: "uint", lem: "uint", interpreter: "uint", coq: "uint", lean: "BitVec.toNatInt", _: "sail_unsigned"}: forall ('n : Int).
bits('n) -> range(0, 2 ^ 'n - 1)An 8-bit byte.
type byte = bits(8)An EVM instruction byte.
type opcode = range(0, 255)function exchange_immediate_valid¶
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
}converts a bit vector of length $n$ to an integer in the range $0$ to $2^n - 1$.
val unsigned = pure {ocaml: "uint", lem: "uint", interpreter: "uint", coq: "uint", lean: "BitVec.toNatInt", _: "sail_unsigned"}: forall ('n : Int).
bits('n) -> range(0, 2 ^ 'n - 1)An 8-bit byte.
type byte = bits(8)An EVM instruction byte.
type opcode = range(0, 255)function deep_stack_operation_immediate_valid¶
Applies the immediate-validity rule selected by a decoded deep-stack
operation. DUPN and SWAPN share the single-index encoding, while
EXCHANGE uses the pair encoding.
function deep_stack_operation_immediate_valid(operation : DeepStackOperation, immediate : byte) -> bool =
match operation {
DeepStackDuplicate => deep_stack_immediate_valid(immediate),
DeepStackSwap => deep_stack_immediate_valid(immediate),
DeepStackExchange => exchange_immediate_valid(immediate),
NotDeepStackOperation => false,
}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
}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
}The closed family of Amsterdam opcodes whose instruction encoding carries one validity-sensitive immediate byte. Keeping this classification in the specification lets instruction fetch and PUSH-aware code analysis share one dispatch without introducing a function-valued decoder.
enum DeepStackOperation = { DeepStackDuplicate, DeepStackSwap, DeepStackExchange, NotDeepStackOperation }An 8-bit byte.
type byte = bits(8)type CodeFields¶
Executable code: its byte address, length, and resolved JUMPDEST table.
The flat dependent record keeps the byte address and length relationship
explicit while allowing optimized C to represent both addresses directly
as pointers. The interpreter saves and restores all three together; the
code hash remains the stable code-DB key.
struct CodeFields('off : Int, 'len : Int),
code_region_valid_range('off, 'len) & code_valid_length('len) = {
bytes : int('off),
len : int('len),
jumpdests : jump_table_index,
}Whether an offset/length pair is contained by the executable-code arena.
type code_region_valid_range('off : Int, 'len : Int) -> Bool =
0 <= 'off & 0 <= 'len & 'off + 'len <= code_region_boundThe representation invariant required of executable code, including enough cursor headroom for a complete PUSH32 immediate.
type code_valid_length('len : Int) -> Bool =
0 <= 'len & 'len + 32 <= code_region_boundA reference to a code's completed JUMPDEST analysis; zero denotes
the empty bitmap.
type jump_table_index = range(0, 2 ^ 64 - 1)type Code¶
Existential 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)
}Executable code: its byte address, length, and resolved JUMPDEST table.
The flat dependent record keeps the byte address and length relationship
explicit while allowing optimized C to represent both addresses directly
as pointers. The interpreter saves and restores all three together; the
code hash remains the stable code-DB key.
struct CodeFields('off : Int, 'len : Int),
code_region_valid_range('off, 'len) & code_valid_length('len) = {
bytes : int('off),
len : int('len),
jumpdests : jump_table_index,
}Whether an offset/length pair is contained by the executable-code arena.
type code_region_valid_range('off : Int, 'len : Int) -> Bool =
0 <= 'off & 0 <= 'len & 'off + 'len <= code_region_boundThe representation invariant required of executable code, including enough cursor headroom for a complete PUSH32 immediate.
type code_valid_length('len : Int) -> Bool =
0 <= 'len & 'len + 32 <= code_region_boundfunction analyzed_code¶
function analyzed_code(bytes, jumpdests) =
struct { bytes = bytes.bytes, len = bytes.len, jumpdests = jumpdests }function analyzed_code(bytes, jumpdests) =
struct { bytes = bytes.bytes, len = bytes.len, jumpdests = jumpdests }function code_bytes¶
function code_bytes(code) = struct { bytes = code.bytes, len = code.len }function code_bytes(code) = struct { bytes = code.bytes, len = code.len }let EMPTY_CODE¶
let EMPTY_CODE : Code = analyzed_code(EMPTY_CODE_SLICE, EMPTY_JUMP_TABLE)function analyzed_code(bytes, jumpdests) =
struct { bytes = bytes.bytes, len = bytes.len, jumpdests = jumpdests }Canonical empty executable code.
let EMPTY_CODE_SLICE : CodeSlice = code_slice(EMPTY_CODE_REGION_SLICE)let EMPTY_JUMP_TABLE : jump_table_index = 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)
}