Line data Source code
1 : #include "../fd_executor.h" 2 : #include "fd_solfuzz_private.h" 3 : #include "fd_txn_harness.h" 4 : #include "generated/cost.pb.h" 5 : 6 : #include "../fd_cost_tracker.h" 7 : #include "../program/fd_compute_budget_program.h" 8 : 9 : ulong 10 : fd_solfuzz_pb_cost_run( fd_solfuzz_runner_t * runner, 11 : void const * input_, 12 : void ** output_, 13 : void * output_buf, 14 996 : ulong output_bufsz ) { 15 996 : fd_exec_test_cost_context_t const * input = fd_type_pun_const( input_ ); 16 996 : fd_exec_test_cost_result_t ** output = fd_type_pun( output_ ); 17 : 18 996 : if( FD_UNLIKELY( !input->has_tx || !input->has_features ) ) return 0UL; 19 : 20 996 : fd_banks_clear_bank( runner->banks, runner->bank ); 21 996 : runner->bank->f.slot = 1UL; 22 996 : FD_TEST( fd_solfuzz_pb_restore_features( &runner->bank->f.features, &input->features ) ); 23 : 24 996 : fd_txn_p_t * txn_p = fd_spad_alloc( runner->spad, alignof(fd_txn_p_t), sizeof(fd_txn_p_t) ); 25 996 : ulong txn_sz = fd_solfuzz_pb_txn_serialize( txn_p->payload, &input->tx ); 26 996 : if( FD_UNLIKELY( txn_sz==ULONG_MAX ) ) return 0UL; 27 : 28 996 : txn_p->payload_sz = (ushort)txn_sz; 29 996 : if( FD_UNLIKELY( !fd_txn_parse( txn_p->payload, txn_p->payload_sz, TXN( txn_p ), NULL ) ) ) { 30 0 : return 0UL; 31 0 : } 32 : 33 996 : fd_txn_in_t txn_in = {0}; 34 996 : txn_in.txn = txn_p; 35 : 36 996 : fd_txn_out_t * txn_out = fd_spad_alloc( runner->spad, alignof(fd_txn_out_t), sizeof(fd_txn_out_t) ); 37 996 : fd_memset( &txn_out->err, 0, sizeof(txn_out->err) ); 38 996 : fd_memset( &txn_out->details, 0, sizeof(txn_out->details) ); 39 996 : txn_out->accounts.is_setup = 0; 40 996 : txn_out->accounts.is_bundle = 0; 41 996 : txn_out->accounts.cnt = 0UL; 42 996 : txn_out->accounts.executable_cnt = 0UL; 43 996 : fd_compute_budget_details_new( &txn_out->details.compute_budget ); 44 996 : txn_out->details.loaded_accounts_data_size = txn_out->details.compute_budget.loaded_accounts_data_size_limit; 45 996 : txn_out->details.is_simple_vote = fd_txn_is_simple_vote_transaction( TXN( txn_p ), txn_p->payload ); 46 : 47 996 : int err; 48 996 : if( TXN( txn_p )->transaction_version==FD_TXN_V1 ) { 49 0 : err = fd_executor_sanitize_txn_v1_config( &txn_in, txn_out ); 50 996 : } else { 51 996 : err = fd_executor_compute_budget_program_execute_instructions( runner->bank, &txn_in, txn_out ); 52 996 : } 53 1001 : if( FD_LIKELY( !err ) ) err = fd_sanitize_compute_unit_limits( txn_out ); 54 996 : if( FD_UNLIKELY( err && input->mode==FD_EXEC_TEST_TXN_COST_MODE_ACTUAL ) ) return 0UL; 55 : 56 996 : if( input->mode==FD_EXEC_TEST_TXN_COST_MODE_ACTUAL ) { 57 485 : ulong actual_cost = (ulong)input->actual_programs_execution_cost; 58 485 : ulong limit = txn_out->details.compute_budget.compute_unit_limit; 59 485 : txn_out->details.compute_budget.compute_meter = fd_ulong_sat_sub( limit, fd_ulong_min( actual_cost, limit ) ); 60 485 : txn_out->details.loaded_accounts_data_size = (ulong)input->actual_loaded_accounts_data_size_bytes; 61 511 : } else { 62 : /* In ESTIMATE mode, a compute-budget processing failure still produces a 63 : cost with zero execution and loaded-accounts-data costs. Otherwise, 64 : programs_execution_cost = compute_unit_limit (see agave 65 : cost_model.rs:get_estimated_execution_cost). fd_cost_tracker computes 66 : programs_execution_cost as (limit - compute_meter). */ 67 511 : if( FD_UNLIKELY( err ) ) { 68 0 : txn_out->details.compute_budget.compute_unit_limit = 0UL; 69 0 : txn_out->details.loaded_accounts_data_size = 0UL; 70 511 : } else { 71 511 : txn_out->details.loaded_accounts_data_size = txn_out->details.compute_budget.loaded_accounts_data_size_limit; 72 511 : } 73 511 : txn_out->details.compute_budget.compute_meter = 0UL; 74 511 : } 75 : 76 996 : fd_cost_tracker_calculate_cost( runner->bank, &txn_in, txn_out ); 77 : 78 : /* In ACTUAL mode agave passes actual_programs_execution_cost through 79 : without clamping to compute_unit_limit (see agave cost_model.rs: 80 : calculate_cost_for_executed_transaction). The (limit - meter) 81 : formula in fd_cost_tracker inherently clamps, so overwrite with the 82 : raw actual value here for parity. */ 83 996 : if( input->mode==FD_EXEC_TEST_TXN_COST_MODE_ACTUAL ) { 84 485 : txn_out->details.txn_cost.transaction.programs_execution_cost = input->actual_programs_execution_cost; 85 485 : } 86 : 87 : /* Build output into the caller-provided scratch buffer */ 88 996 : ulong output_end = (ulong)output_buf + output_bufsz; 89 996 : FD_SCRATCH_ALLOC_INIT( l, output_buf ); 90 996 : fd_exec_test_cost_result_t * result = 91 996 : FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_cost_result_t), sizeof(fd_exec_test_cost_result_t) ); 92 996 : FD_TEST( _l <= output_end ); 93 996 : *result = (fd_exec_test_cost_result_t)FD_EXEC_TEST_COST_RESULT_INIT_ZERO; 94 : 95 996 : result->has_cost = 1; 96 996 : result->signature_cost = txn_out->details.txn_cost.transaction.signature_cost; 97 996 : result->write_lock_cost = txn_out->details.txn_cost.transaction.write_lock_cost; 98 996 : result->data_bytes_cost = txn_out->details.txn_cost.transaction.data_bytes_cost; 99 996 : result->programs_execution_cost = txn_out->details.txn_cost.transaction.programs_execution_cost; 100 996 : result->loaded_accounts_data_size_cost = txn_out->details.txn_cost.transaction.loaded_accounts_data_size_cost; 101 996 : result->allocated_accounts_data_size = txn_out->details.txn_cost.transaction.allocated_accounts_data_size; 102 : /* Saturating add to match agave's UsageCostDetails::sum (transaction_cost.rs: 103 : saturating_add chain). Plain + wraps on u64::MAX inputs (e.g. adversarial 104 : actual_programs_execution_cost = u64::MAX). */ 105 996 : result->total_cost = fd_ulong_sat_add( result->signature_cost, result->write_lock_cost ); 106 996 : result->total_cost = fd_ulong_sat_add( result->total_cost, result->data_bytes_cost ); 107 996 : result->total_cost = fd_ulong_sat_add( result->total_cost, result->programs_execution_cost ); 108 996 : result->total_cost = fd_ulong_sat_add( result->total_cost, result->loaded_accounts_data_size_cost ); 109 : 110 996 : ulong actual_end = FD_SCRATCH_ALLOC_FINI( l, 1UL ); 111 996 : *output = result; 112 996 : return actual_end - (ulong)output_buf; 113 996 : }