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 6048 : #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 10995 : fd_txn_instr_t const * instr ) { 18 10995 : fd_pubkey_t const * txn_accs = ctx->accounts; 19 10995 : fd_pubkey_t const * program_pubkey = &txn_accs[ instr->program_id ]; 20 10995 : return !memcmp(program_pubkey, fd_solana_compute_budget_program_id.key, sizeof(fd_pubkey_t)); 21 10995 : } 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 6210 : fd_executor_compute_budget_program_execute_instructions( fd_exec_txn_ctx_t * ctx, fd_rawtxn_b_t const * txn_raw ) { 32 6210 : uint has_compute_units_limit_update = 0UL; 33 6210 : uint has_compute_units_price_update = 0UL; 34 6210 : uint has_requested_heap_size = 0UL; 35 6210 : uint has_loaded_accounts_data_size_limit_update = 0UL; 36 : 37 6210 : ushort requested_heap_size_instr_index = 0; 38 6210 : uint num_non_compute_budget_instrs = 0U; 39 : 40 6210 : uint updated_compute_unit_limit = 0U; 41 6210 : uint updated_requested_heap_size = 0U; 42 6210 : uint updated_loaded_accounts_data_size_limit = 0U; 43 6210 : ulong updated_compute_unit_price = 0UL; 44 : 45 6210 : uint prioritization_fee_type = FD_COMPUTE_BUDGET_PRIORITIZATION_FEE_TYPE_COMPUTE_UNIT_PRICE; 46 : 47 17121 : for( ushort i=0; i<ctx->txn_descriptor->instr_cnt; i++ ) { 48 10995 : fd_txn_instr_t const * instr = &ctx->txn_descriptor->instr[i]; 49 : 50 10995 : if( !is_compute_budget_instruction( ctx, instr ) ) { 51 10668 : num_non_compute_budget_instrs++; 52 10668 : continue; 53 10668 : } 54 : /* Deserialize the ComputeBudgetInstruction enum */ 55 327 : uchar * data = (uchar *)txn_raw->raw + instr->data_off; 56 : 57 327 : fd_compute_budget_program_instruction_t instruction; 58 327 : fd_bincode_decode_ctx_t decode_ctx = { 59 327 : .data = data, 60 327 : .dataend = &data[ instr->data_sz ], 61 327 : .valloc = ctx->valloc, 62 327 : }; 63 : 64 327 : int ret = fd_compute_budget_program_instruction_decode( &instruction, &decode_ctx ); 65 327 : 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 261 : 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 75 : case fd_compute_budget_program_instruction_enum_set_compute_unit_limit: { 85 75 : if( FD_UNLIKELY( has_compute_units_limit_update ) ) { 86 3 : return FD_RUNTIME_TXN_ERR_DUPLICATE_INSTRUCTION; 87 3 : } 88 : 89 72 : has_compute_units_limit_update = 1U; 90 72 : updated_compute_unit_limit = instruction.inner.set_compute_unit_limit; 91 : 92 72 : break; 93 75 : } 94 63 : case fd_compute_budget_program_instruction_enum_set_compute_unit_price: { 95 63 : if( FD_UNLIKELY( has_compute_units_price_update ) ) { 96 3 : return FD_RUNTIME_TXN_ERR_DUPLICATE_INSTRUCTION; 97 3 : } 98 : 99 60 : has_compute_units_price_update = 1U; 100 60 : prioritization_fee_type = FD_COMPUTE_BUDGET_PRIORITIZATION_FEE_TYPE_COMPUTE_UNIT_PRICE; 101 60 : updated_compute_unit_price = instruction.inner.set_compute_unit_price; 102 : 103 60 : break; 104 63 : } 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 261 : } 120 261 : } 121 : 122 : /* https://github.com/anza-xyz/agave/blob/v2.1/runtime-transaction/src/compute_budget_instruction_details.rs#L51-L64 */ 123 6126 : 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 6117 : if( has_compute_units_limit_update ) { 133 69 : ctx->compute_unit_limit = fd_ulong_min( FD_MAX_COMPUTE_UNIT_LIMIT, updated_compute_unit_limit ); 134 6048 : } else { 135 6048 : ctx->compute_unit_limit = fd_ulong_min( FD_MAX_COMPUTE_UNIT_LIMIT, 136 6048 : (ulong)fd_uint_sat_mul( num_non_compute_budget_instrs, DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT ) ); 137 6048 : } 138 6117 : ctx->compute_meter = ctx->compute_unit_limit; 139 : 140 6117 : if( has_compute_units_price_update ) { 141 57 : ctx->prioritization_fee_type = prioritization_fee_type; 142 57 : ctx->compute_unit_price = updated_compute_unit_price; 143 57 : } 144 : 145 : /* https://github.com/anza-xyz/agave/blob/v2.1/runtime-transaction/src/compute_budget_instruction_details.rs#L84-L93 */ 146 6117 : 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 6111 : return FD_RUNTIME_EXECUTE_SUCCESS; 155 6117 : } 156 : 157 : 158 543 : int fd_compute_budget_program_execute( fd_exec_instr_ctx_t * ctx ) { 159 543 : FD_EXEC_CU_UPDATE( ctx, DEFAULT_COMPUTE_UNITS ); 160 519 : return FD_EXECUTOR_INSTR_SUCCESS; 161 543 : }