14class TxExecutionException :
public std::runtime_error {
16 TxExecutionException(
const std::string& message)
17 :
std::runtime_error(message)
64 const Gas& gas_limit =
tx.gas_settings.gas_limits;
65 const Gas& teardown_gas_limit =
tx.gas_settings.teardown_gas_limits;
75 .gas_limit = gas_limit,
76 .teardown_gas_limit = teardown_gas_limit,
80 vinfo(
"Simulating tx ",
83 tx.setup_enqueued_calls.size(),
84 " setup enqueued calls, ",
85 tx.app_logic_enqueued_calls.size(),
86 " app logic enqueued calls, and ",
87 tx.teardown_enqueued_call.has_value() ?
"1 teardown enqueued call" :
"no teardown enqueued call");
98 if (
tx.setup_enqueued_calls.empty()) {
101 for (
const auto& call :
tx.setup_enqueued_calls) {
102 vinfo(
"[SETUP] Executing enqueued call to ",
103 call.request.contract_address,
107 const Gas start_gas =
110 call.request.msg_sender,
113 call.request.is_static_call,
130 throw TxExecutionException(
131 format(
"[SETUP] UNRECOVERABLE ERROR! Enqueued call to ", call.request.contract_address,
" failed"));
150 }
catch (
const TxExecutionException& e) {
156 if (
tx.app_logic_enqueued_calls.empty()) {
159 for (
const auto& call :
tx.app_logic_enqueued_calls) {
160 vinfo(
"[APP_LOGIC] Executing enqueued call to ",
161 call.request.contract_address,
165 const Gas start_gas =
169 call.request.msg_sender,
172 call.request.is_static_call,
190 throw TxExecutionException(
191 format(
"[APP_LOGIC] Enqueued call to ", call.request.contract_address,
" failed"));
195 }
catch (
const TxExecutionException& e) {
196 vinfo(
"Revertible failure while simulating tx ",
tx.hash,
": ", e.what());
211 const uint128_t& fee_per_da_gas =
tx.effective_gas_fees.fee_per_da_gas;
212 const uint128_t& fee_per_l2_gas =
tx.effective_gas_fees.fee_per_l2_gas;
215 Gas gas_used_by_teardown = { 0, 0 };
219 if (!
tx.teardown_enqueued_call.has_value()) {
222 const auto& teardown_enqueued_call =
tx.teardown_enqueued_call.value();
223 vinfo(
"[TEARDOWN] Executing enqueued call to ",
224 teardown_enqueued_call.request.contract_address,
227 teardown_enqueued_call.calldata));
229 constexpr Gas start_gas = { 0, 0 };
232 teardown_enqueued_call.request.msg_sender,
234 teardown_enqueued_call.calldata,
235 teardown_enqueued_call.request.is_static_call,
241 gas_used_by_teardown = result.
gas_used;
252 throw TxExecutionException(
253 format(
"[TEARDOWN] Enqueued call to ", teardown_enqueued_call.request.contract_address,
" failed"));
260 }
catch (
const TxExecutionException& e) {
261 info(
"Teardown failure while simulating tx ",
tx.hash,
": ", e.what());
271 pay_fee(
tx.fee_payer, fee, fee_per_da_gas, fee_per_l2_gas);
280 .total_gas =
tx_context.gas_used + (
tx.teardown_enqueued_call ? (gas_used_by_teardown - teardown_gas_limit) :
Gas {0, 0}),
281 .teardown_gas = gas_used_by_teardown,
283 .public_gas =
tx_context.gas_used + gas_used_by_teardown -
tx.gas_used_by_private,
288 .transaction_fee = fee,
307 const FF& transaction_fee,
309 const Gas& start_gas,
315 .state_before = state_before,
316 .state_after = state_after,
317 .reverted = !success,
321 .transaction_fee = transaction_fee,
323 .calldata_size =
static_cast<uint32_t
>(call.
calldata.size()),
325 .start_gas = start_gas,
348 throw TxExecutionException(
"Maximum number of nullifiers reached");
354 throw TxExecutionException(e.what());
358 .state_before = state_before,
359 .state_after =
tx_context.serialize_tx_context_event(),
363 }
catch (
const TxExecutionException& e) {
366 .state_before = state_before,
367 .state_after =
tx_context.serialize_tx_context_event(),
394 throw TxExecutionException(
"Maximum number of note hashes reached");
404 .state_before = state_before,
405 .state_after =
tx_context.serialize_tx_context_event(),
408 }
catch (
const TxExecutionException& e) {
410 .state_before = state_before,
411 .state_after =
tx_context.serialize_tx_context_event(),
437 throw TxExecutionException(
"Maximum number of L2 to L1 messages reached");
442 .state_before = state_before,
443 .state_after =
tx_context.serialize_tx_context_event(),
446 }
catch (
const TxExecutionException& e) {
448 .state_before = state_before,
449 .state_after =
tx_context.serialize_tx_context_event(),
468 vinfo(
"[NON_REVERTIBLE] Inserting ",
469 tx.non_revertible_accumulated_data.nullifiers.size(),
471 tx.non_revertible_accumulated_data.note_hashes.size(),
472 " note hashes, and ",
473 tx.non_revertible_accumulated_data.l2_to_l1_messages.size(),
474 " L2 to L1 messages for tx ",
478 if (
tx.non_revertible_accumulated_data.nullifiers.empty()) {
481 for (
const auto&
nullifier :
tx.non_revertible_accumulated_data.nullifiers) {
487 if (
tx.non_revertible_accumulated_data.note_hashes.empty()) {
490 for (
const auto& unique_note_hash :
tx.non_revertible_accumulated_data.note_hashes) {
496 if (
tx.non_revertible_accumulated_data.l2_to_l1_messages.empty()) {
499 for (
const auto& l2_to_l1_msg :
tx.non_revertible_accumulated_data.l2_to_l1_messages) {
518 vinfo(
"[REVERTIBLE] Inserting ",
519 tx.revertible_accumulated_data.nullifiers.size(),
521 tx.revertible_accumulated_data.note_hashes.size(),
522 " note hashes, and ",
523 tx.revertible_accumulated_data.l2_to_l1_messages.size(),
524 " L2 to L1 messages for tx ",
528 if (
tx.revertible_accumulated_data.nullifiers.empty()) {
531 for (
const auto& siloed_nullifier :
tx.revertible_accumulated_data.nullifiers) {
537 if (
tx.revertible_accumulated_data.note_hashes.empty()) {
540 for (
const auto& siloed_note_hash :
tx.revertible_accumulated_data.note_hashes) {
546 if (
tx.revertible_accumulated_data.l2_to_l1_messages.empty()) {
549 for (
const auto& l2_to_l1_msg :
tx.revertible_accumulated_data.l2_to_l1_messages) {
573 if (fee_payer == 0) {
575 vinfo(
"Fee payer is 0. Skipping fee enforcement. No one is paying the fee of ", fee);
581 throw TxExecutionException(
"Fee payer cannot be 0 unless skipping fee enforcement for simulation");
590 vinfo(
"Fee payer balance insufficient, but we're skipping fee enforcement");
592 fee_payer_balance = fee;
596 throw TxExecutionException(
"Not enough balance for fee payer to pay for transaction");
603 .state_before = state_before,
604 .state_after =
tx_context.serialize_tx_context_event(),
608 .effective_fee_per_l2_gas = fee_per_l2_gas,
609 .fee_payer = fee_payer,
610 .fee_payer_balance = fee_payer_balance,
611 .fee_juice_balance_slot = fee_juice_balance_slot,
625 .state_before = state_before,
626 .state_after =
tx_context.serialize_tx_context_event(),
639 .state_before = current_state,
640 .state_after = current_state,
656 .state_before = current_state,
657 .state_after = current_state,
684 return format(
"<selector: ", selector,
">");
std::shared_ptr< Napi::ThreadSafeFunction > debug_name
#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
virtual std::unique_ptr< ContextInterface > make_enqueued_context(AztecAddress address, AztecAddress msg_sender, FF transaction_fee, std::span< const FF > calldata, bool is_static, Gas gas_limit, 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)
AztecAddress contract_address
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