feature gate to enable compute_budget::request_heap_frame on mainnetBeta (#30077)
This commit is contained in:
parent
9b297ac89c
commit
4293f11cf1
|
@ -165,6 +165,7 @@ impl ComputeBudget {
|
|||
instructions: impl Iterator<Item = (&'a Pubkey, &'a CompiledInstruction)>,
|
||||
default_units_per_instruction: bool,
|
||||
support_request_units_deprecated: bool,
|
||||
enable_request_heap_frame_ix: bool,
|
||||
) -> Result<PrioritizationFeeDetails, TransactionError> {
|
||||
let mut num_non_compute_budget_instructions: usize = 0;
|
||||
let mut updated_compute_unit_limit = None;
|
||||
|
@ -223,7 +224,8 @@ impl ComputeBudget {
|
|||
}
|
||||
|
||||
if let Some((bytes, i)) = requested_heap_size {
|
||||
if bytes > MAX_HEAP_FRAME_BYTES
|
||||
if !enable_request_heap_frame_ix
|
||||
|| bytes > MAX_HEAP_FRAME_BYTES
|
||||
|| bytes < MIN_HEAP_FRAME_BYTES as u32
|
||||
|| bytes % 1024 != 0
|
||||
{
|
||||
|
@ -270,7 +272,7 @@ mod tests {
|
|||
};
|
||||
|
||||
macro_rules! test {
|
||||
( $instructions: expr, $expected_result: expr, $expected_budget: expr ) => {
|
||||
( $instructions: expr, $expected_result: expr, $expected_budget: expr, $enable_request_heap_frame_ix: expr ) => {
|
||||
let payer_keypair = Keypair::new();
|
||||
let tx = SanitizedTransaction::from_transaction_for_tests(Transaction::new(
|
||||
&[&payer_keypair],
|
||||
|
@ -282,12 +284,13 @@ mod tests {
|
|||
tx.message().program_instructions_iter(),
|
||||
true,
|
||||
false, /*not support request_units_deprecated*/
|
||||
$enable_request_heap_frame_ix,
|
||||
);
|
||||
assert_eq!($expected_result, result);
|
||||
assert_eq!(compute_budget, $expected_budget);
|
||||
};
|
||||
( $instructions: expr, $expected_result: expr, $expected_budget: expr) => {
|
||||
test!($instructions, $expected_result, $expected_budget);
|
||||
test!($instructions, $expected_result, $expected_budget, true);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -547,4 +550,92 @@ mod tests {
|
|||
ComputeBudget::default()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_instructions_disable_request_heap_frame() {
|
||||
// assert empty message results default compute budget and fee
|
||||
test!(
|
||||
&[],
|
||||
Ok(PrioritizationFeeDetails::default()),
|
||||
ComputeBudget {
|
||||
compute_unit_limit: 0,
|
||||
..ComputeBudget::default()
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
// assert requesting heap frame when feature is disable will result instruction error
|
||||
test!(
|
||||
&[
|
||||
ComputeBudgetInstruction::request_heap_frame(40 * 1024),
|
||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
|
||||
],
|
||||
Err(TransactionError::InstructionError(
|
||||
0,
|
||||
InstructionError::InvalidInstructionData
|
||||
)),
|
||||
ComputeBudget::default(),
|
||||
false
|
||||
);
|
||||
test!(
|
||||
&[
|
||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
|
||||
ComputeBudgetInstruction::request_heap_frame(MAX_HEAP_FRAME_BYTES),
|
||||
],
|
||||
Err(TransactionError::InstructionError(
|
||||
1,
|
||||
InstructionError::InvalidInstructionData,
|
||||
)),
|
||||
ComputeBudget::default(),
|
||||
false
|
||||
);
|
||||
test!(
|
||||
&[
|
||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
|
||||
ComputeBudgetInstruction::request_heap_frame(MAX_HEAP_FRAME_BYTES),
|
||||
ComputeBudgetInstruction::set_compute_unit_limit(MAX_COMPUTE_UNIT_LIMIT),
|
||||
ComputeBudgetInstruction::set_compute_unit_price(u64::MAX),
|
||||
],
|
||||
Err(TransactionError::InstructionError(
|
||||
1,
|
||||
InstructionError::InvalidInstructionData,
|
||||
)),
|
||||
ComputeBudget::default(),
|
||||
false
|
||||
);
|
||||
test!(
|
||||
&[
|
||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
|
||||
ComputeBudgetInstruction::set_compute_unit_limit(1),
|
||||
ComputeBudgetInstruction::request_heap_frame(MAX_HEAP_FRAME_BYTES),
|
||||
ComputeBudgetInstruction::set_compute_unit_price(u64::MAX),
|
||||
],
|
||||
Err(TransactionError::InstructionError(
|
||||
2,
|
||||
InstructionError::InvalidInstructionData,
|
||||
)),
|
||||
ComputeBudget::default(),
|
||||
false
|
||||
);
|
||||
|
||||
// assert normal results when not requesting heap frame when the feature is disabled
|
||||
test!(
|
||||
&[
|
||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
|
||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
|
||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
|
||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
|
||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
|
||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
|
||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
|
||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
|
||||
],
|
||||
Ok(PrioritizationFeeDetails::default()),
|
||||
ComputeBudget {
|
||||
compute_unit_limit: DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64 * 7,
|
||||
..ComputeBudget::default()
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3588,6 +3588,7 @@ fn test_program_fees() {
|
|||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
bank_client
|
||||
.send_and_confirm_message(&[&mint_keypair], message)
|
||||
|
@ -3611,6 +3612,7 @@ fn test_program_fees() {
|
|||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
assert!(expected_normal_fee < expected_prioritized_fee);
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ use {
|
|||
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
|
||||
clock::{BankId, Slot},
|
||||
feature_set::{
|
||||
self, remove_congestion_multiplier_from_fee_calculation,
|
||||
self, enable_request_heap_frame_ix, remove_congestion_multiplier_from_fee_calculation,
|
||||
remove_deprecated_request_unit_ix, use_default_units_in_fee_calculation, FeatureSet,
|
||||
},
|
||||
fee::FeeStructure,
|
||||
|
@ -601,6 +601,7 @@ impl Accounts {
|
|||
feature_set.is_active(&use_default_units_in_fee_calculation::id()),
|
||||
!feature_set.is_active(&remove_deprecated_request_unit_ix::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,
|
||||
)
|
||||
} else {
|
||||
return (Err(TransactionError::BlockhashNotFound), None);
|
||||
|
@ -1641,6 +1642,7 @@ mod tests {
|
|||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
assert_eq!(fee, lamports_per_signature);
|
||||
|
||||
|
|
|
@ -120,8 +120,8 @@ use {
|
|||
feature,
|
||||
feature_set::{
|
||||
self, disable_fee_calculator, enable_early_verification_of_account_modifications,
|
||||
remove_congestion_multiplier_from_fee_calculation, remove_deprecated_request_unit_ix,
|
||||
use_default_units_in_fee_calculation, FeatureSet,
|
||||
enable_request_heap_frame_ix, remove_congestion_multiplier_from_fee_calculation,
|
||||
remove_deprecated_request_unit_ix, use_default_units_in_fee_calculation, FeatureSet,
|
||||
},
|
||||
fee::FeeStructure,
|
||||
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
||||
|
@ -3445,6 +3445,7 @@ impl Bank {
|
|||
.is_active(&remove_deprecated_request_unit_ix::id()),
|
||||
self.feature_set
|
||||
.is_active(&remove_congestion_multiplier_from_fee_calculation::id()),
|
||||
self.enable_request_heap_frame_ix(),
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -3491,6 +3492,7 @@ impl Bank {
|
|||
.is_active(&remove_deprecated_request_unit_ix::id()),
|
||||
self.feature_set
|
||||
.is_active(&remove_congestion_multiplier_from_fee_calculation::id()),
|
||||
self.enable_request_heap_frame_ix(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -4297,6 +4299,15 @@ impl Bank {
|
|||
}
|
||||
}
|
||||
|
||||
// A cluster specific feature gate, when not activated it keeps v1.13 behavior in mainnet-beta;
|
||||
// once activated for v1.14+, it allows compute_budget::request_heap_frame and
|
||||
// compute_budget::set_compute_unit_price co-exist in same transaction.
|
||||
fn enable_request_heap_frame_ix(&self) -> bool {
|
||||
self.feature_set
|
||||
.is_active(&enable_request_heap_frame_ix::id())
|
||||
|| self.cluster_type() != ClusterType::MainnetBeta
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn load_and_execute_transactions(
|
||||
&self,
|
||||
|
@ -4397,6 +4408,7 @@ impl Bank {
|
|||
!self
|
||||
.feature_set
|
||||
.is_active(&remove_deprecated_request_unit_ix::id()),
|
||||
true, // don't reject txs that use request heap size ix
|
||||
);
|
||||
compute_budget_process_transaction_time.stop();
|
||||
saturating_add_assign!(
|
||||
|
@ -4676,6 +4688,7 @@ impl Bank {
|
|||
use_default_units_per_instruction: bool,
|
||||
support_request_units_deprecated: bool,
|
||||
remove_congestion_multiplier: bool,
|
||||
enable_request_heap_frame_ix: bool,
|
||||
) -> u64 {
|
||||
// Fee based on compute units and signatures
|
||||
let congestion_multiplier = if lamports_per_signature == 0 {
|
||||
|
@ -4694,6 +4707,7 @@ impl Bank {
|
|||
message.program_instructions_iter(),
|
||||
use_default_units_per_instruction,
|
||||
support_request_units_deprecated,
|
||||
enable_request_heap_frame_ix,
|
||||
)
|
||||
.unwrap_or_default();
|
||||
let prioritization_fee = prioritization_fee_details.get_fee();
|
||||
|
@ -4764,6 +4778,7 @@ impl Bank {
|
|||
.is_active(&remove_deprecated_request_unit_ix::id()),
|
||||
self.feature_set
|
||||
.is_active(&remove_congestion_multiplier_from_fee_calculation::id()),
|
||||
self.enable_request_heap_frame_ix(),
|
||||
);
|
||||
|
||||
// In case of instruction error, even though no accounts
|
||||
|
|
|
@ -3036,6 +3036,7 @@ fn test_bank_tx_compute_unit_fee() {
|
|||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
|
||||
let (expected_fee_collected, expected_fee_burned) =
|
||||
|
@ -3218,6 +3219,7 @@ fn test_bank_blockhash_compute_unit_fee_structure() {
|
|||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
assert_eq!(
|
||||
bank.get_balance(&mint_keypair.pubkey()),
|
||||
|
@ -3237,6 +3239,7 @@ fn test_bank_blockhash_compute_unit_fee_structure() {
|
|||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
assert_eq!(
|
||||
bank.get_balance(&mint_keypair.pubkey()),
|
||||
|
@ -3351,6 +3354,7 @@ fn test_filter_program_errors_and_collect_compute_unit_fee() {
|
|||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
) * 2
|
||||
)
|
||||
.0
|
||||
|
@ -10496,6 +10500,7 @@ fn test_calculate_fee() {
|
|||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
),
|
||||
0
|
||||
);
|
||||
|
@ -10512,6 +10517,7 @@ fn test_calculate_fee() {
|
|||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
),
|
||||
1
|
||||
);
|
||||
|
@ -10533,6 +10539,7 @@ fn test_calculate_fee() {
|
|||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
),
|
||||
4
|
||||
);
|
||||
|
@ -10552,7 +10559,7 @@ fn test_calculate_fee_compute_units() {
|
|||
let message =
|
||||
SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap();
|
||||
assert_eq!(
|
||||
Bank::calculate_fee(&message, 1, &fee_structure, true, false, true),
|
||||
Bank::calculate_fee(&message, 1, &fee_structure, true, false, true, true),
|
||||
max_fee + lamports_per_signature
|
||||
);
|
||||
|
||||
|
@ -10563,7 +10570,7 @@ fn test_calculate_fee_compute_units() {
|
|||
let message =
|
||||
SanitizedMessage::try_from(Message::new(&[ix0, ix1], Some(&Pubkey::new_unique()))).unwrap();
|
||||
assert_eq!(
|
||||
Bank::calculate_fee(&message, 1, &fee_structure, true, false, true),
|
||||
Bank::calculate_fee(&message, 1, &fee_structure, true, false, true, true),
|
||||
max_fee + 3 * lamports_per_signature
|
||||
);
|
||||
|
||||
|
@ -10596,7 +10603,7 @@ fn test_calculate_fee_compute_units() {
|
|||
Some(&Pubkey::new_unique()),
|
||||
))
|
||||
.unwrap();
|
||||
let fee = Bank::calculate_fee(&message, 1, &fee_structure, true, false, true);
|
||||
let fee = Bank::calculate_fee(&message, 1, &fee_structure, true, false, true, true);
|
||||
assert_eq!(
|
||||
fee,
|
||||
lamports_per_signature + prioritization_fee_details.get_fee()
|
||||
|
@ -10635,7 +10642,7 @@ fn test_calculate_fee_secp256k1() {
|
|||
))
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
Bank::calculate_fee(&message, 1, &fee_structure, true, false, true),
|
||||
Bank::calculate_fee(&message, 1, &fee_structure, true, false, true, true),
|
||||
2
|
||||
);
|
||||
|
||||
|
@ -10647,7 +10654,7 @@ fn test_calculate_fee_secp256k1() {
|
|||
))
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
Bank::calculate_fee(&message, 1, &fee_structure, true, false, true),
|
||||
Bank::calculate_fee(&message, 1, &fee_structure, true, false, true, true),
|
||||
11
|
||||
);
|
||||
}
|
||||
|
@ -12378,6 +12385,7 @@ fn test_calculate_fee_with_congestion_multiplier() {
|
|||
true,
|
||||
false,
|
||||
remove_congestion_multiplier,
|
||||
true,
|
||||
),
|
||||
signature_fee * signature_count
|
||||
);
|
||||
|
@ -12400,8 +12408,65 @@ fn test_calculate_fee_with_congestion_multiplier() {
|
|||
true,
|
||||
false,
|
||||
remove_congestion_multiplier,
|
||||
true,
|
||||
),
|
||||
signature_fee * signature_count / denominator
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_calculate_fee_with_request_heap_frame_flag() {
|
||||
let key0 = Pubkey::new_unique();
|
||||
let key1 = Pubkey::new_unique();
|
||||
let lamports_per_signature: u64 = 5_000;
|
||||
let signature_fee: u64 = 10;
|
||||
let request_cu: u64 = 1;
|
||||
let lamports_per_cu: u64 = 5;
|
||||
let fee_structure = FeeStructure {
|
||||
lamports_per_signature: signature_fee,
|
||||
..FeeStructure::default()
|
||||
};
|
||||
let message = SanitizedMessage::try_from(Message::new(
|
||||
&[
|
||||
system_instruction::transfer(&key0, &key1, 1),
|
||||
ComputeBudgetInstruction::set_compute_unit_limit(request_cu as u32),
|
||||
ComputeBudgetInstruction::request_heap_frame(40 * 1024),
|
||||
ComputeBudgetInstruction::set_compute_unit_price(lamports_per_cu * 1_000_000),
|
||||
],
|
||||
Some(&key0),
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// assert when enable_request_heap_frame_ix is enabled, prioritization fee will be counted
|
||||
// into transaction fee
|
||||
let mut enable_request_heap_frame_ix = true;
|
||||
assert_eq!(
|
||||
Bank::calculate_fee(
|
||||
&message,
|
||||
lamports_per_signature,
|
||||
&fee_structure,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
enable_request_heap_frame_ix,
|
||||
),
|
||||
signature_fee + request_cu * lamports_per_cu
|
||||
);
|
||||
|
||||
// assert when enable_request_heap_frame_ix is disabled (an v1.13 behavior), prioritization fee will not be counted
|
||||
// into transaction fee
|
||||
enable_request_heap_frame_ix = false;
|
||||
assert_eq!(
|
||||
Bank::calculate_fee(
|
||||
&message,
|
||||
lamports_per_signature,
|
||||
&fee_structure,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
enable_request_heap_frame_ix,
|
||||
),
|
||||
signature_fee
|
||||
);
|
||||
}
|
||||
|
|
|
@ -142,10 +142,19 @@ impl CostModel {
|
|||
|
||||
// calculate bpf cost based on compute budget instructions
|
||||
let mut budget = ComputeBudget::default();
|
||||
|
||||
// Starting from v1.14, cost model uses compute_budget.set_compute_unit_limit to
|
||||
// measure bpf_costs (code below), vs earlier versions that use estimated
|
||||
// bpf instruction costs. The calculated transaction costs are used by leaders
|
||||
// during block packing, different costs for same transaction due to different versions
|
||||
// will not impact consensus. So for v1.14+, should call compute budget with
|
||||
// the feature gate `enable_request_heap_frame_ix` enabled.
|
||||
let enable_request_heap_frame_ix = true;
|
||||
let result = budget.process_instructions(
|
||||
transaction.message().program_instructions_iter(),
|
||||
feature_set.is_active(&use_default_units_in_fee_calculation::id()),
|
||||
!feature_set.is_active(&remove_deprecated_request_unit_ix::id()),
|
||||
enable_request_heap_frame_ix,
|
||||
);
|
||||
|
||||
// if tx contained user-space instructions and a more accurate estimate available correct it
|
||||
|
|
|
@ -25,6 +25,7 @@ pub trait GetTransactionPriorityDetails {
|
|||
instructions,
|
||||
true, // use default units per instruction
|
||||
false, // stop supporting prioritization by request_units_deprecated instruction
|
||||
true, // enable request heap frame instruction
|
||||
)
|
||||
.ok()?;
|
||||
Some(TransactionPriorityDetails {
|
||||
|
|
|
@ -602,6 +602,10 @@ pub mod remove_congestion_multiplier_from_fee_calculation {
|
|||
solana_sdk::declare_id!("A8xyMHZovGXFkorFqEmVH2PKGLiBip5JD7jt4zsUWo4H");
|
||||
}
|
||||
|
||||
pub mod enable_request_heap_frame_ix {
|
||||
solana_sdk::declare_id!("Hr1nUA9b7NJ6eChS26o7Vi8gYYDDwWD3YeBfzJkTbU86");
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Map of feature identifiers to user-visible description
|
||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||
|
@ -747,6 +751,7 @@ lazy_static! {
|
|||
(disable_builtin_loader_ownership_chains::id(), "disable builtin loader ownership chains #29956"),
|
||||
(cap_transaction_accounts_data_size::id(), "cap transaction accounts data size up to a limit #27839"),
|
||||
(remove_congestion_multiplier_from_fee_calculation::id(), "Remove congestion multiplier from transaction fee calculation #29881"),
|
||||
(enable_request_heap_frame_ix::id(), "Enable transaction to request heap frame using compute budget instruction #30076"),
|
||||
/*************** ADD NEW FEATURES HERE ***************/
|
||||
]
|
||||
.iter()
|
||||
|
|
Loading…
Reference in New Issue