Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
tx_execution.cpp
Go to the documentation of this file.
2
3#include <cstdint>
4#include <stdexcept>
5
7
8namespace bb::avm2::simulation {
9namespace {
10
11// A tx-level exception that is expected to be handled.
12// This is in contrast to other runtime exceptions that might occur and should be propagated.
13// Note, however, that we re-throw unrecoverable errors of this type (exceptions thrown in insert_non_revertibles()).
14class TxExecutionException : public std::runtime_error {
15 public:
16 TxExecutionException(const std::string& message)
17 : std::runtime_error(message)
18 {}
19};
20
21std::string get_halting_information(const EnqueuedCallResult& result)
22{
23 std::string halting_message =
24 result.halting_message.has_value() ? " with message: " + result.halting_message.value() : "";
25
26 switch (result.halting_mode) {
28 return "RETURN" + halting_message;
30 return "REVERT" + halting_message;
32 return "EXCEPTIONAL_HALT";
33 default:
34 return "UNKNOWN" + halting_message;
35 }
36}
37
38} // namespace
39
85{
86 BB_BENCH_NAME("TxExecution::simulate");
87
88 const Gas& gas_limit = tx.gas_settings.gas_limits;
89 const Gas& teardown_gas_limit = tx.gas_settings.teardown_gas_limits;
90 tx_context.gas_used = tx.gas_used_by_private;
91
93 .gas_used = tx_context.gas_used,
94 .gas_limit = gas_limit,
95 .teardown_gas_limit = teardown_gas_limit,
96 .phase_lengths = PhaseLengths::from_tx(tx), // Extract lengths of each phase at start.
97 });
98
99 vinfo("Simulating tx ",
100 tx.hash,
101 " with ",
102 tx.setup_enqueued_calls.size(),
103 " setup enqueued calls, ",
104 tx.app_logic_enqueued_calls.size(),
105 " app logic enqueued calls, and ",
106 tx.teardown_enqueued_call.has_value() ? "1 teardown enqueued call" : "no teardown enqueued call");
107
108 // Let the metadata collector know that we are entering the SETUP phase.
110
111 // Insert non-revertibles. This can throw if there is a nullifier collision or the maximum number of
112 // nullifiers, note hashes, or L2 to L1 messages is reached.
113 // That would result in an unprovable tx.
115
116 // Setup.
117 if (tx.setup_enqueued_calls.empty()) {
119 } else {
120 for (const auto& call : tx.setup_enqueued_calls) {
121 vinfo("[SETUP] Executing enqueued call to ",
122 call.request.contract_address,
123 "::",
124 get_debug_function_name(call.request.contract_address, call.calldata));
125 const TxContextEvent state_before = tx_context.serialize_tx_context_event();
126 const Gas start_gas =
127 tx_context.gas_used; // Do not use a const reference as tx_context.gas_used will be modified.
128 auto context = context_provider.make_enqueued_context(call.request.contract_address,
129 call.request.msg_sender,
130 /*transaction_fee=*/FF(0),
131 call.calldata,
132 call.request.calldata_hash,
133 call.request.is_static_call,
134 gas_limit,
135 start_gas,
137 // This call should not throw unless it's an unexpected unrecoverable failure.
139 tx_context.gas_used = result.gas_used;
140 vinfo("[SETUP] Enqueued call to ",
141 call.request.contract_address,
142 " halted via ",
143 get_halting_information(result));
144
147 /*transaction_fee=*/FF(0),
148 result.success,
149 start_gas,
150 tx_context.gas_used,
151 state_before,
152 tx_context.serialize_tx_context_event());
153 if (!result.success) {
154 // This will result in an unprovable tx.
155 throw TxExecutionException(
156 format("[SETUP] UNRECOVERABLE ERROR! Enqueued call to ", call.request.contract_address, " failed"));
157 }
158 }
159 }
160
161 // The checkpoint we should go back to if anything from now on reverts.
164
165 // Let the metadata collector know that we are entering the APP_LOGIC phase.
167
168 try {
169 // Insert revertibles. This can throw TxExecutionException on a side-effect limit error
170 // (handled here, tx is provable) or NullifierCollisionException on a collision
171 // (not handled here - propagates as unrecoverable, since the tx is unprovable).
172 // We catch separately here to record the revert reason in call stack metadata,
173 // since no calls have populated the metadata yet at this point.
174 try {
176 } catch (const TxExecutionException& e) {
178 throw;
179 }
180
181 // App Logic.
182 if (tx.app_logic_enqueued_calls.empty()) {
184 } else {
185 for (const auto& call : tx.app_logic_enqueued_calls) {
186 vinfo("[APP_LOGIC] Executing enqueued call to ",
187 call.request.contract_address,
188 "::",
189 get_debug_function_name(call.request.contract_address, call.calldata));
190 const TxContextEvent state_before = tx_context.serialize_tx_context_event();
191 const Gas start_gas =
192 tx_context.gas_used; // Do not use a const reference as tx_context.gas_used will be modified.
193
194 auto context = context_provider.make_enqueued_context(call.request.contract_address,
195 call.request.msg_sender,
196 /*transaction_fee=*/FF(0),
197 call.calldata,
198 call.request.calldata_hash,
199 call.request.is_static_call,
200 gas_limit,
201 start_gas,
203 // This call should not throw unless it's an unexpected unrecoverable failure.
205 tx_context.gas_used = result.gas_used;
206 vinfo("[APP_LOGIC] Enqueued call to ",
207 call.request.contract_address,
208 " halted via ",
209 get_halting_information(result));
210
213 /*transaction_fee=*/FF(0),
214 result.success,
215 start_gas,
216 tx_context.gas_used,
217 state_before,
218 tx_context.serialize_tx_context_event());
219 if (!result.success) {
220 // This exception should be handled, and the tx should be provable.
221 throw TxExecutionException(
222 format("[APP_LOGIC] Enqueued call to ", call.request.contract_address, " failed"));
223 }
224 }
225 }
226 } catch (const TxExecutionException& e) {
227 vinfo("Revertible failure while simulating tx ", tx.hash, ": ", e.what());
229 // We revert to the post-setup state.
232 // But we also create a new fork so that the teardown phase can transparently
233 // commit or rollback to the end of teardown.
236 }
237
238 // Let the metadata collector know that we are entering the teardown phase.
240
241 // Compute the transaction fee here so it can be passed to teardown.
242 const uint128_t& fee_per_da_gas = tx.effective_gas_fees.fee_per_da_gas;
243 const uint128_t& fee_per_l2_gas = tx.effective_gas_fees.fee_per_l2_gas;
244 const FF fee =
245 FF(fee_per_da_gas) * FF(tx_context.gas_used.da_gas) + FF(fee_per_l2_gas) * FF(tx_context.gas_used.l2_gas);
246 Gas gas_used_by_teardown = { 0, 0 };
247
248 // Teardown.
249 try {
250 if (!tx.teardown_enqueued_call.has_value()) {
252 } else {
253 const auto& teardown_enqueued_call = tx.teardown_enqueued_call.value();
254 vinfo("[TEARDOWN] Executing enqueued call to ",
255 teardown_enqueued_call.request.contract_address,
256 "::",
257 get_debug_function_name(teardown_enqueued_call.request.contract_address,
258 teardown_enqueued_call.calldata));
259 // Teardown has its own gas limit and usage.
260 constexpr Gas start_gas = { 0, 0 };
261 const TxContextEvent state_before = tx_context.serialize_tx_context_event();
262 auto context = context_provider.make_enqueued_context(teardown_enqueued_call.request.contract_address,
263 teardown_enqueued_call.request.msg_sender,
264 fee,
265 teardown_enqueued_call.calldata,
266 teardown_enqueued_call.request.calldata_hash,
267 teardown_enqueued_call.request.is_static_call,
268 teardown_gas_limit,
269 start_gas,
271 // This call should not throw unless it's an unexpected unrecoverable failure.
273 gas_used_by_teardown = result.gas_used;
274 vinfo("[TEARDOWN] Enqueued call to ",
275 teardown_enqueued_call.request.contract_address,
276 " halted via ",
277 get_halting_information(result));
278
279 emit_public_call_request(teardown_enqueued_call,
281 fee,
282 result.success,
283 start_gas,
284 result.gas_used,
285 state_before,
286 tx_context.serialize_tx_context_event());
287 if (!result.success) {
288 // This exception should be handled, and the tx should be provable.
289 throw TxExecutionException(
290 format("[TEARDOWN] Enqueued call to ", teardown_enqueued_call.request.contract_address, " failed"));
291 }
292 }
293
294 // We commit the forked state and we are done.
297 } catch (const TxExecutionException& e) {
298 // TODO(fcarreiro): move these back to important log once/if we have log levels properly set up.
299 vinfo("Teardown failure while simulating tx ", tx.hash, ": ", e.what());
300 tx_context.revert_code = tx_context.revert_code == RevertCode::APP_LOGIC_REVERTED
303 // We rollback to the post-setup state.
306 }
307
308 // Fee payment
309 pay_fee(tx.fee_payer, fee, fee_per_da_gas, fee_per_l2_gas);
310
311 pad_trees();
312
313 cleanup();
314
315 return {
316 .gas_used = {
317 // Follows PublicTxContext.getActualGasUsed()
318 .total_gas = tx_context.gas_used + (tx.teardown_enqueued_call ? (gas_used_by_teardown - teardown_gas_limit) : Gas {0, 0}),
319 .teardown_gas = gas_used_by_teardown,
320 // Follows PublicTxContext.getActualPublicGasUsed()
321 .public_gas = tx_context.gas_used + gas_used_by_teardown - tx.gas_used_by_private,
322 // Follows PublicTxContext.getTotalGasUsed()
323 .billed_gas = tx_context.gas_used,
324 },
325 .revert_code = tx_context.revert_code,
326 .transaction_fee = fee,
327 };
328}
329
344 TransactionPhase phase,
345 const FF& transaction_fee,
346 bool success,
347 const Gas& start_gas,
348 const Gas& end_gas,
349 const TxContextEvent& state_before,
350 const TxContextEvent& state_after)
351{
352 events.emit(TxPhaseEvent{ .phase = phase,
353 .state_before = state_before,
354 .state_after = state_after,
355 .reverted = !success,
356 .event = EnqueuedCallEvent{
358 .contract_address = call.request.contract_address,
359 .transaction_fee = transaction_fee,
360 .is_static = call.request.is_static_call,
361 .calldata_size = static_cast<uint32_t>(call.calldata.size()),
362 .calldata_hash = call.request.calldata_hash,
363 .start_gas = start_gas,
364 .end_gas = end_gas,
365 .success = success,
366 } });
367}
368
378void TxExecution::emit_nullifier(bool revertible, const FF& nullifier)
379{
380 const TransactionPhase phase =
382 const TxContextEvent state_before = tx_context.serialize_tx_context_event();
383 try {
384 uint32_t prev_nullifier_count = merkle_db.get_tree_state().nullifier_tree.counter;
385
386 if (prev_nullifier_count == MAX_NULLIFIERS_PER_TX) {
387 throw TxExecutionException("Maximum number of nullifiers reached");
388 }
389
390 try {
392 } catch (const NullifierCollisionException& e) {
393 // Do not handle the NullifierCollisionException as any collision at the tx execution
394 // level is unprovable (i.e. this is an unrecoverable error).
395 // Rethrow with more information - note that this exception isn't being caught in this file
397 revertible ? "R" : "NR",
398 "_NULLIFIER_INSERTION] UNRECOVERABLE ERROR! Nullifier collision: ",
399 e.what()));
400 }
401
402 events.emit(TxPhaseEvent{ .phase = phase,
403 .state_before = state_before,
404 .state_after = tx_context.serialize_tx_context_event(),
405 .reverted = false,
406 .event = PrivateAppendTreeEvent{ .leaf_value = nullifier } });
407
408 } catch (const TxExecutionException& e) {
410 .phase = phase,
411 .state_before = state_before,
412 .state_after = tx_context.serialize_tx_context_event(),
413 .reverted = true,
414 .event = PrivateAppendTreeEvent{ .leaf_value = nullifier },
415 });
416 // Rethrow the error.
417 throw e;
418 }
419}
420
429void TxExecution::emit_note_hash(bool revertible, const FF& note_hash)
430{
431 const TransactionPhase phase =
433 const TxContextEvent state_before = tx_context.serialize_tx_context_event();
434
435 try {
436 uint32_t prev_note_hash_count = merkle_db.get_tree_state().note_hash_tree.counter;
437
438 if (prev_note_hash_count == MAX_NOTE_HASHES_PER_TX) {
439 throw TxExecutionException("Maximum number of note hashes reached");
440 }
441
442 if (revertible) {
444 } else {
446 }
447
448 events.emit(TxPhaseEvent{ .phase = phase,
449 .state_before = state_before,
450 .state_after = tx_context.serialize_tx_context_event(),
451 .reverted = false,
453 } catch (const TxExecutionException& e) {
454 events.emit(TxPhaseEvent{ .phase = phase,
455 .state_before = state_before,
456 .state_after = tx_context.serialize_tx_context_event(),
457 .reverted = true,
459 // Rethrow the error.
460 throw e;
461 }
462}
463
472void TxExecution::emit_l2_to_l1_message(bool revertible, const ScopedL2ToL1Message& l2_to_l1_message)
473{
474 const TransactionPhase phase =
476 const TxContextEvent state_before = tx_context.serialize_tx_context_event();
477 auto& side_effect_tracker = tx_context.side_effect_tracker;
478 const auto& side_effects = side_effect_tracker.get_side_effects();
479
480 try {
481 if (side_effects.l2_to_l1_messages.size() == MAX_L2_TO_L1_MSGS_PER_TX) {
482 throw TxExecutionException("Maximum number of L2 to L1 messages reached");
483 }
484 side_effect_tracker.add_l2_to_l1_message(
485 l2_to_l1_message.contract_address, l2_to_l1_message.message.recipient, l2_to_l1_message.message.content);
486 events.emit(TxPhaseEvent{ .phase = phase,
487 .state_before = state_before,
488 .state_after = tx_context.serialize_tx_context_event(),
489 .reverted = false,
490 .event = PrivateEmitL2L1MessageEvent{ .scoped_msg = l2_to_l1_message } });
491 } catch (const TxExecutionException& e) {
492 events.emit(TxPhaseEvent{ .phase = phase,
493 .state_before = state_before,
494 .state_after = tx_context.serialize_tx_context_event(),
495 .reverted = true,
496 .event = PrivateEmitL2L1MessageEvent{ .scoped_msg = l2_to_l1_message } });
497 // Rethrow the error.
498 throw e;
499 }
500}
501
512{
513 BB_BENCH_NAME("TxExecution::insert_non_revertibles");
514
515 vinfo("[NON_REVERTIBLE] Inserting ",
516 tx.non_revertible_accumulated_data.nullifiers.size(),
517 " nullifiers, ",
518 tx.non_revertible_accumulated_data.note_hashes.size(),
519 " note hashes, and ",
520 tx.non_revertible_accumulated_data.l2_to_l1_messages.size(),
521 " L2 to L1 messages for tx ",
522 tx.hash);
523
524 // 1. Write the already siloed nullifiers.
525 if (tx.non_revertible_accumulated_data.nullifiers.empty()) {
527 } else {
528 for (const auto& nullifier : tx.non_revertible_accumulated_data.nullifiers) {
529 emit_nullifier(false, nullifier);
530 }
531 }
532
533 // 2. Write already unique note hashes.
534 if (tx.non_revertible_accumulated_data.note_hashes.empty()) {
536 } else {
537 for (const auto& unique_note_hash : tx.non_revertible_accumulated_data.note_hashes) {
538 emit_note_hash(false, unique_note_hash);
539 }
540 }
541
542 // 3. Write L2 to L1 messages.
543 if (tx.non_revertible_accumulated_data.l2_to_l1_messages.empty()) {
545 } else {
546 for (const auto& l2_to_l1_msg : tx.non_revertible_accumulated_data.l2_to_l1_messages) {
547 emit_l2_to_l1_message(false, l2_to_l1_msg);
548 }
549 }
550
551 // Add new contracts to the contracts DB so that their code may be found and called.
552 contract_db.add_contracts(tx.non_revertible_contract_deployment_data);
553}
554
565{
566 BB_BENCH_NAME("TxExecution::insert_revertibles");
567
568 vinfo("[REVERTIBLE] Inserting ",
569 tx.revertible_accumulated_data.nullifiers.size(),
570 " nullifiers, ",
571 tx.revertible_accumulated_data.note_hashes.size(),
572 " note hashes, and ",
573 tx.revertible_accumulated_data.l2_to_l1_messages.size(),
574 " L2 to L1 messages for tx ",
575 tx.hash);
576
577 // 1. Write the already siloed nullifiers.
578 if (tx.revertible_accumulated_data.nullifiers.empty()) {
580 } else {
581 for (const auto& siloed_nullifier : tx.revertible_accumulated_data.nullifiers) {
582 emit_nullifier(true, siloed_nullifier);
583 }
584 }
585
586 // 2. Write the siloed non-unique note hashes.
587 if (tx.revertible_accumulated_data.note_hashes.empty()) {
589 } else {
590 for (const auto& siloed_note_hash : tx.revertible_accumulated_data.note_hashes) {
591 emit_note_hash(true, siloed_note_hash);
592 }
593 }
594
595 // 3. Write L2 to L1 messages.
596 if (tx.revertible_accumulated_data.l2_to_l1_messages.empty()) {
598 } else {
599 for (const auto& l2_to_l1_msg : tx.revertible_accumulated_data.l2_to_l1_messages) {
600 emit_l2_to_l1_message(true, l2_to_l1_msg);
601 }
602 }
603
604 // Add new contracts to the contracts DB so that their functions may be found and called.
605 contract_db.add_contracts(tx.revertible_contract_deployment_data);
606}
607
618void TxExecution::pay_fee(const AztecAddress& fee_payer,
619 const FF& fee,
620 const uint128_t& fee_per_da_gas,
621 const uint128_t& fee_per_l2_gas)
622{
623 BB_BENCH_NAME("TxExecution::pay_fee");
624
625 if (fee_payer == 0) {
627 vinfo("Fee payer is 0. Skipping fee enforcement. No one is paying the fee of ", fee);
628 return;
629 }
630 // Real transactions are enforced by the private kernel to have a non-zero fee payer.
631 // Real transactions cannot skip fee enforcement (skipping fee enforcement makes them unprovable).
632 // Unrecoverable error.
633 throw TxExecutionException("Fee payer cannot be 0 unless skipping fee enforcement for simulation");
634 }
635
636 const TxContextEvent state_before = tx_context.serialize_tx_context_event();
637 const FF fee_juice_balance_slot =
639 FF fee_payer_balance = merkle_db.storage_read(FEE_JUICE_ADDRESS, fee_juice_balance_slot);
640
641 if (field_gt.ff_gt(fee, fee_payer_balance)) {
643 vinfo("Fee payer balance insufficient, but we're skipping fee enforcement");
644 // We still proceed and perform the storage write to minimize deviation from normal execution.
645 fee_payer_balance = fee;
646 } else {
647 // Without "skipFeeEnforcement", such transactions should be filtered by GasTxValidator.
648 // Unrecoverable error.
649 throw TxExecutionException("Not enough balance for fee payer to pay for transaction");
650 }
651 }
652
653 merkle_db.storage_write(FEE_JUICE_ADDRESS, fee_juice_balance_slot, fee_payer_balance - fee, true);
654
656 .state_before = state_before,
657 .state_after = tx_context.serialize_tx_context_event(),
658 .reverted = false,
660 .effective_fee_per_da_gas = fee_per_da_gas,
661 .effective_fee_per_l2_gas = fee_per_l2_gas,
662 .fee_payer = fee_payer,
663 .fee_payer_balance = fee_payer_balance,
664 .fee_juice_balance_slot = fee_juice_balance_slot,
665 .fee = fee,
666 } });
667}
668
674{
675 BB_BENCH_NAME("TxExecution::pad_trees");
676
677 const TxContextEvent state_before = tx_context.serialize_tx_context_event();
680 .state_before = state_before,
681 .state_after = tx_context.serialize_tx_context_event(),
682 .reverted = false,
683 .event = PadTreesEvent{} });
684}
685
691{
692 const TxContextEvent current_state = tx_context.serialize_tx_context_event();
694 .state_before = current_state,
695 .state_after = current_state,
696 .reverted = false,
697 .event = CleanupEvent{} });
698}
699
708{
709 const TxContextEvent current_state = tx_context.serialize_tx_context_event();
710 events.emit(TxPhaseEvent{ .phase = phase,
711 .state_before = current_state,
712 .state_after = current_state,
713 .reverted = false,
714 .event = EmptyPhaseEvent{} });
715}
716
724std::string TxExecution::get_debug_function_name(const AztecAddress& contract_address, const std::vector<FF>& calldata)
725{
726 // Public function is dispatched, and therefore the target function is passed in the first argument.
727 if (calldata.empty()) {
728 return format("<calldata[0] undefined> (Contract Address: ", contract_address, ")");
729 }
730
731 const FF& selector = calldata[0];
732 auto debug_name = contract_db.get_debug_function_name(contract_address, selector);
733
734 if (debug_name.has_value()) {
735 return debug_name.value();
736 }
737
738 // Return selector as hex string if debug name is not found.
739 return format("<selector: ", selector, ">");
740}
741
742} // namespace bb::avm2::simulation
std::shared_ptr< Napi::ThreadSafeFunction > debug_name
#define DOM_SEP__PUBLIC_STORAGE_MAP_SLOT
#define FEE_JUICE_ADDRESS
#define MAX_L2_TO_L1_MSGS_PER_TX
#define MAX_NOTE_HASHES_PER_TX
#define FEE_JUICE_BALANCES_SLOT
#define MAX_NULLIFIERS_PER_TX
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
virtual void set_phase(CoarseTransactionPhase phase)=0
virtual void notify_tx_revert(const std::string &revert_message)=0
virtual std::unique_ptr< ContextInterface > make_enqueued_context(const AztecAddress &address, const AztecAddress &msg_sender, const FF &transaction_fee, std::span< const FF > calldata, const FF &calldata_hash, bool is_static, const Gas &gas_limit, const Gas &gas_used, TransactionPhase phase)=0
virtual void add_contracts(const ContractDeploymentData &contract_deployment_data)=0
virtual std::optional< std::string > get_debug_function_name(const AztecAddress &address, const FunctionSelector &selector) const =0
virtual void emit(Event &&event)=0
virtual EnqueuedCallResult execute(std::unique_ptr< ContextInterface > context)=0
virtual bool ff_gt(const FF &a, const FF &b)=0
virtual void unique_note_hash_write(const FF &note_hash)=0
virtual FF storage_read(const AztecAddress &contract_address, const FF &slot) const =0
virtual void siloed_note_hash_write(const FF &note_hash)=0
virtual void storage_write(const AztecAddress &contract_address, const FF &slot, const FF &value, bool is_protocol_write)=0
virtual void siloed_nullifier_write(const FF &nullifier)=0
virtual TreeStates get_tree_state() const =0
void cleanup()
Emit a TxPhaseEvent event with the embedded event type CleanupEvent. This is used to finalize the acc...
void emit_public_call_request(const PublicCallRequestWithCalldata &call, TransactionPhase phase, const FF &transaction_fee, bool success, const Gas &start_gas, const Gas &end_gas, const TxContextEvent &state_before, const TxContextEvent &state_after)
Handle a public call request and emit a TxPhaseEvent event with the embedded event type EnqueuedCallE...
TxExecutionResult simulate(const Tx &tx)
Simulates the entire transaction execution phases.
void insert_revertibles(const Tx &tx)
Insert the revertible accumulated data into the Merkle DB and emit corresponding events....
FieldGreaterThanInterface & field_gt
void pad_trees()
Pad the note hash and nullifier trees and emit a TxPhaseEvent event with the embedded event type PadT...
std::string get_debug_function_name(const AztecAddress &contract_address, const std::vector< FF > &calldata)
Get the debug function name for a given contract address and calldata.
void emit_empty_phase(TransactionPhase phase)
Emit a TxPhaseEvent event with the embedded event type EmptyPhaseEvent. This is used to indicate that...
void insert_non_revertibles(const Tx &tx)
Insert the non-revertible accumulated data into the Merkle DB and emit corresponding events....
HighLevelMerkleDBInterface & merkle_db
EventEmitterInterface< TxEvent > & events
void pay_fee(const AztecAddress &fee_payer, const FF &fee, const uint128_t &fee_per_da_gas, const uint128_t &fee_per_l2_gas)
Pay the fee for the transaction and emit a TxPhaseEvent event with the embedded event type CollectGas...
void emit_nullifier(bool revertible, const FF &nullifier)
Handle a nullifier insertion and emit a TxPhaseEvent event with the embedded event type PrivateAppend...
ContractDBInterface & contract_db
void emit_note_hash(bool revertible, const FF &note_hash)
Handle a note hash insertion and emit a TxPhaseEvent event with the embedded event type PrivateAppend...
ContextProviderInterface & context_provider
void emit_l2_to_l1_message(bool revertible, const ScopedL2ToL1Message &l2_to_l1_message)
Handle an L2 to L1 message insertion and emit a TxPhaseEvent event with the embedded event type Priva...
CallStackMetadataCollectorInterface & call_stack_metadata_collector
ExecutionInterface & call_execution
static FF hash(const std::vector< FF > &input)
Hashes a vector of field elements.
std::string format(Args... args)
Definition log.hpp:23
#define vinfo(...)
Definition log.hpp:94
AVM range check gadget for witness generation.
AvmFlavorSettings::FF FF
Definition field.hpp:10
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
simulation::PublicDataTreeReadWriteEvent event
unsigned __int128 uint128_t
Definition serialize.hpp:45
static PhaseLengths from_tx(const Tx &tx)
Definition tx_events.hpp:24
SideEffectTracker side_effect_tracker