add compute budget instruction to set loaded accounts data size limit (#30377)

* add compute budget instruction to set accounts data size limit

* changes names to explicitly for loaded accounts data size
This commit is contained in:
Tao Zhu 2023-02-24 09:27:49 -06:00 committed by GitHub
parent 0a75be399b
commit 66ea750182
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 421 additions and 104 deletions

View File

@ -60,8 +60,9 @@ to.
As the transaction is processed compute units are consumed by its
instruction's programs performing operations such as executing SBF instructions,
calling syscalls, etc... When the transaction consumes its entire budget, or
exceeds a bound such as attempting a call stack that is too deep, the runtime
halts the transaction processing and returns an error.
exceeds a bound such as attempting a call stack that is too deep, or loaded
account data size exceeds limit, the runtime halts the transaction processing and
returns an error.
The following operations incur a compute cost:
@ -150,6 +151,21 @@ let instruction = ComputeBudgetInstruction::set_compute_unit_limit(300_000);
let instruction = ComputeBudgetInstruction::set_compute_unit_price(1);
```
### Accounts data size limit
A transaction should request the maximum bytes of accounts data it is
allowed to load by including a `SetLoadedAccountsDataSizeLimit` instruction, requested
limit is capped by `MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES`. If no
`SetLoadedAccountsDataSizeLimit` is provided, the transaction is defaulted to
have limit of `MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES`.
The `ComputeBudgetInstruction::set_loaded_accounts_data_size_limit` function can be used
to create this instruction:
```rust
let instruction = ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(100_000);
```
## New Features
As Solana evolves, new features or patches may be introduced that changes the

View File

@ -10,6 +10,10 @@ use {
},
};
/// The total accounts data a transaction can load is limited to 64MiB to not break
/// anyone in Mainnet-beta today. It can be set by set_loaded_accounts_data_size_limit instruction
pub const MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES: usize = 64 * 1024 * 1024;
pub const DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT: u32 = 200_000;
pub const MAX_COMPUTE_UNIT_LIMIT: u32 = 1_400_000;
const MAX_HEAP_FRAME_BYTES: u32 = 256 * 1024;
@ -109,6 +113,9 @@ pub struct ComputeBudget {
pub alt_bn128_pairing_one_pair_cost_other: u64,
/// Big integer modular exponentiation cost
pub big_modular_exponentiation_cost: u64,
/// Maximum accounts data size, in bytes, that a transaction is allowed to load; The
/// value is capped by MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES to prevent overuse of memory.
pub loaded_accounts_data_size_limit: usize,
}
impl Default for ComputeBudget {
@ -157,6 +164,7 @@ impl ComputeBudget {
alt_bn128_pairing_one_pair_cost_first: 36_364,
alt_bn128_pairing_one_pair_cost_other: 12_121,
big_modular_exponentiation_cost: 33,
loaded_accounts_data_size_limit: MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES,
}
}
@ -166,11 +174,13 @@ impl ComputeBudget {
default_units_per_instruction: bool,
support_request_units_deprecated: bool,
enable_request_heap_frame_ix: bool,
support_set_loaded_accounts_data_size_limit_ix: bool,
) -> Result<PrioritizationFeeDetails, TransactionError> {
let mut num_non_compute_budget_instructions: usize = 0;
let mut updated_compute_unit_limit = None;
let mut requested_heap_size = None;
let mut prioritization_fee = None;
let mut updated_loaded_accounts_data_size_limit = None;
for (i, (program_id, instruction)) in instructions.enumerate() {
if compute_budget::check_id(program_id) {
@ -214,6 +224,14 @@ impl ComputeBudget {
prioritization_fee =
Some(PrioritizationFeeType::ComputeUnitPrice(micro_lamports));
}
Ok(ComputeBudgetInstruction::SetLoadedAccountsDataSizeLimit(bytes))
if support_set_loaded_accounts_data_size_limit_ix =>
{
if updated_loaded_accounts_data_size_limit.is_some() {
return Err(duplicate_instruction_error);
}
updated_loaded_accounts_data_size_limit = Some(bytes as usize);
}
_ => return Err(invalid_instruction_data_error),
}
} else {
@ -250,6 +268,10 @@ impl ComputeBudget {
.unwrap_or(MAX_COMPUTE_UNIT_LIMIT)
.min(MAX_COMPUTE_UNIT_LIMIT) as u64;
self.loaded_accounts_data_size_limit = updated_loaded_accounts_data_size_limit
.unwrap_or(MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES)
.min(MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES);
Ok(prioritization_fee
.map(|fee_type| PrioritizationFeeDetails::new(fee_type, self.compute_unit_limit))
.unwrap_or_default())
@ -272,7 +294,7 @@ mod tests {
};
macro_rules! test {
( $instructions: expr, $expected_result: expr, $expected_budget: expr, $enable_request_heap_frame_ix: expr ) => {
( $instructions: expr, $expected_result: expr, $expected_budget: expr, $enable_request_heap_frame_ix: expr, $support_set_loaded_accounts_data_size_limit_ix: expr ) => {
let payer_keypair = Keypair::new();
let tx = SanitizedTransaction::from_transaction_for_tests(Transaction::new(
&[&payer_keypair],
@ -285,12 +307,19 @@ mod tests {
true,
false, /*not support request_units_deprecated*/
$enable_request_heap_frame_ix,
$support_set_loaded_accounts_data_size_limit_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, true);
test!(
$instructions,
$expected_result,
$expected_budget,
true,
false
);
};
}
@ -561,6 +590,7 @@ mod tests {
compute_unit_limit: 0,
..ComputeBudget::default()
},
false,
false
);
@ -575,6 +605,7 @@ mod tests {
InstructionError::InvalidInstructionData
)),
ComputeBudget::default(),
false,
false
);
test!(
@ -587,6 +618,7 @@ mod tests {
InstructionError::InvalidInstructionData,
)),
ComputeBudget::default(),
false,
false
);
test!(
@ -601,6 +633,7 @@ mod tests {
InstructionError::InvalidInstructionData,
)),
ComputeBudget::default(),
false,
false
);
test!(
@ -615,6 +648,7 @@ mod tests {
InstructionError::InvalidInstructionData,
)),
ComputeBudget::default(),
false,
false
);
@ -635,7 +669,170 @@ mod tests {
compute_unit_limit: DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64 * 7,
..ComputeBudget::default()
},
false,
false
);
}
#[test]
fn test_process_loaded_accounts_data_size_limit_instruction() {
let enable_request_heap_frame_ix: bool = true;
// Assert for empty instructions, change value of support_set_loaded_accounts_data_size_limit_ix
// will not change results, which should all be default
for support_set_loaded_accounts_data_size_limit_ix in [true, false] {
test!(
&[],
Ok(PrioritizationFeeDetails::default()),
ComputeBudget {
compute_unit_limit: 0,
..ComputeBudget::default()
},
enable_request_heap_frame_ix,
support_set_loaded_accounts_data_size_limit_ix
);
}
// Assert when set_loaded_accounts_data_size_limit presents,
// if support_set_loaded_accounts_data_size_limit_ix then
// budget is set with data_size
// else
// return InstructionError
let data_size: usize = 1;
for support_set_loaded_accounts_data_size_limit_ix in [true, false] {
let (expected_result, expected_budget) =
if support_set_loaded_accounts_data_size_limit_ix {
(
Ok(PrioritizationFeeDetails::default()),
ComputeBudget {
compute_unit_limit: DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64,
loaded_accounts_data_size_limit: data_size,
..ComputeBudget::default()
},
)
} else {
(
Err(TransactionError::InstructionError(
0,
InstructionError::InvalidInstructionData,
)),
ComputeBudget::default(),
)
};
test!(
&[
ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(data_size as u32),
Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
],
expected_result,
expected_budget,
enable_request_heap_frame_ix,
support_set_loaded_accounts_data_size_limit_ix
);
}
// Assert when set_loaded_accounts_data_size_limit presents, with greater than max value
// if support_set_loaded_accounts_data_size_limit_ix then
// budget is set to max data size
// else
// return InstructionError
let data_size: usize = MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES + 1;
for support_set_loaded_accounts_data_size_limit_ix in [true, false] {
let (expected_result, expected_budget) =
if support_set_loaded_accounts_data_size_limit_ix {
(
Ok(PrioritizationFeeDetails::default()),
ComputeBudget {
compute_unit_limit: DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64,
loaded_accounts_data_size_limit: MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES,
..ComputeBudget::default()
},
)
} else {
(
Err(TransactionError::InstructionError(
0,
InstructionError::InvalidInstructionData,
)),
ComputeBudget::default(),
)
};
test!(
&[
ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(data_size as u32),
Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
],
expected_result,
expected_budget,
enable_request_heap_frame_ix,
support_set_loaded_accounts_data_size_limit_ix
);
}
// Assert when set_loaded_accounts_data_size_limit is not presented
// if support_set_loaded_accounts_data_size_limit_ix then
// budget is set to default data size
// else
// return
for support_set_loaded_accounts_data_size_limit_ix in [true, false] {
let (expected_result, expected_budget) = (
Ok(PrioritizationFeeDetails::default()),
ComputeBudget {
compute_unit_limit: DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64,
loaded_accounts_data_size_limit: MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES,
..ComputeBudget::default()
},
);
test!(
&[Instruction::new_with_bincode(
Pubkey::new_unique(),
&0_u8,
vec![]
),],
expected_result,
expected_budget,
enable_request_heap_frame_ix,
support_set_loaded_accounts_data_size_limit_ix
);
}
// Assert when set_loaded_accounts_data_size_limit presents more than once,
// if support_set_loaded_accounts_data_size_limit_ix then
// return DuplicateInstruction
// else
// return InstructionError
let data_size: usize = MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES;
for support_set_loaded_accounts_data_size_limit_ix in [true, false] {
let (expected_result, expected_budget) =
if support_set_loaded_accounts_data_size_limit_ix {
(
Err(TransactionError::DuplicateInstruction(2)),
ComputeBudget::default(),
)
} else {
(
Err(TransactionError::InstructionError(
1,
InstructionError::InvalidInstructionData,
)),
ComputeBudget::default(),
)
};
test!(
&[
Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(data_size as u32),
ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(data_size as u32),
],
expected_result,
expected_budget,
enable_request_heap_frame_ix,
support_set_loaded_accounts_data_size_limit_ix
);
}
}
}

View File

@ -3590,6 +3590,7 @@ fn test_program_fees() {
false,
true,
true,
true,
);
bank_client
.send_and_confirm_message(&[&mint_keypair], message)
@ -3614,6 +3615,7 @@ fn test_program_fees() {
false,
true,
true,
true,
);
assert!(expected_normal_fee < expected_prioritized_fee);

View File

@ -31,8 +31,9 @@ use {
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
clock::{BankId, Slot},
feature_set::{
self, enable_request_heap_frame_ix, remove_congestion_multiplier_from_fee_calculation,
remove_deprecated_request_unit_ix, use_default_units_in_fee_calculation, FeatureSet,
self, add_set_tx_loaded_accounts_data_size_instruction, 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,
genesis_config::ClusterType,
@ -640,6 +641,7 @@ impl Accounts {
!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,
feature_set.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()),
)
} else {
return (Err(TransactionError::BlockhashNotFound), None);
@ -1667,6 +1669,7 @@ mod tests {
false,
true,
true,
true,
);
assert_eq!(fee, lamports_per_signature);

View File

@ -118,9 +118,10 @@ use {
epoch_schedule::EpochSchedule,
feature,
feature_set::{
self, disable_fee_calculator, enable_early_verification_of_account_modifications,
enable_request_heap_frame_ix, remove_congestion_multiplier_from_fee_calculation,
remove_deprecated_request_unit_ix, use_default_units_in_fee_calculation, FeatureSet,
self, add_set_tx_loaded_accounts_data_size_instruction, disable_fee_calculator,
enable_early_verification_of_account_modifications, 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},
@ -3497,6 +3498,8 @@ impl Bank {
self.feature_set
.is_active(&remove_congestion_multiplier_from_fee_calculation::id()),
self.enable_request_heap_frame_ix(),
self.feature_set
.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()),
))
}
@ -3544,6 +3547,8 @@ impl Bank {
self.feature_set
.is_active(&remove_congestion_multiplier_from_fee_calculation::id()),
self.enable_request_heap_frame_ix(),
self.feature_set
.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()),
)
}
@ -4584,35 +4589,38 @@ impl Bank {
.map(|(accs, tx)| match accs {
(Err(e), _nonce) => TransactionExecutionResult::NotExecuted(e.clone()),
(Ok(loaded_transaction), nonce) => {
let compute_budget =
if let Some(compute_budget) = self.runtime_config.compute_budget {
compute_budget
} else {
let mut compute_budget =
ComputeBudget::new(compute_budget::MAX_COMPUTE_UNIT_LIMIT as u64);
let compute_budget = if let Some(compute_budget) =
self.runtime_config.compute_budget
{
compute_budget
} else {
let mut compute_budget =
ComputeBudget::new(compute_budget::MAX_COMPUTE_UNIT_LIMIT as u64);
let mut compute_budget_process_transaction_time =
Measure::start("compute_budget_process_transaction_time");
let process_transaction_result = compute_budget.process_instructions(
tx.message().program_instructions_iter(),
true,
!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!(
timings
.execute_accessories
.compute_budget_process_transaction_us,
compute_budget_process_transaction_time.as_us()
);
if let Err(err) = process_transaction_result {
return TransactionExecutionResult::NotExecuted(err);
}
compute_budget
};
let mut compute_budget_process_transaction_time =
Measure::start("compute_budget_process_transaction_time");
let process_transaction_result = compute_budget.process_instructions(
tx.message().program_instructions_iter(),
true,
!self
.feature_set
.is_active(&remove_deprecated_request_unit_ix::id()),
true, // don't reject txs that use request heap size ix
self.feature_set
.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()),
);
compute_budget_process_transaction_time.stop();
saturating_add_assign!(
timings
.execute_accessories
.compute_budget_process_transaction_us,
compute_budget_process_transaction_time.as_us()
);
if let Err(err) = process_transaction_result {
return TransactionExecutionResult::NotExecuted(err);
}
compute_budget
};
self.execute_loaded_transaction(
tx,
@ -4880,6 +4888,7 @@ impl Bank {
support_request_units_deprecated: bool,
remove_congestion_multiplier: bool,
enable_request_heap_frame_ix: bool,
support_set_accounts_data_size_limit_ix: bool,
) -> u64 {
// Fee based on compute units and signatures
let congestion_multiplier = if lamports_per_signature == 0 {
@ -4899,6 +4908,7 @@ impl Bank {
use_default_units_per_instruction,
support_request_units_deprecated,
enable_request_heap_frame_ix,
support_set_accounts_data_size_limit_ix,
)
.unwrap_or_default();
let prioritization_fee = prioritization_fee_details.get_fee();
@ -4970,6 +4980,8 @@ impl Bank {
self.feature_set
.is_active(&remove_congestion_multiplier_from_fee_calculation::id()),
self.enable_request_heap_frame_ix(),
self.feature_set
.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()),
);
// In case of instruction error, even though no accounts

View File

@ -3220,6 +3220,7 @@ fn test_bank_tx_compute_unit_fee() {
false,
true,
true,
true,
);
let (expected_fee_collected, expected_fee_burned) =
@ -3403,6 +3404,7 @@ fn test_bank_blockhash_compute_unit_fee_structure() {
false,
true,
true,
true,
);
assert_eq!(
bank.get_balance(&mint_keypair.pubkey()),
@ -3423,6 +3425,7 @@ fn test_bank_blockhash_compute_unit_fee_structure() {
false,
true,
true,
true,
);
assert_eq!(
bank.get_balance(&mint_keypair.pubkey()),
@ -3538,6 +3541,7 @@ fn test_filter_program_errors_and_collect_compute_unit_fee() {
false,
true,
true,
true,
) * 2
)
.0
@ -10709,38 +10713,44 @@ fn test_calculate_fee() {
// Default: no fee.
let message =
SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap();
assert_eq!(
Bank::calculate_fee(
&message,
0,
&FeeStructure {
lamports_per_signature: 0,
..FeeStructure::default()
},
true,
false,
true,
true,
),
0
);
for support_set_accounts_data_size_limit_ix in [true, false] {
assert_eq!(
Bank::calculate_fee(
&message,
0,
&FeeStructure {
lamports_per_signature: 0,
..FeeStructure::default()
},
true,
false,
true,
true,
support_set_accounts_data_size_limit_ix,
),
0
);
}
// One signature, a fee.
assert_eq!(
Bank::calculate_fee(
&message,
1,
&FeeStructure {
lamports_per_signature: 1,
..FeeStructure::default()
},
true,
false,
true,
true,
),
1
);
for support_set_accounts_data_size_limit_ix in [true, false] {
assert_eq!(
Bank::calculate_fee(
&message,
1,
&FeeStructure {
lamports_per_signature: 1,
..FeeStructure::default()
},
true,
false,
true,
true,
support_set_accounts_data_size_limit_ix,
),
1
);
}
// Two signatures, double the fee.
let key0 = Pubkey::new_unique();
@ -10748,21 +10758,24 @@ fn test_calculate_fee() {
let ix0 = system_instruction::transfer(&key0, &key1, 1);
let ix1 = system_instruction::transfer(&key1, &key0, 1);
let message = SanitizedMessage::try_from(Message::new(&[ix0, ix1], Some(&key0))).unwrap();
assert_eq!(
Bank::calculate_fee(
&message,
2,
&FeeStructure {
lamports_per_signature: 2,
..FeeStructure::default()
},
true,
false,
true,
true,
),
4
);
for support_set_accounts_data_size_limit_ix in [true, false] {
assert_eq!(
Bank::calculate_fee(
&message,
2,
&FeeStructure {
lamports_per_signature: 2,
..FeeStructure::default()
},
true,
false,
true,
true,
support_set_accounts_data_size_limit_ix,
),
4
);
}
}
#[test]
@ -10778,10 +10791,21 @@ 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, true),
max_fee + lamports_per_signature
);
for support_set_accounts_data_size_limit_ix in [true, false] {
assert_eq!(
Bank::calculate_fee(
&message,
1,
&fee_structure,
true,
false,
true,
true,
support_set_accounts_data_size_limit_ix
),
max_fee + lamports_per_signature
);
}
// Three signatures, two instructions, no unit request
@ -10789,10 +10813,21 @@ fn test_calculate_fee_compute_units() {
let ix1 = system_instruction::transfer(&Pubkey::new_unique(), &Pubkey::new_unique(), 1);
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, true),
max_fee + 3 * lamports_per_signature
);
for support_set_accounts_data_size_limit_ix in [true, false] {
assert_eq!(
Bank::calculate_fee(
&message,
1,
&fee_structure,
true,
false,
true,
true,
support_set_accounts_data_size_limit_ix
),
max_fee + 3 * lamports_per_signature
);
}
// Explicit fee schedule
@ -10823,11 +10858,22 @@ fn test_calculate_fee_compute_units() {
Some(&Pubkey::new_unique()),
))
.unwrap();
let fee = Bank::calculate_fee(&message, 1, &fee_structure, true, false, true, true);
assert_eq!(
fee,
lamports_per_signature + prioritization_fee_details.get_fee()
);
for support_set_accounts_data_size_limit_ix in [true, false] {
let fee = Bank::calculate_fee(
&message,
1,
&fee_structure,
true,
false,
true,
true,
support_set_accounts_data_size_limit_ix,
);
assert_eq!(
fee,
lamports_per_signature + prioritization_fee_details.get_fee()
);
}
}
}
@ -10861,10 +10907,21 @@ fn test_calculate_fee_secp256k1() {
Some(&key0),
))
.unwrap();
assert_eq!(
Bank::calculate_fee(&message, 1, &fee_structure, true, false, true, true),
2
);
for support_set_accounts_data_size_limit_ix in [true, false] {
assert_eq!(
Bank::calculate_fee(
&message,
1,
&fee_structure,
true,
false,
true,
true,
support_set_accounts_data_size_limit_ix
),
2
);
}
secp_instruction1.data = vec![0];
secp_instruction2.data = vec![10];
@ -10873,10 +10930,21 @@ fn test_calculate_fee_secp256k1() {
Some(&key0),
))
.unwrap();
assert_eq!(
Bank::calculate_fee(&message, 1, &fee_structure, true, false, true, true),
11
);
for support_set_accounts_data_size_limit_ix in [true, false] {
assert_eq!(
Bank::calculate_fee(
&message,
1,
&fee_structure,
true,
false,
true,
true,
support_set_accounts_data_size_limit_ix
),
11
);
}
}
#[test]
@ -12606,6 +12674,7 @@ fn test_calculate_fee_with_congestion_multiplier() {
false,
remove_congestion_multiplier,
true,
true,
),
signature_fee * signature_count
);
@ -12629,6 +12698,7 @@ fn test_calculate_fee_with_congestion_multiplier() {
false,
remove_congestion_multiplier,
true,
true,
),
signature_fee * signature_count / denominator
);
@ -12670,6 +12740,7 @@ fn test_calculate_fee_with_request_heap_frame_flag() {
false,
true,
enable_request_heap_frame_ix,
true,
),
signature_fee + request_cu * lamports_per_cu
);
@ -12686,6 +12757,7 @@ fn test_calculate_fee_with_request_heap_frame_flag() {
false,
true,
enable_request_heap_frame_ix,
true,
),
signature_fee
);

View File

@ -13,7 +13,8 @@ use {
},
solana_sdk::{
feature_set::{
remove_deprecated_request_unit_ix, use_default_units_in_fee_calculation, FeatureSet,
add_set_tx_loaded_accounts_data_size_instruction, remove_deprecated_request_unit_ix,
use_default_units_in_fee_calculation, FeatureSet,
},
instruction::CompiledInstruction,
program_utils::limited_deserialize,
@ -155,6 +156,7 @@ impl CostModel {
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,
feature_set.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()),
);
// if tx contained user-space instructions and a more accurate estimate available correct it

View File

@ -26,6 +26,7 @@ pub trait GetTransactionPriorityDetails {
true, // use default units per instruction
false, // stop supporting prioritization by request_units_deprecated instruction
true, // enable request heap frame instruction
true, // enable support set accounts data size instruction
)
.ok()?;
Some(TransactionPriorityDetails {

View File

@ -41,6 +41,8 @@ pub enum ComputeBudgetInstruction {
/// Set a compute unit price in "micro-lamports" to pay a higher transaction
/// fee for higher transaction prioritization.
SetComputeUnitPrice(u64),
/// Set a specific transaction-wide account data size limit, in bytes, is allowed to load.
SetLoadedAccountsDataSizeLimit(u32),
}
impl ComputeBudgetInstruction {
@ -65,4 +67,9 @@ impl ComputeBudgetInstruction {
pub fn pack(self) -> Result<Vec<u8>, std::io::Error> {
self.try_to_vec()
}
/// Create a `ComputeBudgetInstruction::SetLoadedAccountsDataSizeLimit` `Instruction`
pub fn set_loaded_accounts_data_size_limit(bytes: u32) -> Instruction {
Instruction::new_with_borsh(id(), &Self::SetLoadedAccountsDataSizeLimit(bytes), vec![])
}
}

View File

@ -618,6 +618,10 @@ pub mod apply_cost_tracker_during_replay {
solana_sdk::declare_id!("2ry7ygxiYURULZCrypHhveanvP5tzZ4toRwVp89oCNSj");
}
pub mod add_set_tx_loaded_accounts_data_size_instruction {
solana_sdk::declare_id!("G6vbf1UBok8MWb8m25ex86aoQHeKTzDKzuZADHkShqm6");
}
lazy_static! {
/// Map of feature identifiers to user-visible description
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
@ -767,6 +771,7 @@ lazy_static! {
(prevent_rent_paying_rent_recipients::id(), "prevent recipients of rent rewards from ending in rent-paying state #30151"),
(delay_visibility_of_program_deployment::id(), "delay visibility of program upgrades #30085"),
(apply_cost_tracker_during_replay::id(), "apply cost tracker to blocks during replay #29595"),
(add_set_tx_loaded_accounts_data_size_instruction::id(), "add compute budget instruction for setting account data size per transaction #30366"),
/*************** ADD NEW FEATURES HERE ***************/
]
.iter()