14class TxExecutionException :
public std::runtime_error {
16 TxExecutionException(
const std::string& message)
17 :
std::runtime_error(message)
21std::string get_halting_information(
const EnqueuedCallResult& result)
23 std::string halting_message =
24 result.halting_message.has_value() ?
" with message: " + result.halting_message.value() :
"";
26 switch (result.halting_mode) {
28 return "RETURN" + halting_message;
30 return "REVERT" + halting_message;
32 return "EXCEPTIONAL_HALT";
34 return "UNKNOWN" + halting_message;
88 const Gas& gas_limit =
tx.gas_settings.gas_limits;
89 const Gas& teardown_gas_limit =
tx.gas_settings.teardown_gas_limits;
94 .gas_limit = gas_limit,
95 .teardown_gas_limit = teardown_gas_limit,
99 vinfo(
"Simulating tx ",
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");
117 if (
tx.setup_enqueued_calls.empty()) {
120 for (
const auto& call :
tx.setup_enqueued_calls) {
121 vinfo(
"[SETUP] Executing enqueued call to ",
122 call.request.contract_address,
126 const Gas start_gas =
129 call.request.msg_sender,
132 call.request.calldata_hash,
133 call.request.is_static_call,
140 vinfo(
"[SETUP] Enqueued call to ",
141 call.request.contract_address,
143 get_halting_information(result));
155 throw TxExecutionException(
156 format(
"[SETUP] UNRECOVERABLE ERROR! Enqueued call to ", call.request.contract_address,
" failed"));
176 }
catch (
const TxExecutionException& e) {
182 if (
tx.app_logic_enqueued_calls.empty()) {
185 for (
const auto& call :
tx.app_logic_enqueued_calls) {
186 vinfo(
"[APP_LOGIC] Executing enqueued call to ",
187 call.request.contract_address,
191 const Gas start_gas =
195 call.request.msg_sender,
198 call.request.calldata_hash,
199 call.request.is_static_call,
206 vinfo(
"[APP_LOGIC] Enqueued call to ",
207 call.request.contract_address,
209 get_halting_information(result));
221 throw TxExecutionException(
222 format(
"[APP_LOGIC] Enqueued call to ", call.request.contract_address,
" failed"));
226 }
catch (
const TxExecutionException& e) {
227 vinfo(
"Revertible failure while simulating tx ",
tx.hash,
": ", e.what());
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;
246 Gas gas_used_by_teardown = { 0, 0 };
250 if (!
tx.teardown_enqueued_call.has_value()) {
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,
258 teardown_enqueued_call.calldata));
260 constexpr Gas start_gas = { 0, 0 };
263 teardown_enqueued_call.request.msg_sender,
265 teardown_enqueued_call.calldata,
266 teardown_enqueued_call.request.calldata_hash,
267 teardown_enqueued_call.request.is_static_call,
273 gas_used_by_teardown = result.
gas_used;
274 vinfo(
"[TEARDOWN] Enqueued call to ",
275 teardown_enqueued_call.request.contract_address,
277 get_halting_information(result));
289 throw TxExecutionException(
290 format(
"[TEARDOWN] Enqueued call to ", teardown_enqueued_call.request.contract_address,
" failed"));
297 }
catch (
const TxExecutionException& e) {
299 vinfo(
"Teardown failure while simulating tx ",
tx.hash,
": ", e.what());
309 pay_fee(
tx.fee_payer, fee, fee_per_da_gas, fee_per_l2_gas);
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,
321 .public_gas =
tx_context.gas_used + gas_used_by_teardown -
tx.gas_used_by_private,
326 .transaction_fee = fee,
345 const FF& transaction_fee,
347 const Gas& start_gas,
353 .state_before = state_before,
354 .state_after = state_after,
355 .reverted = !success,
359 .transaction_fee = transaction_fee,
361 .calldata_size =
static_cast<uint32_t
>(call.
calldata.size()),
363 .start_gas = start_gas,
387 throw TxExecutionException(
"Maximum number of nullifiers reached");
397 revertible ?
"R" :
"NR",
398 "_NULLIFIER_INSERTION] UNRECOVERABLE ERROR! Nullifier collision: ",
403 .state_before = state_before,
404 .state_after =
tx_context.serialize_tx_context_event(),
408 }
catch (
const TxExecutionException& e) {
411 .state_before = state_before,
412 .state_after =
tx_context.serialize_tx_context_event(),
439 throw TxExecutionException(
"Maximum number of note hashes reached");
449 .state_before = state_before,
450 .state_after =
tx_context.serialize_tx_context_event(),
453 }
catch (
const TxExecutionException& e) {
455 .state_before = state_before,
456 .state_after =
tx_context.serialize_tx_context_event(),
482 throw TxExecutionException(
"Maximum number of L2 to L1 messages reached");
487 .state_before = state_before,
488 .state_after =
tx_context.serialize_tx_context_event(),
491 }
catch (
const TxExecutionException& e) {
493 .state_before = state_before,
494 .state_after =
tx_context.serialize_tx_context_event(),
515 vinfo(
"[NON_REVERTIBLE] Inserting ",
516 tx.non_revertible_accumulated_data.nullifiers.size(),
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 ",
525 if (
tx.non_revertible_accumulated_data.nullifiers.empty()) {
528 for (
const auto& nullifier :
tx.non_revertible_accumulated_data.nullifiers) {
534 if (
tx.non_revertible_accumulated_data.note_hashes.empty()) {
537 for (
const auto& unique_note_hash :
tx.non_revertible_accumulated_data.note_hashes) {
543 if (
tx.non_revertible_accumulated_data.l2_to_l1_messages.empty()) {
546 for (
const auto& l2_to_l1_msg :
tx.non_revertible_accumulated_data.l2_to_l1_messages) {
568 vinfo(
"[REVERTIBLE] Inserting ",
569 tx.revertible_accumulated_data.nullifiers.size(),
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 ",
578 if (
tx.revertible_accumulated_data.nullifiers.empty()) {
581 for (
const auto& siloed_nullifier :
tx.revertible_accumulated_data.nullifiers) {
587 if (
tx.revertible_accumulated_data.note_hashes.empty()) {
590 for (
const auto& siloed_note_hash :
tx.revertible_accumulated_data.note_hashes) {
596 if (
tx.revertible_accumulated_data.l2_to_l1_messages.empty()) {
599 for (
const auto& l2_to_l1_msg :
tx.revertible_accumulated_data.l2_to_l1_messages) {
625 if (fee_payer == 0) {
627 vinfo(
"Fee payer is 0. Skipping fee enforcement. No one is paying the fee of ", fee);
633 throw TxExecutionException(
"Fee payer cannot be 0 unless skipping fee enforcement for simulation");
637 const FF fee_juice_balance_slot =
643 vinfo(
"Fee payer balance insufficient, but we're skipping fee enforcement");
645 fee_payer_balance = fee;
649 throw TxExecutionException(
"Not enough balance for fee payer to pay for transaction");
656 .state_before = state_before,
657 .state_after =
tx_context.serialize_tx_context_event(),
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,
680 .state_before = state_before,
681 .state_after =
tx_context.serialize_tx_context_event(),
694 .state_before = current_state,
695 .state_after = current_state,
711 .state_before = current_state,
712 .state_after = current_state,
728 return format(
"<calldata[0] undefined> (Contract Address: ", contract_address,
")");
739 return format(
"<selector: ", selector,
">");
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)
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 commit_checkpoint()=0
virtual void revert_checkpoint()=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 create_checkpoint()=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 revert_checkpoint()=0
virtual void unique_note_hash_write(const FF ¬e_hash)=0
virtual void create_checkpoint()=0
virtual FF storage_read(const AztecAddress &contract_address, const FF &slot) const =0
virtual void commit_checkpoint()=0
virtual void siloed_note_hash_write(const FF ¬e_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 void pad_trees()=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
bool skip_fee_enforcement
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 ¬e_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)
AVM range check gadget for witness generation.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
simulation::PublicDataTreeReadWriteEvent event
unsigned __int128 uint128_t
AztecAddress contract_address
std::vector< FF > calldata
PublicCallRequest request
AztecAddress contract_address
uint128_t effective_fee_per_da_gas
static PhaseLengths from_tx(const Tx &tx)
ScopedL2ToL1Message scoped_msg
SideEffectTracker side_effect_tracker