Line data Source code
1 : #include "fd_event_runtime.h" 2 : #include "../../disco/events/fd_event_report.h" 3 : 4 : void 5 : fd_event_runtime_txn_emit( fd_txn_in_t const * txn_in, 6 : fd_txn_out_t const * txn_out, 7 0 : fd_bank_t const * bank ) { 8 0 : if( FD_LIKELY( !fd_event_tl ) ) return; 9 0 : if( FD_UNLIKELY( !txn_in->txn || !bank ) ) return; 10 : 11 0 : fd_event_runtime_txn_t ev = {0}; 12 : 13 : /* Identity */ 14 0 : uchar const * payload = (uchar const *)txn_in->txn->payload; 15 0 : fd_txn_t const * txn_d = TXN( txn_in->txn ); 16 0 : fd_memcpy( ev.signature, payload + txn_d->signature_off, 64UL ); 17 0 : fd_memcpy( ev.blockhash, txn_out->details.blockhash.uc, 32UL ); 18 0 : fd_memcpy( ev.fec_merkle_root, txn_in->fec_merkle_root, 32UL ); 19 0 : if( FD_LIKELY( txn_out->accounts.cnt>0UL ) ) { 20 0 : fd_memcpy( ev.fee_payer, txn_out->accounts.keys[ 0 ].uc, 32UL ); 21 0 : } 22 : 23 0 : ev.bank_seq = bank->bank_seq; 24 0 : ev.slot = bank->f.slot; 25 0 : ev.epoch = bank->f.epoch; 26 0 : ev.index_in_slot = txn_in->index_in_slot; 27 0 : ev.commit_index_in_slot = txn_out->err.is_committable ? txn_out->details.commit_index_in_slot : 0UL; 28 : 29 : /* Flags */ 30 0 : ev.is_simple_vote = !!txn_out->details.is_simple_vote; 31 0 : ev.is_bundle = !!txn_in->bundle.is_bundle; 32 0 : ev.is_committable = !!txn_out->err.is_committable; 33 0 : ev.is_fees_only = !!txn_out->err.is_fees_only; 34 : 35 : /* Errors */ 36 0 : ev.txn_err = fd_event_txn_err_from_txn_err( txn_out->err.txn_err ); 37 0 : int is_instr_err = ( txn_out->err.txn_err==FD_RUNTIME_TXN_ERR_INSTRUCTION_ERROR ); 38 0 : ev.exec_err = is_instr_err ? fd_event_exec_err_from_exec_err ( txn_out->err.exec_err ) : FD_EVENT_RUNTIME_TXN_EXEC_ERR_SUCCESS; 39 0 : ev.exec_err_kind = is_instr_err ? fd_event_exec_err_kind_from_exec_err_kind( txn_out->err.exec_err_kind ) : FD_EVENT_RUNTIME_TXN_EXEC_ERR_KIND_NONE; 40 0 : ev.exec_err_idx = is_instr_err ? txn_out->err.exec_err_idx : UINT_MAX; 41 0 : ev.custom_err = ( is_instr_err && txn_out->err.exec_err==FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR ) 42 0 : ? txn_out->err.custom_err : UINT_MAX; 43 : 44 : /* Compute budget */ 45 0 : fd_compute_budget_details_t const * cb = &txn_out->details.compute_budget; 46 0 : ev.compute_unit_limit = cb->compute_unit_limit; 47 0 : ev.compute_unit_price = cb->compute_unit_price; 48 0 : ev.compute_units_consumed = (cb->compute_unit_limit > cb->compute_meter) 49 0 : ? cb->compute_unit_limit - cb->compute_meter : 0UL; 50 0 : ev.heap_size = cb->heap_size; 51 0 : ev.num_builtin_instrs = cb->num_builtin_instrs; 52 0 : ev.num_non_builtin_instrs = cb->num_non_builtin_instrs; 53 0 : ev.loaded_accounts_data_size = txn_out->details.loaded_accounts_data_size; 54 0 : ev.loaded_accounts_data_size_limit = cb->loaded_accounts_data_size_limit; 55 0 : ev.accounts_resize_delta = txn_out->details.accounts_resize_delta; 56 : 57 : /* Fees */ 58 0 : ev.execution_fee = txn_out->details.execution_fee; 59 0 : ev.priority_fee = txn_out->details.priority_fee; 60 0 : ev.tips = txn_out->details.tips; 61 0 : ev.signature_count = txn_out->details.signature_count; 62 : 63 : /* Cost-tracker (non-vote only) */ 64 0 : if( txn_out->details.txn_cost.type==FD_TXN_COST_TYPE_TRANSACTION ) { 65 0 : fd_usage_cost_details_t const * c = &txn_out->details.txn_cost.transaction; 66 0 : ev.cost_signature = c->signature_cost; 67 0 : ev.cost_write_lock = c->write_lock_cost; 68 0 : ev.cost_data_bytes = c->data_bytes_cost; 69 0 : ev.cost_programs_execution = c->programs_execution_cost; 70 0 : ev.cost_loaded_accounts_data_size = c->loaded_accounts_data_size_cost; 71 0 : ev.cost_allocated_accounts_data_size = c->allocated_accounts_data_size; 72 0 : } 73 : 74 : /* account_diffs: walk per-txn writable accounts, compare prior vs current */ 75 0 : ulong diff_cnt = 0UL; 76 0 : for( ulong i=0UL; i<txn_out->accounts.cnt; i++ ) { 77 0 : if( diff_cnt>=64UL ) break; 78 0 : fd_acc_t const * acc = txn_out->accounts.account[ i ]; 79 0 : if( FD_UNLIKELY( !acc ) ) continue; 80 0 : if( !txn_out->accounts.is_writable[ i ] ) continue; 81 : 82 0 : int changed = ( acc->prior_lamports != acc->lamports ) || 83 0 : ( acc->prior_executable != acc->executable ) || 84 0 : ( acc->prior_data_len != acc->data_len ) || 85 0 : ( memcmp( acc->prior_owner, acc->owner, 32UL )!=0 ); 86 0 : if( !changed && acc->prior_data && acc->data && 87 0 : memcmp( acc->prior_data, acc->data, acc->data_len )!=0 ) { 88 0 : changed = 1; 89 0 : } 90 0 : if( !changed ) continue; 91 : 92 0 : fd_event_runtime_txn_account_diffs_t * d = &ev.account_diffs[ diff_cnt++ ]; 93 0 : fd_memcpy( d->pubkey, txn_out->accounts.keys[ i ].uc, 32UL ); 94 0 : fd_memcpy( d->owner, acc->owner, 32UL ); 95 0 : fd_memcpy( d->prev_owner, acc->prior_owner, 32UL ); 96 0 : d->lamports = acc->lamports; 97 0 : d->prev_lamports = acc->prior_lamports; 98 0 : d->data_sz = acc->data_len; 99 0 : d->prev_data_sz = acc->prior_data_len; 100 0 : d->is_executable = !!acc->executable; 101 0 : d->is_stake_update = !!txn_out->accounts.stake_update[ i ]; 102 0 : d->is_vote_update = !!txn_out->accounts.vote_update [ i ]; 103 0 : d->is_new_vote = !!txn_out->accounts.new_vote [ i ]; 104 0 : d->is_rm_vote = !!txn_out->accounts.rm_vote [ i ]; 105 0 : } 106 0 : ev.account_diffs_cnt = diff_cnt; 107 : 108 : /* writable / readonly account lists */ 109 0 : ulong w_cnt = 0UL, r_cnt = 0UL; 110 0 : for( ulong i=0UL; i<txn_out->accounts.cnt; i++ ) { 111 0 : fd_acc_t const * acc = txn_out->accounts.account[ i ]; 112 0 : if( FD_UNLIKELY( !acc ) ) continue; 113 0 : if( txn_out->accounts.is_writable[ i ] ) { 114 0 : if( w_cnt<64UL ) fd_memcpy( ev.writable_accounts[ w_cnt++ ], txn_out->accounts.keys[ i ].uc, 32UL ); 115 0 : } else { 116 0 : if( r_cnt<64UL ) fd_memcpy( ev.readonly_accounts[ r_cnt++ ], txn_out->accounts.keys[ i ].uc, 32UL ); 117 0 : } 118 0 : } 119 0 : ev.writable_accounts_cnt = w_cnt; 120 0 : ev.readonly_accounts_cnt = r_cnt; 121 : 122 : /* program_ids: walk top-level instructions, dedupe in first-occurrence order */ 123 0 : ulong p_cnt = 0UL; 124 0 : for( ushort ii=0; ii<txn_d->instr_cnt; ii++ ) { 125 0 : if( p_cnt>=64UL ) break; 126 0 : uchar pid_idx = txn_d->instr[ ii ].program_id; 127 0 : if( (ulong)pid_idx>=txn_out->accounts.cnt ) continue; 128 0 : uchar const * pid = txn_out->accounts.keys[ pid_idx ].uc; 129 0 : int seen = 0; 130 0 : for( ulong j=0UL; j<p_cnt; j++ ) { 131 0 : if( memcmp( ev.program_ids[ j ], pid, 32UL )==0 ) { seen = 1; break; } 132 0 : } 133 0 : if( !seen ) fd_memcpy( ev.program_ids[ p_cnt++ ], pid, 32UL ); 134 0 : } 135 0 : ev.program_ids_cnt = p_cnt; 136 : 137 0 : fd_event_report_runtime_txn( &ev ); 138 0 : }