14class TxExecutionException :
public std::runtime_error {
16 TxExecutionException(
const std::string& message)
17 :
std::runtime_error(message)
66 const Gas& gas_limit =
tx.gas_settings.gas_limits;
67 const Gas& teardown_gas_limit =
tx.gas_settings.teardown_gas_limits;
72 .gas_limit = gas_limit,
73 .teardown_gas_limit = teardown_gas_limit,
77 vinfo(
"Simulating tx ",
80 tx.setup_enqueued_calls.size(),
81 " setup enqueued calls, ",
82 tx.app_logic_enqueued_calls.size(),
83 " app logic enqueued calls, and ",
84 tx.teardown_enqueued_call.has_value() ?
"1 teardown enqueued call" :
"no teardown enqueued call");
95 if (
tx.setup_enqueued_calls.empty()) {
98 for (
const auto& call :
tx.setup_enqueued_calls) {
99 vinfo(
"[SETUP] Executing enqueued call to ",
100 call.request.contract_address,
104 const Gas start_gas =
107 call.request.msg_sender,
110 call.request.calldata_hash,
111 call.request.is_static_call,
128 throw TxExecutionException(
129 format(
"[SETUP] UNRECOVERABLE ERROR! Enqueued call to ", call.request.contract_address,
" failed"));
148 }
catch (
const TxExecutionException& e) {
154 if (
tx.app_logic_enqueued_calls.empty()) {
157 for (
const auto& call :
tx.app_logic_enqueued_calls) {
158 vinfo(
"[APP_LOGIC] Executing enqueued call to ",
159 call.request.contract_address,
163 const Gas start_gas =
167 call.request.msg_sender,
170 call.request.calldata_hash,
171 call.request.is_static_call,
189 throw TxExecutionException(
190 format(
"[APP_LOGIC] Enqueued call to ", call.request.contract_address,
" failed"));
194 }
catch (
const TxExecutionException& e) {
195 vinfo(
"Revertible failure while simulating tx ",
tx.hash,
": ", e.what());
210 const uint128_t& fee_per_da_gas =
tx.effective_gas_fees.fee_per_da_gas;
211 const uint128_t& fee_per_l2_gas =
tx.effective_gas_fees.fee_per_l2_gas;
214 Gas gas_used_by_teardown = { 0, 0 };
218 if (!
tx.teardown_enqueued_call.has_value()) {
221 const auto& teardown_enqueued_call =
tx.teardown_enqueued_call.value();
222 vinfo(
"[TEARDOWN] Executing enqueued call to ",
223 teardown_enqueued_call.request.contract_address,
226 teardown_enqueued_call.calldata));
228 constexpr Gas start_gas = { 0, 0 };
231 teardown_enqueued_call.request.msg_sender,
233 teardown_enqueued_call.calldata,
234 teardown_enqueued_call.request.calldata_hash,
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) {
262 vinfo(
"Teardown failure while simulating tx ",
tx.hash,
": ", e.what());
272 pay_fee(
tx.fee_payer, fee, fee_per_da_gas, fee_per_l2_gas);
281 .total_gas =
tx_context.gas_used + (
tx.teardown_enqueued_call ? (gas_used_by_teardown - teardown_gas_limit) :
Gas {0, 0}),
282 .teardown_gas = gas_used_by_teardown,
284 .public_gas =
tx_context.gas_used + gas_used_by_teardown -
tx.gas_used_by_private,
289 .transaction_fee = fee,
308 const FF& transaction_fee,
310 const Gas& start_gas,
316 .state_before = state_before,
317 .state_after = state_after,
318 .reverted = !success,
322 .transaction_fee = transaction_fee,
324 .calldata_size =
static_cast<uint32_t
>(call.
calldata.size()),
326 .start_gas = start_gas,
349 throw TxExecutionException(
"Maximum number of nullifiers reached");
355 throw TxExecutionException(e.what());
359 .state_before = state_before,
360 .state_after =
tx_context.serialize_tx_context_event(),
364 }
catch (
const TxExecutionException& e) {
367 .state_before = state_before,
368 .state_after =
tx_context.serialize_tx_context_event(),
395 throw TxExecutionException(
"Maximum number of note hashes reached");
405 .state_before = state_before,
406 .state_after =
tx_context.serialize_tx_context_event(),
409 }
catch (
const TxExecutionException& e) {
411 .state_before = state_before,
412 .state_after =
tx_context.serialize_tx_context_event(),
438 throw TxExecutionException(
"Maximum number of L2 to L1 messages reached");
443 .state_before = state_before,
444 .state_after =
tx_context.serialize_tx_context_event(),
447 }
catch (
const TxExecutionException& e) {
449 .state_before = state_before,
450 .state_after =
tx_context.serialize_tx_context_event(),
471 vinfo(
"[NON_REVERTIBLE] Inserting ",
472 tx.non_revertible_accumulated_data.nullifiers.size(),
474 tx.non_revertible_accumulated_data.note_hashes.size(),
475 " note hashes, and ",
476 tx.non_revertible_accumulated_data.l2_to_l1_messages.size(),
477 " L2 to L1 messages for tx ",
481 if (
tx.non_revertible_accumulated_data.nullifiers.empty()) {
484 for (
const auto&
nullifier :
tx.non_revertible_accumulated_data.nullifiers) {
490 if (
tx.non_revertible_accumulated_data.note_hashes.empty()) {
493 for (
const auto& unique_note_hash :
tx.non_revertible_accumulated_data.note_hashes) {
499 if (
tx.non_revertible_accumulated_data.l2_to_l1_messages.empty()) {
502 for (
const auto& l2_to_l1_msg :
tx.non_revertible_accumulated_data.l2_to_l1_messages) {
523 vinfo(
"[REVERTIBLE] Inserting ",
524 tx.revertible_accumulated_data.nullifiers.size(),
526 tx.revertible_accumulated_data.note_hashes.size(),
527 " note hashes, and ",
528 tx.revertible_accumulated_data.l2_to_l1_messages.size(),
529 " L2 to L1 messages for tx ",
533 if (
tx.revertible_accumulated_data.nullifiers.empty()) {
536 for (
const auto& siloed_nullifier :
tx.revertible_accumulated_data.nullifiers) {
542 if (
tx.revertible_accumulated_data.note_hashes.empty()) {
545 for (
const auto& siloed_note_hash :
tx.revertible_accumulated_data.note_hashes) {
551 if (
tx.revertible_accumulated_data.l2_to_l1_messages.empty()) {
554 for (
const auto& l2_to_l1_msg :
tx.revertible_accumulated_data.l2_to_l1_messages) {
580 if (fee_payer == 0) {
582 vinfo(
"Fee payer is 0. Skipping fee enforcement. No one is paying the fee of ", fee);
588 throw TxExecutionException(
"Fee payer cannot be 0 unless skipping fee enforcement for simulation");
597 vinfo(
"Fee payer balance insufficient, but we're skipping fee enforcement");
599 fee_payer_balance = fee;
603 throw TxExecutionException(
"Not enough balance for fee payer to pay for transaction");
610 .state_before = state_before,
611 .state_after =
tx_context.serialize_tx_context_event(),
615 .effective_fee_per_l2_gas = fee_per_l2_gas,
616 .fee_payer = fee_payer,
617 .fee_payer_balance = fee_payer_balance,
618 .fee_juice_balance_slot = fee_juice_balance_slot,
634 .state_before = state_before,
635 .state_after =
tx_context.serialize_tx_context_event(),
648 .state_before = current_state,
649 .state_after = current_state,
665 .state_before = current_state,
666 .state_after = current_state,
693 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
#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)
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