Cleanup load_program() in bank.rs (#32146)

This commit is contained in:
Pankaj Garg 2023-07-21 13:43:46 -07:00 committed by GitHub
parent a7eda70ddb
commit fc35b13365
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 106 additions and 137 deletions

View File

@ -99,73 +99,6 @@ pub fn load_program_from_bytes(
Ok(loaded_program) Ok(loaded_program)
} }
pub fn load_program_from_account(
feature_set: &FeatureSet,
log_collector: Option<Rc<RefCell<LogCollector>>>,
program: &BorrowedAccount,
programdata: &BorrowedAccount,
program_runtime_environment: Arc<BuiltinProgram<InvokeContext<'static>>>,
) -> Result<(Arc<LoadedProgram>, LoadProgramMetrics), InstructionError> {
if !check_loader_id(program.get_owner()) {
ic_logger_msg!(
log_collector,
"Executable account not owned by the BPF loader"
);
return Err(InstructionError::IncorrectProgramId);
}
let (programdata_offset, deployment_slot) =
if bpf_loader_upgradeable::check_id(program.get_owner()) {
if let UpgradeableLoaderState::Program {
programdata_address: _,
} = program.get_state()?
{
if let UpgradeableLoaderState::ProgramData {
slot,
upgrade_authority_address: _,
} = programdata.get_state()?
{
(UpgradeableLoaderState::size_of_programdata_metadata(), slot)
} else {
ic_logger_msg!(log_collector, "Program has been closed");
return Err(InstructionError::InvalidAccountData);
}
} else {
ic_logger_msg!(log_collector, "Invalid Program account");
return Err(InstructionError::InvalidAccountData);
}
} else {
(0, 0)
};
let programdata_size = if programdata_offset != 0 {
programdata.get_data().len()
} else {
0
};
let mut load_program_metrics = LoadProgramMetrics {
program_id: program.get_key().to_string(),
..LoadProgramMetrics::default()
};
let loaded_program = Arc::new(load_program_from_bytes(
feature_set,
log_collector,
&mut load_program_metrics,
programdata
.get_data()
.get(programdata_offset..)
.ok_or(InstructionError::AccountDataTooSmall)?,
program.get_owner(),
program.get_data().len().saturating_add(programdata_size),
deployment_slot,
program_runtime_environment,
)?);
Ok((loaded_program, load_program_metrics))
}
fn find_program_in_cache( fn find_program_in_cache(
invoke_context: &InvokeContext, invoke_context: &InvokeContext,
pubkey: &Pubkey, pubkey: &Pubkey,
@ -246,7 +179,7 @@ fn write_program_data(
Ok(()) Ok(())
} }
fn check_loader_id(id: &Pubkey) -> bool { pub fn check_loader_id(id: &Pubkey) -> bool {
bpf_loader::check_id(id) bpf_loader::check_id(id)
|| bpf_loader_deprecated::check_id(id) || bpf_loader_deprecated::check_id(id)
|| bpf_loader_upgradeable::check_id(id) || bpf_loader_upgradeable::check_id(id)

View File

@ -105,8 +105,8 @@ use {
compute_budget::{self, ComputeBudget}, compute_budget::{self, ComputeBudget},
invoke_context::ProcessInstructionWithContext, invoke_context::ProcessInstructionWithContext,
loaded_programs::{ loaded_programs::{
LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType, LoadedPrograms, LoadProgramMetrics, LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType,
LoadedProgramsForTxBatch, WorkingSlot, LoadedPrograms, LoadedProgramsForTxBatch, WorkingSlot,
}, },
log_collector::LogCollector, log_collector::LogCollector,
message_processor::MessageProcessor, message_processor::MessageProcessor,
@ -144,6 +144,7 @@ use {
hash::{extend_and_hash, hashv, Hash}, hash::{extend_and_hash, hashv, Hash},
incinerator, incinerator,
inflation::Inflation, inflation::Inflation,
instruction::InstructionError,
lamports::LamportsError, lamports::LamportsError,
loader_v4, loader_v4,
message::{AccountKeys, SanitizedMessage}, message::{AccountKeys, SanitizedMessage},
@ -295,6 +296,13 @@ impl BankRc {
} }
} }
enum ProgramAccountLoadResult {
AccountNotFound,
InvalidAccountData,
ProgramOfLoaderV1orV2(AccountSharedData),
ProgramOfLoaderV3(AccountSharedData, AccountSharedData, Slot),
}
pub struct LoadAndExecuteTransactionsOutput { pub struct LoadAndExecuteTransactionsOutput {
pub loaded_transactions: Vec<TransactionLoadResult>, pub loaded_transactions: Vec<TransactionLoadResult>,
// Vector of results indicating whether a transaction was executed or could not // Vector of results indicating whether a transaction was executed or could not
@ -4594,86 +4602,114 @@ impl Bank {
} }
} }
pub fn load_program(&self, pubkey: &Pubkey) -> Arc<LoadedProgram> { fn load_program_accounts(&self, pubkey: &Pubkey) -> ProgramAccountLoadResult {
let Some(program) = self.get_account_with_fixed_root(pubkey) else { let program_account = match self.get_account_with_fixed_root(pubkey) {
return Arc::new(LoadedProgram::new_tombstone( None => return ProgramAccountLoadResult::AccountNotFound,
self.slot, Some(account) => account,
LoadedProgramType::Closed,
));
}; };
let mut transaction_accounts = vec![(*pubkey, program)];
let is_upgradeable_loader = debug_assert!(solana_bpf_loader_program::check_loader_id(
bpf_loader_upgradeable::check_id(transaction_accounts[0].1.owner()); program_account.owner()
if is_upgradeable_loader { ));
if let Ok(UpgradeableLoaderState::Program {
programdata_address, if !bpf_loader_upgradeable::check_id(program_account.owner()) {
}) = transaction_accounts[0].1.state() return ProgramAccountLoadResult::ProgramOfLoaderV1orV2(program_account);
}
if let Ok(UpgradeableLoaderState::Program {
programdata_address,
}) = program_account.state()
{
let programdata_account = match self.get_account_with_fixed_root(&programdata_address) {
None => return ProgramAccountLoadResult::AccountNotFound,
Some(account) => account,
};
if let Ok(UpgradeableLoaderState::ProgramData {
slot,
upgrade_authority_address: _,
}) = programdata_account.state()
{ {
if let Some(programdata_account) = return ProgramAccountLoadResult::ProgramOfLoaderV3(
self.get_account_with_fixed_root(&programdata_address) program_account,
{ programdata_account,
transaction_accounts.push((programdata_address, programdata_account)); slot,
} else { );
return Arc::new(LoadedProgram::new_tombstone(
self.slot,
LoadedProgramType::Closed,
));
}
} else {
return Arc::new(LoadedProgram::new_tombstone(
self.slot,
LoadedProgramType::Closed,
));
} }
} }
let mut transaction_context = TransactionContext::new( ProgramAccountLoadResult::InvalidAccountData
transaction_accounts, }
Some(sysvar::rent::Rent::default()),
1, pub fn load_program(&self, pubkey: &Pubkey) -> Arc<LoadedProgram> {
1,
);
let instruction_context = transaction_context.get_next_instruction_context().unwrap();
instruction_context.configure(if is_upgradeable_loader { &[0, 1] } else { &[0] }, &[], &[]);
transaction_context.push().unwrap();
let instruction_context = transaction_context
.get_current_instruction_context()
.unwrap();
let program = instruction_context
.try_borrow_program_account(&transaction_context, 0)
.unwrap();
let programdata = if is_upgradeable_loader {
Some(
instruction_context
.try_borrow_program_account(&transaction_context, 1)
.unwrap(),
)
} else {
None
};
let program_runtime_environment_v1 = self let program_runtime_environment_v1 = self
.loaded_programs_cache .loaded_programs_cache
.read() .read()
.unwrap() .unwrap()
.program_runtime_environment_v1 .program_runtime_environment_v1
.clone(); .clone();
solana_bpf_loader_program::load_program_from_account(
&self.feature_set, let mut load_program_metrics = LoadProgramMetrics {
None, // log_collector program_id: pubkey.to_string(),
&program, ..LoadProgramMetrics::default()
programdata.as_ref().unwrap_or(&program), };
program_runtime_environment_v1.clone(),
) let loaded_program = match self.load_program_accounts(pubkey) {
.map(|(loaded_program, metrics)| { ProgramAccountLoadResult::AccountNotFound => Ok(LoadedProgram::new_tombstone(
let mut timings = ExecuteDetailsTimings::default(); self.slot,
metrics.submit_datapoint(&mut timings); LoadedProgramType::Closed,
loaded_program )),
})
ProgramAccountLoadResult::InvalidAccountData => {
Err(InstructionError::InvalidAccountData)
}
ProgramAccountLoadResult::ProgramOfLoaderV1orV2(program_account) => {
solana_bpf_loader_program::load_program_from_bytes(
&self.feature_set,
None,
&mut load_program_metrics,
program_account.data(),
program_account.owner(),
program_account.data().len(),
0,
program_runtime_environment_v1.clone(),
)
}
ProgramAccountLoadResult::ProgramOfLoaderV3(
program_account,
programdata_account,
slot,
) => programdata_account
.data()
.get(UpgradeableLoaderState::size_of_programdata_metadata()..)
.ok_or(InstructionError::InvalidAccountData)
.and_then(|programdata| {
solana_bpf_loader_program::load_program_from_bytes(
&self.feature_set,
None,
&mut load_program_metrics,
programdata,
program_account.owner(),
program_account
.data()
.len()
.saturating_add(programdata_account.data().len()),
slot,
program_runtime_environment_v1.clone(),
)
}),
}
.unwrap_or_else(|_| { .unwrap_or_else(|_| {
Arc::new(LoadedProgram::new_tombstone( LoadedProgram::new_tombstone(
self.slot, self.slot,
LoadedProgramType::FailedVerification(program_runtime_environment_v1), LoadedProgramType::FailedVerification(program_runtime_environment_v1),
)) )
}) });
let mut timings = ExecuteDetailsTimings::default();
load_program_metrics.submit_datapoint(&mut timings);
Arc::new(loaded_program)
} }
pub fn clear_program_cache(&self) { pub fn clear_program_cache(&self) {