Replace executor cache usage with LoadedPrograms cache (#31462)
* Replace executor cache usage with LoadedPrograms cache * clippy fixes * update cache with updated programs * fixes * more cleanup * update tx batch cache with the tx results * address review comments * handle program closing backward compatibility * handle unloaded programs during extraction
This commit is contained in:
parent
fb7ba97afc
commit
2210af60ee
|
@ -15,7 +15,9 @@ use {
|
|||
},
|
||||
solana_program_runtime::{
|
||||
invoke_context::InvokeContext,
|
||||
loaded_programs::{LoadProgramMetrics, LoadedProgram, LoadedProgramType},
|
||||
loaded_programs::{
|
||||
LoadProgramMetrics, LoadedProgram, LoadedProgramType, DELAY_VISIBILITY_SLOT_OFFSET,
|
||||
},
|
||||
with_mock_invoke_context,
|
||||
},
|
||||
solana_rbpf::{
|
||||
|
@ -416,6 +418,9 @@ pub fn run(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
|||
bank.get_builtin_programs()
|
||||
);
|
||||
|
||||
// Adding `DELAY_VISIBILITY_SLOT_OFFSET` to slots to accommodate for delay visibility of the program
|
||||
let mut loaded_programs =
|
||||
LoadedProgramsForTxBatch::new(bank.slot() + DELAY_VISIBILITY_SLOT_OFFSET);
|
||||
for key in cached_account_keys {
|
||||
let program = bank.load_program(&key, true).unwrap_or_else(|err| {
|
||||
// Create a tombstone for the program in the cache
|
||||
|
@ -426,11 +431,9 @@ pub fn run(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
|||
))
|
||||
});
|
||||
debug!("Loaded program {}", key);
|
||||
invoke_context
|
||||
.tx_executor_cache
|
||||
.borrow_mut()
|
||||
.set(key, program, false, false, 0);
|
||||
loaded_programs.replenish(key, program);
|
||||
}
|
||||
invoke_context.programs_loaded_for_tx_batch = Rc::new(RefCell::new(loaded_programs));
|
||||
|
||||
invoke_context
|
||||
.transaction_context
|
||||
|
|
|
@ -3,9 +3,8 @@ use {
|
|||
accounts_data_meter::AccountsDataMeter,
|
||||
builtin_program::{BuiltinPrograms, ProcessInstructionWithContext},
|
||||
compute_budget::ComputeBudget,
|
||||
executor_cache::TransactionExecutorCache,
|
||||
ic_logger_msg, ic_msg,
|
||||
loaded_programs::LoadedProgramType,
|
||||
loaded_programs::{LoadedProgramType, LoadedProgramsForTxBatch},
|
||||
log_collector::LogCollector,
|
||||
pre_account::PreAccount,
|
||||
stable_log,
|
||||
|
@ -160,7 +159,9 @@ pub struct InvokeContext<'a> {
|
|||
current_compute_budget: ComputeBudget,
|
||||
compute_meter: RefCell<u64>,
|
||||
accounts_data_meter: AccountsDataMeter,
|
||||
pub tx_executor_cache: Rc<RefCell<TransactionExecutorCache>>,
|
||||
pub programs_loaded_for_tx_batch: Rc<RefCell<LoadedProgramsForTxBatch>>,
|
||||
pub programs_modified_by_tx: Rc<RefCell<LoadedProgramsForTxBatch>>,
|
||||
pub programs_updated_only_for_global_cache: Rc<RefCell<LoadedProgramsForTxBatch>>,
|
||||
pub feature_set: Arc<FeatureSet>,
|
||||
pub timings: ExecuteDetailsTimings,
|
||||
pub blockhash: Hash,
|
||||
|
@ -178,7 +179,9 @@ impl<'a> InvokeContext<'a> {
|
|||
sysvar_cache: &'a SysvarCache,
|
||||
log_collector: Option<Rc<RefCell<LogCollector>>>,
|
||||
compute_budget: ComputeBudget,
|
||||
tx_executor_cache: Rc<RefCell<TransactionExecutorCache>>,
|
||||
programs_loaded_for_tx_batch: Rc<RefCell<LoadedProgramsForTxBatch>>,
|
||||
programs_modified_by_tx: Rc<RefCell<LoadedProgramsForTxBatch>>,
|
||||
programs_updated_only_for_global_cache: Rc<RefCell<LoadedProgramsForTxBatch>>,
|
||||
feature_set: Arc<FeatureSet>,
|
||||
blockhash: Hash,
|
||||
lamports_per_signature: u64,
|
||||
|
@ -195,7 +198,9 @@ impl<'a> InvokeContext<'a> {
|
|||
compute_budget,
|
||||
compute_meter: RefCell::new(compute_budget.compute_unit_limit),
|
||||
accounts_data_meter: AccountsDataMeter::new(prev_accounts_data_len),
|
||||
tx_executor_cache,
|
||||
programs_loaded_for_tx_batch,
|
||||
programs_modified_by_tx,
|
||||
programs_updated_only_for_global_cache,
|
||||
feature_set,
|
||||
timings: ExecuteDetailsTimings::default(),
|
||||
blockhash,
|
||||
|
@ -902,8 +907,8 @@ macro_rules! with_mock_invoke_context_and_builtin_programs {
|
|||
},
|
||||
std::{cell::RefCell, rc::Rc, sync::Arc},
|
||||
$crate::{
|
||||
compute_budget::ComputeBudget, executor_cache::TransactionExecutorCache,
|
||||
invoke_context::InvokeContext, log_collector::LogCollector,
|
||||
compute_budget::ComputeBudget, invoke_context::InvokeContext,
|
||||
loaded_programs::LoadedProgramsForTxBatch, log_collector::LogCollector,
|
||||
sysvar_cache::SysvarCache,
|
||||
},
|
||||
};
|
||||
|
@ -940,7 +945,9 @@ macro_rules! with_mock_invoke_context_and_builtin_programs {
|
|||
&sysvar_cache,
|
||||
Some(LogCollector::new_ref()),
|
||||
compute_budget,
|
||||
Rc::new(RefCell::new(TransactionExecutorCache::default())),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Arc::new(FeatureSet::all_enabled()),
|
||||
Hash::default(),
|
||||
0,
|
||||
|
|
|
@ -281,9 +281,16 @@ pub struct LoadedProgramsForTxBatch {
|
|||
}
|
||||
|
||||
impl LoadedProgramsForTxBatch {
|
||||
pub fn new(slot: Slot) -> Self {
|
||||
Self {
|
||||
entries: HashMap::new(),
|
||||
slot,
|
||||
}
|
||||
}
|
||||
|
||||
/// Refill the cache with a single entry. It's typically called during transaction loading, and
|
||||
/// transaction processing (for program management instructions).
|
||||
/// The replaces the existing entry (if any) with the provided entry. The return value contains
|
||||
/// It replaces the existing entry (if any) with the provided entry. The return value contains
|
||||
/// `true` if an entry existed.
|
||||
/// The function also returns the newly inserted value.
|
||||
pub fn replenish(
|
||||
|
@ -291,7 +298,6 @@ impl LoadedProgramsForTxBatch {
|
|||
key: Pubkey,
|
||||
entry: Arc<LoadedProgram>,
|
||||
) -> (bool, Arc<LoadedProgram>) {
|
||||
debug_assert!(entry.effective_slot <= self.slot);
|
||||
(self.entries.insert(key, entry.clone()).is_some(), entry)
|
||||
}
|
||||
|
||||
|
@ -314,6 +320,16 @@ impl LoadedProgramsForTxBatch {
|
|||
pub fn slot(&self) -> Slot {
|
||||
self.slot
|
||||
}
|
||||
|
||||
pub fn set_slot_for_tests(&mut self, slot: Slot) {
|
||||
self.slot = slot;
|
||||
}
|
||||
|
||||
pub fn merge(&mut self, other: &Self) {
|
||||
other.entries.iter().for_each(|(key, entry)| {
|
||||
self.replenish(*key, entry.clone());
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub enum LoadedProgramMatchCriteria {
|
||||
|
@ -453,6 +469,12 @@ impl LoadedPrograms {
|
|||
return None;
|
||||
}
|
||||
|
||||
if matches!(entry.program, LoadedProgramType::Unloaded) {
|
||||
// The program was unloaded. Consider it as missing, so it can be reloaded.
|
||||
missing.push(key);
|
||||
return None;
|
||||
}
|
||||
|
||||
if current_slot >= entry.effective_slot {
|
||||
return Some((key, entry.clone()));
|
||||
} else if entry.is_implicit_delay_visibility_tombstone(current_slot) {
|
||||
|
@ -483,6 +505,12 @@ impl LoadedPrograms {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn merge(&mut self, tx_batch_cache: &LoadedProgramsForTxBatch) {
|
||||
tx_batch_cache.entries.iter().for_each(|(key, entry)| {
|
||||
self.replenish(*key, entry.clone());
|
||||
})
|
||||
}
|
||||
|
||||
/// Unloads programs which were used infrequently
|
||||
pub fn sort_and_unload(&mut self, shrink_to: PercentageInteger) {
|
||||
let sorted_candidates: Vec<(Pubkey, Arc<LoadedProgram>)> = self
|
||||
|
|
|
@ -10,7 +10,9 @@ use {
|
|||
compute_budget::ComputeBudget,
|
||||
ic_logger_msg, ic_msg,
|
||||
invoke_context::{BpfAllocator, InvokeContext, SyscallContext},
|
||||
loaded_programs::{LoadProgramMetrics, LoadedProgram, LoadedProgramType},
|
||||
loaded_programs::{
|
||||
LoadProgramMetrics, LoadedProgram, LoadedProgramType, DELAY_VISIBILITY_SLOT_OFFSET,
|
||||
},
|
||||
log_collector::LogCollector,
|
||||
stable_log,
|
||||
sysvar_cache::get_sysvar_with_account_check,
|
||||
|
@ -91,7 +93,7 @@ pub fn load_program_from_bytes(
|
|||
register_syscalls_time.stop();
|
||||
load_program_metrics.register_syscalls_us = register_syscalls_time.as_us();
|
||||
let effective_slot = if feature_set.is_active(&delay_visibility_of_program_deployment::id()) {
|
||||
deployment_slot.saturating_add(1)
|
||||
deployment_slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET)
|
||||
} else {
|
||||
deployment_slot
|
||||
};
|
||||
|
@ -190,12 +192,27 @@ pub fn load_program_from_account(
|
|||
Ok((loaded_program, Some(load_program_metrics)))
|
||||
}
|
||||
|
||||
fn find_program_in_cache(
|
||||
invoke_context: &InvokeContext,
|
||||
pubkey: &Pubkey,
|
||||
) -> Option<Arc<LoadedProgram>> {
|
||||
// First lookup the cache of the programs modified by the current transaction. If not found, lookup
|
||||
// the cache of the cache of the programs that are loaded for the transaction batch.
|
||||
invoke_context
|
||||
.programs_modified_by_tx
|
||||
.borrow()
|
||||
.find(pubkey)
|
||||
.or_else(|| {
|
||||
invoke_context
|
||||
.programs_loaded_for_tx_batch
|
||||
.borrow()
|
||||
.find(pubkey)
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! deploy_program {
|
||||
($invoke_context:expr, $program_id:expr, $loader_key:expr,
|
||||
$account_size:expr, $slot:expr, $drop:expr, $new_programdata:expr $(,)?) => {{
|
||||
let delay_visibility_of_program_deployment = $invoke_context
|
||||
.feature_set
|
||||
.is_active(&delay_visibility_of_program_deployment::id());
|
||||
let mut load_program_metrics = LoadProgramMetrics::default();
|
||||
let executor = load_program_from_bytes(
|
||||
&$invoke_context.feature_set,
|
||||
|
@ -209,20 +226,14 @@ macro_rules! deploy_program {
|
|||
true, /* reject_deployment_of_broken_elfs */
|
||||
false, /* debugging_features */
|
||||
)?;
|
||||
if let Some(old_entry) = $invoke_context.tx_executor_cache.borrow().get(&$program_id) {
|
||||
if let Some(old_entry) = find_program_in_cache($invoke_context, &$program_id) {
|
||||
let usage_counter = old_entry.usage_counter.load(Ordering::Relaxed);
|
||||
executor.usage_counter.store(usage_counter, Ordering::Relaxed);
|
||||
}
|
||||
$drop
|
||||
load_program_metrics.program_id = $program_id.to_string();
|
||||
load_program_metrics.submit_datapoint(&mut $invoke_context.timings);
|
||||
$invoke_context.tx_executor_cache.borrow_mut().set(
|
||||
$program_id,
|
||||
Arc::new(executor),
|
||||
true,
|
||||
delay_visibility_of_program_deployment,
|
||||
$slot,
|
||||
);
|
||||
$invoke_context.programs_modified_by_tx.borrow_mut().replenish($program_id, Arc::new(executor));
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -562,10 +573,7 @@ fn process_instruction_inner(
|
|||
}
|
||||
|
||||
let mut get_or_create_executor_time = Measure::start("get_or_create_executor_time");
|
||||
let executor = invoke_context
|
||||
.tx_executor_cache
|
||||
.borrow()
|
||||
.get(program_account.get_key())
|
||||
let executor = find_program_in_cache(invoke_context, program_account.get_key())
|
||||
.ok_or(InstructionError::InvalidAccountData)?;
|
||||
|
||||
if executor.is_tombstone() {
|
||||
|
@ -1265,15 +1273,32 @@ fn process_loader_upgradeable_instruction(
|
|||
instruction_context,
|
||||
&log_collector,
|
||||
)?;
|
||||
let clock = invoke_context.get_sysvar_cache().get_clock()?;
|
||||
if invoke_context
|
||||
.feature_set
|
||||
.is_active(&delay_visibility_of_program_deployment::id())
|
||||
{
|
||||
let clock = invoke_context.get_sysvar_cache().get_clock()?;
|
||||
invoke_context
|
||||
.tx_executor_cache
|
||||
.programs_modified_by_tx
|
||||
.borrow_mut()
|
||||
.set_tombstone(program_key, clock.slot);
|
||||
.replenish(
|
||||
program_key,
|
||||
Arc::new(LoadedProgram::new_tombstone(
|
||||
clock.slot,
|
||||
LoadedProgramType::Closed,
|
||||
)),
|
||||
);
|
||||
} else {
|
||||
invoke_context
|
||||
.programs_updated_only_for_global_cache
|
||||
.borrow_mut()
|
||||
.replenish(
|
||||
program_key,
|
||||
Arc::new(LoadedProgram::new_tombstone(
|
||||
clock.slot,
|
||||
LoadedProgramType::Closed,
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
@ -1661,7 +1686,10 @@ fn execute<'a, 'b: 'a>(
|
|||
}
|
||||
|
||||
pub mod test_utils {
|
||||
use {super::*, solana_sdk::account::ReadableAccount};
|
||||
use {
|
||||
super::*, solana_program_runtime::loaded_programs::DELAY_VISIBILITY_SLOT_OFFSET,
|
||||
solana_sdk::account::ReadableAccount,
|
||||
};
|
||||
|
||||
pub fn load_all_invoked_programs(invoke_context: &mut InvokeContext) {
|
||||
let num_accounts = invoke_context.transaction_context.get_number_of_accounts();
|
||||
|
@ -1693,8 +1721,9 @@ pub mod test_utils {
|
|||
true,
|
||||
false,
|
||||
) {
|
||||
let mut cache = invoke_context.tx_executor_cache.borrow_mut();
|
||||
cache.set(*pubkey, Arc::new(loaded_program), true, false, 0)
|
||||
let mut cache = invoke_context.programs_modified_by_tx.borrow_mut();
|
||||
cache.set_slot_for_tests(DELAY_VISIBILITY_SLOT_OFFSET);
|
||||
cache.replenish(*pubkey, Arc::new(loaded_program));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4096,13 +4125,10 @@ mod tests {
|
|||
maybe_expiration_slot: None,
|
||||
usage_counter: AtomicU64::new(100),
|
||||
};
|
||||
invoke_context.tx_executor_cache.borrow_mut().set(
|
||||
program_id,
|
||||
Arc::new(program),
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
);
|
||||
invoke_context
|
||||
.programs_modified_by_tx
|
||||
.borrow_mut()
|
||||
.replenish(program_id, Arc::new(program));
|
||||
|
||||
assert!(matches!(
|
||||
deploy_test_program(&mut invoke_context, program_id,),
|
||||
|
@ -4110,9 +4136,9 @@ mod tests {
|
|||
));
|
||||
|
||||
let updated_program = invoke_context
|
||||
.tx_executor_cache
|
||||
.programs_modified_by_tx
|
||||
.borrow()
|
||||
.get(&program_id)
|
||||
.find(&program_id)
|
||||
.expect("Didn't find upgraded program in the cache");
|
||||
|
||||
assert_eq!(updated_program.deployment_slot, 2);
|
||||
|
@ -4132,13 +4158,10 @@ mod tests {
|
|||
maybe_expiration_slot: None,
|
||||
usage_counter: AtomicU64::new(100),
|
||||
};
|
||||
invoke_context.tx_executor_cache.borrow_mut().set(
|
||||
program_id,
|
||||
Arc::new(program),
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
);
|
||||
invoke_context
|
||||
.programs_modified_by_tx
|
||||
.borrow_mut()
|
||||
.replenish(program_id, Arc::new(program));
|
||||
|
||||
let program_id2 = Pubkey::new_unique();
|
||||
assert!(matches!(
|
||||
|
@ -4147,9 +4170,9 @@ mod tests {
|
|||
));
|
||||
|
||||
let program2 = invoke_context
|
||||
.tx_executor_cache
|
||||
.programs_modified_by_tx
|
||||
.borrow()
|
||||
.get(&program_id2)
|
||||
.find(&program_id2)
|
||||
.expect("Didn't find upgraded program in the cache");
|
||||
|
||||
assert_eq!(program2.deployment_slot, 2);
|
||||
|
|
|
@ -379,7 +379,10 @@ fn test_program_sbf_loader_deprecated() {
|
|||
let bank = Bank::new_for_tests(&genesis_config);
|
||||
let program_id = create_program(&bank, &bpf_loader_deprecated::id(), program);
|
||||
|
||||
let bank_client = BankClient::new(bank);
|
||||
let mut bank_client = BankClient::new(bank);
|
||||
bank_client
|
||||
.advance_slot(1, &Pubkey::default())
|
||||
.expect("Failed to advance the slot");
|
||||
let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)];
|
||||
let instruction = Instruction::new_with_bytes(program_id, &[1], account_metas);
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
|
@ -2065,8 +2068,10 @@ fn test_program_sbf_invoke_in_same_tx_as_redeployment() {
|
|||
],
|
||||
);
|
||||
|
||||
// load_upgradeable_program sets clock sysvar to 1, which causes the program to be effective
|
||||
// after 2 slots. So we need to advance the bank client by 2 slots here.
|
||||
let bank = bank_client
|
||||
.advance_slot(1, &Pubkey::default())
|
||||
.advance_slot(2, &Pubkey::default())
|
||||
.expect("Failed to advance slot");
|
||||
|
||||
// Prepare redeployment
|
||||
|
@ -2160,8 +2165,10 @@ fn test_program_sbf_invoke_in_same_tx_as_undeployment() {
|
|||
],
|
||||
);
|
||||
|
||||
// load_upgradeable_program sets clock sysvar to 1, which causes the program to be effective
|
||||
// after 2 slots. So we need to advance the bank client by 2 slots here.
|
||||
let bank = bank_client
|
||||
.advance_slot(1, &Pubkey::default())
|
||||
.advance_slot(2, &Pubkey::default())
|
||||
.expect("Failed to advance slot");
|
||||
|
||||
// Prepare undeployment
|
||||
|
@ -3904,7 +3911,10 @@ fn test_program_sbf_inner_instruction_alignment_checks() {
|
|||
|
||||
// invoke unaligned program, which will call aligned program twice,
|
||||
// unaligned should be allowed once invoke completes
|
||||
let bank_client = BankClient::new(bank);
|
||||
let mut bank_client = BankClient::new(bank);
|
||||
bank_client
|
||||
.advance_slot(1, &Pubkey::default())
|
||||
.expect("Failed to advance the slot");
|
||||
let mut instruction = Instruction::new_with_bytes(
|
||||
inner_instruction_alignment_check,
|
||||
&[0],
|
||||
|
|
|
@ -26,7 +26,7 @@ use {
|
|||
solana_address_lookup_table_program::{error::AddressLookupError, state::AddressLookupTable},
|
||||
solana_program_runtime::{
|
||||
compute_budget::{self, ComputeBudget},
|
||||
loaded_programs::{LoadedProgram, LoadedProgramType},
|
||||
loaded_programs::{LoadedProgram, LoadedProgramType, LoadedProgramsForTxBatch},
|
||||
},
|
||||
solana_sdk::{
|
||||
account::{Account, AccountSharedData, ReadableAccount, WritableAccount},
|
||||
|
@ -337,7 +337,7 @@ impl Accounts {
|
|||
feature_set: &FeatureSet,
|
||||
account_overrides: Option<&AccountOverrides>,
|
||||
program_accounts: &HashMap<Pubkey, &Pubkey>,
|
||||
loaded_programs: &HashMap<Pubkey, Arc<LoadedProgram>>,
|
||||
loaded_programs: &LoadedProgramsForTxBatch,
|
||||
) -> Result<LoadedTransaction> {
|
||||
// NOTE: this check will never fail because `tx` is sanitized
|
||||
if tx.signatures().is_empty() && fee != 0 {
|
||||
|
@ -390,7 +390,7 @@ impl Accounts {
|
|||
(account_override.data().len(), account_override.clone(), 0)
|
||||
} else if let Some(program) = (!instruction_account && !message.is_writable(i))
|
||||
.then_some(())
|
||||
.and_then(|_| loaded_programs.get(key))
|
||||
.and_then(|_| loaded_programs.find(key))
|
||||
{
|
||||
// This condition block does special handling for accounts that are passed
|
||||
// as instruction account to any of the instructions in the transaction.
|
||||
|
@ -401,7 +401,7 @@ impl Accounts {
|
|||
Self::account_shared_data_from_program(
|
||||
key,
|
||||
feature_set,
|
||||
program,
|
||||
program.as_ref(),
|
||||
program_accounts,
|
||||
)
|
||||
.map(|program_account| (program.account_size, program_account, 0))?
|
||||
|
@ -695,7 +695,7 @@ impl Accounts {
|
|||
fee_structure: &FeeStructure,
|
||||
account_overrides: Option<&AccountOverrides>,
|
||||
program_accounts: &HashMap<Pubkey, &Pubkey>,
|
||||
loaded_programs: &HashMap<Pubkey, Arc<LoadedProgram>>,
|
||||
loaded_programs: &LoadedProgramsForTxBatch,
|
||||
) -> Vec<TransactionLoadResult> {
|
||||
txs.iter()
|
||||
.zip(lock_results)
|
||||
|
@ -1470,9 +1470,8 @@ mod tests {
|
|||
},
|
||||
assert_matches::assert_matches,
|
||||
solana_address_lookup_table_program::state::LookupTableMeta,
|
||||
solana_program_runtime::{
|
||||
executor_cache::TransactionExecutorCache,
|
||||
prioritization_fee::{PrioritizationFeeDetails, PrioritizationFeeType},
|
||||
solana_program_runtime::prioritization_fee::{
|
||||
PrioritizationFeeDetails, PrioritizationFeeType,
|
||||
},
|
||||
solana_sdk::{
|
||||
account::{AccountSharedData, WritableAccount},
|
||||
|
@ -1525,7 +1524,10 @@ mod tests {
|
|||
executed_units: 0,
|
||||
accounts_data_len_delta: 0,
|
||||
},
|
||||
tx_executor_cache: Rc::new(RefCell::new(TransactionExecutorCache::default())),
|
||||
programs_modified_by_tx: Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
programs_updated_only_for_global_cache: Rc::new(RefCell::new(
|
||||
LoadedProgramsForTxBatch::default(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1563,7 +1565,7 @@ mod tests {
|
|||
fee_structure,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
&HashMap::new(),
|
||||
&LoadedProgramsForTxBatch::default(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -3367,7 +3369,7 @@ mod tests {
|
|||
&FeeStructure::default(),
|
||||
account_overrides,
|
||||
&HashMap::new(),
|
||||
&HashMap::new(),
|
||||
&LoadedProgramsForTxBatch::default(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
//! It offers a high-level API that signs transactions
|
||||
//! on behalf of the caller, and a low-level API for when they have
|
||||
//! already been signed and verified.
|
||||
#[cfg(test)]
|
||||
use solana_program_runtime::executor_cache::TransactionExecutorCache;
|
||||
#[allow(deprecated)]
|
||||
use solana_sdk::recent_blockhashes_account;
|
||||
pub use solana_sdk::reward_type::RewardType;
|
||||
|
@ -95,7 +97,7 @@ use {
|
|||
accounts_data_meter::MAX_ACCOUNTS_DATA_LEN,
|
||||
builtin_program::BuiltinPrograms,
|
||||
compute_budget::{self, ComputeBudget},
|
||||
executor_cache::{BankExecutorCache, TransactionExecutorCache, MAX_CACHED_EXECUTORS},
|
||||
executor_cache::{BankExecutorCache, MAX_CACHED_EXECUTORS},
|
||||
loaded_programs::{
|
||||
LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType, LoadedPrograms,
|
||||
LoadedProgramsForTxBatch, WorkingSlot,
|
||||
|
@ -321,7 +323,8 @@ pub struct TransactionExecutionDetails {
|
|||
pub enum TransactionExecutionResult {
|
||||
Executed {
|
||||
details: TransactionExecutionDetails,
|
||||
tx_executor_cache: Rc<RefCell<TransactionExecutorCache>>,
|
||||
programs_modified_by_tx: Rc<RefCell<LoadedProgramsForTxBatch>>,
|
||||
programs_updated_only_for_global_cache: Rc<RefCell<LoadedProgramsForTxBatch>>,
|
||||
},
|
||||
NotExecuted(TransactionError),
|
||||
}
|
||||
|
@ -4108,6 +4111,7 @@ impl Bank {
|
|||
}
|
||||
|
||||
/// Add executors back to the bank's cache if they were missing and not re-/deployed
|
||||
#[cfg(test)]
|
||||
fn store_executors_which_added_to_the_cache(
|
||||
&self,
|
||||
tx_executor_cache: &RefCell<TransactionExecutorCache>,
|
||||
|
@ -4124,6 +4128,7 @@ impl Bank {
|
|||
}
|
||||
|
||||
/// Add re-/deployed executors to the bank's cache
|
||||
#[cfg(test)]
|
||||
fn store_executors_which_were_deployed(
|
||||
&self,
|
||||
tx_executor_cache: &RefCell<TransactionExecutorCache>,
|
||||
|
@ -4174,7 +4179,6 @@ impl Bank {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Preparation for BankExecutorCache rework
|
||||
pub fn load_program(
|
||||
&self,
|
||||
pubkey: &Pubkey,
|
||||
|
@ -4263,7 +4267,7 @@ impl Bank {
|
|||
timings: &mut ExecuteTimings,
|
||||
error_counters: &mut TransactionErrorMetrics,
|
||||
log_messages_bytes_limit: Option<usize>,
|
||||
tx_executor_cache: Rc<RefCell<TransactionExecutorCache>>,
|
||||
programs_loaded_for_tx_batch: Rc<RefCell<LoadedProgramsForTxBatch>>,
|
||||
) -> TransactionExecutionResult {
|
||||
let prev_accounts_data_len = self.load_accounts_data_size();
|
||||
let transaction_accounts = std::mem::take(&mut loaded_transaction.accounts);
|
||||
|
@ -4313,7 +4317,10 @@ impl Bank {
|
|||
let (blockhash, lamports_per_signature) = self.last_blockhash_and_lamports_per_signature();
|
||||
|
||||
let mut executed_units = 0u64;
|
||||
|
||||
let programs_modified_by_tx =
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::new(self.slot)));
|
||||
let programs_updated_only_for_global_cache =
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::new(self.slot)));
|
||||
let mut process_message_time = Measure::start("process_message_time");
|
||||
let process_result = MessageProcessor::process_message(
|
||||
&self.builtin_programs,
|
||||
|
@ -4322,7 +4329,9 @@ impl Bank {
|
|||
&mut transaction_context,
|
||||
self.rent_collector.rent,
|
||||
log_collector.clone(),
|
||||
tx_executor_cache.clone(),
|
||||
programs_loaded_for_tx_batch,
|
||||
programs_modified_by_tx.clone(),
|
||||
programs_updated_only_for_global_cache.clone(),
|
||||
self.feature_set.clone(),
|
||||
compute_budget,
|
||||
timings,
|
||||
|
@ -4339,15 +4348,6 @@ impl Bank {
|
|||
process_message_time.as_us()
|
||||
);
|
||||
|
||||
let mut store_executors_which_added_to_the_cache_time =
|
||||
Measure::start("store_executors_which_added_to_the_cache_time");
|
||||
self.store_executors_which_added_to_the_cache(&tx_executor_cache);
|
||||
store_executors_which_added_to_the_cache_time.stop();
|
||||
saturating_add_assign!(
|
||||
timings.execute_accessories.update_executors_us,
|
||||
store_executors_which_added_to_the_cache_time.as_us()
|
||||
);
|
||||
|
||||
let status = process_result
|
||||
.and_then(|info| {
|
||||
let post_account_state_info =
|
||||
|
@ -4435,7 +4435,8 @@ impl Bank {
|
|||
executed_units,
|
||||
accounts_data_len_delta,
|
||||
},
|
||||
tx_executor_cache,
|
||||
programs_modified_by_tx,
|
||||
programs_updated_only_for_global_cache,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4448,8 +4449,7 @@ impl Bank {
|
|||
|| self.cluster_type() != ClusterType::MainnetBeta
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Preparation for BankExecutorCache rework
|
||||
fn load_and_get_programs_from_cache(
|
||||
fn replenish_program_cache(
|
||||
&self,
|
||||
program_accounts_map: &HashMap<Pubkey, &Pubkey>,
|
||||
) -> LoadedProgramsForTxBatch {
|
||||
|
@ -4507,6 +4507,7 @@ impl Bank {
|
|||
loaded_programs_for_txs
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Preparation for BankExecutorCache rework
|
||||
fn replenish_executor_cache(
|
||||
&self,
|
||||
program_accounts_map: &HashMap<Pubkey, &Pubkey>,
|
||||
|
@ -4626,17 +4627,9 @@ impl Bank {
|
|||
&self.blockhash_queue.read().unwrap(),
|
||||
);
|
||||
|
||||
// The following code is currently commented out. This is how the new cache will
|
||||
// finally be used, once rest of the code blocks are in place.
|
||||
/*
|
||||
let loaded_programs_map =
|
||||
self.load_and_get_programs_from_cache(&program_accounts_map);
|
||||
*/
|
||||
let loaded_programs_map = self.replenish_executor_cache(&program_accounts_map);
|
||||
|
||||
let tx_executor_cache = Rc::new(RefCell::new(TransactionExecutorCache::new(
|
||||
loaded_programs_map.clone().into_iter(),
|
||||
)));
|
||||
let programs_loaded_for_tx_batch = Rc::new(RefCell::new(
|
||||
self.replenish_program_cache(&program_accounts_map),
|
||||
));
|
||||
|
||||
let mut load_time = Measure::start("accounts_load");
|
||||
let mut loaded_transactions = self.rc.accounts.load_accounts(
|
||||
|
@ -4650,7 +4643,7 @@ impl Bank {
|
|||
&self.fee_structure,
|
||||
account_overrides,
|
||||
&program_accounts_map,
|
||||
&loaded_programs_map,
|
||||
&programs_loaded_for_tx_batch.borrow(),
|
||||
);
|
||||
load_time.stop();
|
||||
|
||||
|
@ -4696,7 +4689,7 @@ impl Bank {
|
|||
compute_budget
|
||||
};
|
||||
|
||||
self.execute_loaded_transaction(
|
||||
let result = self.execute_loaded_transaction(
|
||||
tx,
|
||||
loaded_transaction,
|
||||
compute_budget,
|
||||
|
@ -4707,8 +4700,25 @@ impl Bank {
|
|||
timings,
|
||||
&mut error_counters,
|
||||
log_messages_bytes_limit,
|
||||
tx_executor_cache.clone(),
|
||||
)
|
||||
programs_loaded_for_tx_batch.clone(),
|
||||
);
|
||||
|
||||
if let TransactionExecutionResult::Executed {
|
||||
details,
|
||||
programs_modified_by_tx,
|
||||
programs_updated_only_for_global_cache: _,
|
||||
} = &result
|
||||
{
|
||||
// Update batch specific cache of the loaded programs with the modifications
|
||||
// made by the transaction, if it executed successfully.
|
||||
if details.status.is_ok() {
|
||||
programs_loaded_for_tx_batch
|
||||
.borrow_mut()
|
||||
.merge(&programs_modified_by_tx.borrow());
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
@ -5193,11 +5203,14 @@ impl Bank {
|
|||
for execution_result in &execution_results {
|
||||
if let TransactionExecutionResult::Executed {
|
||||
details,
|
||||
tx_executor_cache,
|
||||
programs_modified_by_tx,
|
||||
programs_updated_only_for_global_cache,
|
||||
} = execution_result
|
||||
{
|
||||
if details.status.is_ok() {
|
||||
self.store_executors_which_were_deployed(tx_executor_cache);
|
||||
let mut cache = self.loaded_programs_cache.write().unwrap();
|
||||
cache.merge(&programs_modified_by_tx.borrow());
|
||||
cache.merge(&programs_updated_only_for_global_cache.borrow());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ use {
|
|||
declare_process_instruction,
|
||||
executor_cache::TransactionExecutorCache,
|
||||
invoke_context::mock_process_instruction,
|
||||
loaded_programs::{LoadedProgram, LoadedProgramType},
|
||||
loaded_programs::{LoadedProgram, LoadedProgramType, DELAY_VISIBILITY_SLOT_OFFSET},
|
||||
prioritization_fee::{PrioritizationFeeDetails, PrioritizationFeeType},
|
||||
timings::ExecuteTimings,
|
||||
},
|
||||
|
@ -176,7 +176,10 @@ fn new_execution_result(
|
|||
executed_units: 0,
|
||||
accounts_data_len_delta: 0,
|
||||
},
|
||||
tx_executor_cache: Rc::new(RefCell::new(TransactionExecutorCache::default())),
|
||||
programs_modified_by_tx: Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
programs_updated_only_for_global_cache: Rc::new(RefCell::new(
|
||||
LoadedProgramsForTxBatch::default(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7771,14 +7774,9 @@ fn test_bpf_loader_upgradeable_deploy_with_max_len() {
|
|||
Ok(()),
|
||||
solana_bpf_loader_program::process_instruction,
|
||||
|invoke_context| {
|
||||
let mut cache = invoke_context.tx_executor_cache.borrow_mut();
|
||||
cache.set(
|
||||
program_keypair.pubkey(),
|
||||
loaded_program.clone(),
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
);
|
||||
let mut cache = invoke_context.programs_modified_by_tx.borrow_mut();
|
||||
cache.set_slot_for_tests(bank.slot() + DELAY_VISIBILITY_SLOT_OFFSET);
|
||||
cache.replenish(program_keypair.pubkey(), loaded_program.clone());
|
||||
},
|
||||
|_invoke_context| {},
|
||||
);
|
||||
|
@ -11506,7 +11504,7 @@ fn test_rent_state_list_len() {
|
|||
&FeeStructure::default(),
|
||||
None,
|
||||
&HashMap::new(),
|
||||
&HashMap::new(),
|
||||
&LoadedProgramsForTxBatch::default(),
|
||||
);
|
||||
|
||||
let compute_budget = bank.runtime_config.compute_budget.unwrap_or_else(|| {
|
||||
|
|
|
@ -4,8 +4,8 @@ use {
|
|||
solana_program_runtime::{
|
||||
builtin_program::BuiltinPrograms,
|
||||
compute_budget::ComputeBudget,
|
||||
executor_cache::TransactionExecutorCache,
|
||||
invoke_context::InvokeContext,
|
||||
loaded_programs::LoadedProgramsForTxBatch,
|
||||
log_collector::LogCollector,
|
||||
sysvar_cache::SysvarCache,
|
||||
timings::{ExecuteDetailsTimings, ExecuteTimings},
|
||||
|
@ -58,7 +58,9 @@ impl MessageProcessor {
|
|||
transaction_context: &mut TransactionContext,
|
||||
rent: Rent,
|
||||
log_collector: Option<Rc<RefCell<LogCollector>>>,
|
||||
tx_executor_cache: Rc<RefCell<TransactionExecutorCache>>,
|
||||
programs_loaded_for_tx_batch: Rc<RefCell<LoadedProgramsForTxBatch>>,
|
||||
programs_modified_by_tx: Rc<RefCell<LoadedProgramsForTxBatch>>,
|
||||
programs_updated_only_for_global_cache: Rc<RefCell<LoadedProgramsForTxBatch>>,
|
||||
feature_set: Arc<FeatureSet>,
|
||||
compute_budget: ComputeBudget,
|
||||
timings: &mut ExecuteTimings,
|
||||
|
@ -75,7 +77,9 @@ impl MessageProcessor {
|
|||
sysvar_cache,
|
||||
log_collector,
|
||||
compute_budget,
|
||||
tx_executor_cache,
|
||||
programs_loaded_for_tx_batch,
|
||||
programs_modified_by_tx,
|
||||
programs_updated_only_for_global_cache,
|
||||
feature_set,
|
||||
blockhash,
|
||||
lamports_per_signature,
|
||||
|
@ -272,7 +276,8 @@ mod tests {
|
|||
let mut transaction_context =
|
||||
TransactionContext::new(accounts, Some(Rent::default()), 1, 3);
|
||||
let program_indices = vec![vec![2]];
|
||||
let tx_executor_cache = Rc::new(RefCell::new(TransactionExecutorCache::default()));
|
||||
let programs_loaded_for_tx_batch =
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default()));
|
||||
let account_keys = (0..transaction_context.get_number_of_accounts())
|
||||
.map(|index| {
|
||||
*transaction_context
|
||||
|
@ -308,7 +313,9 @@ mod tests {
|
|||
&mut transaction_context,
|
||||
rent_collector.rent,
|
||||
None,
|
||||
tx_executor_cache.clone(),
|
||||
programs_loaded_for_tx_batch.clone(),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Arc::new(FeatureSet::all_enabled()),
|
||||
ComputeBudget::default(),
|
||||
&mut ExecuteTimings::default(),
|
||||
|
@ -358,7 +365,9 @@ mod tests {
|
|||
&mut transaction_context,
|
||||
rent_collector.rent,
|
||||
None,
|
||||
tx_executor_cache.clone(),
|
||||
programs_loaded_for_tx_batch.clone(),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Arc::new(FeatureSet::all_enabled()),
|
||||
ComputeBudget::default(),
|
||||
&mut ExecuteTimings::default(),
|
||||
|
@ -398,7 +407,9 @@ mod tests {
|
|||
&mut transaction_context,
|
||||
rent_collector.rent,
|
||||
None,
|
||||
tx_executor_cache,
|
||||
programs_loaded_for_tx_batch,
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Arc::new(FeatureSet::all_enabled()),
|
||||
ComputeBudget::default(),
|
||||
&mut ExecuteTimings::default(),
|
||||
|
@ -496,7 +507,8 @@ mod tests {
|
|||
let mut transaction_context =
|
||||
TransactionContext::new(accounts, Some(Rent::default()), 1, 3);
|
||||
let program_indices = vec![vec![2]];
|
||||
let tx_executor_cache = Rc::new(RefCell::new(TransactionExecutorCache::default()));
|
||||
let programs_loaded_for_tx_batch =
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default()));
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(
|
||||
*transaction_context.get_key_of_account_at_index(0).unwrap(),
|
||||
|
@ -529,7 +541,9 @@ mod tests {
|
|||
&mut transaction_context,
|
||||
rent_collector.rent,
|
||||
None,
|
||||
tx_executor_cache.clone(),
|
||||
programs_loaded_for_tx_batch.clone(),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Arc::new(FeatureSet::all_enabled()),
|
||||
ComputeBudget::default(),
|
||||
&mut ExecuteTimings::default(),
|
||||
|
@ -563,7 +577,9 @@ mod tests {
|
|||
&mut transaction_context,
|
||||
rent_collector.rent,
|
||||
None,
|
||||
tx_executor_cache.clone(),
|
||||
programs_loaded_for_tx_batch.clone(),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Arc::new(FeatureSet::all_enabled()),
|
||||
ComputeBudget::default(),
|
||||
&mut ExecuteTimings::default(),
|
||||
|
@ -594,7 +610,9 @@ mod tests {
|
|||
&mut transaction_context,
|
||||
rent_collector.rent,
|
||||
None,
|
||||
tx_executor_cache,
|
||||
programs_loaded_for_tx_batch,
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Arc::new(FeatureSet::all_enabled()),
|
||||
ComputeBudget::default(),
|
||||
&mut ExecuteTimings::default(),
|
||||
|
@ -668,7 +686,9 @@ mod tests {
|
|||
&mut transaction_context,
|
||||
RentCollector::default().rent,
|
||||
None,
|
||||
Rc::new(RefCell::new(TransactionExecutorCache::default())),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Rc::new(RefCell::new(LoadedProgramsForTxBatch::default())),
|
||||
Arc::new(FeatureSet::all_enabled()),
|
||||
ComputeBudget::default(),
|
||||
&mut ExecuteTimings::default(),
|
||||
|
|
Loading…
Reference in New Issue