293 const FailingContexts failures = preprocess_for_discard(ex_events);
298 uint32_t dying_context_id = 0;
299 bool is_first_event_in_enqueued_call =
true;
300 bool prev_row_was_enter_call =
false;
302 for (
const auto& ex_event : ex_events) {
305 if (
discard == 0 && is_first_event_in_enqueued_call &&
306 is_phase_discarded(ex_event.after_context_event.phase, failures)) {
308 dying_context_id = dying_context_for_phase(ex_event.after_context_event.phase, failures);
311 const bool has_parent = ex_event.after_context_event.parent_id != 0;
320 { C::execution_sel, 1 },
323 { C::execution_enqueued_call_start, is_first_event_in_enqueued_call ? 1 : 0 },
325 { C::execution_context_id, ex_event.after_context_event.id },
326 { C::execution_parent_id, ex_event.after_context_event.parent_id },
327 { C::execution_pc, ex_event.before_context_event.pc },
328 { C::execution_msg_sender, ex_event.after_context_event.msg_sender },
329 { C::execution_contract_address, ex_event.after_context_event.contract_addr },
330 { C::execution_transaction_fee, ex_event.after_context_event.transaction_fee },
331 { C::execution_is_static, ex_event.after_context_event.is_static },
332 { C::execution_parent_calldata_addr, ex_event.after_context_event.parent_cd_addr },
333 { C::execution_parent_calldata_size, ex_event.after_context_event.parent_cd_size },
334 { C::execution_last_child_returndata_addr, ex_event.after_context_event.last_child_rd_addr },
335 { C::execution_last_child_returndata_size, ex_event.after_context_event.last_child_rd_size },
336 { C::execution_last_child_success, ex_event.after_context_event.last_child_success },
337 { C::execution_last_child_id, ex_event.after_context_event.last_child_id },
338 { C::execution_l2_gas_limit, ex_event.after_context_event.gas_limit.l2_gas },
339 { C::execution_da_gas_limit, ex_event.after_context_event.gas_limit.da_gas },
340 { C::execution_l2_gas_used, ex_event.after_context_event.gas_used.l2_gas },
341 { C::execution_da_gas_used, ex_event.after_context_event.gas_used.da_gas },
342 { C::execution_parent_l2_gas_limit, ex_event.after_context_event.parent_gas_limit.l2_gas },
343 { C::execution_parent_da_gas_limit, ex_event.after_context_event.parent_gas_limit.da_gas },
344 { C::execution_parent_l2_gas_used, ex_event.after_context_event.parent_gas_used.l2_gas },
345 { C::execution_parent_da_gas_used, ex_event.after_context_event.parent_gas_used.da_gas },
346 { C::execution_next_context_id, ex_event.next_context_id },
348 { C::execution_prev_l2_gas_used, ex_event.before_context_event.gas_used.l2_gas },
349 { C::execution_prev_da_gas_used, ex_event.before_context_event.gas_used.da_gas },
352 { C::execution_prev_written_public_data_slots_tree_root,
353 ex_event.before_context_event.written_public_data_slots_tree_snapshot.root },
354 { C::execution_prev_written_public_data_slots_tree_size,
355 ex_event.before_context_event.written_public_data_slots_tree_snapshot.next_available_leaf_index },
356 { C::execution_written_public_data_slots_tree_root,
357 ex_event.after_context_event.written_public_data_slots_tree_snapshot.root },
358 { C::execution_written_public_data_slots_tree_size,
359 ex_event.after_context_event.written_public_data_slots_tree_snapshot.next_available_leaf_index },
361 { C::execution_prev_nullifier_tree_root,
362 ex_event.before_context_event.tree_states.nullifier_tree.tree.root },
363 { C::execution_prev_nullifier_tree_size,
364 ex_event.before_context_event.tree_states.nullifier_tree.tree.next_available_leaf_index },
365 { C::execution_prev_num_nullifiers_emitted,
366 ex_event.before_context_event.tree_states.nullifier_tree.counter },
367 { C::execution_nullifier_tree_root, ex_event.after_context_event.tree_states.nullifier_tree.tree.root },
368 { C::execution_nullifier_tree_size,
369 ex_event.after_context_event.tree_states.nullifier_tree.tree.next_available_leaf_index },
370 { C::execution_num_nullifiers_emitted,
371 ex_event.after_context_event.tree_states.nullifier_tree.counter },
373 { C::execution_prev_public_data_tree_root,
374 ex_event.before_context_event.tree_states.public_data_tree.tree.root },
375 { C::execution_prev_public_data_tree_size,
376 ex_event.before_context_event.tree_states.public_data_tree.tree.next_available_leaf_index },
377 { C::execution_public_data_tree_root,
378 ex_event.after_context_event.tree_states.public_data_tree.tree.root },
379 { C::execution_public_data_tree_size,
380 ex_event.after_context_event.tree_states.public_data_tree.tree.next_available_leaf_index },
382 { C::execution_prev_note_hash_tree_root,
383 ex_event.before_context_event.tree_states.note_hash_tree.tree.root },
384 { C::execution_prev_note_hash_tree_size,
385 ex_event.before_context_event.tree_states.note_hash_tree.tree.next_available_leaf_index },
386 { C::execution_prev_num_note_hashes_emitted,
387 ex_event.before_context_event.tree_states.note_hash_tree.counter },
388 { C::execution_note_hash_tree_root, ex_event.after_context_event.tree_states.note_hash_tree.tree.root },
389 { C::execution_note_hash_tree_size,
390 ex_event.after_context_event.tree_states.note_hash_tree.tree.next_available_leaf_index },
391 { C::execution_num_note_hashes_emitted,
392 ex_event.after_context_event.tree_states.note_hash_tree.counter },
394 { C::execution_l1_l2_tree_root,
395 ex_event.after_context_event.tree_states.l1_to_l2_message_tree.tree.root },
397 { C::execution_prev_retrieved_bytecodes_tree_root,
398 ex_event.before_context_event.retrieved_bytecodes_tree_snapshot.root },
399 { C::execution_prev_retrieved_bytecodes_tree_size,
400 ex_event.before_context_event.retrieved_bytecodes_tree_snapshot.next_available_leaf_index },
401 { C::execution_retrieved_bytecodes_tree_root,
402 ex_event.after_context_event.retrieved_bytecodes_tree_snapshot.root },
403 { C::execution_retrieved_bytecodes_tree_size,
404 ex_event.after_context_event.retrieved_bytecodes_tree_snapshot.next_available_leaf_index },
406 { C::execution_prev_num_unencrypted_log_fields, ex_event.before_context_event.numUnencryptedLogFields },
407 { C::execution_num_unencrypted_log_fields, ex_event.after_context_event.numUnencryptedLogFields },
408 { C::execution_prev_num_l2_to_l1_messages, ex_event.before_context_event.numL2ToL1Messages },
409 { C::execution_num_l2_to_l1_messages, ex_event.after_context_event.numL2ToL1Messages },
411 { C::execution_has_parent_ctx, has_parent ? 1 : 0 },
412 { C::execution_is_parent_id_inv, ex_event.after_context_event.parent_id },
418 { C::execution_internal_call_id, ex_event.before_context_event.internal_call_id },
419 { C::execution_internal_call_return_id, ex_event.before_context_event.internal_call_return_id },
420 { C::execution_next_internal_call_id, ex_event.before_context_event.next_internal_call_id },
427 const bool bytecode_retrieval_failed = ex_event.error == ExecutionError::BYTECODE_RETRIEVAL;
428 const bool sel_first_row_in_context = prev_row_was_enter_call || is_first_event_in_enqueued_call;
431 { C::execution_sel_first_row_in_context, sel_first_row_in_context ? 1 : 0 },
432 { C::execution_sel_bytecode_retrieval_failure, bytecode_retrieval_failed ? 1 : 0 },
433 { C::execution_sel_bytecode_retrieval_success, !bytecode_retrieval_failed ? 1 : 0 },
434 { C::execution_bytecode_id, ex_event.after_context_event.bytecode_id },
443 const bool error_in_instruction_fetching = ex_event.error == ExecutionError::INSTRUCTION_FETCHING;
444 const bool instruction_fetching_success = !bytecode_retrieval_failed && !error_in_instruction_fetching;
445 trace.set(C::execution_sel_instruction_fetching_failure, row, error_in_instruction_fetching ? 1 : 0);
447 if (instruction_fetching_success) {
448 exec_opcode = ex_event.wire_instruction.get_exec_opcode();
453 { C::execution_next_pc,
454 ex_event.before_context_event.pc + ex_event.wire_instruction.size_in_bytes() },
463 const bool addressing_failed = ex_event.error == ExecutionError::ADDRESSING;
471 std::ranges::fill(
registers, MemoryValue::from<FF>(0));
472 const bool should_process_registers = instruction_fetching_success && !addressing_failed;
473 const bool register_processing_failed = ex_event.error == ExecutionError::REGISTER_READ;
474 if (should_process_registers) {
482 const bool should_check_gas = should_process_registers && !register_processing_failed;
483 const bool oog = ex_event.error == ExecutionError::GAS;
484 trace.set(C::execution_sel_should_check_gas, row, should_check_gas ? 1 : 0);
485 if (should_check_gas) {
492 uint32_t radix = ex_event.inputs[1].as<uint32_t>();
493 uint32_t num_limbs = ex_event.inputs[2].as<uint32_t>();
498 { C::execution_two_five_six, 256 },
499 { C::execution_sel_radix_gt_256, radix > 256 ? 1 : 0 },
500 { C::execution_sel_lookup_num_p_limbs, radix <= 256 ? 1 : 0 },
501 { C::execution_num_p_limbs, num_p_limbs },
502 { C::execution_sel_use_num_limbs, num_limbs > num_p_limbs ? 1 : 0 },
512 const bool should_execute_opcode = should_check_gas && !oog;
516 bool sel_enter_call =
false;
517 bool sel_exit_call =
false;
518 bool should_execute_revert =
false;
520 const bool opcode_execution_failed = ex_event.error == ExecutionError::OPCODE_EXECUTION;
521 if (should_execute_opcode) {
526 { C::execution_sel_should_execute_opcode, 1 },
527 { C::execution_sel_opcode_error, opcode_execution_failed ? 1 : 0 },
533 trace.set(get_execution_opcode_selector(*exec_opcode), row, 1);
539 sel_enter_call =
true;
541 Gas gas_left = ex_event.after_context_event.gas_limit - ex_event.after_context_event.gas_used;
543 uint32_t allocated_l2_gas =
registers[0].as<uint32_t>();
544 bool is_l2_gas_allocated_lt_left = allocated_l2_gas < gas_left.
l2_gas;
546 uint32_t allocated_da_gas =
registers[1].as<uint32_t>();
547 bool is_da_gas_allocated_lt_left = allocated_da_gas < gas_left.
da_gas;
551 { C::execution_sel_enter_call, 1 },
552 { C::execution_l2_gas_left, gas_left.
l2_gas },
553 { C::execution_da_gas_left, gas_left.
da_gas },
554 { C::execution_call_is_l2_gas_allocated_lt_left, is_l2_gas_allocated_lt_left },
555 { C::execution_call_is_da_gas_allocated_lt_left, is_da_gas_allocated_lt_left },
558 sel_exit_call =
true;
561 { C::execution_nested_return, has_parent ? 1 : 0 },
564 sel_exit_call =
true;
565 should_execute_revert =
true;
567 assert(ex_event.addressing_event.resolution_info.size() == 2 &&
568 "GETENVVAR should have exactly two resolved operands (envvar enum and output)");
570 Operand envvar_enum = ex_event.addressing_event.resolution_info[1].resolved_operand;
573 trace.set(C::execution_internal_call_return_id_inv,
575 ex_event.before_context_event.internal_call_return_id);
578 ex_event.before_context_event.tree_states.public_data_tree.counter;
582 { C::execution_max_data_writes_reached, remaining_data_writes == 0 },
583 { C::execution_remaining_data_writes_inv,
584 remaining_data_writes },
585 { C::execution_sel_write_public_data, !opcode_execution_failed },
588 uint64_t leaf_index =
registers[1].as<uint64_t>();
590 bool note_hash_leaf_in_range = leaf_index < note_hash_tree_leaf_count;
594 { C::execution_note_hash_leaf_in_range, note_hash_leaf_in_range },
595 { C::execution_note_hash_tree_leaf_count,
FF(note_hash_tree_leaf_count) },
598 uint32_t remaining_note_hashes =
603 { C::execution_sel_reached_max_note_hashes, remaining_note_hashes == 0 },
604 { C::execution_remaining_note_hashes_inv,
605 remaining_note_hashes },
606 { C::execution_sel_write_note_hash, !opcode_execution_failed },
609 uint64_t leaf_index =
registers[1].as<uint64_t>();
611 bool l1_to_l2_msg_leaf_in_range = leaf_index < l1_to_l2_msg_tree_leaf_count;
615 { C::execution_l1_to_l2_msg_leaf_in_range, l1_to_l2_msg_leaf_in_range },
616 { C::execution_l1_to_l2_msg_tree_leaf_count,
FF(l1_to_l2_msg_tree_leaf_count) },
621 uint32_t remaining_nullifiers =
626 { C::execution_sel_reached_max_nullifiers, remaining_nullifiers == 0 },
627 { C::execution_remaining_nullifiers_inv,
628 remaining_nullifiers },
629 { C::execution_sel_write_nullifier,
630 remaining_nullifiers != 0 && !ex_event.before_context_event.is_static },
633 uint32_t remaining_l2_to_l1_msgs =
637 { { { C::execution_sel_l2_to_l1_msg_limit_error, remaining_l2_to_l1_msgs == 0 },
638 { C::execution_remaining_l2_to_l1_msgs_inv,
639 remaining_l2_to_l1_msgs },
640 { C::execution_sel_write_l2_to_l1_msg, !opcode_execution_failed &&
discard == 0 },
642 C::execution_public_inputs_index,
644 ex_event.before_context_event.numL2ToL1Messages,
653 const bool should_process_register_write = should_execute_opcode && !opcode_execution_failed;
654 if (should_process_register_write) {
662 const bool is_dying_context =
discard == 1 && (ex_event.after_context_event.id == dying_context_id);
665 FF dying_context_diff = 0;
666 if (!is_dying_context) {
668 dying_context_diff =
FF(ex_event.after_context_event.id) -
FF(dying_context_id);
673 const bool is_err = ex_event.error != ExecutionError::NONE;
674 sel_exit_call = sel_exit_call || is_err;
675 const bool is_failure = should_execute_revert || is_err;
676 const bool nested_exit_call = sel_exit_call && has_parent;
677 const bool enqueued_call_end = sel_exit_call && !has_parent;
678 const bool rollback_context = (should_execute_revert || is_err) && has_parent;
679 const bool resolves_dying_context = is_failure && is_dying_context;
680 const bool nested_call_rom_undiscarded_context = sel_enter_call &&
discard == 0;
685 { C::execution_sel_exit_call, sel_exit_call ? 1 : 0 },
686 { C::execution_nested_exit_call, nested_exit_call ? 1 : 0 },
687 { C::execution_rollback_context, rollback_context ? 1 : 0 },
688 { C::execution_sel_error, is_err ? 1 : 0 },
689 { C::execution_sel_failure, is_failure ? 1 : 0 },
690 { C::execution_discard,
discard },
691 { C::execution_dying_context_id, dying_context_id },
692 { C::execution_dying_context_id_inv, dying_context_id },
693 { C::execution_is_dying_context, is_dying_context ? 1 : 0 },
694 { C::execution_dying_context_diff_inv, dying_context_diff },
695 { C::execution_enqueued_call_end, enqueued_call_end ? 1 : 0 },
696 { C::execution_resolves_dying_context, resolves_dying_context ? 1 : 0 },
697 { C::execution_nested_call_from_undiscarded_context, nested_call_rom_undiscarded_context ? 1 : 0 },
702 const bool event_kills_dying_context =
703 discard == 1 && is_failure && ex_event.after_context_event.id == dying_context_id;
705 if (event_kills_dying_context) {
707 dying_context_id = 0;
709 }
else if (sel_enter_call &&
discard == 0 && !is_err &&
710 failures.does_context_fail.contains(ex_event.next_context_id)) {
715 dying_context_id = ex_event.next_context_id;
724 is_first_event_in_enqueued_call = !has_parent && sel_exit_call;
727 prev_row_was_enter_call = sel_enter_call;
845 .after_relative = Operand::from<FF>(0),
846 .resolved_operand = Operand::from<FF>(0),
856 uint8_t num_relative_operands = 0;
858 bool base_address_invalid =
false;
859 bool do_base_check =
false;
863 const auto& resolution_info = resolution_info_vec.at(i);
865 relative_oob[i] = resolution_info.error.has_value() &&
866 *resolution_info.error == AddressingEventError::RELATIVE_COMPUTATION_OOB;
867 base_address_invalid =
868 base_address_invalid ||
869 (resolution_info.error.has_value() && *resolution_info.error == AddressingEventError::BASE_ADDRESS_INVALID);
872 should_apply_indirection[i] = is_indirect_effective[i] && !relative_oob[i] && !base_address_invalid;
873 resolved_operand_tag[i] =
static_cast<uint8_t
>(resolution_info.resolved_operand.get_tag());
874 after_relative[i] = resolution_info.after_relative;
875 resolved_operand[i] = resolution_info.resolved_operand;
876 if (is_relative_effective[i]) {
877 do_base_check =
true;
878 num_relative_operands++;
886 { OPERAND_RELATIVE_OVERFLOW_COLUMNS[i], relative_oob[i] ? 1 : 0 },
887 { OPERAND_AFTER_RELATIVE_COLUMNS[i], after_relative[i] },
888 { OPERAND_SHOULD_APPLY_INDIRECTION_COLUMNS[i], should_apply_indirection[i] ? 1 : 0 },
889 { OPERAND_IS_RELATIVE_VALID_BASE_COLUMNS[i],
890 is_relative_effective[i] && !base_address_invalid ? 1 : 0 },
891 { RESOLVED_OPERAND_COLUMNS[i], resolved_operand[i] },
892 { RESOLVED_OPERAND_TAG_COLUMNS[i], resolved_operand_tag[i] },
898 for (
size_t i = 0; i < TOTAL_INDIRECT_BITS / 2; i++) {
903 { OPERAND_IS_RELATIVE_WIRE_COLUMNS[i], is_relative ? 1 : 0 },
904 { OPERAND_IS_INDIRECT_WIRE_COLUMNS[i], is_indirect ? 1 : 0 },
909 FF base_address_tag_diff = base_address_invalid ?
FF(
static_cast<uint8_t
>(addr_event.
base_address.
get_tag())) -
914 bool some_final_check_failed = std::ranges::any_of(addr_event.
resolution_info, [](
const auto&
info) {
915 return info.error.has_value() && *info.error == AddressingEventError::INVALID_ADDRESS_AFTER_INDIRECTION;
917 FF batched_tags_diff = 0;
918 if (some_final_check_failed) {
922 FF(is_indirect_effective[i] ? 1 : 0) * power_of_2 * (
FF(resolved_operand_tag[i]) -
FF(
MEM_TAG_U32));
928 bool addressing_failed =
929 std::ranges::any_of(addr_event.
resolution_info, [](
const auto&
info) { return info.error.has_value(); });
930 FF addressing_error_collection =
934 (base_address_invalid ? 1 : 0) +
938 static_cast<uint32_t
>(0),
939 [](uint32_t acc,
const auto&
info) {
941 (
info.error.has_value() &&
942 *
info.error == AddressingEventError::RELATIVE_COMPUTATION_OOB
947 (some_final_check_failed ? 1 : 0))
953 { C::execution_sel_addressing_error, addressing_failed ? 1 : 0 },
954 { C::execution_addressing_error_collection_inv, addressing_error_collection },
956 { C::execution_base_address_tag,
static_cast<uint8_t
>(addr_event.
base_address.
get_tag()) },
957 { C::execution_base_address_tag_diff_inv, base_address_tag_diff },
958 { C::execution_batched_tags_diff_inv, batched_tags_diff },
959 { C::execution_sel_some_final_check_failed, some_final_check_failed ? 1 : 0 },
960 { C::execution_sel_base_address_failure, base_address_invalid ? 1 : 0 },
961 { C::execution_num_relative_operands_inv,
962 do_base_check ? num_relative_operands : 0 },
963 { C::execution_sel_do_base_check, do_base_check ? 1 : 0 },