Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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 all 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()

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,
);
}
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