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)
}
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(
invoke_context: &InvokeContext,
pubkey: &Pubkey,
@ -246,7 +179,7 @@ fn write_program_data(
Ok(())
}
fn check_loader_id(id: &Pubkey) -> bool {
pub fn check_loader_id(id: &Pubkey) -> bool {
bpf_loader::check_id(id)
|| bpf_loader_deprecated::check_id(id)
|| bpf_loader_upgradeable::check_id(id)

View File

@ -105,8 +105,8 @@ use {
compute_budget::{self, ComputeBudget},
invoke_context::ProcessInstructionWithContext,
loaded_programs::{
LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType, LoadedPrograms,
LoadedProgramsForTxBatch, WorkingSlot,
LoadProgramMetrics, LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType,
LoadedPrograms, LoadedProgramsForTxBatch, WorkingSlot,
},
log_collector::LogCollector,
message_processor::MessageProcessor,
@ -144,6 +144,7 @@ use {
hash::{extend_and_hash, hashv, Hash},
incinerator,
inflation::Inflation,
instruction::InstructionError,
lamports::LamportsError,
loader_v4,
message::{AccountKeys, SanitizedMessage},
@ -295,6 +296,13 @@ impl BankRc {
}
}
enum ProgramAccountLoadResult {
AccountNotFound,
InvalidAccountData,
ProgramOfLoaderV1orV2(AccountSharedData),
ProgramOfLoaderV3(AccountSharedData, AccountSharedData, Slot),
}
pub struct LoadAndExecuteTransactionsOutput {
pub loaded_transactions: Vec<TransactionLoadResult>,
// 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> {
let Some(program) = self.get_account_with_fixed_root(pubkey) else {
return Arc::new(LoadedProgram::new_tombstone(
self.slot,
LoadedProgramType::Closed,
));
fn load_program_accounts(&self, pubkey: &Pubkey) -> ProgramAccountLoadResult {
let program_account = match self.get_account_with_fixed_root(pubkey) {
None => return ProgramAccountLoadResult::AccountNotFound,
Some(account) => account,
};
let mut transaction_accounts = vec![(*pubkey, program)];
let is_upgradeable_loader =
bpf_loader_upgradeable::check_id(transaction_accounts[0].1.owner());
if is_upgradeable_loader {
if let Ok(UpgradeableLoaderState::Program {
programdata_address,
}) = transaction_accounts[0].1.state()
debug_assert!(solana_bpf_loader_program::check_loader_id(
program_account.owner()
));
if !bpf_loader_upgradeable::check_id(program_account.owner()) {
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) =
self.get_account_with_fixed_root(&programdata_address)
{
transaction_accounts.push((programdata_address, programdata_account));
} else {
return Arc::new(LoadedProgram::new_tombstone(
self.slot,
LoadedProgramType::Closed,
));
}
} else {
return Arc::new(LoadedProgram::new_tombstone(
self.slot,
LoadedProgramType::Closed,
));
return ProgramAccountLoadResult::ProgramOfLoaderV3(
program_account,
programdata_account,
slot,
);
}
}
let mut transaction_context = TransactionContext::new(
transaction_accounts,
Some(sysvar::rent::Rent::default()),
1,
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
};
ProgramAccountLoadResult::InvalidAccountData
}
pub fn load_program(&self, pubkey: &Pubkey) -> Arc<LoadedProgram> {
let program_runtime_environment_v1 = self
.loaded_programs_cache
.read()
.unwrap()
.program_runtime_environment_v1
.clone();
solana_bpf_loader_program::load_program_from_account(
&self.feature_set,
None, // log_collector
&program,
programdata.as_ref().unwrap_or(&program),
program_runtime_environment_v1.clone(),
)
.map(|(loaded_program, metrics)| {
let mut timings = ExecuteDetailsTimings::default();
metrics.submit_datapoint(&mut timings);
loaded_program
})
let mut load_program_metrics = LoadProgramMetrics {
program_id: pubkey.to_string(),
..LoadProgramMetrics::default()
};
let loaded_program = match self.load_program_accounts(pubkey) {
ProgramAccountLoadResult::AccountNotFound => Ok(LoadedProgram::new_tombstone(
self.slot,
LoadedProgramType::Closed,
)),
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(|_| {
Arc::new(LoadedProgram::new_tombstone(
LoadedProgram::new_tombstone(
self.slot,
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) {