include loaded accounts data size limit in transaction fee calculation (#30659)
* include loaded accounts data size limit in transaction base fee calculation * citing compute_budget for heap cost; * update sbf tests Co-authored-by: Trent Nelson <trent.a.b.nelson@gmail.com>
This commit is contained in:
parent
d4a6e00ffc
commit
21c287a64f
|
@ -3634,6 +3634,7 @@ fn test_program_fees() {
|
|||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
bank_client
|
||||
.send_and_confirm_message(&[&mint_keypair], message)
|
||||
|
@ -3659,6 +3660,7 @@ fn test_program_fees() {
|
|||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert!(expected_normal_fee < expected_prioritized_fee);
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ use {
|
|||
clock::{BankId, Slot},
|
||||
feature_set::{
|
||||
self, add_set_tx_loaded_accounts_data_size_instruction, enable_request_heap_frame_ix,
|
||||
include_loaded_accounts_data_size_in_fee_calculation,
|
||||
remove_congestion_multiplier_from_fee_calculation, remove_deprecated_request_unit_ix,
|
||||
use_default_units_in_fee_calculation, FeatureSet,
|
||||
},
|
||||
|
@ -661,6 +662,7 @@ impl Accounts {
|
|||
feature_set.is_active(&remove_congestion_multiplier_from_fee_calculation::id()),
|
||||
feature_set.is_active(&enable_request_heap_frame_ix::id()) || self.accounts_db.expected_cluster_type() != ClusterType::MainnetBeta,
|
||||
feature_set.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()),
|
||||
feature_set.is_active(&include_loaded_accounts_data_size_in_fee_calculation::id()),
|
||||
)
|
||||
} else {
|
||||
return (Err(TransactionError::BlockhashNotFound), None);
|
||||
|
@ -1690,6 +1692,7 @@ mod tests {
|
|||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert_eq!(fee, lamports_per_signature);
|
||||
|
||||
|
|
|
@ -121,6 +121,7 @@ use {
|
|||
feature_set::{
|
||||
self, add_set_tx_loaded_accounts_data_size_instruction, disable_fee_calculator,
|
||||
enable_early_verification_of_account_modifications, enable_request_heap_frame_ix,
|
||||
include_loaded_accounts_data_size_in_fee_calculation,
|
||||
remove_congestion_multiplier_from_fee_calculation, remove_deprecated_request_unit_ix,
|
||||
use_default_units_in_fee_calculation, FeatureSet,
|
||||
},
|
||||
|
@ -3505,6 +3506,8 @@ impl Bank {
|
|||
self.enable_request_heap_frame_ix(),
|
||||
self.feature_set
|
||||
.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()),
|
||||
self.feature_set
|
||||
.is_active(&include_loaded_accounts_data_size_in_fee_calculation::id()),
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -3554,6 +3557,8 @@ impl Bank {
|
|||
self.enable_request_heap_frame_ix(),
|
||||
self.feature_set
|
||||
.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()),
|
||||
self.feature_set
|
||||
.is_active(&include_loaded_accounts_data_size_in_fee_calculation::id()),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -4894,6 +4899,7 @@ impl Bank {
|
|||
remove_congestion_multiplier: bool,
|
||||
enable_request_heap_frame_ix: bool,
|
||||
support_set_accounts_data_size_limit_ix: bool,
|
||||
include_loaded_account_data_size_in_fee: bool,
|
||||
) -> u64 {
|
||||
// Fee based on compute units and signatures
|
||||
let congestion_multiplier = if lamports_per_signature == 0 {
|
||||
|
@ -4921,10 +4927,20 @@ impl Bank {
|
|||
.saturating_mul(fee_structure.lamports_per_signature);
|
||||
let write_lock_fee = Self::get_num_write_locks_in_message(message)
|
||||
.saturating_mul(fee_structure.lamports_per_write_lock);
|
||||
|
||||
// `compute_fee` covers costs for both requested_compute_units and
|
||||
// requested_loaded_account_data_size
|
||||
let loaded_accounts_data_size_cost = if include_loaded_account_data_size_in_fee {
|
||||
Self::calculate_loaded_accounts_data_size_cost(&compute_budget)
|
||||
} else {
|
||||
0_u64
|
||||
};
|
||||
let total_compute_units =
|
||||
loaded_accounts_data_size_cost.saturating_add(compute_budget.compute_unit_limit);
|
||||
let compute_fee = fee_structure
|
||||
.compute_fee_bins
|
||||
.iter()
|
||||
.find(|bin| compute_budget.compute_unit_limit <= bin.limit)
|
||||
.find(|bin| total_compute_units <= bin.limit)
|
||||
.map(|bin| bin.fee)
|
||||
.unwrap_or_else(|| {
|
||||
fee_structure
|
||||
|
@ -4942,6 +4958,23 @@ impl Bank {
|
|||
.round() as u64
|
||||
}
|
||||
|
||||
// Calculate cost of loaded accounts size in the same way heap cost is charged at
|
||||
// rate of 8cu per 32K. Citing `program_runtime\src\compute_budget.rs`: "(cost of
|
||||
// heap is about) 0.5us per 32k at 15 units/us rounded up"
|
||||
//
|
||||
// Before feature `support_set_loaded_accounts_data_size_limit_ix` is enabled, or
|
||||
// if user doesn't use compute budget ix `set_loaded_accounts_data_size_limit_ix`
|
||||
// to set limit, `compute_budget.loaded_accounts_data_size_limit` is set to default
|
||||
// limit of 64MB; which will convert to (64M/32K)*8CU = 16_000 CUs
|
||||
//
|
||||
fn calculate_loaded_accounts_data_size_cost(compute_budget: &ComputeBudget) -> u64 {
|
||||
const ACCOUNT_DATA_COST_PAGE_SIZE: u64 = 32_u64.saturating_mul(1024);
|
||||
(compute_budget.loaded_accounts_data_size_limit as u64)
|
||||
.saturating_add(ACCOUNT_DATA_COST_PAGE_SIZE.saturating_sub(1))
|
||||
.saturating_div(ACCOUNT_DATA_COST_PAGE_SIZE)
|
||||
.saturating_mul(compute_budget.heap_cost)
|
||||
}
|
||||
|
||||
fn filter_program_errors_and_collect_fee(
|
||||
&self,
|
||||
txs: &[SanitizedTransaction],
|
||||
|
@ -4987,6 +5020,8 @@ impl Bank {
|
|||
self.enable_request_heap_frame_ix(),
|
||||
self.feature_set
|
||||
.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()),
|
||||
self.feature_set
|
||||
.is_active(&include_loaded_accounts_data_size_in_fee_calculation::id()),
|
||||
);
|
||||
|
||||
// In case of instruction error, even though no accounts
|
||||
|
|
|
@ -3221,6 +3221,7 @@ fn test_bank_tx_compute_unit_fee() {
|
|||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
|
||||
let (expected_fee_collected, expected_fee_burned) =
|
||||
|
@ -3405,6 +3406,7 @@ fn test_bank_blockhash_compute_unit_fee_structure() {
|
|||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert_eq!(
|
||||
bank.get_balance(&mint_keypair.pubkey()),
|
||||
|
@ -3426,6 +3428,7 @@ fn test_bank_blockhash_compute_unit_fee_structure() {
|
|||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert_eq!(
|
||||
bank.get_balance(&mint_keypair.pubkey()),
|
||||
|
@ -3542,6 +3545,7 @@ fn test_filter_program_errors_and_collect_compute_unit_fee() {
|
|||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
) * 2
|
||||
)
|
||||
.0
|
||||
|
@ -10713,6 +10717,7 @@ fn test_calculate_fee() {
|
|||
true,
|
||||
true,
|
||||
support_set_accounts_data_size_limit_ix,
|
||||
false,
|
||||
),
|
||||
0
|
||||
);
|
||||
|
@ -10733,6 +10738,7 @@ fn test_calculate_fee() {
|
|||
true,
|
||||
true,
|
||||
support_set_accounts_data_size_limit_ix,
|
||||
false,
|
||||
),
|
||||
1
|
||||
);
|
||||
|
@ -10758,6 +10764,7 @@ fn test_calculate_fee() {
|
|||
true,
|
||||
true,
|
||||
support_set_accounts_data_size_limit_ix,
|
||||
false,
|
||||
),
|
||||
4
|
||||
);
|
||||
|
@ -10787,7 +10794,8 @@ fn test_calculate_fee_compute_units() {
|
|||
false,
|
||||
true,
|
||||
true,
|
||||
support_set_accounts_data_size_limit_ix
|
||||
support_set_accounts_data_size_limit_ix,
|
||||
false,
|
||||
),
|
||||
max_fee + lamports_per_signature
|
||||
);
|
||||
|
@ -10809,7 +10817,8 @@ fn test_calculate_fee_compute_units() {
|
|||
false,
|
||||
true,
|
||||
true,
|
||||
support_set_accounts_data_size_limit_ix
|
||||
support_set_accounts_data_size_limit_ix,
|
||||
false,
|
||||
),
|
||||
max_fee + 3 * lamports_per_signature
|
||||
);
|
||||
|
@ -10854,6 +10863,7 @@ fn test_calculate_fee_compute_units() {
|
|||
true,
|
||||
true,
|
||||
support_set_accounts_data_size_limit_ix,
|
||||
false,
|
||||
);
|
||||
assert_eq!(
|
||||
fee,
|
||||
|
@ -10903,7 +10913,8 @@ fn test_calculate_fee_secp256k1() {
|
|||
false,
|
||||
true,
|
||||
true,
|
||||
support_set_accounts_data_size_limit_ix
|
||||
support_set_accounts_data_size_limit_ix,
|
||||
false,
|
||||
),
|
||||
2
|
||||
);
|
||||
|
@ -10926,7 +10937,8 @@ fn test_calculate_fee_secp256k1() {
|
|||
false,
|
||||
true,
|
||||
true,
|
||||
support_set_accounts_data_size_limit_ix
|
||||
support_set_accounts_data_size_limit_ix,
|
||||
false,
|
||||
),
|
||||
11
|
||||
);
|
||||
|
@ -12659,6 +12671,7 @@ fn test_calculate_fee_with_congestion_multiplier() {
|
|||
remove_congestion_multiplier,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
signature_fee * signature_count
|
||||
);
|
||||
|
@ -12683,6 +12696,7 @@ fn test_calculate_fee_with_congestion_multiplier() {
|
|||
remove_congestion_multiplier,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
signature_fee * signature_count / denominator
|
||||
);
|
||||
|
@ -12725,6 +12739,7 @@ fn test_calculate_fee_with_request_heap_frame_flag() {
|
|||
true,
|
||||
enable_request_heap_frame_ix,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
signature_fee + request_cu * lamports_per_cu
|
||||
);
|
||||
|
@ -12742,6 +12757,7 @@ fn test_calculate_fee_with_request_heap_frame_flag() {
|
|||
true,
|
||||
enable_request_heap_frame_ix,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
signature_fee
|
||||
);
|
||||
|
@ -12914,3 +12930,39 @@ fn test_bank_verify_accounts_hash_with_base() {
|
|||
},
|
||||
));
|
||||
}
|
||||
|
||||
#[allow(clippy::field_reassign_with_default)]
|
||||
#[test]
|
||||
fn test_calculate_loaded_accounts_data_size_cost() {
|
||||
let mut compute_budget = ComputeBudget::default();
|
||||
|
||||
// accounts data size are priced in block of 32K, ...
|
||||
|
||||
// ... requesting less than 32K should still be charged as one block
|
||||
compute_budget.loaded_accounts_data_size_limit = 31_usize * 1024;
|
||||
assert_eq!(
|
||||
compute_budget.heap_cost,
|
||||
Bank::calculate_loaded_accounts_data_size_cost(&compute_budget)
|
||||
);
|
||||
|
||||
// ... requesting exact 32K should be charged as one block
|
||||
compute_budget.loaded_accounts_data_size_limit = 32_usize * 1024;
|
||||
assert_eq!(
|
||||
compute_budget.heap_cost,
|
||||
Bank::calculate_loaded_accounts_data_size_cost(&compute_budget)
|
||||
);
|
||||
|
||||
// ... requesting slightly above 32K should be charged as 2 block
|
||||
compute_budget.loaded_accounts_data_size_limit = 33_usize * 1024;
|
||||
assert_eq!(
|
||||
compute_budget.heap_cost * 2,
|
||||
Bank::calculate_loaded_accounts_data_size_cost(&compute_budget)
|
||||
);
|
||||
|
||||
// ... requesting exact 64K should be charged as 2 block
|
||||
compute_budget.loaded_accounts_data_size_limit = 64_usize * 1024;
|
||||
assert_eq!(
|
||||
compute_budget.heap_cost * 2,
|
||||
Bank::calculate_loaded_accounts_data_size_cost(&compute_budget)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -634,6 +634,10 @@ pub mod remove_bpf_loader_incorrect_program_id {
|
|||
solana_sdk::declare_id!("2HmTkCj9tXuPE4ueHzdD7jPeMf9JGCoZh5AsyoATiWEe");
|
||||
}
|
||||
|
||||
pub mod include_loaded_accounts_data_size_in_fee_calculation {
|
||||
solana_sdk::declare_id!("EaQpmC6GtRssaZ3PCUM5YksGqUdMLeZ46BQXYtHYakDS");
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Map of feature identifiers to user-visible description
|
||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||
|
@ -787,6 +791,7 @@ lazy_static! {
|
|||
(switch_to_new_elf_parser::id(), "switch to new ELF parser #30497"),
|
||||
(round_up_heap_size::id(), "round up heap size when calculating heap cost #30679"),
|
||||
(remove_bpf_loader_incorrect_program_id::id(), "stop incorrectly throwing IncorrectProgramId in bpf_loader #30747"),
|
||||
(include_loaded_accounts_data_size_in_fee_calculation::id(), "include transaction loaded accounts data size in base fee calculation #30657"),
|
||||
/*************** ADD NEW FEATURES HERE ***************/
|
||||
]
|
||||
.iter()
|
||||
|
|
Loading…
Reference in New Issue