Skip to content

Commit

Permalink
- update process_compute_budget_instructions function to collect nati…
Browse files Browse the repository at this point in the history
…ve and non-native ix costs separately

- sanity check user specified compute-unit-limit
- add transaction error for invalid compute-unit-limit
  • Loading branch information
tao-stones committed Apr 12, 2024
1 parent cf1299a commit 7484bfd
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 9 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions program-runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ num-derive = { workspace = true }
num-traits = { workspace = true }
percentage = { workspace = true }
rand = { workspace = true }
solana-builtin-cost-info = { workspace = true }
solana-frozen-abi = { workspace = true }
solana-frozen-abi-macro = { workspace = true }
solana-measure = { workspace = true }
Expand Down
34 changes: 25 additions & 9 deletions program-runtime/src/compute_budget_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use {
fee::FeeBudgetLimits,
instruction::{CompiledInstruction, InstructionError},
pubkey::Pubkey,
saturating_add_assign,
transaction::TransactionError,
},
};
Expand Down Expand Up @@ -68,13 +69,26 @@ impl From<ComputeBudgetLimits> for FeeBudgetLimits {
pub fn process_compute_budget_instructions<'a>(
instructions: impl Iterator<Item = (&'a Pubkey, &'a CompiledInstruction)>,
) -> Result<ComputeBudgetLimits, TransactionError> {
let mut num_non_compute_budget_instructions: u32 = 0;
let mut updated_compute_unit_limit = None;
let mut updated_compute_unit_price = None;
let mut requested_heap_size = None;
let mut updated_loaded_accounts_data_size_limit = None;
// The change needs to be feature gated, since it's break consensus
let mut static_builtin_ix_costs: u32 = 0;
let mut non_builtin_ix_costs: u32 = 0;

for (i, (program_id, instruction)) in instructions.enumerate() {
if let Some(builtin_ix_cost) =
solana_builtin_cost_info::BUILT_IN_INSTRUCTION_COSTS.get(program_id)
{
saturating_add_assign!(
static_builtin_ix_costs,
(*builtin_ix_cost).try_into().unwrap()
);
} else {
saturating_add_assign!(non_builtin_ix_costs, DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT);
}

if compute_budget::check_id(program_id) {
let invalid_instruction_data_error = TransactionError::InstructionError(
i as u8,
Expand Down Expand Up @@ -113,10 +127,15 @@ pub fn process_compute_budget_instructions<'a>(
}
_ => return Err(invalid_instruction_data_error),
}
} else {
// only include non-request instructions in default max calc
num_non_compute_budget_instructions =
num_non_compute_budget_instructions.saturating_add(1);
}
}

// sanity check updated_compute_unit_limit
if let Some(user_specified_cu_limit) = updated_compute_unit_limit {
if user_specified_cu_limit < static_builtin_ix_costs
|| user_specified_cu_limit > MAX_COMPUTE_UNIT_LIMIT
{
return Err(TransactionError::InvalidComputeUnitLimitRequested);
}
}

Expand All @@ -126,10 +145,7 @@ pub fn process_compute_budget_instructions<'a>(
.min(MAX_HEAP_FRAME_BYTES);

let compute_unit_limit = updated_compute_unit_limit
.unwrap_or_else(|| {
num_non_compute_budget_instructions
.saturating_mul(DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT)
})
.unwrap_or_else(|| static_builtin_ix_costs.saturating_add(non_builtin_ix_costs))
.min(MAX_COMPUTE_UNIT_LIMIT);

let compute_unit_price = updated_compute_unit_price.unwrap_or(0);
Expand Down
5 changes: 5 additions & 0 deletions sdk/src/transaction/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,11 @@ pub enum TransactionError {
/// The total balance before the transaction does not equal the total balance after the transaction
#[error("Sum of account balances before and after transaction do not match")]
UnbalancedTransaction,

/// The requested compute-unit limit is either lesser than minimally required by the
/// transaction, or greater than maximal transaction compute-unit limit
#[error("Requested compute-unit limit is invalid")]
InvalidComputeUnitLimitRequested,
}

impl From<SanitizeError> for TransactionError {
Expand Down
1 change: 1 addition & 0 deletions storage-proto/proto/transaction_by_addr.proto
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ enum TransactionErrorType {
RESANITIZATION_NEEDED = 34;
PROGRAM_EXECUTION_TEMPORARILY_RESTRICTED = 35;
UNBALANCED_TRANSACTION = 36;
INVALID_COMPUTE_UNIT_LIMIT_REQUESTED = 37;
}

message InstructionError {
Expand Down
12 changes: 12 additions & 0 deletions storage-proto/src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,7 @@ impl TryFrom<tx_by_addr::TransactionError> for TransactionError {
33 => TransactionError::InvalidLoadedAccountsDataSizeLimit,
34 => TransactionError::ResanitizationNeeded,
36 => TransactionError::UnbalancedTransaction,
37 => TransactionError::InvalidComputeUnitLimitRequested,
_ => return Err("Invalid TransactionError"),
})
}
Expand Down Expand Up @@ -936,6 +937,9 @@ impl From<TransactionError> for tx_by_addr::TransactionError {
TransactionError::UnbalancedTransaction => {
tx_by_addr::TransactionErrorType::UnbalancedTransaction
}
TransactionError::InvalidComputeUnitLimitRequested => {
tx_by_addr::TransactionErrorType::InvalidComputeUnitLimitRequested
}
} as i32,
instruction_error: match transaction_error {
TransactionError::InstructionError(index, ref instruction_error) => {
Expand Down Expand Up @@ -1851,6 +1855,14 @@ mod test {
transaction_error,
tx_by_addr_transaction_error.try_into().unwrap()
);

let transaction_error = TransactionError::InvalidComputeUnitLimitRequested;
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
transaction_error.clone().into();
assert_eq!(
transaction_error,
tx_by_addr_transaction_error.try_into().unwrap()
);
}

#[test]
Expand Down

0 comments on commit 7484bfd

Please sign in to comment.