Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Cleanup load_program() in bank.rs #32146

Merged
merged 4 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 1 addition & 68 deletions programs/bpf_loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
174 changes: 105 additions & 69 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -144,6 +144,7 @@ use {
hash::{extend_and_hash, hashv, Hash},
incinerator,
inflation::Inflation,
instruction::InstructionError,
lamports::LamportsError,
loader_v4,
message::{AccountKeys, SanitizedMessage},
Expand Down Expand Up @@ -294,6 +295,13 @@ impl BankRc {
}
}

enum ProgramAccountLoadResult {
AccountNotFound,
InvalidAccountData,
Lichtso marked this conversation as resolved.
Show resolved Hide resolved
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
Expand Down Expand Up @@ -4788,86 +4796,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()

if !solana_bpf_loader_program::check_loader_id(program_account.owner()) {
return ProgramAccountLoadResult::InvalidAccountData;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this originally returned InstructionError::IncorrectProgramId in load_program_from_account() and all errors from there were turned into LoadedProgramType::FailedVerification in load_program(). But it should be unreachable, so try placing a debug_assert(solana_bpf_loader_program::check_loader_id(); here instead.

}

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,
);
}
Lichtso marked this conversation as resolved.
Show resolved Hide resolved
}
Lichtso marked this conversation as resolved.
Show resolved Hide resolved
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)
Lichtso marked this conversation as resolved.
Show resolved Hide resolved
.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) {
Expand Down