Line data Source code
1 : #include "fd_compute_budget_program.h" 2 : 3 : #include "../fd_runtime_err.h" 4 : #include "../fd_system_ids.h" 5 : #include "../fd_executor.h" 6 : #include "../context/fd_exec_instr_ctx.h" 7 : #include "../context/fd_exec_txn_ctx.h" 8 : #include "../context/fd_exec_slot_ctx.h" 9 : #include "../context/fd_exec_epoch_ctx.h" 10 : #include "../../vm/fd_vm.h" 11 : 12 6762 : #define DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT (200000) 13 : #define DEFAULT_COMPUTE_UNITS (150UL) 14 : 15 : FD_FN_PURE static inline int 16 : is_compute_budget_instruction( fd_exec_txn_ctx_t const * ctx, 17 11745 : fd_txn_instr_t const * instr ) { 18 11745 : fd_pubkey_t const * txn_accs = ctx->accounts; 19 11745 : fd_pubkey_t const * program_pubkey = &txn_accs[ instr->program_id ]; 20 11745 : return !memcmp(program_pubkey, fd_solana_compute_budget_program_id.key, sizeof(fd_pubkey_t)); 21 11745 : } 22 : 23 : /* https://github.com/anza-xyz/agave/blob/16de8b75ebcd57022409b422de557dd37b1de8db/compute-budget/src/compute_budget_processor.rs#L150-L153 */ 24 : FD_FN_PURE static inline int 25 57 : sanitize_requested_heap_size( ulong bytes ) { 26 57 : return !(bytes>FD_MAX_HEAP_FRAME_BYTES || bytes<FD_MIN_HEAP_FRAME_BYTES || bytes%FD_HEAP_FRAME_BYTES_GRANULARITY); 27 57 : } 28 : 29 : /* https://github.com/anza-xyz/agave/blob/16de8b75ebcd57022409b422de557dd37b1de8db/compute-budget/src/compute_budget_processor.rs#L69-L148 */ 30 : int 31 6930 : fd_executor_compute_budget_program_execute_instructions( fd_exec_txn_ctx_t * ctx, fd_rawtxn_b_t const * txn_raw ) { 32 6930 : uint has_compute_units_limit_update = 0UL; 33 6930 : uint has_compute_units_price_update = 0UL; 34 6930 : uint has_requested_heap_size = 0UL; 35 6930 : uint has_loaded_accounts_data_size_limit_update = 0UL; 36 : 37 6930 : ushort requested_heap_size_instr_index = 0; 38 6930 : uint num_non_compute_budget_instrs = 0U; 39 : 40 6930 : uint updated_compute_unit_limit = 0U; 41 6930 : uint updated_requested_heap_size = 0U; 42 6930 : uint updated_loaded_accounts_data_size_limit = 0U; 43 6930 : ulong updated_compute_unit_price = 0UL; 44 : 45 6930 : uint prioritization_fee_type = FD_COMPUTE_BUDGET_PRIORITIZATION_FEE_TYPE_COMPUTE_UNIT_PRICE; 46 : 47 18591 : for( ushort i=0; i<ctx->txn_descriptor->instr_cnt; i++ ) { 48 11745 : fd_txn_instr_t const * instr = &ctx->txn_descriptor->instr[i]; 49 : 50 11745 : if( !is_compute_budget_instruction( ctx, instr ) ) { 51 11409 : num_non_compute_budget_instrs++; 52 11409 : continue; 53 11409 : } 54 : /* Deserialize the ComputeBudgetInstruction enum */ 55 336 : uchar * data = (uchar *)txn_raw->raw + instr->data_off; 56 : 57 336 : fd_compute_budget_program_instruction_t instruction; 58 336 : fd_bincode_decode_ctx_t decode_ctx = { 59 336 : .data = data, 60 336 : .dataend = &data[ instr->data_sz ], 61 336 : .valloc = fd_spad_virtual( ctx->spad ), 62 336 : }; 63 : 64 336 : int ret = fd_compute_budget_program_instruction_decode( &instruction, &decode_ctx ); 65 336 : if ( ret ) { 66 66 : FD_LOG_WARNING(("fd_compute_budget_program_instruction_decode failed")); 67 66 : FD_LOG_HEXDUMP_WARNING(("cbi data", data, instr->data_sz)); 68 66 : FD_TXN_ERR_FOR_LOG_INSTR( ctx, FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA, i ); 69 66 : return FD_RUNTIME_TXN_ERR_INSTRUCTION_ERROR; 70 66 : } 71 : 72 270 : switch( instruction.discriminant ) { 73 69 : case fd_compute_budget_program_instruction_enum_request_heap_frame: { 74 69 : if( FD_UNLIKELY( has_requested_heap_size ) ) { 75 6 : return FD_RUNTIME_TXN_ERR_DUPLICATE_INSTRUCTION; 76 6 : } 77 : 78 63 : has_requested_heap_size = 1U; 79 63 : updated_requested_heap_size = instruction.inner.request_heap_frame; 80 63 : requested_heap_size_instr_index = i; 81 : 82 63 : break; 83 69 : } 84 81 : case fd_compute_budget_program_instruction_enum_set_compute_unit_limit: { 85 81 : if( FD_UNLIKELY( has_compute_units_limit_update ) ) { 86 3 : return FD_RUNTIME_TXN_ERR_DUPLICATE_INSTRUCTION; 87 3 : } 88 : 89 78 : has_compute_units_limit_update = 1U; 90 78 : updated_compute_unit_limit = instruction.inner.set_compute_unit_limit; 91 : 92 78 : break; 93 81 : } 94 66 : case fd_compute_budget_program_instruction_enum_set_compute_unit_price: { 95 66 : if( FD_UNLIKELY( has_compute_units_price_update ) ) { 96 3 : return FD_RUNTIME_TXN_ERR_DUPLICATE_INSTRUCTION; 97 3 : } 98 : 99 63 : has_compute_units_price_update = 1U; 100 63 : prioritization_fee_type = FD_COMPUTE_BUDGET_PRIORITIZATION_FEE_TYPE_COMPUTE_UNIT_PRICE; 101 63 : updated_compute_unit_price = instruction.inner.set_compute_unit_price; 102 : 103 63 : break; 104 66 : } 105 48 : case fd_compute_budget_program_instruction_enum_set_loaded_accounts_data_size_limit: { 106 48 : if( FD_UNLIKELY( has_loaded_accounts_data_size_limit_update ) ) { 107 0 : return FD_RUNTIME_TXN_ERR_DUPLICATE_INSTRUCTION; 108 0 : } 109 : 110 48 : has_loaded_accounts_data_size_limit_update = 1U; 111 48 : updated_loaded_accounts_data_size_limit = instruction.inner.set_loaded_accounts_data_size_limit; 112 : 113 48 : break; 114 48 : } 115 6 : default: { 116 6 : FD_TXN_ERR_FOR_LOG_INSTR( ctx, FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA, i ); 117 6 : return FD_RUNTIME_TXN_ERR_INSTRUCTION_ERROR; 118 48 : } 119 270 : } 120 270 : } 121 : 122 : /* https://github.com/anza-xyz/agave/blob/v2.1/runtime-transaction/src/compute_budget_instruction_details.rs#L51-L64 */ 123 6846 : if( has_requested_heap_size ) { 124 57 : if( FD_UNLIKELY( !sanitize_requested_heap_size( updated_requested_heap_size ) ) ) { 125 9 : FD_TXN_ERR_FOR_LOG_INSTR( ctx, FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA, requested_heap_size_instr_index ); 126 9 : return FD_RUNTIME_TXN_ERR_INSTRUCTION_ERROR; 127 9 : } 128 48 : ctx->heap_size = updated_requested_heap_size; 129 48 : } 130 : 131 : /* https://github.com/anza-xyz/agave/blob/v2.1/runtime-transaction/src/compute_budget_instruction_details.rs#L66-L76 */ 132 6837 : if( has_compute_units_limit_update ) { 133 75 : ctx->compute_unit_limit = fd_ulong_min( FD_MAX_COMPUTE_UNIT_LIMIT, updated_compute_unit_limit ); 134 6762 : } else { 135 6762 : ctx->compute_unit_limit = fd_ulong_min( FD_MAX_COMPUTE_UNIT_LIMIT, 136 6762 : (ulong)fd_uint_sat_mul( num_non_compute_budget_instrs, DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT ) ); 137 6762 : } 138 6837 : ctx->compute_meter = ctx->compute_unit_limit; 139 : 140 6837 : if( has_compute_units_price_update ) { 141 60 : ctx->prioritization_fee_type = prioritization_fee_type; 142 60 : ctx->compute_unit_price = updated_compute_unit_price; 143 60 : } 144 : 145 : /* https://github.com/anza-xyz/agave/blob/v2.1/runtime-transaction/src/compute_budget_instruction_details.rs#L84-L93 */ 146 6837 : if( has_loaded_accounts_data_size_limit_update ) { 147 48 : if( FD_UNLIKELY( updated_loaded_accounts_data_size_limit==0UL ) ) { 148 6 : return FD_RUNTIME_TXN_ERR_INVALID_LOADED_ACCOUNTS_DATA_SIZE_LIMIT; 149 6 : } 150 42 : ctx->loaded_accounts_data_size_limit = 151 42 : fd_ulong_min( FD_VM_LOADED_ACCOUNTS_DATA_SIZE_LIMIT, updated_loaded_accounts_data_size_limit ); 152 42 : } 153 : 154 6831 : return FD_RUNTIME_EXECUTE_SUCCESS; 155 6837 : } 156 : 157 : 158 546 : int fd_compute_budget_program_execute( fd_exec_instr_ctx_t * ctx ) { 159 546 : FD_EXEC_CU_UPDATE( ctx, DEFAULT_COMPUTE_UNITS ); 160 522 : return FD_EXECUTOR_INSTR_SUCCESS; 161 546 : }