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:
parent
0a75be399b
commit
66ea750182
|
@ -60,8 +60,9 @@ to.
|
||||||
As the transaction is processed compute units are consumed by its
|
As the transaction is processed compute units are consumed by its
|
||||||
instruction's programs performing operations such as executing SBF instructions,
|
instruction's programs performing operations such as executing SBF instructions,
|
||||||
calling syscalls, etc... When the transaction consumes its entire budget, or
|
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
|
exceeds a bound such as attempting a call stack that is too deep, or loaded
|
||||||
halts the transaction processing and returns an error.
|
account data size exceeds limit, the runtime halts the transaction processing and
|
||||||
|
returns an error.
|
||||||
|
|
||||||
The following operations incur a compute cost:
|
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);
|
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
|
## New Features
|
||||||
|
|
||||||
As Solana evolves, new features or patches may be introduced that changes the
|
As Solana evolves, new features or patches may be introduced that changes the
|
||||||
|
|
|
@ -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 DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT: u32 = 200_000;
|
||||||
pub const MAX_COMPUTE_UNIT_LIMIT: u32 = 1_400_000;
|
pub const MAX_COMPUTE_UNIT_LIMIT: u32 = 1_400_000;
|
||||||
const MAX_HEAP_FRAME_BYTES: u32 = 256 * 1024;
|
const MAX_HEAP_FRAME_BYTES: u32 = 256 * 1024;
|
||||||
|
@ -109,6 +113,9 @@ pub struct ComputeBudget {
|
||||||
pub alt_bn128_pairing_one_pair_cost_other: u64,
|
pub alt_bn128_pairing_one_pair_cost_other: u64,
|
||||||
/// Big integer modular exponentiation cost
|
/// Big integer modular exponentiation cost
|
||||||
pub big_modular_exponentiation_cost: u64,
|
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 {
|
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_first: 36_364,
|
||||||
alt_bn128_pairing_one_pair_cost_other: 12_121,
|
alt_bn128_pairing_one_pair_cost_other: 12_121,
|
||||||
big_modular_exponentiation_cost: 33,
|
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,
|
default_units_per_instruction: bool,
|
||||||
support_request_units_deprecated: bool,
|
support_request_units_deprecated: bool,
|
||||||
enable_request_heap_frame_ix: bool,
|
enable_request_heap_frame_ix: bool,
|
||||||
|
support_set_loaded_accounts_data_size_limit_ix: bool,
|
||||||
) -> Result<PrioritizationFeeDetails, TransactionError> {
|
) -> Result<PrioritizationFeeDetails, TransactionError> {
|
||||||
let mut num_non_compute_budget_instructions: usize = 0;
|
let mut num_non_compute_budget_instructions: usize = 0;
|
||||||
let mut updated_compute_unit_limit = None;
|
let mut updated_compute_unit_limit = None;
|
||||||
let mut requested_heap_size = None;
|
let mut requested_heap_size = None;
|
||||||
let mut prioritization_fee = None;
|
let mut prioritization_fee = None;
|
||||||
|
let mut updated_loaded_accounts_data_size_limit = None;
|
||||||
|
|
||||||
for (i, (program_id, instruction)) in instructions.enumerate() {
|
for (i, (program_id, instruction)) in instructions.enumerate() {
|
||||||
if compute_budget::check_id(program_id) {
|
if compute_budget::check_id(program_id) {
|
||||||
|
@ -214,6 +224,14 @@ impl ComputeBudget {
|
||||||
prioritization_fee =
|
prioritization_fee =
|
||||||
Some(PrioritizationFeeType::ComputeUnitPrice(micro_lamports));
|
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),
|
_ => return Err(invalid_instruction_data_error),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -250,6 +268,10 @@ impl ComputeBudget {
|
||||||
.unwrap_or(MAX_COMPUTE_UNIT_LIMIT)
|
.unwrap_or(MAX_COMPUTE_UNIT_LIMIT)
|
||||||
.min(MAX_COMPUTE_UNIT_LIMIT) as u64;
|
.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
|
Ok(prioritization_fee
|
||||||
.map(|fee_type| PrioritizationFeeDetails::new(fee_type, self.compute_unit_limit))
|
.map(|fee_type| PrioritizationFeeDetails::new(fee_type, self.compute_unit_limit))
|
||||||
.unwrap_or_default())
|
.unwrap_or_default())
|
||||||
|
@ -272,7 +294,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
macro_rules! test {
|
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 payer_keypair = Keypair::new();
|
||||||
let tx = SanitizedTransaction::from_transaction_for_tests(Transaction::new(
|
let tx = SanitizedTransaction::from_transaction_for_tests(Transaction::new(
|
||||||
&[&payer_keypair],
|
&[&payer_keypair],
|
||||||
|
@ -285,12 +307,19 @@ mod tests {
|
||||||
true,
|
true,
|
||||||
false, /*not support request_units_deprecated*/
|
false, /*not support request_units_deprecated*/
|
||||||
$enable_request_heap_frame_ix,
|
$enable_request_heap_frame_ix,
|
||||||
|
$support_set_loaded_accounts_data_size_limit_ix,
|
||||||
);
|
);
|
||||||
assert_eq!($expected_result, result);
|
assert_eq!($expected_result, result);
|
||||||
assert_eq!(compute_budget, $expected_budget);
|
assert_eq!(compute_budget, $expected_budget);
|
||||||
};
|
};
|
||||||
( $instructions: expr, $expected_result: expr, $expected_budget: expr) => {
|
( $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,
|
compute_unit_limit: 0,
|
||||||
..ComputeBudget::default()
|
..ComputeBudget::default()
|
||||||
},
|
},
|
||||||
|
false,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -575,6 +605,7 @@ mod tests {
|
||||||
InstructionError::InvalidInstructionData
|
InstructionError::InvalidInstructionData
|
||||||
)),
|
)),
|
||||||
ComputeBudget::default(),
|
ComputeBudget::default(),
|
||||||
|
false,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
test!(
|
test!(
|
||||||
|
@ -587,6 +618,7 @@ mod tests {
|
||||||
InstructionError::InvalidInstructionData,
|
InstructionError::InvalidInstructionData,
|
||||||
)),
|
)),
|
||||||
ComputeBudget::default(),
|
ComputeBudget::default(),
|
||||||
|
false,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
test!(
|
test!(
|
||||||
|
@ -601,6 +633,7 @@ mod tests {
|
||||||
InstructionError::InvalidInstructionData,
|
InstructionError::InvalidInstructionData,
|
||||||
)),
|
)),
|
||||||
ComputeBudget::default(),
|
ComputeBudget::default(),
|
||||||
|
false,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
test!(
|
test!(
|
||||||
|
@ -615,6 +648,7 @@ mod tests {
|
||||||
InstructionError::InvalidInstructionData,
|
InstructionError::InvalidInstructionData,
|
||||||
)),
|
)),
|
||||||
ComputeBudget::default(),
|
ComputeBudget::default(),
|
||||||
|
false,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -635,7 +669,170 @@ mod tests {
|
||||||
compute_unit_limit: DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64 * 7,
|
compute_unit_limit: DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64 * 7,
|
||||||
..ComputeBudget::default()
|
..ComputeBudget::default()
|
||||||
},
|
},
|
||||||
|
false,
|
||||||
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3590,6 +3590,7 @@ fn test_program_fees() {
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
bank_client
|
bank_client
|
||||||
.send_and_confirm_message(&[&mint_keypair], message)
|
.send_and_confirm_message(&[&mint_keypair], message)
|
||||||
|
@ -3614,6 +3615,7 @@ fn test_program_fees() {
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
assert!(expected_normal_fee < expected_prioritized_fee);
|
assert!(expected_normal_fee < expected_prioritized_fee);
|
||||||
|
|
||||||
|
|
|
@ -31,8 +31,9 @@ use {
|
||||||
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
|
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
|
||||||
clock::{BankId, Slot},
|
clock::{BankId, Slot},
|
||||||
feature_set::{
|
feature_set::{
|
||||||
self, enable_request_heap_frame_ix, remove_congestion_multiplier_from_fee_calculation,
|
self, add_set_tx_loaded_accounts_data_size_instruction, enable_request_heap_frame_ix,
|
||||||
remove_deprecated_request_unit_ix, use_default_units_in_fee_calculation, FeatureSet,
|
remove_congestion_multiplier_from_fee_calculation, remove_deprecated_request_unit_ix,
|
||||||
|
use_default_units_in_fee_calculation, FeatureSet,
|
||||||
},
|
},
|
||||||
fee::FeeStructure,
|
fee::FeeStructure,
|
||||||
genesis_config::ClusterType,
|
genesis_config::ClusterType,
|
||||||
|
@ -640,6 +641,7 @@ impl Accounts {
|
||||||
!feature_set.is_active(&remove_deprecated_request_unit_ix::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(&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()),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return (Err(TransactionError::BlockhashNotFound), None);
|
return (Err(TransactionError::BlockhashNotFound), None);
|
||||||
|
@ -1667,6 +1669,7 @@ mod tests {
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
assert_eq!(fee, lamports_per_signature);
|
assert_eq!(fee, lamports_per_signature);
|
||||||
|
|
||||||
|
|
|
@ -118,9 +118,10 @@ use {
|
||||||
epoch_schedule::EpochSchedule,
|
epoch_schedule::EpochSchedule,
|
||||||
feature,
|
feature,
|
||||||
feature_set::{
|
feature_set::{
|
||||||
self, disable_fee_calculator, enable_early_verification_of_account_modifications,
|
self, add_set_tx_loaded_accounts_data_size_instruction, disable_fee_calculator,
|
||||||
enable_request_heap_frame_ix, remove_congestion_multiplier_from_fee_calculation,
|
enable_early_verification_of_account_modifications, enable_request_heap_frame_ix,
|
||||||
remove_deprecated_request_unit_ix, use_default_units_in_fee_calculation, FeatureSet,
|
remove_congestion_multiplier_from_fee_calculation, remove_deprecated_request_unit_ix,
|
||||||
|
use_default_units_in_fee_calculation, FeatureSet,
|
||||||
},
|
},
|
||||||
fee::FeeStructure,
|
fee::FeeStructure,
|
||||||
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
||||||
|
@ -3497,6 +3498,8 @@ impl Bank {
|
||||||
self.feature_set
|
self.feature_set
|
||||||
.is_active(&remove_congestion_multiplier_from_fee_calculation::id()),
|
.is_active(&remove_congestion_multiplier_from_fee_calculation::id()),
|
||||||
self.enable_request_heap_frame_ix(),
|
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
|
self.feature_set
|
||||||
.is_active(&remove_congestion_multiplier_from_fee_calculation::id()),
|
.is_active(&remove_congestion_multiplier_from_fee_calculation::id()),
|
||||||
self.enable_request_heap_frame_ix(),
|
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 {
|
.map(|(accs, tx)| match accs {
|
||||||
(Err(e), _nonce) => TransactionExecutionResult::NotExecuted(e.clone()),
|
(Err(e), _nonce) => TransactionExecutionResult::NotExecuted(e.clone()),
|
||||||
(Ok(loaded_transaction), nonce) => {
|
(Ok(loaded_transaction), nonce) => {
|
||||||
let compute_budget =
|
let compute_budget = if let Some(compute_budget) =
|
||||||
if let Some(compute_budget) = self.runtime_config.compute_budget {
|
self.runtime_config.compute_budget
|
||||||
compute_budget
|
{
|
||||||
} else {
|
compute_budget
|
||||||
let mut compute_budget =
|
} else {
|
||||||
ComputeBudget::new(compute_budget::MAX_COMPUTE_UNIT_LIMIT as u64);
|
let mut compute_budget =
|
||||||
|
ComputeBudget::new(compute_budget::MAX_COMPUTE_UNIT_LIMIT as u64);
|
||||||
|
|
||||||
let mut compute_budget_process_transaction_time =
|
let mut compute_budget_process_transaction_time =
|
||||||
Measure::start("compute_budget_process_transaction_time");
|
Measure::start("compute_budget_process_transaction_time");
|
||||||
let process_transaction_result = compute_budget.process_instructions(
|
let process_transaction_result = compute_budget.process_instructions(
|
||||||
tx.message().program_instructions_iter(),
|
tx.message().program_instructions_iter(),
|
||||||
true,
|
true,
|
||||||
!self
|
!self
|
||||||
.feature_set
|
.feature_set
|
||||||
.is_active(&remove_deprecated_request_unit_ix::id()),
|
.is_active(&remove_deprecated_request_unit_ix::id()),
|
||||||
true, // don't reject txs that use request heap size ix
|
true, // don't reject txs that use request heap size ix
|
||||||
);
|
self.feature_set
|
||||||
compute_budget_process_transaction_time.stop();
|
.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()),
|
||||||
saturating_add_assign!(
|
);
|
||||||
timings
|
compute_budget_process_transaction_time.stop();
|
||||||
.execute_accessories
|
saturating_add_assign!(
|
||||||
.compute_budget_process_transaction_us,
|
timings
|
||||||
compute_budget_process_transaction_time.as_us()
|
.execute_accessories
|
||||||
);
|
.compute_budget_process_transaction_us,
|
||||||
if let Err(err) = process_transaction_result {
|
compute_budget_process_transaction_time.as_us()
|
||||||
return TransactionExecutionResult::NotExecuted(err);
|
);
|
||||||
}
|
if let Err(err) = process_transaction_result {
|
||||||
compute_budget
|
return TransactionExecutionResult::NotExecuted(err);
|
||||||
};
|
}
|
||||||
|
compute_budget
|
||||||
|
};
|
||||||
|
|
||||||
self.execute_loaded_transaction(
|
self.execute_loaded_transaction(
|
||||||
tx,
|
tx,
|
||||||
|
@ -4880,6 +4888,7 @@ impl Bank {
|
||||||
support_request_units_deprecated: bool,
|
support_request_units_deprecated: bool,
|
||||||
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,
|
||||||
) -> 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 {
|
||||||
|
@ -4899,6 +4908,7 @@ impl Bank {
|
||||||
use_default_units_per_instruction,
|
use_default_units_per_instruction,
|
||||||
support_request_units_deprecated,
|
support_request_units_deprecated,
|
||||||
enable_request_heap_frame_ix,
|
enable_request_heap_frame_ix,
|
||||||
|
support_set_accounts_data_size_limit_ix,
|
||||||
)
|
)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let prioritization_fee = prioritization_fee_details.get_fee();
|
let prioritization_fee = prioritization_fee_details.get_fee();
|
||||||
|
@ -4970,6 +4980,8 @@ impl Bank {
|
||||||
self.feature_set
|
self.feature_set
|
||||||
.is_active(&remove_congestion_multiplier_from_fee_calculation::id()),
|
.is_active(&remove_congestion_multiplier_from_fee_calculation::id()),
|
||||||
self.enable_request_heap_frame_ix(),
|
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
|
// In case of instruction error, even though no accounts
|
||||||
|
|
|
@ -3220,6 +3220,7 @@ fn test_bank_tx_compute_unit_fee() {
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (expected_fee_collected, expected_fee_burned) =
|
let (expected_fee_collected, expected_fee_burned) =
|
||||||
|
@ -3403,6 +3404,7 @@ fn test_bank_blockhash_compute_unit_fee_structure() {
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.get_balance(&mint_keypair.pubkey()),
|
bank.get_balance(&mint_keypair.pubkey()),
|
||||||
|
@ -3423,6 +3425,7 @@ fn test_bank_blockhash_compute_unit_fee_structure() {
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.get_balance(&mint_keypair.pubkey()),
|
bank.get_balance(&mint_keypair.pubkey()),
|
||||||
|
@ -3538,6 +3541,7 @@ fn test_filter_program_errors_and_collect_compute_unit_fee() {
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
) * 2
|
) * 2
|
||||||
)
|
)
|
||||||
.0
|
.0
|
||||||
|
@ -10709,38 +10713,44 @@ fn test_calculate_fee() {
|
||||||
// Default: no fee.
|
// Default: no fee.
|
||||||
let message =
|
let message =
|
||||||
SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap();
|
SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap();
|
||||||
assert_eq!(
|
for support_set_accounts_data_size_limit_ix in [true, false] {
|
||||||
Bank::calculate_fee(
|
assert_eq!(
|
||||||
&message,
|
Bank::calculate_fee(
|
||||||
0,
|
&message,
|
||||||
&FeeStructure {
|
0,
|
||||||
lamports_per_signature: 0,
|
&FeeStructure {
|
||||||
..FeeStructure::default()
|
lamports_per_signature: 0,
|
||||||
},
|
..FeeStructure::default()
|
||||||
true,
|
},
|
||||||
false,
|
true,
|
||||||
true,
|
false,
|
||||||
true,
|
true,
|
||||||
),
|
true,
|
||||||
0
|
support_set_accounts_data_size_limit_ix,
|
||||||
);
|
),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// One signature, a fee.
|
// One signature, a fee.
|
||||||
assert_eq!(
|
for support_set_accounts_data_size_limit_ix in [true, false] {
|
||||||
Bank::calculate_fee(
|
assert_eq!(
|
||||||
&message,
|
Bank::calculate_fee(
|
||||||
1,
|
&message,
|
||||||
&FeeStructure {
|
1,
|
||||||
lamports_per_signature: 1,
|
&FeeStructure {
|
||||||
..FeeStructure::default()
|
lamports_per_signature: 1,
|
||||||
},
|
..FeeStructure::default()
|
||||||
true,
|
},
|
||||||
false,
|
true,
|
||||||
true,
|
false,
|
||||||
true,
|
true,
|
||||||
),
|
true,
|
||||||
1
|
support_set_accounts_data_size_limit_ix,
|
||||||
);
|
),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Two signatures, double the fee.
|
// Two signatures, double the fee.
|
||||||
let key0 = Pubkey::new_unique();
|
let key0 = Pubkey::new_unique();
|
||||||
|
@ -10748,21 +10758,24 @@ fn test_calculate_fee() {
|
||||||
let ix0 = system_instruction::transfer(&key0, &key1, 1);
|
let ix0 = system_instruction::transfer(&key0, &key1, 1);
|
||||||
let ix1 = system_instruction::transfer(&key1, &key0, 1);
|
let ix1 = system_instruction::transfer(&key1, &key0, 1);
|
||||||
let message = SanitizedMessage::try_from(Message::new(&[ix0, ix1], Some(&key0))).unwrap();
|
let message = SanitizedMessage::try_from(Message::new(&[ix0, ix1], Some(&key0))).unwrap();
|
||||||
assert_eq!(
|
for support_set_accounts_data_size_limit_ix in [true, false] {
|
||||||
Bank::calculate_fee(
|
assert_eq!(
|
||||||
&message,
|
Bank::calculate_fee(
|
||||||
2,
|
&message,
|
||||||
&FeeStructure {
|
2,
|
||||||
lamports_per_signature: 2,
|
&FeeStructure {
|
||||||
..FeeStructure::default()
|
lamports_per_signature: 2,
|
||||||
},
|
..FeeStructure::default()
|
||||||
true,
|
},
|
||||||
false,
|
true,
|
||||||
true,
|
false,
|
||||||
true,
|
true,
|
||||||
),
|
true,
|
||||||
4
|
support_set_accounts_data_size_limit_ix,
|
||||||
);
|
),
|
||||||
|
4
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -10778,10 +10791,21 @@ fn test_calculate_fee_compute_units() {
|
||||||
|
|
||||||
let message =
|
let message =
|
||||||
SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap();
|
SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap();
|
||||||
assert_eq!(
|
for support_set_accounts_data_size_limit_ix in [true, false] {
|
||||||
Bank::calculate_fee(&message, 1, &fee_structure, true, false, true, true),
|
assert_eq!(
|
||||||
max_fee + lamports_per_signature
|
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
|
// 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 ix1 = system_instruction::transfer(&Pubkey::new_unique(), &Pubkey::new_unique(), 1);
|
||||||
let message =
|
let message =
|
||||||
SanitizedMessage::try_from(Message::new(&[ix0, ix1], Some(&Pubkey::new_unique()))).unwrap();
|
SanitizedMessage::try_from(Message::new(&[ix0, ix1], Some(&Pubkey::new_unique()))).unwrap();
|
||||||
assert_eq!(
|
for support_set_accounts_data_size_limit_ix in [true, false] {
|
||||||
Bank::calculate_fee(&message, 1, &fee_structure, true, false, true, true),
|
assert_eq!(
|
||||||
max_fee + 3 * lamports_per_signature
|
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
|
// Explicit fee schedule
|
||||||
|
|
||||||
|
@ -10823,11 +10858,22 @@ fn test_calculate_fee_compute_units() {
|
||||||
Some(&Pubkey::new_unique()),
|
Some(&Pubkey::new_unique()),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let fee = Bank::calculate_fee(&message, 1, &fee_structure, true, false, true, true);
|
for support_set_accounts_data_size_limit_ix in [true, false] {
|
||||||
assert_eq!(
|
let fee = Bank::calculate_fee(
|
||||||
fee,
|
&message,
|
||||||
lamports_per_signature + prioritization_fee_details.get_fee()
|
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),
|
Some(&key0),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
for support_set_accounts_data_size_limit_ix in [true, false] {
|
||||||
Bank::calculate_fee(&message, 1, &fee_structure, true, false, true, true),
|
assert_eq!(
|
||||||
2
|
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_instruction1.data = vec![0];
|
||||||
secp_instruction2.data = vec![10];
|
secp_instruction2.data = vec![10];
|
||||||
|
@ -10873,10 +10930,21 @@ fn test_calculate_fee_secp256k1() {
|
||||||
Some(&key0),
|
Some(&key0),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
for support_set_accounts_data_size_limit_ix in [true, false] {
|
||||||
Bank::calculate_fee(&message, 1, &fee_structure, true, false, true, true),
|
assert_eq!(
|
||||||
11
|
Bank::calculate_fee(
|
||||||
);
|
&message,
|
||||||
|
1,
|
||||||
|
&fee_structure,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
support_set_accounts_data_size_limit_ix
|
||||||
|
),
|
||||||
|
11
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -12606,6 +12674,7 @@ fn test_calculate_fee_with_congestion_multiplier() {
|
||||||
false,
|
false,
|
||||||
remove_congestion_multiplier,
|
remove_congestion_multiplier,
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
),
|
),
|
||||||
signature_fee * signature_count
|
signature_fee * signature_count
|
||||||
);
|
);
|
||||||
|
@ -12629,6 +12698,7 @@ fn test_calculate_fee_with_congestion_multiplier() {
|
||||||
false,
|
false,
|
||||||
remove_congestion_multiplier,
|
remove_congestion_multiplier,
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
),
|
),
|
||||||
signature_fee * signature_count / denominator
|
signature_fee * signature_count / denominator
|
||||||
);
|
);
|
||||||
|
@ -12670,6 +12740,7 @@ fn test_calculate_fee_with_request_heap_frame_flag() {
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
enable_request_heap_frame_ix,
|
enable_request_heap_frame_ix,
|
||||||
|
true,
|
||||||
),
|
),
|
||||||
signature_fee + request_cu * lamports_per_cu
|
signature_fee + request_cu * lamports_per_cu
|
||||||
);
|
);
|
||||||
|
@ -12686,6 +12757,7 @@ fn test_calculate_fee_with_request_heap_frame_flag() {
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
enable_request_heap_frame_ix,
|
enable_request_heap_frame_ix,
|
||||||
|
true,
|
||||||
),
|
),
|
||||||
signature_fee
|
signature_fee
|
||||||
);
|
);
|
||||||
|
|
|
@ -13,7 +13,8 @@ use {
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
feature_set::{
|
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,
|
instruction::CompiledInstruction,
|
||||||
program_utils::limited_deserialize,
|
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(&use_default_units_in_fee_calculation::id()),
|
||||||
!feature_set.is_active(&remove_deprecated_request_unit_ix::id()),
|
!feature_set.is_active(&remove_deprecated_request_unit_ix::id()),
|
||||||
enable_request_heap_frame_ix,
|
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
|
// if tx contained user-space instructions and a more accurate estimate available correct it
|
||||||
|
|
|
@ -26,6 +26,7 @@ pub trait GetTransactionPriorityDetails {
|
||||||
true, // use default units per instruction
|
true, // use default units per instruction
|
||||||
false, // stop supporting prioritization by request_units_deprecated instruction
|
false, // stop supporting prioritization by request_units_deprecated instruction
|
||||||
true, // enable request heap frame instruction
|
true, // enable request heap frame instruction
|
||||||
|
true, // enable support set accounts data size instruction
|
||||||
)
|
)
|
||||||
.ok()?;
|
.ok()?;
|
||||||
Some(TransactionPriorityDetails {
|
Some(TransactionPriorityDetails {
|
||||||
|
|
|
@ -41,6 +41,8 @@ pub enum ComputeBudgetInstruction {
|
||||||
/// Set a compute unit price in "micro-lamports" to pay a higher transaction
|
/// Set a compute unit price in "micro-lamports" to pay a higher transaction
|
||||||
/// fee for higher transaction prioritization.
|
/// fee for higher transaction prioritization.
|
||||||
SetComputeUnitPrice(u64),
|
SetComputeUnitPrice(u64),
|
||||||
|
/// Set a specific transaction-wide account data size limit, in bytes, is allowed to load.
|
||||||
|
SetLoadedAccountsDataSizeLimit(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComputeBudgetInstruction {
|
impl ComputeBudgetInstruction {
|
||||||
|
@ -65,4 +67,9 @@ impl ComputeBudgetInstruction {
|
||||||
pub fn pack(self) -> Result<Vec<u8>, std::io::Error> {
|
pub fn pack(self) -> Result<Vec<u8>, std::io::Error> {
|
||||||
self.try_to_vec()
|
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![])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -618,6 +618,10 @@ pub mod apply_cost_tracker_during_replay {
|
||||||
solana_sdk::declare_id!("2ry7ygxiYURULZCrypHhveanvP5tzZ4toRwVp89oCNSj");
|
solana_sdk::declare_id!("2ry7ygxiYURULZCrypHhveanvP5tzZ4toRwVp89oCNSj");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod add_set_tx_loaded_accounts_data_size_instruction {
|
||||||
|
solana_sdk::declare_id!("G6vbf1UBok8MWb8m25ex86aoQHeKTzDKzuZADHkShqm6");
|
||||||
|
}
|
||||||
|
|
||||||
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> = [
|
||||||
|
@ -767,6 +771,7 @@ lazy_static! {
|
||||||
(prevent_rent_paying_rent_recipients::id(), "prevent recipients of rent rewards from ending in rent-paying state #30151"),
|
(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"),
|
(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"),
|
(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 ***************/
|
/*************** ADD NEW FEATURES HERE ***************/
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
|
|
Loading…
Reference in New Issue