15#include <unordered_map>
22using simulation::PhaseLengths;
23using simulation::TxContextEvent;
26template <
class... Ts>
struct overloaded : Ts... {
27 using Ts::operator()...;
30template <
class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
33uint32_t get_phase_length(
const PhaseLengths& phase_lengths,
TransactionPhase phase)
37 return phase_lengths.nr_nullifier_insertion;
39 return phase_lengths.nr_note_insertion;
41 return phase_lengths.nr_l2_to_l1_message;
43 return phase_lengths.setup;
45 return phase_lengths.r_nullifier_insertion;
47 return phase_lengths.r_note_insertion;
49 return phase_lengths.r_l2_to_l1_message;
51 return phase_lengths.app_logic;
53 return phase_lengths.teardown;
80 return is_note_hash_insert_phase(phase) || is_nullifier_insert_phase(phase);
111 return is_collect_fee_phase(phase) || is_tree_padding_phase(phase) || is_cleanup_phase(phase);
125 { Column::tx_prev_note_hash_tree_root, prev_state.tree_states.noteHashTree.tree.root },
126 { Column::tx_prev_note_hash_tree_size, prev_state.tree_states.noteHashTree.tree.nextAvailableLeafIndex },
127 { Column::tx_prev_num_note_hashes_emitted, prev_state.tree_states.noteHashTree.counter },
129 { Column::tx_prev_nullifier_tree_root, prev_state.tree_states.nullifierTree.tree.root },
130 { Column::tx_prev_nullifier_tree_size, prev_state.tree_states.nullifierTree.tree.nextAvailableLeafIndex },
131 { Column::tx_prev_num_nullifiers_emitted, prev_state.tree_states.nullifierTree.counter },
133 { Column::tx_prev_public_data_tree_root, prev_state.tree_states.publicDataTree.tree.root },
134 { Column::tx_prev_public_data_tree_size, prev_state.tree_states.publicDataTree.tree.nextAvailableLeafIndex },
136 { Column::tx_prev_written_public_data_slots_tree_root,
137 prev_state.written_public_data_slots_tree_snapshot.root },
138 { Column::tx_prev_written_public_data_slots_tree_size,
139 prev_state.written_public_data_slots_tree_snapshot.nextAvailableLeafIndex },
141 { Column::tx_l1_l2_tree_root, prev_state.tree_states.l1ToL2MessageTree.tree.root },
143 { Column::tx_prev_retrieved_bytecodes_tree_root, prev_state.retrieved_bytecodes_tree_snapshot.root },
144 { Column::tx_prev_retrieved_bytecodes_tree_size,
145 prev_state.retrieved_bytecodes_tree_snapshot.nextAvailableLeafIndex },
148 { Column::tx_next_note_hash_tree_root, next_state.tree_states.noteHashTree.tree.root },
149 { Column::tx_next_note_hash_tree_size, next_state.tree_states.noteHashTree.tree.nextAvailableLeafIndex },
150 { Column::tx_next_num_note_hashes_emitted, next_state.tree_states.noteHashTree.counter },
152 { Column::tx_next_nullifier_tree_root, next_state.tree_states.nullifierTree.tree.root },
153 { Column::tx_next_nullifier_tree_size, next_state.tree_states.nullifierTree.tree.nextAvailableLeafIndex },
154 { Column::tx_next_num_nullifiers_emitted, next_state.tree_states.nullifierTree.counter },
156 { Column::tx_next_public_data_tree_root, next_state.tree_states.publicDataTree.tree.root },
157 { Column::tx_next_public_data_tree_size, next_state.tree_states.publicDataTree.tree.nextAvailableLeafIndex },
159 { Column::tx_next_written_public_data_slots_tree_root,
160 next_state.written_public_data_slots_tree_snapshot.root },
161 { Column::tx_next_written_public_data_slots_tree_size,
162 next_state.written_public_data_slots_tree_snapshot.nextAvailableLeafIndex },
164 { Column::tx_next_retrieved_bytecodes_tree_root, next_state.retrieved_bytecodes_tree_snapshot.root },
165 { Column::tx_next_retrieved_bytecodes_tree_size,
166 next_state.retrieved_bytecodes_tree_snapshot.nextAvailableLeafIndex },
169 { Column::tx_prev_num_unencrypted_log_fields, prev_state.side_effect_states.numUnencryptedLogFields },
170 { Column::tx_prev_num_l2_to_l1_messages, prev_state.side_effect_states.numL2ToL1Messages },
173 { Column::tx_next_num_unencrypted_log_fields, next_state.side_effect_states.numUnencryptedLogFields },
174 { Column::tx_next_num_l2_to_l1_messages, next_state.side_effect_states.numL2ToL1Messages },
177 { Column::tx_next_context_id, prev_state.next_context_id },
182 const SideEffectStates& next_side_effect_states)
186 Column::tx_prev_num_unencrypted_log_fields,
187 prev_side_effect_states.numUnencryptedLogFields,
190 Column::tx_prev_num_l2_to_l1_messages,
191 prev_side_effect_states.numL2ToL1Messages,
194 Column::tx_next_num_unencrypted_log_fields,
195 next_side_effect_states.numUnencryptedLogFields,
198 Column::tx_next_num_l2_to_l1_messages,
199 next_side_effect_states.numL2ToL1Messages,
210 auto remaining_length = phase_length - read_counter;
213 { Column::tx_read_pi_offset, read_offset + read_counter },
214 { Column::tx_read_pi_length_offset, length_offset - read_counter },
216 { Column::tx_remaining_phase_counter, remaining_length },
217 { Column::tx_remaining_phase_inv, remaining_length },
218 { Column::tx_remaining_phase_minus_one_inv, remaining_length - 1 },
225 { Column::tx_prev_da_gas_used, prev_gas_used.daGas },
226 { Column::tx_prev_l2_gas_used, prev_gas_used.l2Gas },
233 { Column::tx_next_da_gas_used, next_gas_used.daGas },
234 { Column::tx_next_l2_gas_used, next_gas_used.l2Gas },
241 { Column::tx_da_gas_limit, gas_limit.daGas },
242 { Column::tx_l2_gas_limit, gas_limit.l2Gas },
247 const simulation::EnqueuedCallEvent&
event)
249 return { { Column::tx_is_public_call_request, 1 },
250 { Column::tx_should_process_call_request, 1 },
251 { Column::tx_is_teardown_phase, is_teardown_phase(phase) },
252 { Column::tx_msg_sender,
event.msg_sender },
253 { Column::tx_contract_addr,
event.contract_address },
254 { Column::tx_fee,
event.transaction_fee },
255 { Column::tx_is_static,
event.is_static },
256 { Column::tx_calldata_size,
event.calldata_size },
257 { Column::tx_calldata_hash,
event.calldata_hash },
258 { Column::tx_reverted, !
event.success },
259 { Column::tx_prev_da_gas_used_sent_to_enqueued_call,
event.start_gas.daGas },
260 { Column::tx_prev_l2_gas_used_sent_to_enqueued_call,
event.start_gas.l2Gas },
261 { Column::tx_next_da_gas_used_sent_to_enqueued_call,
event.end_gas.daGas },
262 { Column::tx_next_l2_gas_used_sent_to_enqueued_call,
event.end_gas.l2Gas },
263 { Column::tx_gas_limit_pi_offset,
265 { Column::tx_should_read_gas_limit, is_teardown_phase(phase) } };
270 const TxContextEvent& state_before,
276 { Column::tx_is_tree_insert_phase, 1 },
277 { Column::tx_leaf_value,
event.leaf_value },
278 { Column::tx_remaining_side_effects_inv, remaining_note_hashes },
281 { Column::tx_should_try_note_hash_append, 1 },
282 { Column::tx_should_note_hash_append, remaining_note_hashes > 0 },
283 { Column::tx_reverted, reverted ? 1 : 0 },
289 const TxContextEvent& state_before,
292 uint32_t remaining_nullifiers =
MAX_NULLIFIERS_PER_TX - state_before.tree_states.nullifierTree.counter;
295 { Column::tx_is_tree_insert_phase, 1 },
296 { Column::tx_leaf_value,
event.leaf_value },
297 { Column::tx_remaining_side_effects_inv, remaining_nullifiers },
300 { Column::tx_should_try_nullifier_append, 1 },
301 { Column::tx_should_nullifier_append, remaining_nullifiers > 0 },
302 { Column::tx_reverted, reverted ? 1 : 0 },
308 const TxContextEvent& state_before,
311 if (is_note_hash_insert_phase(phase)) {
312 return handle_note_hash_append(
event, phase, state_before, reverted);
314 if (is_nullifier_insert_phase(phase)) {
315 return handle_nullifier_append(
event, phase, state_before, reverted);
317 throw std::runtime_error(
"Invalid phase for append tree event");
322 const TxContextEvent& state_before,
329 { Column::tx_should_try_l2_l1_msg_append, 1 },
330 { Column::tx_remaining_side_effects_inv, remaining_l2_to_l1_msgs },
331 { Column::tx_should_l2_l1_msg_append, remaining_l2_to_l1_msgs > 0 },
332 { Column::tx_l2_l1_msg_contract_address,
event.scoped_msg.contractAddress },
333 { Column::tx_l2_l1_msg_recipient,
event.scoped_msg.message.recipient },
334 { Column::tx_l2_l1_msg_content,
event.scoped_msg.message.content },
335 { Column::tx_write_pi_offset,
337 state_before.side_effect_states.numL2ToL1Messages },
339 { Column::tx_reverted, reverted ? 1 : 0 },
346 { Column::tx_is_collect_fee, 1 },
347 { Column::tx_effective_fee_per_da_gas,
FF(
event.effective_fee_per_da_gas) },
348 { Column::tx_effective_fee_per_l2_gas,
FF(
event.effective_fee_per_l2_gas) },
349 { Column::tx_fee_payer,
event.fee_payer },
356 Column::tx_fee_juice_contract_address,
360 Column::tx_fee_juice_balances_slot,
364 Column::tx_fee_juice_balance_slot,
365 event.fee_juice_balance_slot,
368 Column::tx_fee_payer_balance,
369 event.fee_payer_balance,
372 Column::tx_fee_payer_new_balance,
373 event.fee_payer_balance -
event.fee,
375 { Column::tx_uint32_max, 0xffffffff },
383 { Column::tx_is_tree_padding, 1 },
390 { Column::tx_is_cleanup, 1 },
393 { Column::tx_should_read_note_hash_tree, 1 },
395 { Column::tx_should_read_nullifier_tree, 1 },
397 { Column::tx_should_read_public_data_tree, 1 },
399 { Column::tx_should_read_l1_l2_tree, 1 },
401 { Column::tx_should_read_gas_used, 1 },
402 { Column::tx_array_length_note_hashes_pi_offset,
404 { Column::tx_array_length_nullifiers_pi_offset,
407 { Column::tx_array_length_l2_to_l1_messages_pi_offset,
409 { Column::tx_fields_length_unencrypted_logs_pi_offset,
417 { Column::tx_start_tx, 1 },
419 { Column::tx_should_read_note_hash_tree, 1 },
421 { Column::tx_should_read_nullifier_tree, 1 },
423 { Column::tx_should_read_public_data_tree, 1 },
425 { Column::tx_should_read_l1_l2_tree, 1 },
427 { Column::tx_should_read_gas_used, 1 },
429 { Column::tx_should_read_gas_limit, 1 },
443 { Column::tx_sel, 1 },
444 { Column::tx_discard,
discard ? 1 : 0 },
445 { Column::tx_phase_value,
static_cast<uint8_t
>(phase) },
447 { Column::tx_is_padded, 1 },
448 { Column::tx_start_phase, 1 },
449 { Column::tx_sel_read_phase_length, !is_one_shot_phase(phase) },
452 { Column::tx_is_collect_fee, is_collect_fee_phase(phase) ? 1 : 0 },
453 { Column::tx_end_phase, 1 },
455 { Column::tx_is_tree_insert_phase, is_tree_insert_phase(phase) ? 1 : 0 },
456 { Column::tx_is_public_call_request, is_public_call_request_phase(phase) ? 1 : 0 },
457 { Column::tx_is_collect_fee, is_collect_fee_phase(phase) ? 1 : 0 },
466 { Column::tx_is_collect_fee, is_collect_fee_phase(phase) ? 1 : 0 },
468 { Column::tx_is_revertible, is_revertible(phase) ? 1 : 0 },
470 { Column::tx_is_teardown_phase, is_teardown_phase(phase) },
471 { Column::tx_gas_limit_pi_offset,
473 { Column::tx_should_read_gas_limit, is_teardown_phase(phase) },
475 { Column::tx_prev_da_gas_used_sent_to_enqueued_call,
477 { Column::tx_prev_l2_gas_used_sent_to_enqueued_call,
479 { Column::tx_next_da_gas_used_sent_to_enqueued_call,
481 { Column::tx_next_l2_gas_used_sent_to_enqueued_call,
491 { Column::tx_sel_can_emit_note_hash,
492 is_note_hash_insert_phase(phase) || is_public_call_request_phase(phase) || is_tree_padding_phase(phase) },
493 { Column::tx_sel_can_emit_nullifier,
494 is_nullifier_insert_phase(phase) || is_public_call_request_phase(phase) || is_tree_padding_phase(phase) },
495 { Column::tx_sel_can_write_public_data, is_collect_fee_phase(phase) || is_public_call_request_phase(phase) },
496 { Column::tx_sel_can_emit_unencrypted_log, is_public_call_request_phase(phase) },
497 { Column::tx_sel_can_emit_l2_l1_msg, is_l2_l1_msg_phase(phase) || is_public_call_request_phase(phase) },
533 bool r_insertion_or_app_logic_failure =
false;
535 for (
const auto& tx_event : events) {
538 phase_lengths = startup_event.value().phase_lengths;
542 phase_buckets[
static_cast<uint8_t
>(tx_phase_event.
phase) - 1].push_back(&tx_phase_event);
546 if (!is_revertible(tx_phase_event.
phase)) {
547 throw std::runtime_error(
"Reverted in non-revertible phase: " +
554 r_insertion_or_app_logic_failure =
true;
560 if (!startup_event.has_value()) {
561 throw std::runtime_error(
"Transaction startup event is missing");
564 const auto& startup_event_data = startup_event.value();
569 Gas current_gas_limit = startup_event_data.gas_limit;
570 Gas teardown_gas_limit = startup_event_data.teardown_gas_limit;
571 Gas gas_used = startup_event_data.state.gas_used;
574 for (uint32_t i = 0; i < NUM_PHASES; i++) {
575 const auto& phase_events = phase_buckets[i];
576 if (phase_events.empty()) {
586 if (is_revertible(phase)) {
595 if (is_teardown_phase(phase)) {
596 current_gas_limit = teardown_gas_limit;
600 uint32_t phase_counter = 0;
604 uint32_t phase_length = get_phase_length(phase_lengths, phase);
607 for (
const auto& tx_phase_event : phase_events) {
609 trace.set(row, insert_state(tx_phase_event->state_before, tx_phase_event->state_after));
611 insert_side_effect_states(tx_phase_event->state_before.side_effect_states,
612 tx_phase_event->state_after.side_effect_states));
617 { C::tx_discard,
discard ? 1 : 0 },
618 { C::tx_phase_value,
static_cast<uint8_t
>(tx_phase_event->phase) },
620 { C::tx_is_padded, 0 },
621 { C::tx_start_phase, phase_counter == 0 ? 1 : 0 },
622 { C::tx_sel_read_phase_length, phase_counter == 0 && !is_one_shot_phase(tx_phase_event->phase) },
623 { C::tx_is_revertible, is_revertible(tx_phase_event->phase) ? 1 : 0 },
624 { C::tx_end_phase, phase_counter == phase_events.size() - 1 ? 1 : 0 },
626 trace.set(row, handle_prev_gas_used(gas_used));
627 trace.set(row, handle_state_change_selectors(tx_phase_event->phase));
629 trace.set(row, handle_first_row());
635 trace.set(row, handle_enqueued_call_event(tx_phase_event->phase,
event));
637 trace.set(row, handle_pi_read(tx_phase_event->phase, phase_length, phase_counter));
639 gas_used = tx_phase_event->state_after.gas_used;
643 handle_append_tree_event(
event,
644 tx_phase_event->phase,
645 tx_phase_event->state_before,
646 tx_phase_event->reverted));
648 trace.set(row, handle_pi_read(tx_phase_event->phase, phase_length, phase_counter));
652 handle_l2_l1_msg_event(
event,
653 tx_phase_event->phase,
654 tx_phase_event->state_before,
655 tx_phase_event->reverted));
656 trace.set(row, handle_pi_read(tx_phase_event->phase, phase_length, phase_counter));
659 trace.set(row, handle_pi_read(tx_phase_event->phase, 1, 0));
660 trace.set(row, handle_collect_gas_fee_event(
event));
663 trace.set(row, handle_pi_read(tx_phase_event->phase, 1, 0));
664 trace.set(row, handle_tree_padding());
667 trace.set(row, handle_pi_read(tx_phase_event->phase, 1, 0));
668 trace.set(row, handle_cleanup());
674 trace.set(row, handle_pi_read(tx_phase_event->phase, 0, 0));
675 trace.set(row, handle_padded_row(tx_phase_event->phase, gas_used,
discard));
677 tx_phase_event->event);
678 trace.set(row, handle_next_gas_used(gas_used));
679 trace.set(row, handle_gas_limit(current_gas_limit));
685 propagated_state = phase_events.back()->state_after;
689 trace.invert_columns(
690 { { C::tx_remaining_phase_inv, C::tx_remaining_phase_minus_one_inv, C::tx_remaining_side_effects_inv } });
697 .add<lookup_tx_phase_jump_on_revert_settings, InteractionType::LookupGeneric>()
699 .add<lookup_tx_read_calldata_hash_settings, InteractionType::LookupSequential>()
701 .add<lookup_tx_dispatch_exec_start_settings, InteractionType::LookupGeneric>()
703 .add<lookup_tx_read_tree_insert_value_settings, InteractionType::LookupGeneric>()
705 .add<lookup_tx_write_l2_l1_msg_settings, InteractionType::LookupGeneric>()
707 .add<lookup_tx_read_fee_payer_public_inputs_settings, InteractionType::LookupGeneric>()
709 .add<lookup_tx_note_hash_append_settings, InteractionType::LookupGeneric>()
711 .add<lookup_tx_balance_read_settings, InteractionType::LookupGeneric>()
713 .add<lookup_tx_balance_slot_poseidon2_settings, InteractionType::LookupGeneric>()
715 .add<lookup_tx_context_public_inputs_nullifier_tree_settings, InteractionType::LookupIntoIndexedByClk>()
717 .add<lookup_tx_context_public_inputs_l1_l2_tree_settings, InteractionType::LookupIntoIndexedByClk>()
719 .add<lookup_tx_context_public_inputs_read_gas_limit_settings, InteractionType::LookupIntoIndexedByClk>()
721 .add<lookup_tx_context_public_inputs_write_nullifier_count_settings, InteractionType::LookupIntoIndexedByClk>()
#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_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 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 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
std::vector< Event > Container
InteractionDefinition & add(auto &&... args)
static const Offsets & get_offsets(TransactionPhase phase)
void process(const simulation::EventEmitterInterface< simulation::TxEvent >::Container &events, TraceContainer &trace)
static const InteractionDefinition interactions
lookup_settings< lookup_tx_read_effective_fee_public_inputs_settings_ > lookup_tx_read_effective_fee_public_inputs_settings
lookup_settings< lookup_tx_context_public_inputs_write_l2_to_l1_message_count_settings_ > lookup_tx_context_public_inputs_write_l2_to_l1_message_count_settings
lookup_settings< lookup_tx_context_public_inputs_note_hash_tree_settings_ > lookup_tx_context_public_inputs_note_hash_tree_settings
lookup_settings< lookup_tx_dispatch_exec_end_settings_ > lookup_tx_dispatch_exec_end_settings
lookup_settings< lookup_tx_balance_validation_settings_ > lookup_tx_balance_validation_settings
lookup_settings< lookup_tx_read_phase_table_settings_ > lookup_tx_read_phase_table_settings
lookup_settings< lookup_tx_write_fee_public_inputs_settings_ > lookup_tx_write_fee_public_inputs_settings
lookup_settings< lookup_tx_context_public_inputs_public_data_tree_settings_ > lookup_tx_context_public_inputs_public_data_tree_settings
lookup_settings< lookup_tx_context_public_inputs_gas_used_settings_ > lookup_tx_context_public_inputs_gas_used_settings
lookup_settings< lookup_tx_nullifier_append_settings_ > lookup_tx_nullifier_append_settings
lookup_settings< lookup_tx_read_l2_l1_msg_settings_ > lookup_tx_read_l2_l1_msg_settings
lookup_settings< lookup_tx_context_restore_state_on_revert_settings_ > lookup_tx_context_restore_state_on_revert_settings
lookup_settings< lookup_tx_context_public_inputs_write_note_hash_count_settings_ > lookup_tx_context_public_inputs_write_note_hash_count_settings
lookup_settings< lookup_tx_read_public_call_request_phase_settings_ > lookup_tx_read_public_call_request_phase_settings
lookup_settings< lookup_tx_read_phase_length_settings_ > lookup_tx_read_phase_length_settings
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
std::string to_string(bb::avm2::ValueTag tag)
simulation::PublicDataTreeReadWriteEvent event