Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
tx_trace.cpp
Go to the documentation of this file.
2
3#include <array>
4#include <cstdint>
5#include <optional>
6#include <utility>
7#include <variant>
8#include <vector>
9
21
22namespace bb::avm2::tracegen {
23
24namespace {
25
26using C = Column;
27
28using simulation::CollectGasFeeEvent;
29using simulation::EnqueuedCallEvent;
30using simulation::PhaseLengths;
31using simulation::PrivateAppendTreeEvent;
32using simulation::PrivateEmitL2L1MessageEvent;
33using simulation::TxContextEvent;
34
35// Helper type for the visitor (See https://en.cppreference.com/w/cpp/utility/variant/visit)
36template <class... Ts> struct overloaded : Ts... {
37 using Ts::operator()...;
38};
39// Explicit deduction guide (not needed as of C++20)
40template <class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
41
42// Helper to get the phase length from PhaseLengths struct
43uint32_t get_phase_length(const PhaseLengths& phase_lengths, TransactionPhase phase)
44{
45 switch (phase) {
47 return phase_lengths.nr_nullifier_insertion;
49 return phase_lengths.nr_note_insertion;
51 return phase_lengths.nr_l2_to_l1_message;
53 return phase_lengths.setup;
55 return phase_lengths.r_nullifier_insertion;
57 return phase_lengths.r_note_insertion;
59 return phase_lengths.r_l2_to_l1_message;
61 return phase_lengths.app_logic;
63 return phase_lengths.teardown;
64 default:
65 return 1; // One-shot phases (COLLECT_GAS_FEES, TREE_PADDING, CLEANUP).
66 }
67}
68
69constexpr size_t NUM_PHASES = static_cast<size_t>(TransactionPhase::LAST) + 1;
70
77bool is_revertible(TransactionPhase phase)
78{
79 return get_tx_phase_spec_map().at(phase).is_revertible;
80}
81
88bool is_note_hash_insert_phase(TransactionPhase phase)
89{
90 return get_tx_phase_spec_map().at(phase).non_revertible_append_note_hash ||
91 get_tx_phase_spec_map().at(phase).revertible_append_note_hash;
92}
93
100bool is_nullifier_insert_phase(TransactionPhase phase)
101{
102 return get_tx_phase_spec_map().at(phase).non_revertible_append_nullifier ||
103 get_tx_phase_spec_map().at(phase).revertible_append_nullifier;
104}
105
113bool is_one_shot_phase(TransactionPhase phase)
114{
115 return get_tx_phase_spec_map().at(phase).is_collect_fee || get_tx_phase_spec_map().at(phase).is_tree_padding ||
116 get_tx_phase_spec_map().at(phase).is_cleanup;
117}
118
125bool is_teardown(TransactionPhase phase)
126{
127 return get_tx_phase_spec_map().at(phase).is_teardown;
128}
129
137std::vector<std::pair<C, FF>> insert_tree_state(const TxContextEvent& prev_state, const TxContextEvent& next_state)
138{
139 return {
140 // Previous Tree State
141 // Note Hash
142 { C::tx_prev_note_hash_tree_root, prev_state.tree_states.note_hash_tree.tree.root },
143 { C::tx_prev_note_hash_tree_size, prev_state.tree_states.note_hash_tree.tree.next_available_leaf_index },
144 { C::tx_prev_num_note_hashes_emitted, prev_state.tree_states.note_hash_tree.counter },
145 // Nullifier Tree Roots
146 { C::tx_prev_nullifier_tree_root, prev_state.tree_states.nullifier_tree.tree.root },
147 { C::tx_prev_nullifier_tree_size, prev_state.tree_states.nullifier_tree.tree.next_available_leaf_index },
148 { C::tx_prev_num_nullifiers_emitted, prev_state.tree_states.nullifier_tree.counter },
149 // Public Data Tree Roots
150 { C::tx_prev_public_data_tree_root, prev_state.tree_states.public_data_tree.tree.root },
151 { C::tx_prev_public_data_tree_size, prev_state.tree_states.public_data_tree.tree.next_available_leaf_index },
152 // Written Public Data Slots Tree Roots
153 { C::tx_prev_written_public_data_slots_tree_root, prev_state.written_public_data_slots_tree_snapshot.root },
154 { C::tx_prev_written_public_data_slots_tree_size,
155 prev_state.written_public_data_slots_tree_snapshot.next_available_leaf_index },
156 // L1 to L2 Message Tree Roots
157 { C::tx_l1_l2_tree_root, prev_state.tree_states.l1_to_l2_message_tree.tree.root },
158 { C::tx_l1_l2_tree_size, prev_state.tree_states.l1_to_l2_message_tree.tree.next_available_leaf_index },
159 // Retrieved bytecodes Tree Roots
160 { C::tx_prev_retrieved_bytecodes_tree_root, prev_state.retrieved_bytecodes_tree_snapshot.root },
161 { C::tx_prev_retrieved_bytecodes_tree_size,
162 prev_state.retrieved_bytecodes_tree_snapshot.next_available_leaf_index },
163
164 // Next Tree State
165 { C::tx_next_note_hash_tree_root, next_state.tree_states.note_hash_tree.tree.root },
166 { C::tx_next_note_hash_tree_size, next_state.tree_states.note_hash_tree.tree.next_available_leaf_index },
167 { C::tx_next_num_note_hashes_emitted, next_state.tree_states.note_hash_tree.counter },
168 // Nullifier Tree Roots
169 { C::tx_next_nullifier_tree_root, next_state.tree_states.nullifier_tree.tree.root },
170 { C::tx_next_nullifier_tree_size, next_state.tree_states.nullifier_tree.tree.next_available_leaf_index },
171 { C::tx_next_num_nullifiers_emitted, next_state.tree_states.nullifier_tree.counter },
172 // Public Data Tree Roots
173 { C::tx_next_public_data_tree_root, next_state.tree_states.public_data_tree.tree.root },
174 { C::tx_next_public_data_tree_size, next_state.tree_states.public_data_tree.tree.next_available_leaf_index },
175 // Written Public Data Slots Tree Roots
176 { C::tx_next_written_public_data_slots_tree_root, next_state.written_public_data_slots_tree_snapshot.root },
177 { C::tx_next_written_public_data_slots_tree_size,
178 next_state.written_public_data_slots_tree_snapshot.next_available_leaf_index },
179 // Retrieved bytecodes Tree Roots
180 { C::tx_next_retrieved_bytecodes_tree_root, next_state.retrieved_bytecodes_tree_snapshot.root },
181 { C::tx_next_retrieved_bytecodes_tree_size,
182 next_state.retrieved_bytecodes_tree_snapshot.next_available_leaf_index },
183
184 // Execution context
185 { C::tx_next_context_id, prev_state.next_context_id },
186 };
187}
188
197std::vector<std::pair<C, FF>> insert_side_effect_states(const TxContextEvent& prev_state,
198 const TxContextEvent& next_state)
199{
200 return {
201 { C::tx_prev_num_public_log_fields, prev_state.numPublicLogFields },
202 { C::tx_prev_num_l2_to_l1_messages, prev_state.numL2ToL1Messages },
203 { C::tx_next_num_public_log_fields, next_state.numPublicLogFields },
204 { C::tx_next_num_l2_to_l1_messages, next_state.numL2ToL1Messages },
205 };
206}
207
217std::vector<std::pair<C, FF>> handle_pi_read(TransactionPhase phase, uint32_t phase_length, uint32_t read_counter)
218{
219 const auto& phase_spec = get_tx_phase_spec_map().at(phase);
220
221 const auto remaining_length = phase_length - read_counter;
222
223 return {
224 { C::tx_read_pi_offset, phase_spec.read_pi_start_offset + read_counter },
225 { C::tx_remaining_phase_counter, remaining_length },
226 { C::tx_remaining_phase_inv, remaining_length }, // Will be inverted in batch later
227 { C::tx_remaining_phase_minus_one_inv, remaining_length - 1 }, // Will be inverted in batch later
228 };
229}
230
239std::vector<std::pair<C, FF>> handle_phase_spec(TransactionPhase phase)
240{
241 const auto& phase_spec = get_tx_phase_spec_map().at(phase);
242 return {
243 { C::tx_phase_value, static_cast<uint8_t>(phase) },
244 { C::tx_is_public_call_request, phase_spec.is_public_call_request ? 1 : 0 },
245 { C::tx_is_teardown, phase_spec.is_teardown ? 1 : 0 },
246 { C::tx_is_collect_fee, phase_spec.is_collect_fee ? 1 : 0 },
247 { C::tx_is_tree_padding, phase_spec.is_tree_padding ? 1 : 0 },
248 { C::tx_is_cleanup, phase_spec.is_cleanup ? 1 : 0 },
249 { C::tx_is_revertible, phase_spec.is_revertible ? 1 : 0 },
250 { C::tx_read_pi_start_offset, phase_spec.read_pi_start_offset },
251 { C::tx_read_pi_length_offset, phase_spec.read_pi_length_offset },
252 { C::tx_sel_non_revertible_append_note_hash, phase_spec.non_revertible_append_note_hash ? 1 : 0 },
253 { C::tx_sel_non_revertible_append_nullifier, phase_spec.non_revertible_append_nullifier ? 1 : 0 },
254 { C::tx_sel_non_revertible_append_l2_l1_msg, phase_spec.non_revertible_append_l2_l1_msg ? 1 : 0 },
255 { C::tx_sel_revertible_append_note_hash, phase_spec.revertible_append_note_hash ? 1 : 0 },
256 { C::tx_sel_revertible_append_nullifier, phase_spec.revertible_append_nullifier ? 1 : 0 },
257 { C::tx_sel_revertible_append_l2_l1_msg, phase_spec.revertible_append_l2_l1_msg ? 1 : 0 },
258 { C::tx_next_phase_on_revert, phase_spec.next_phase_on_revert },
259
260 // Directly derived from the phase spec but not part of the phase spec struct.
261 { C::tx_is_tree_insert_phase, (is_note_hash_insert_phase(phase) || is_nullifier_insert_phase(phase)) ? 1 : 0 },
262 };
263}
264
271std::vector<std::pair<C, FF>> handle_prev_gas_used(const Gas& prev_gas_used)
272{
273 return {
274 { C::tx_prev_da_gas_used, prev_gas_used.da_gas },
275 { C::tx_prev_l2_gas_used, prev_gas_used.l2_gas },
276 };
277}
278
285std::vector<std::pair<C, FF>> handle_next_gas_used(const Gas& next_gas_used)
286{
287 return {
288 { C::tx_next_da_gas_used, next_gas_used.da_gas },
289 { C::tx_next_l2_gas_used, next_gas_used.l2_gas },
290 };
291}
292
299std::vector<std::pair<C, FF>> handle_gas_limit(TransactionPhase phase, const Gas& gas_limit, bool is_first_active_row)
300{
301 const bool is_phase_teardown = is_teardown(phase);
302
303 uint32_t gas_limit_pi_offset = 0;
304 if (is_phase_teardown) {
306 } else if (is_first_active_row) {
308 }
309
310 return {
311 { C::tx_gas_limit_pi_offset, gas_limit_pi_offset },
312 { C::tx_should_read_gas_limit, (is_phase_teardown || is_first_active_row) ? 1 : 0 },
313 { C::tx_da_gas_limit, gas_limit.da_gas },
314 { C::tx_l2_gas_limit, gas_limit.l2_gas },
315 };
316}
317
325std::vector<std::pair<C, FF>> handle_enqueued_call_event(const EnqueuedCallEvent& event)
326{
327 return { { C::tx_sel_process_call_request, 1 },
328 { C::tx_msg_sender, event.msg_sender },
329 { C::tx_contract_addr, event.contract_address },
330 { C::tx_fee, event.transaction_fee },
331 { C::tx_is_static, event.is_static ? 1 : 0 },
332 { C::tx_calldata_size, event.calldata_size },
333 { C::tx_calldata_hash, event.calldata_hash },
334 { C::tx_prev_da_gas_used_sent_to_enqueued_call, event.start_gas.da_gas },
335 { C::tx_prev_l2_gas_used_sent_to_enqueued_call, event.start_gas.l2_gas },
336 { C::tx_next_da_gas_used_sent_to_enqueued_call, event.end_gas.da_gas },
337 { C::tx_next_l2_gas_used_sent_to_enqueued_call, event.end_gas.l2_gas } };
338}
339
348std::vector<std::pair<C, FF>> handle_note_hash_append(const PrivateAppendTreeEvent& event,
349 const TxContextEvent& state_before)
350{
351 uint32_t remaining_note_hashes = MAX_NOTE_HASHES_PER_TX - state_before.tree_states.note_hash_tree.counter;
352
353 return {
354 { C::tx_leaf_value, event.leaf_value },
355 { C::tx_remaining_side_effects_inv, remaining_note_hashes }, // Will be inverted in batch later
356 { C::tx_sel_try_note_hash_append, 1 },
357 { C::tx_sel_note_hash_append, remaining_note_hashes > 0 ? 1 : 0 },
358 };
359}
360
369std::vector<std::pair<C, FF>> handle_nullifier_append(const PrivateAppendTreeEvent& event,
370 const TxContextEvent& state_before)
371{
372 uint32_t remaining_nullifiers = MAX_NULLIFIERS_PER_TX - state_before.tree_states.nullifier_tree.counter;
373
374 return { { C::tx_leaf_value, event.leaf_value },
375 { C::tx_nullifier_limit_error, remaining_nullifiers > 0 ? 0 : 1 },
376 { C::tx_remaining_side_effects_inv, remaining_nullifiers }, // Will be inverted in batch later
377 { C::tx_sel_try_nullifier_append, 1 },
378 { C::tx_sel_nullifier_append, remaining_nullifiers > 0 ? 1 : 0 },
379 { C::tx_write_nullifier_pi_offset,
381 state_before.tree_states.nullifier_tree.counter },
382 { C::tx_nullifier_tree_height, NULLIFIER_TREE_HEIGHT },
383 { C::tx_nullifier_merkle_separator, DOM_SEP__NULLIFIER_MERKLE } };
384}
385
394std::vector<std::pair<C, FF>> handle_append_tree_event(const PrivateAppendTreeEvent& event,
395 TransactionPhase phase,
396 const TxContextEvent& state_before)
397{
398 if (is_note_hash_insert_phase(phase)) {
399 return handle_note_hash_append(event, state_before);
400 }
401 if (is_nullifier_insert_phase(phase)) {
402 return handle_nullifier_append(event, state_before);
403 }
404
405 BB_ASSERT(false, format("Invalid phase for append tree event: ", static_cast<uint8_t>(phase)));
406 return {};
407}
408
417std::vector<std::pair<C, FF>> handle_l2_l1_msg_event(const PrivateEmitL2L1MessageEvent& event,
418 const TxContextEvent& state_before,
419 bool discard)
420{
421 uint32_t remaining_l2_to_l1_msgs = MAX_L2_TO_L1_MSGS_PER_TX - state_before.numL2ToL1Messages;
422 return {
423 { C::tx_sel_try_l2_l1_msg_append, 1 },
424 { C::tx_remaining_side_effects_inv, remaining_l2_to_l1_msgs }, // Will be inverted in batch later
425 { C::tx_sel_l2_l1_msg_append, (remaining_l2_to_l1_msgs > 0 && !discard) ? 1 : 0 },
426 { C::tx_l2_l1_msg_contract_address, event.scoped_msg.contract_address },
427 { C::tx_l2_l1_msg_recipient, event.scoped_msg.message.recipient },
428 { C::tx_l2_l1_msg_content, event.scoped_msg.message.content },
429 { C::tx_write_pi_offset,
430 AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX + state_before.numL2ToL1Messages },
431 };
432}
433
440std::vector<std::pair<C, FF>> handle_collect_gas_fee_event(const CollectGasFeeEvent& event)
441{
442 return {
443 { C::tx_effective_fee_per_da_gas, FF(event.effective_fee_per_da_gas) },
444 { C::tx_effective_fee_per_l2_gas, FF(event.effective_fee_per_l2_gas) },
445 { C::tx_fee_payer, event.fee_payer },
446 { C::tx_fee_payer_pi_offset, AVM_PUBLIC_INPUTS_FEE_PAYER_ROW_IDX },
447 { C::tx_fee, event.fee },
448 { C::tx_fee_juice_contract_address, FEE_JUICE_ADDRESS },
449 { C::tx_fee_juice_balances_slot_constant, FEE_JUICE_BALANCES_SLOT },
450 { C::tx_dom_sep_public_storage_map_slot, DOM_SEP__PUBLIC_STORAGE_MAP_SLOT },
451 { C::tx_fee_juice_balance_slot, event.fee_juice_balance_slot },
452 { C::tx_const_three, 3 },
453 { C::tx_fee_payer_balance, event.fee_payer_balance },
454 { C::tx_fee_payer_new_balance, event.fee_payer_balance - event.fee },
455 { C::tx_uint32_max, UINT32_MAX },
456 { C::tx_write_pi_offset, AVM_PUBLIC_INPUTS_TRANSACTION_FEE_ROW_IDX },
457 };
458}
459
465std::vector<std::pair<C, FF>> handle_cleanup()
466{
467 return {
468 // End state
469 { C::tx_sel_read_trees_and_gas_used, 1 },
474 { C::tx_gas_used_pi_offset, AVM_PUBLIC_INPUTS_END_GAS_USED_ROW_IDX },
475 { C::tx_reverted_pi_offset, AVM_PUBLIC_INPUTS_REVERTED_ROW_IDX },
476 { C::tx_array_length_note_hashes_pi_offset,
478 { C::tx_array_length_nullifiers_pi_offset,
480 // Public data write counter is handled by the public data check trace due to squashing.
481 { C::tx_array_length_l2_to_l1_messages_pi_offset,
483 { C::tx_fields_length_public_logs_pi_offset, AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_PUBLIC_LOGS_ROW_IDX },
484 };
485}
486
492std::vector<std::pair<C, FF>> handle_first_active_row()
493{
495 { C::tx_start_tx, 1 },
496 { C::tx_sel_read_trees_and_gas_used, 1 },
501 { C::tx_gas_used_pi_offset, AVM_PUBLIC_INPUTS_START_GAS_USED_ROW_IDX },
502 };
503
504 return columns;
505}
506
507} // namespace
508
553 TraceContainer& trace)
554{
560
561 uint32_t row = 1; // Shifts
562
563 // We bucket the events by phase to make it easier to detect phases with no events.
564 std::array<std::vector<const TxPhaseEvent*>, NUM_PHASES> phase_buckets = {};
565 // We have the phases in iterable form so that, in the main loop, when we encounter an empty phase,
566 // we can map back to this enum.
567
568 std::optional<TxStartupEvent> startup_event;
569 PhaseLengths phase_lengths{}; // Will be populated from startup event
570
571 // Some flags used to populate the discard column.
572 bool r_insertion_or_app_logic_failure = false;
573 bool teardown_failure = false;
574
575 // Pre-processing pass:
576 // - Extract the startup event and phase lengths.
577 // - Set the flags defined above.
578 // - Bucket the events by phase.
579 for (const auto& tx_event : events) {
581 startup_event = std::get<TxStartupEvent>(tx_event);
582 phase_lengths = startup_event.value().phase_lengths;
583 } else {
584 const TxPhaseEvent& tx_phase_event = std::get<TxPhaseEvent>(tx_event);
585 phase_buckets[static_cast<uint8_t>(tx_phase_event.phase)].push_back(&tx_phase_event);
586
587 // Set some flags for use when populating the discard column.
588 if (tx_phase_event.reverted) {
589 // Simulation must have been aborted if we reverted in a non-revertible phase.
590 BB_ASSERT(is_revertible(tx_phase_event.phase),
591 format("Reverted in non-revertible phase: ", static_cast<uint8_t>(tx_phase_event.phase)));
592
593 if (is_teardown(tx_phase_event.phase)) {
594 teardown_failure = true;
595 } else {
596 r_insertion_or_app_logic_failure = true;
597 }
598 }
599 }
600 }
601
602 // Our simulation always emits a startup event.
603 BB_ASSERT(startup_event.has_value(), "Transaction startup event is missing");
604
605 const auto& startup_event_data = startup_event.value();
606
607 Gas current_gas_limit = startup_event_data.gas_limit;
608 const Gas& teardown_gas_limit = startup_event_data.teardown_gas_limit;
609 // Track the gas used over the course of the transaction.
610 Gas gas_used = startup_event_data.gas_used;
611 // Track whether this tx reverted.
612 bool tx_reverted = false;
613
614 // From here we start populating the trace.
615
616 trace.set(row, handle_first_active_row());
617
618 // Go through each phase except startup and process the events in the phase.
619 for (uint32_t i = 0; i < NUM_PHASES; i++) {
620 const auto& phase_events = phase_buckets[i];
621 if (phase_events.empty()) {
622 // There will be no events for a phase if it is skipped (jumped over) due to a revert.
623 // This is different from a phase that has an EmptyPhaseEvent, which is a phase that has no contents to
624 // process, like when app logic starts but has no enqueued calls.
625 continue;
626 }
627
628 const TransactionPhase phase = static_cast<TransactionPhase>(i);
629
630 bool discard = false;
631 if (is_revertible(phase)) {
632 if (is_teardown(phase)) {
634 } else {
635 // Even if we don't fail until later in teardown, all revertible phases discard.
636 discard = teardown_failure || r_insertion_or_app_logic_failure;
637 }
638 }
639
640 if (is_teardown(phase)) {
641 current_gas_limit = teardown_gas_limit;
642 }
643
644 // Count the number of steps in this phase.
645 uint32_t phase_counter = 0;
646 // Get the phase length from the startup event's phase_lengths.
647 // This represents how many items were specified for this phase in the transaction itself.
648 // In case of a revert, we may process fewer items in a phase as we'll stop at the revert.
649 const uint32_t phase_length = get_phase_length(phase_lengths, phase);
650
651 // We have events to process in this phase.
652 for (const auto* tx_phase_event : phase_events) {
653 // If this phase is the first revert, set tx_reverted:
654 tx_reverted = tx_reverted || tx_phase_event->reverted;
655
656 // Generic selectors and values common to all phase events.
657 trace.set(row,
658 { {
659 { C::tx_sel, 1 },
660 { C::tx_discard, discard ? 1 : 0 },
661 { C::tx_reverted, tx_phase_event->reverted ? 1 : 0 },
662 { C::tx_tx_reverted, tx_reverted ? 1 : 0 },
663 { C::tx_setup_phase_value, static_cast<uint8_t>(TransactionPhase::SETUP) },
664 { C::tx_start_phase, phase_counter == 0 ? 1 : 0 },
665 { C::tx_sel_read_phase_length, (phase_counter == 0 && !is_one_shot_phase(phase)) ? 1 : 0 },
666 { C::tx_end_phase, phase_counter == phase_events.size() - 1 ? 1 : 0 },
667 } });
668
669 // Populate all phase_spec related columns.
670 trace.set(row, handle_phase_spec(phase));
671
672 // Read PI offset and remaining phase counter related columns.
673 trace.set(row, handle_pi_read(phase, phase_length, phase_counter));
674
675 // We always set the tree state and side effect states.
676 trace.set(row, insert_tree_state(tx_phase_event->state_before, tx_phase_event->state_after));
677 trace.set(row, insert_side_effect_states(tx_phase_event->state_before, tx_phase_event->state_after));
678 trace.set(row, handle_prev_gas_used(gas_used));
679
680 // Pattern match on the variant event type and call the appropriate handler.
681 std::visit(
683 [&](const EnqueuedCallEvent& event) {
684 trace.set(row, handle_enqueued_call_event(event));
685 gas_used = tx_phase_event->state_after.gas_used;
686 },
687 [&](const PrivateAppendTreeEvent& event) {
688 trace.set(row, handle_append_tree_event(event, phase, tx_phase_event->state_before));
689 },
691 trace.set(row, handle_l2_l1_msg_event(event, tx_phase_event->state_before, discard));
692 },
693 [&](const CollectGasFeeEvent& event) { trace.set(row, handle_collect_gas_fee_event(event)); },
694 [&](const PadTreesEvent&) {},
695 [&](const CleanupEvent&) { trace.set(row, handle_cleanup()); },
696 [&](const EmptyPhaseEvent&) {
697 // EmptyPhaseEvent represents a phase that is not explicitly skipped because of a
698 // revert, but just has no contents to process, like when app logic starts but
699 // has no enqueued calls.
700 trace.set(C::tx_is_padded, row, 1);
701 } },
702 tx_phase_event->event);
703
704 trace.set(row, handle_next_gas_used(gas_used));
705 trace.set(row, handle_gas_limit(phase, current_gas_limit, row == 1));
706
707 phase_counter++; // Inner loop counter.
708 row++;
709 }
710 }
711
712 // Batch invert the columns.
713 trace.invert_columns(
714 { { C::tx_remaining_phase_inv, C::tx_remaining_phase_minus_one_inv, C::tx_remaining_side_effects_inv } });
715}
716
717const InteractionDefinition TxTraceBuilder::interactions =
719 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_read_phase_spec_settings>()
720 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_read_phase_length_settings>()
721 .add<InteractionType::Permutation, perm_tx_read_calldata_hash_settings>()
722 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_read_public_call_request_phase_settings>()
723 .add<InteractionType::Permutation, perm_tx_dispatch_exec_start_settings>()
724 .add<InteractionType::Permutation, perm_tx_dispatch_exec_end_settings>()
725 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_read_tree_insert_value_settings>()
726 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_read_l2_l1_msg_settings>()
727 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_write_l2_l1_msg_settings>()
728 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_read_effective_fee_public_inputs_settings>()
729 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_read_fee_payer_public_inputs_settings>()
730 .add<InteractionType::LookupGeneric, lookup_tx_balance_validation_settings>() // ff_gt deduplicates
731 .add<InteractionType::LookupSequential, lookup_tx_note_hash_append_settings>()
732 .add<InteractionType::LookupSequential, lookup_tx_nullifier_append_settings>()
733 // Cannot be sequential (sorting happens in public data tree trace)
734 .add<InteractionType::LookupGeneric, lookup_tx_balance_read_settings>()
735 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_write_fee_public_inputs_settings>()
736 .add<InteractionType::LookupSequential, lookup_tx_balance_slot_poseidon2_settings>()
737 // Lookups from tx_context.pil
738 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_context_public_inputs_note_hash_tree_settings>()
739 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_context_public_inputs_nullifier_tree_settings>()
740 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_context_public_inputs_public_data_tree_settings>()
741 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_context_public_inputs_l1_l2_tree_settings>()
742 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_context_public_inputs_gas_used_settings>()
743 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_context_public_inputs_read_gas_limit_settings>()
744 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_context_public_inputs_read_reverted_settings>()
745 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_context_public_inputs_write_note_hash_count_settings>()
746 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_context_public_inputs_write_nullifier_count_settings>()
747 .add<InteractionType::LookupIntoIndexedByRow,
749 .add<InteractionType::LookupIntoIndexedByRow, lookup_tx_context_public_inputs_write_public_log_count_settings>()
750 .add<InteractionType::LookupGeneric, lookup_tx_context_restore_state_on_revert_settings>();
751
752} // namespace bb::avm2::tracegen
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_NOTE_HASHES_ROW_IDX
#define AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_L1_TO_L2_MESSAGE_TREE_ROW_IDX
#define AVM_PUBLIC_INPUTS_FEE_PAYER_ROW_IDX
#define AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX
#define AVM_PUBLIC_INPUTS_GAS_SETTINGS_TEARDOWN_GAS_LIMITS_ROW_IDX
#define AVM_PUBLIC_INPUTS_TRANSACTION_FEE_ROW_IDX
#define AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX
#define DOM_SEP__PUBLIC_STORAGE_MAP_SLOT
#define AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_L2_TO_L1_MSGS_ROW_IDX
#define AVM_PUBLIC_INPUTS_END_GAS_USED_ROW_IDX
#define AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_NULLIFIERS_ROW_IDX
#define AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_L1_TO_L2_MESSAGE_TREE_ROW_IDX
#define AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_NULLIFIER_TREE_ROW_IDX
#define FEE_JUICE_ADDRESS
#define AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_NOTE_HASH_TREE_ROW_IDX
#define AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_NOTE_HASH_TREE_ROW_IDX
#define NULLIFIER_TREE_HEIGHT
#define MAX_L2_TO_L1_MSGS_PER_TX
#define MAX_NOTE_HASHES_PER_TX
#define AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_PUBLIC_DATA_TREE_ROW_IDX
#define DOM_SEP__NULLIFIER_MERKLE
#define AVM_PUBLIC_INPUTS_REVERTED_ROW_IDX
#define FEE_JUICE_BALANCES_SLOT
#define AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_NULLIFIER_TREE_ROW_IDX
#define MAX_NULLIFIERS_PER_TX
#define AVM_PUBLIC_INPUTS_START_GAS_USED_ROW_IDX
#define AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_PUBLIC_LOGS_ROW_IDX
#define AVM_PUBLIC_INPUTS_GAS_SETTINGS_GAS_LIMITS_ROW_IDX
#define AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_PUBLIC_DATA_TREE_ROW_IDX
InteractionDefinition & add(auto &&... args)
std::string format(Args... args)
Definition log.hpp:23
TestTraceContainer trace
bool teardown_failure
const std::unordered_map< TransactionPhase, TxPhaseSpec > & get_tx_phase_spec_map()
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
simulation::PublicDataTreeReadWriteEvent event
Settings to be passed ot GenericLookupRelationImpl.