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,
|
true,
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
bank_client
|
bank_client
|
||||||
.send_and_confirm_message(&[&mint_keypair], message)
|
.send_and_confirm_message(&[&mint_keypair], message)
|
||||||
|
@ -3659,6 +3660,7 @@ fn test_program_fees() {
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
assert!(expected_normal_fee < expected_prioritized_fee);
|
assert!(expected_normal_fee < expected_prioritized_fee);
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ use {
|
||||||
clock::{BankId, Slot},
|
clock::{BankId, Slot},
|
||||||
feature_set::{
|
feature_set::{
|
||||||
self, add_set_tx_loaded_accounts_data_size_instruction, enable_request_heap_frame_ix,
|
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,
|
remove_congestion_multiplier_from_fee_calculation, remove_deprecated_request_unit_ix,
|
||||||
use_default_units_in_fee_calculation, FeatureSet,
|
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(&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(&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(&add_set_tx_loaded_accounts_data_size_instruction::id()),
|
||||||
|
feature_set.is_active(&include_loaded_accounts_data_size_in_fee_calculation::id()),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return (Err(TransactionError::BlockhashNotFound), None);
|
return (Err(TransactionError::BlockhashNotFound), None);
|
||||||
|
@ -1690,6 +1692,7 @@ mod tests {
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
assert_eq!(fee, lamports_per_signature);
|
assert_eq!(fee, lamports_per_signature);
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,7 @@ use {
|
||||||
feature_set::{
|
feature_set::{
|
||||||
self, add_set_tx_loaded_accounts_data_size_instruction, disable_fee_calculator,
|
self, add_set_tx_loaded_accounts_data_size_instruction, disable_fee_calculator,
|
||||||
enable_early_verification_of_account_modifications, enable_request_heap_frame_ix,
|
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,
|
remove_congestion_multiplier_from_fee_calculation, remove_deprecated_request_unit_ix,
|
||||||
use_default_units_in_fee_calculation, FeatureSet,
|
use_default_units_in_fee_calculation, FeatureSet,
|
||||||
},
|
},
|
||||||
|
@ -3505,6 +3506,8 @@ impl Bank {
|
||||||
self.enable_request_heap_frame_ix(),
|
self.enable_request_heap_frame_ix(),
|
||||||
self.feature_set
|
self.feature_set
|
||||||
.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()),
|
.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.enable_request_heap_frame_ix(),
|
||||||
self.feature_set
|
self.feature_set
|
||||||
.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()),
|
.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,
|
remove_congestion_multiplier: bool,
|
||||||
enable_request_heap_frame_ix: bool,
|
enable_request_heap_frame_ix: bool,
|
||||||
support_set_accounts_data_size_limit_ix: bool,
|
support_set_accounts_data_size_limit_ix: bool,
|
||||||
|
include_loaded_account_data_size_in_fee: bool,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
// Fee based on compute units and signatures
|
// Fee based on compute units and signatures
|
||||||
let congestion_multiplier = if lamports_per_signature == 0 {
|
let congestion_multiplier = if lamports_per_signature == 0 {
|
||||||
|
@ -4921,10 +4927,20 @@ impl Bank {
|
||||||
.saturating_mul(fee_structure.lamports_per_signature);
|
.saturating_mul(fee_structure.lamports_per_signature);
|
||||||
let write_lock_fee = Self::get_num_write_locks_in_message(message)
|
let write_lock_fee = Self::get_num_write_locks_in_message(message)
|
||||||
.saturating_mul(fee_structure.lamports_per_write_lock);
|
.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
|
let compute_fee = fee_structure
|
||||||
.compute_fee_bins
|
.compute_fee_bins
|
||||||
.iter()
|
.iter()
|
||||||
.find(|bin| compute_budget.compute_unit_limit <= bin.limit)
|
.find(|bin| total_compute_units <= bin.limit)
|
||||||
.map(|bin| bin.fee)
|
.map(|bin| bin.fee)
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
fee_structure
|
fee_structure
|
||||||
|
@ -4942,6 +4958,23 @@ impl Bank {
|
||||||
.round() as u64
|
.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(
|
fn filter_program_errors_and_collect_fee(
|
||||||
&self,
|
&self,
|
||||||
txs: &[SanitizedTransaction],
|
txs: &[SanitizedTransaction],
|
||||||
|
@ -4987,6 +5020,8 @@ impl Bank {
|
||||||
self.enable_request_heap_frame_ix(),
|
self.enable_request_heap_frame_ix(),
|
||||||
self.feature_set
|
self.feature_set
|
||||||
.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()),
|
.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
|
// In case of instruction error, even though no accounts
|
||||||
|
|
|
@ -3221,6 +3221,7 @@ fn test_bank_tx_compute_unit_fee() {
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (expected_fee_collected, expected_fee_burned) =
|
let (expected_fee_collected, expected_fee_burned) =
|
||||||
|
@ -3405,6 +3406,7 @@ fn test_bank_blockhash_compute_unit_fee_structure() {
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.get_balance(&mint_keypair.pubkey()),
|
bank.get_balance(&mint_keypair.pubkey()),
|
||||||
|
@ -3426,6 +3428,7 @@ fn test_bank_blockhash_compute_unit_fee_structure() {
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.get_balance(&mint_keypair.pubkey()),
|
bank.get_balance(&mint_keypair.pubkey()),
|
||||||
|
@ -3542,6 +3545,7 @@ fn test_filter_program_errors_and_collect_compute_unit_fee() {
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
) * 2
|
) * 2
|
||||||
)
|
)
|
||||||
.0
|
.0
|
||||||
|
@ -10713,6 +10717,7 @@ fn test_calculate_fee() {
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
support_set_accounts_data_size_limit_ix,
|
support_set_accounts_data_size_limit_ix,
|
||||||
|
false,
|
||||||
),
|
),
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
@ -10733,6 +10738,7 @@ fn test_calculate_fee() {
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
support_set_accounts_data_size_limit_ix,
|
support_set_accounts_data_size_limit_ix,
|
||||||
|
false,
|
||||||
),
|
),
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
|
@ -10758,6 +10764,7 @@ fn test_calculate_fee() {
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
support_set_accounts_data_size_limit_ix,
|
support_set_accounts_data_size_limit_ix,
|
||||||
|
false,
|
||||||
),
|
),
|
||||||
4
|
4
|
||||||
);
|
);
|
||||||
|
@ -10787,7 +10794,8 @@ fn test_calculate_fee_compute_units() {
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
support_set_accounts_data_size_limit_ix
|
support_set_accounts_data_size_limit_ix,
|
||||||
|
false,
|
||||||
),
|
),
|
||||||
max_fee + lamports_per_signature
|
max_fee + lamports_per_signature
|
||||||
);
|
);
|
||||||
|
@ -10809,7 +10817,8 @@ fn test_calculate_fee_compute_units() {
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
support_set_accounts_data_size_limit_ix
|
support_set_accounts_data_size_limit_ix,
|
||||||
|
false,
|
||||||
),
|
),
|
||||||
max_fee + 3 * lamports_per_signature
|
max_fee + 3 * lamports_per_signature
|
||||||
);
|
);
|
||||||
|
@ -10854,6 +10863,7 @@ fn test_calculate_fee_compute_units() {
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
support_set_accounts_data_size_limit_ix,
|
support_set_accounts_data_size_limit_ix,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
fee,
|
fee,
|
||||||
|
@ -10903,7 +10913,8 @@ fn test_calculate_fee_secp256k1() {
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
support_set_accounts_data_size_limit_ix
|
support_set_accounts_data_size_limit_ix,
|
||||||
|
false,
|
||||||
),
|
),
|
||||||
2
|
2
|
||||||
);
|
);
|
||||||
|
@ -10926,7 +10937,8 @@ fn test_calculate_fee_secp256k1() {
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
support_set_accounts_data_size_limit_ix
|
support_set_accounts_data_size_limit_ix,
|
||||||
|
false,
|
||||||
),
|
),
|
||||||
11
|
11
|
||||||
);
|
);
|
||||||
|
@ -12659,6 +12671,7 @@ fn test_calculate_fee_with_congestion_multiplier() {
|
||||||
remove_congestion_multiplier,
|
remove_congestion_multiplier,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
),
|
),
|
||||||
signature_fee * signature_count
|
signature_fee * signature_count
|
||||||
);
|
);
|
||||||
|
@ -12683,6 +12696,7 @@ fn test_calculate_fee_with_congestion_multiplier() {
|
||||||
remove_congestion_multiplier,
|
remove_congestion_multiplier,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
),
|
),
|
||||||
signature_fee * signature_count / denominator
|
signature_fee * signature_count / denominator
|
||||||
);
|
);
|
||||||
|
@ -12725,6 +12739,7 @@ fn test_calculate_fee_with_request_heap_frame_flag() {
|
||||||
true,
|
true,
|
||||||
enable_request_heap_frame_ix,
|
enable_request_heap_frame_ix,
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
),
|
),
|
||||||
signature_fee + request_cu * lamports_per_cu
|
signature_fee + request_cu * lamports_per_cu
|
||||||
);
|
);
|
||||||
|
@ -12742,6 +12757,7 @@ fn test_calculate_fee_with_request_heap_frame_flag() {
|
||||||
true,
|
true,
|
||||||
enable_request_heap_frame_ix,
|
enable_request_heap_frame_ix,
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
),
|
),
|
||||||
signature_fee
|
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");
|
solana_sdk::declare_id!("2HmTkCj9tXuPE4ueHzdD7jPeMf9JGCoZh5AsyoATiWEe");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod include_loaded_accounts_data_size_in_fee_calculation {
|
||||||
|
solana_sdk::declare_id!("EaQpmC6GtRssaZ3PCUM5YksGqUdMLeZ46BQXYtHYakDS");
|
||||||
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Map of feature identifiers to user-visible description
|
/// Map of feature identifiers to user-visible description
|
||||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
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"),
|
(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"),
|
(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"),
|
(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 ***************/
|
/*************** ADD NEW FEATURES HERE ***************/
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
|
|
Loading…
Reference in New Issue