The public output¶
The guest's public output: the hash_tree_root of the new-payload
request, the validation verdict, and the echoed chain configuration.
let RESULT_METADATA_LENGTH¶
let RESULT_METADATA_LENGTH : int(5) = 5function write_prefix¶
Writes the request root and validation metadata prefix.
function write_prefix(root : hash, success : bool) -> unit = {
scratch_push_b256(root, WORD_BYTE_LENGTH);
let success_byte : byte =
if success then 0x01 else 0x00;
scratch_push_byte(success_byte);
scratch_push_byte(0x25);
scratch_push_byte(0x00);
scratch_push_byte(0x00);
scratch_push_byte(0x00)
}Appends a prefix of a fixed 32-byte value at the cursor.
function scratch_push_b256(data : b256, len : range(0, 32)) -> unit = {
if len != 0 then {
let arena = scratch_arena;
scratch_arena = host_scratch_store_b256(arena.len, data, len)
}
}Appends one byte without constructing a Sail list.
function scratch_push_byte(data : byte) -> unit = {
let arena = scratch_arena;
scratch_arena = host_scratch_store_byte(arena.len, data)
}let WORD_BYTE_LENGTH : int(32) = 32An 8-bit byte.
type byte = bits(8)The common digest type used by trie, code, and block hashes.
type hash = b256function commit_validation_result¶
Serializes and commits the public validation result exactly once.
function commit_validation_result(root : hash, success : bool, chain_config : StatelessInputSlice) -> unit = {
let fixed_length = WORD_BYTE_LENGTH + RESULT_METADATA_LENGTH;
let output_length = scratch_length_add(fixed_length, chain_config.len);
let start = scratch_reserve(output_length);
write_prefix(root, success);
scratch_push_slice(chain_config);
let output = scratch_finish(start);
let written = public_output_write(output);
assert(written, "public output write")
}Appends one byte to the guest's public output — the committed result stream the verifier sees.
val public_output_write = impure { c: "public_output_write" } : ScratchSlice -> boolThe slice covering everything pushed since start.
function scratch_finish(start : source_pointer) -> ScratchSlice =
let start_offset = start in
let arena = scratch_arena in
let stop_offset = arena.len in
if start_offset <= stop_offset then {
sub_slice(arena, start, stop_offset - start_offset)
} else {
assert(false, "scratch finish mark");
EMPTY_SCRATCH_SLICE
}function scratch_length_add(left, right) =
if right <= sizeof(scratch_region_bound) - left then {
left + right
} else {
assert(false, "scratch length overflow");
0
}function scratch_reserve(len) = {
let arena = scratch_arena;
let reserved = host_scratch_reserve(arena.len, len);
assert(reserved, "scratch reserve");
arena.len
}Writes the request root and validation metadata prefix.
function write_prefix(root : hash, success : bool) -> unit = {
scratch_push_b256(root, WORD_BYTE_LENGTH);
let success_byte : byte =
if success then 0x01 else 0x00;
scratch_push_byte(success_byte);
scratch_push_byte(0x25);
scratch_push_byte(0x00);
scratch_push_byte(0x00);
scratch_push_byte(0x00)
}let RESULT_METADATA_LENGTH : int(5) = 5let WORD_BYTE_LENGTH : int(32) = 32A stateless-input range with its coordinate and length packed existentially.
type StatelessInputSlice = {
'off 'len,
stateless_input_valid_range('off, 'len).
StatelessInputSliceFields('off, 'len)
}The common digest type used by trie, code, and block hashes.
type hash = b256A length in the guest output region.
type output_length = range(0, output_region_bound)function write_validation_result¶
Emits the full public output for a decoded input: the request root computed from the input itself, the verdict, and the input's chain configuration echoed byte for byte.
function write_validation_result(input_ref : StatelessInputRef, success : bool) -> unit = {
let root = htr_new_payload_request(input_ref);
commit_validation_result(root, success, input_ref.chain_config)
}Serializes and commits the public validation result exactly once.
function commit_validation_result(root : hash, success : bool, chain_config : StatelessInputSlice) -> unit = {
let fixed_length = WORD_BYTE_LENGTH + RESULT_METADATA_LENGTH;
let output_length = scratch_length_add(fixed_length, chain_config.len);
let start = scratch_reserve(output_length);
write_prefix(root, success);
scratch_push_slice(chain_config);
let output = scratch_finish(start);
let written = public_output_write(output);
assert(written, "public output write")
}hash_tree_root of the SszNewPayloadRequest (4 fields, depth 2) —
the commitment the guest proves its input against.
function htr_new_payload_request(input_ref : StatelessInputRef) -> hash = {
let payload_root = htr_execution_payload(input_ref);
let versioned_hashes_root = htr_versioned_hashes(input_ref.versioned_hashes);
let beacon_root = htr_ssz_bytes32(input_ref.new_payload_request, NPR_BEACON_ROOT);
let requests_root = htr_execution_requests(input_ref);
merkleize([payload_root, versioned_hashes_root, beacon_root, requests_root], 2)
}Every variable region of the input, resolved once before decoding. Consumers receive explicit source spans instead of re-reading nested SSZ offset tables.
struct StatelessInputRef = {
protocol : ProtocolProfile,
new_payload_request : StatelessInputSlice,
execution_payload : StatelessInputSliceAtLeast(540),
versioned_hashes : StatelessInputSlice,
deposits : StatelessInputSlice,
withdrawal_requests : StatelessInputSlice,
consolidation_requests : StatelessInputSlice,
builder_deposit_requests : StatelessInputSlice,
builder_exit_requests : StatelessInputSlice,
extra_data : StatelessInputSliceAtMost(extra_data_length_bound),
transactions : TransactionListRef,
withdrawals : WithdrawalListRef,
block_access_list : StatelessInputSliceAtMost(block_access_list_length_bound),
witness_state : WitnessNodeListRef,
witness_codes : WitnessCodeListRef,
witness_headers : WitnessHeaderListRef,
chain_config : StatelessInputSlice,
public_keys : StatelessInputSlice,
}function write_invalid_result¶
Emits the failure output for an undecodable input: a zero root, a false verdict, and a default configuration frame.
function write_invalid_result() -> unit = {
let start = scratch_reserve(24);
var default_chain_config = ZERO_HASH;
default_chain_config[8] = 0x0c;
default_chain_config[12] = 0x04;
default_chain_config[16] = 0x08;
default_chain_config[20] = 0x08;
scratch_push_b256(default_chain_config, 24);
let chain_config = scratch_finish(start);
let fixed_length = WORD_BYTE_LENGTH + RESULT_METADATA_LENGTH;
let output_length = scratch_length_add(fixed_length, chain_config.len);
let output_start = scratch_reserve(output_length);
write_prefix(ZERO_HASH, false);
scratch_push_slice(chain_config);
let output = scratch_finish(output_start);
let written = public_output_write(output);
assert(written, "public output write")
}Appends one byte to the guest's public output — the committed result stream the verifier sees.
val public_output_write = impure { c: "public_output_write" } : ScratchSlice -> boolThe slice covering everything pushed since start.
function scratch_finish(start : source_pointer) -> ScratchSlice =
let start_offset = start in
let arena = scratch_arena in
let stop_offset = arena.len in
if start_offset <= stop_offset then {
sub_slice(arena, start, stop_offset - start_offset)
} else {
assert(false, "scratch finish mark");
EMPTY_SCRATCH_SLICE
}function scratch_length_add(left, right) =
if right <= sizeof(scratch_region_bound) - left then {
left + right
} else {
assert(false, "scratch length overflow");
0
}Appends a prefix of a fixed 32-byte value at the cursor.
function scratch_push_b256(data : b256, len : range(0, 32)) -> unit = {
if len != 0 then {
let arena = scratch_arena;
scratch_arena = host_scratch_store_b256(arena.len, data, len)
}
}function scratch_reserve(len) = {
let arena = scratch_arena;
let reserved = host_scratch_reserve(arena.len, len);
assert(reserved, "scratch reserve");
arena.len
}Writes the request root and validation metadata prefix.
function write_prefix(root : hash, success : bool) -> unit = {
scratch_push_b256(root, WORD_BYTE_LENGTH);
let success_byte : byte =
if success then 0x01 else 0x00;
scratch_push_byte(success_byte);
scratch_push_byte(0x25);
scratch_push_byte(0x00);
scratch_push_byte(0x00);
scratch_push_byte(0x00)
}let RESULT_METADATA_LENGTH : int(5) = 5let WORD_BYTE_LENGTH : int(32) = 32let ZERO_HASH : hash = hash_from_bits(0x0000000000000000000000000000000000000000000000000000000000000000)A length in the guest output region.
type output_length = range(0, output_region_bound)