330 const FailingContexts failures = preprocess_for_discard(ex_events);
334 uint32_t dying_context_id = 0;
337 auto is_discarding = [&dying_context_id]() {
return dying_context_id != 0; };
338 bool is_first_event_in_enqueued_call =
true;
339 bool prev_row_was_enter_call =
false;
341 for (
const auto& ex_event : ex_events) {
344 if (!is_discarding() && is_first_event_in_enqueued_call &&
345 is_phase_discarded(ex_event.after_context_event.phase, failures)) {
346 dying_context_id = dying_context_for_phase(ex_event.after_context_event.phase, failures);
349 const bool has_parent = ex_event.after_context_event.parent_id != 0;
358 { C::execution_sel, 1 },
359 { C::execution_clk, row },
362 { C::execution_enqueued_call_start, is_first_event_in_enqueued_call ? 1 : 0 },
364 { C::execution_context_id, ex_event.after_context_event.id },
365 { C::execution_parent_id, ex_event.after_context_event.parent_id },
367 { C::execution_pc, ex_event.before_context_event.pc },
368 { C::execution_msg_sender, ex_event.after_context_event.msg_sender },
369 { C::execution_contract_address, ex_event.after_context_event.contract_addr },
370 { C::execution_transaction_fee, ex_event.after_context_event.transaction_fee },
371 { C::execution_is_static, ex_event.after_context_event.is_static },
372 { C::execution_parent_calldata_addr, ex_event.after_context_event.parent_cd_addr },
373 { C::execution_parent_calldata_size, ex_event.after_context_event.parent_cd_size },
374 { C::execution_last_child_returndata_addr, ex_event.after_context_event.last_child_rd_addr },
375 { C::execution_last_child_returndata_size, ex_event.after_context_event.last_child_rd_size },
376 { C::execution_last_child_success, ex_event.after_context_event.last_child_success },
377 { C::execution_last_child_id, ex_event.after_context_event.last_child_id },
378 { C::execution_l2_gas_limit, ex_event.after_context_event.gas_limit.l2_gas },
379 { C::execution_da_gas_limit, ex_event.after_context_event.gas_limit.da_gas },
380 { C::execution_l2_gas_used, ex_event.after_context_event.gas_used.l2_gas },
381 { C::execution_da_gas_used, ex_event.after_context_event.gas_used.da_gas },
382 { C::execution_parent_l2_gas_limit, ex_event.after_context_event.parent_gas_limit.l2_gas },
383 { C::execution_parent_da_gas_limit, ex_event.after_context_event.parent_gas_limit.da_gas },
384 { C::execution_parent_l2_gas_used, ex_event.after_context_event.parent_gas_used.l2_gas },
385 { C::execution_parent_da_gas_used, ex_event.after_context_event.parent_gas_used.da_gas },
386 { C::execution_next_context_id, ex_event.next_context_id },
388 { C::execution_prev_l2_gas_used, ex_event.before_context_event.gas_used.l2_gas },
389 { C::execution_prev_da_gas_used, ex_event.before_context_event.gas_used.da_gas },
392 { C::execution_prev_written_public_data_slots_tree_root,
393 ex_event.before_context_event.written_public_data_slots_tree_snapshot.root },
394 { C::execution_prev_written_public_data_slots_tree_size,
395 ex_event.before_context_event.written_public_data_slots_tree_snapshot.next_available_leaf_index },
396 { C::execution_written_public_data_slots_tree_root,
397 ex_event.after_context_event.written_public_data_slots_tree_snapshot.root },
398 { C::execution_written_public_data_slots_tree_size,
399 ex_event.after_context_event.written_public_data_slots_tree_snapshot.next_available_leaf_index },
401 { C::execution_prev_nullifier_tree_root,
402 ex_event.before_context_event.tree_states.nullifier_tree.tree.root },
403 { C::execution_prev_nullifier_tree_size,
404 ex_event.before_context_event.tree_states.nullifier_tree.tree.next_available_leaf_index },
405 { C::execution_prev_num_nullifiers_emitted,
406 ex_event.before_context_event.tree_states.nullifier_tree.counter },
407 { C::execution_nullifier_tree_root, ex_event.after_context_event.tree_states.nullifier_tree.tree.root },
408 { C::execution_nullifier_tree_size,
409 ex_event.after_context_event.tree_states.nullifier_tree.tree.next_available_leaf_index },
410 { C::execution_num_nullifiers_emitted,
411 ex_event.after_context_event.tree_states.nullifier_tree.counter },
413 { C::execution_prev_public_data_tree_root,
414 ex_event.before_context_event.tree_states.public_data_tree.tree.root },
415 { C::execution_prev_public_data_tree_size,
416 ex_event.before_context_event.tree_states.public_data_tree.tree.next_available_leaf_index },
417 { C::execution_public_data_tree_root,
418 ex_event.after_context_event.tree_states.public_data_tree.tree.root },
419 { C::execution_public_data_tree_size,
420 ex_event.after_context_event.tree_states.public_data_tree.tree.next_available_leaf_index },
422 { C::execution_prev_note_hash_tree_root,
423 ex_event.before_context_event.tree_states.note_hash_tree.tree.root },
424 { C::execution_prev_note_hash_tree_size,
425 ex_event.before_context_event.tree_states.note_hash_tree.tree.next_available_leaf_index },
426 { C::execution_prev_num_note_hashes_emitted,
427 ex_event.before_context_event.tree_states.note_hash_tree.counter },
428 { C::execution_note_hash_tree_root, ex_event.after_context_event.tree_states.note_hash_tree.tree.root },
429 { C::execution_note_hash_tree_size,
430 ex_event.after_context_event.tree_states.note_hash_tree.tree.next_available_leaf_index },
431 { C::execution_num_note_hashes_emitted,
432 ex_event.after_context_event.tree_states.note_hash_tree.counter },
434 { C::execution_l1_l2_tree_root,
435 ex_event.after_context_event.tree_states.l1_to_l2_message_tree.tree.root },
437 { C::execution_prev_retrieved_bytecodes_tree_root,
438 ex_event.before_context_event.retrieved_bytecodes_tree_snapshot.root },
439 { C::execution_prev_retrieved_bytecodes_tree_size,
440 ex_event.before_context_event.retrieved_bytecodes_tree_snapshot.next_available_leaf_index },
441 { C::execution_retrieved_bytecodes_tree_root,
442 ex_event.after_context_event.retrieved_bytecodes_tree_snapshot.root },
443 { C::execution_retrieved_bytecodes_tree_size,
444 ex_event.after_context_event.retrieved_bytecodes_tree_snapshot.next_available_leaf_index },
446 { C::execution_prev_num_public_log_fields, ex_event.before_context_event.numPublicLogFields },
447 { C::execution_num_public_log_fields, ex_event.after_context_event.numPublicLogFields },
448 { C::execution_prev_num_l2_to_l1_messages, ex_event.before_context_event.numL2ToL1Messages },
449 { C::execution_num_l2_to_l1_messages, ex_event.after_context_event.numL2ToL1Messages },
451 { C::execution_has_parent_ctx, has_parent ? 1 : 0 },
452 { C::execution_is_parent_id_inv, ex_event.after_context_event.parent_id },
459 const auto& internal_call_return_id = ex_event.before_context_event.internal_call_return_id;
462 { C::execution_internal_call_id, ex_event.before_context_event.internal_call_id },
463 { C::execution_internal_call_return_id, internal_call_return_id },
464 { C::execution_next_internal_call_id, ex_event.before_context_event.next_internal_call_id },
471 const bool bytecode_retrieval_failed = ex_event.error == ExecutionError::BYTECODE_RETRIEVAL;
472 const bool sel_first_row_in_context = prev_row_was_enter_call || is_first_event_in_enqueued_call;
475 { C::execution_sel_first_row_in_context, sel_first_row_in_context ? 1 : 0 },
476 { C::execution_sel_bytecode_retrieval_failure, bytecode_retrieval_failed ? 1 : 0 },
477 { C::execution_sel_bytecode_retrieval_success, !bytecode_retrieval_failed ? 1 : 0 },
478 { C::execution_bytecode_id, ex_event.after_context_event.bytecode_id },
488 const bool error_in_instruction_fetching = ex_event.error == ExecutionError::INSTRUCTION_FETCHING;
490 const bool instruction_fetching_success = !bytecode_retrieval_failed && !error_in_instruction_fetching;
493 trace.set(C::execution_sel_instruction_fetching_failure, row, error_in_instruction_fetching ? 1 : 0);
495 if (instruction_fetching_success) {
496 exec_opcode = ex_event.wire_instruction.get_exec_opcode();
507 { C::execution_next_pc,
508 static_cast<uint32_t
>(ex_event.before_context_event.pc +
509 ex_event.wire_instruction.size_in_bytes()) },
518 const bool addressing_failed = ex_event.error == ExecutionError::ADDRESSING;
527 const bool do_process_registers = instruction_fetching_success && !addressing_failed;
528 const bool register_processing_failed = ex_event.error == ExecutionError::REGISTER_READ;
529 if (do_process_registers) {
531 *exec_opcode, ex_event.inputs, ex_event.output,
registers, register_processing_failed,
trace, row);
538 const bool check_gas = do_process_registers && !register_processing_failed;
546 uint32_t radix = ex_event.inputs[1].as<uint32_t>();
547 uint32_t num_limbs = ex_event.inputs[2].as<uint32_t>();
552 { C::execution_two_five_six, 256 },
553 { C::execution_sel_radix_gt_256, radix > 256 ? 1 : 0 },
554 { C::execution_sel_lookup_num_p_limbs, radix <= 256 ? 1 : 0 },
555 { C::execution_num_p_limbs, num_p_limbs },
556 { C::execution_sel_use_num_limbs, num_limbs > num_p_limbs ? 1 : 0 },
563 { C::execution_written_slots_tree_height, AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_HEIGHT },
564 { C::execution_written_slots_merkle_separator, DOM_SEP__WRITTEN_SLOTS_MERKLE },
565 { C::execution_written_slots_tree_siloing_separator, DOM_SEP__PUBLIC_LEAF_SLOT },
570 const bool oog = ex_event.error == ExecutionError::GAS;
575 const bool execute_opcode = check_gas && !oog;
579 bool sel_enter_call =
false;
580 bool sel_exit_call =
false;
581 bool execute_revert =
false;
583 const bool opcode_execution_failed = ex_event.error == ExecutionError::OPCODE_EXECUTION;
584 if (execute_opcode) {
589 { C::execution_sel_execute_opcode, 1 },
590 { C::execution_sel_opcode_error, opcode_execution_failed ? 1 : 0 },
596 trace.set(get_execution_opcode_selector(*exec_opcode), row, 1);
602 sel_enter_call =
true;
604 const Gas gas_left = ex_event.after_context_event.gas_limit - ex_event.after_context_event.gas_used;
606 uint32_t allocated_l2_gas =
registers[0].as<uint32_t>();
607 bool is_l2_gas_left_gt_allocated = gas_left.
l2_gas > allocated_l2_gas;
609 uint32_t allocated_da_gas =
registers[1].as<uint32_t>();
610 bool is_da_gas_left_gt_allocated = gas_left.
da_gas > allocated_da_gas;
614 { C::execution_sel_enter_call, 1 },
615 { C::execution_l2_gas_left, gas_left.
l2_gas },
616 { C::execution_da_gas_left, gas_left.
da_gas },
617 { C::execution_is_l2_gas_left_gt_allocated, is_l2_gas_left_gt_allocated ? 1 : 0 },
618 { C::execution_is_da_gas_left_gt_allocated, is_da_gas_left_gt_allocated ? 1 : 0 },
621 sel_exit_call =
true;
624 { C::execution_nested_return, has_parent ? 1 : 0 },
627 sel_exit_call =
true;
628 execute_revert =
true;
630 BB_ASSERT_EQ(ex_event.addressing_event.resolution_info.size(),
631 static_cast<size_t>(2),
632 "GETENVVAR should have exactly two resolved operands (envvar enum and output)");
634 Operand envvar_enum = ex_event.addressing_event.resolution_info[1].resolved_operand;
637 if (!opcode_execution_failed) {
639 trace.set(C::execution_internal_call_return_id_inv,
641 internal_call_return_id);
642 trace.set(C::execution_sel_read_unwind_call_stack, row, 1);
647 uint32_t remaining_data_writes = MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX -
648 ex_event.before_context_event.tree_states.public_data_tree.counter;
652 { C::execution_max_data_writes_reached, (remaining_data_writes == 0) ? 1 : 0 },
653 { C::execution_remaining_data_writes_inv,
654 remaining_data_writes },
655 { C::execution_sel_write_public_data, opcode_execution_failed ? 0 : 1 },
660 uint64_t leaf_index =
registers[1].as<uint64_t>();
661 uint64_t note_hash_tree_leaf_count = NOTE_HASH_TREE_LEAF_COUNT;
662 bool note_hash_leaf_in_range = leaf_index < note_hash_tree_leaf_count;
666 { C::execution_note_hash_leaf_in_range, note_hash_leaf_in_range ? 1 : 0 },
667 { C::execution_note_hash_tree_leaf_count,
FF(note_hash_tree_leaf_count) },
670 uint32_t remaining_note_hashes =
671 MAX_NOTE_HASHES_PER_TX - ex_event.before_context_event.tree_states.note_hash_tree.counter;
675 { C::execution_sel_reached_max_note_hashes, (remaining_note_hashes == 0) ? 1 : 0 },
676 { C::execution_remaining_note_hashes_inv,
677 remaining_note_hashes },
678 { C::execution_sel_write_note_hash, opcode_execution_failed ? 0 : 1 },
681 uint64_t leaf_index =
registers[1].as<uint64_t>();
682 uint64_t l1_to_l2_msg_tree_leaf_count = L1_TO_L2_MSG_TREE_LEAF_COUNT;
683 bool l1_to_l2_msg_leaf_in_range = leaf_index < l1_to_l2_msg_tree_leaf_count;
687 { C::execution_l1_to_l2_msg_leaf_in_range, l1_to_l2_msg_leaf_in_range ? 1 : 0 },
688 { C::execution_l1_to_l2_msg_tree_leaf_count,
FF(l1_to_l2_msg_tree_leaf_count) },
693 { C::execution_nullifier_tree_height, NULLIFIER_TREE_HEIGHT },
694 { C::execution_nullifier_merkle_separator, DOM_SEP__NULLIFIER_MERKLE },
697 uint32_t remaining_nullifiers =
698 MAX_NULLIFIERS_PER_TX - ex_event.before_context_event.tree_states.nullifier_tree.counter;
701 { { { C::execution_sel_reached_max_nullifiers, (remaining_nullifiers == 0) ? 1 : 0 },
702 { C::execution_remaining_nullifiers_inv,
703 remaining_nullifiers },
704 { C::execution_sel_write_nullifier,
705 (remaining_nullifiers != 0 && !ex_event.before_context_event.is_static) ? 1 : 0 },
706 { C::execution_nullifier_pi_offset,
707 AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX +
708 ex_event.before_context_event.tree_states.nullifier_tree.counter },
709 { C::execution_nullifier_tree_height, NULLIFIER_TREE_HEIGHT },
710 { C::execution_nullifier_merkle_separator, DOM_SEP__NULLIFIER_MERKLE },
711 { C::execution_nullifier_siloing_separator, DOM_SEP__SILOED_NULLIFIER } } });
713 uint32_t remaining_l2_to_l1_msgs =
714 MAX_L2_TO_L1_MSGS_PER_TX - ex_event.before_context_event.numL2ToL1Messages;
717 bool sel_too_large_recipient_error =
722 { { { C::execution_sel_l2_to_l1_msg_limit_error, (remaining_l2_to_l1_msgs == 0) ? 1 : 0 },
723 { C::execution_remaining_l2_to_l1_msgs_inv,
724 remaining_l2_to_l1_msgs },
725 { C::execution_max_eth_address_value,
FF(MAX_ETH_ADDRESS_VALUE) },
726 { C::execution_sel_too_large_recipient_error, sel_too_large_recipient_error ? 1 : 0 },
727 { C::execution_sel_write_l2_to_l1_msg, (!opcode_execution_failed && !is_discarding()) ? 1 : 0 },
729 C::execution_public_inputs_index,
730 AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX +
731 ex_event.before_context_event.numL2ToL1Messages,
740 const bool do_process_register_write = execute_opcode && !opcode_execution_failed;
741 if (do_process_register_write) {
749 const bool is_dying_context = ex_event.after_context_event.id == dying_context_id;
752 const FF dying_context_diff =
FF(ex_event.after_context_event.id) -
FF(dying_context_id);
756 const bool is_err = ex_event.error != ExecutionError::NONE;
757 sel_exit_call = sel_exit_call || is_err;
758 const bool is_failure = execute_revert || is_err;
759 const bool enqueued_call_end = sel_exit_call && !has_parent;
760 const bool nested_failure = is_failure && has_parent;
764 { C::execution_sel_exit_call, sel_exit_call ? 1 : 0 },
765 { C::execution_nested_failure, nested_failure ? 1 : 0 },
766 { C::execution_sel_error, is_err ? 1 : 0 },
767 { C::execution_sel_failure, is_failure ? 1 : 0 },
768 { C::execution_discard, is_discarding() ? 1 : 0 },
769 { C::execution_dying_context_id, dying_context_id },
770 { C::execution_dying_context_id_inv, dying_context_id },
771 { C::execution_is_dying_context, is_dying_context ? 1 : 0 },
772 { C::execution_dying_context_diff_inv, dying_context_diff },
773 { C::execution_enqueued_call_end, enqueued_call_end ? 1 : 0 },
779 const bool event_kills_dying_context = is_failure && is_dying_context;
781 if (event_kills_dying_context) {
783 dying_context_id = 0;
784 }
else if (sel_enter_call && !is_discarding() &&
785 failures.does_context_fail.contains(ex_event.next_context_id)) {
792 dying_context_id = ex_event.next_context_id;
800 is_first_event_in_enqueued_call = !has_parent && sel_exit_call;
803 prev_row_was_enter_call = sel_enter_call;
953 resolution_info_vec.size(),
static_cast<size_t>(AVM_MAX_OPERANDS),
"Resolution info size is out of range");
955 resolution_info_vec.resize(AVM_MAX_OPERANDS,
972 uint8_t num_relative_operands = 0;
975 bool base_address_invalid = resolution_info_vec[0].error.has_value() &&
976 *resolution_info_vec[0].error == AddressingEventError::BASE_ADDRESS_INVALID;
977 bool do_base_check =
false;
981 for (
size_t i = 0; i < AVM_MAX_OPERANDS; i++) {
982 const auto& resolution_info = resolution_info_vec[i];
984 relative_oob[i] = resolution_info.error.has_value() &&
985 *resolution_info.error == AddressingEventError::RELATIVE_COMPUTATION_OOB;
988 is_relative_effective[i] = op_is_address && is_relative[i];
989 is_indirect_effective[i] = op_is_address && is_indirect[i];
990 apply_indirection[i] = is_indirect_effective[i] && !relative_oob[i] && !base_address_invalid;
991 resolved_operand_tag[i] =
static_cast<uint8_t
>(resolution_info.resolved_operand.get_tag());
992 after_relative[i] = resolution_info.after_relative;
993 resolved_operand[i] = resolution_info.resolved_operand;
994 if (is_relative_effective[i]) {
995 do_base_check =
true;
996 num_relative_operands++;
1000 BB_ASSERT(do_base_check || !base_address_invalid,
"Base address is invalid but we are not checking it.");
1003 for (
size_t i = 0; i < AVM_MAX_OPERANDS; i++) {
1006 { OPERAND_IS_RELATIVE_WIRE_COLUMNS[i], is_relative[i] ? 1 : 0 },
1007 { OPERAND_IS_INDIRECT_WIRE_COLUMNS[i], is_indirect[i] ? 1 : 0 },
1008 { OPERAND_RELATIVE_OVERFLOW_COLUMNS[i], relative_oob[i] ? 1 : 0 },
1009 { OPERAND_AFTER_RELATIVE_COLUMNS[i], after_relative[i] },
1010 { OPERAND_APPLY_INDIRECTION_COLUMNS[i], apply_indirection[i] ? 1 : 0 },
1011 { OPERAND_IS_RELATIVE_VALID_BASE_COLUMNS[i],
1012 (is_relative_effective[i] && !base_address_invalid) ? 1 : 0 },
1013 { RESOLVED_OPERAND_COLUMNS[i], resolved_operand[i] },
1014 { RESOLVED_OPERAND_TAG_COLUMNS[i], resolved_operand_tag[i] },
1020 for (
size_t i = AVM_MAX_OPERANDS; i < TOTAL_INDIRECT_BITS / 2; i++) {
1025 { OPERAND_IS_RELATIVE_WIRE_COLUMNS[i], is_relative ? 1 : 0 },
1026 { OPERAND_IS_INDIRECT_WIRE_COLUMNS[i], is_indirect ? 1 : 0 },
1031 FF base_address_tag_diff = base_address_invalid ?
FF(
static_cast<uint8_t
>(addr_event.
base_address.
get_tag())) -
1036 bool some_final_check_failed = std::ranges::any_of(addr_event.
resolution_info, [](
const auto&
info) {
1037 return info.error.has_value() && *info.error == AddressingEventError::INVALID_ADDRESS_AFTER_INDIRECTION;
1039 FF batched_tags_diff = 0;
1040 if (some_final_check_failed) {
1042 for (
size_t i = 0; i < AVM_MAX_OPERANDS; ++i) {
1043 if (apply_indirection[i]) {
1044 batched_tags_diff += power_of_2 * (
FF(resolved_operand_tag[i]) -
FF(MEM_TAG_U32));
1051 bool addressing_failed =
1052 std::ranges::any_of(addr_event.
resolution_info, [](
const auto&
info) { return info.error.has_value(); });
1053 FF addressing_error_collection =
1057 (base_address_invalid ? 1 : 0) +
1061 static_cast<uint32_t
>(0),
1062 [](uint32_t acc,
const auto&
info) {
1064 (
info.error.has_value() &&
1065 *
info.error == AddressingEventError::RELATIVE_COMPUTATION_OOB
1070 (some_final_check_failed ? 1 : 0))
1076 { C::execution_sel_addressing_error, addressing_failed ? 1 : 0 },
1077 { C::execution_addressing_error_collection_inv, addressing_error_collection },
1079 { C::execution_base_address_tag,
static_cast<uint8_t
>(addr_event.
base_address.
get_tag()) },
1080 { C::execution_base_address_tag_diff_inv, base_address_tag_diff },
1081 { C::execution_batched_tags_diff_inv, batched_tags_diff },
1082 { C::execution_sel_some_final_check_failed, some_final_check_failed ? 1 : 0 },
1083 { C::execution_sel_base_address_failure, base_address_invalid ? 1 : 0 },
1084 { C::execution_num_relative_operands_inv, num_relative_operands },
1085 { C::execution_sel_do_base_check, do_base_check ? 1 : 0 },
1086 { C::execution_highest_address, AVM_HIGHEST_MEM_ADDRESS },