Skip to content

Commit

Permalink
Simplify code for bank::load_program() (solana-labs#34093)
Browse files Browse the repository at this point in the history
* Simplify code for bank::load_program()

* address review comments
  • Loading branch information
pgarg66 authored Nov 15, 2023
1 parent 061883e commit bc2c98b
Showing 1 changed file with 76 additions and 69 deletions.
145 changes: 76 additions & 69 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,9 @@ use {
compute_budget_processor::process_compute_budget_instructions,
invoke_context::BuiltinFunctionWithContext,
loaded_programs::{
LoadProgramMetrics, LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType,
LoadedPrograms, LoadedProgramsForTxBatch, WorkingSlot, DELAY_VISIBILITY_SLOT_OFFSET,
ExtractedPrograms, LoadProgramMetrics, LoadedProgram, LoadedProgramMatchCriteria,
LoadedProgramType, LoadedPrograms, LoadedProgramsForTxBatch, ProgramRuntimeEnvironment,
ProgramRuntimeEnvironments, WorkingSlot, DELAY_VISIBILITY_SLOT_OFFSET,
},
log_collector::LogCollector,
message_processor::MessageProcessor,
Expand Down Expand Up @@ -278,7 +279,6 @@ pub struct BankRc {

#[cfg(RUSTC_WITH_SPECIALIZATION)]
use solana_frozen_abi::abi_example::AbiExample;
use solana_program_runtime::loaded_programs::ExtractedPrograms;

#[cfg(RUSTC_WITH_SPECIALIZATION)]
impl AbiExample for BankRc {
Expand Down Expand Up @@ -307,8 +307,7 @@ impl BankRc {

enum ProgramAccountLoadResult {
AccountNotFound,
InvalidAccountData,
InvalidV4Program,
InvalidAccountData(ProgramRuntimeEnvironment),
ProgramOfLoaderV1orV2(AccountSharedData),
ProgramOfLoaderV3(AccountSharedData, AccountSharedData, Slot),
ProgramOfLoaderV4(AccountSharedData, Slot),
Expand Down Expand Up @@ -4655,7 +4654,11 @@ impl Bank {
}
}

fn load_program_accounts(&self, pubkey: &Pubkey) -> ProgramAccountLoadResult {
fn load_program_accounts(
&self,
pubkey: &Pubkey,
environments: &ProgramRuntimeEnvironments,
) -> ProgramAccountLoadResult {
let program_account = match self.get_account_with_fixed_root(pubkey) {
None => return ProgramAccountLoadResult::AccountNotFound,
Some(account) => account,
Expand All @@ -4672,7 +4675,9 @@ impl Bank {
(!matches!(state.status, LoaderV4Status::Retracted)).then_some(state.slot)
})
.map(|slot| ProgramAccountLoadResult::ProgramOfLoaderV4(program_account, slot))
.unwrap_or(ProgramAccountLoadResult::InvalidV4Program);
.unwrap_or(ProgramAccountLoadResult::InvalidAccountData(
environments.program_runtime_v2.clone(),
));
}

if !bpf_loader_upgradeable::check_id(program_account.owner()) {
Expand Down Expand Up @@ -4700,7 +4705,44 @@ impl Bank {
);
}
}
ProgramAccountLoadResult::InvalidAccountData
ProgramAccountLoadResult::InvalidAccountData(environments.program_runtime_v1.clone())
}

fn load_program_from_bytes(
load_program_metrics: &mut LoadProgramMetrics,
programdata: &[u8],
loader_key: &Pubkey,
account_size: usize,
deployment_slot: Slot,
program_runtime_environment: ProgramRuntimeEnvironment,
reloading: bool,
) -> std::result::Result<LoadedProgram, Box<dyn std::error::Error>> {
if reloading {
// Safety: this is safe because the program is being reloaded in the cache.
unsafe {
LoadedProgram::reload(
loader_key,
program_runtime_environment.clone(),
deployment_slot,
deployment_slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET),
None,
programdata,
account_size,
load_program_metrics,
)
}
} else {
LoadedProgram::new(
loader_key,
program_runtime_environment.clone(),
deployment_slot,
deployment_slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET),
None,
programdata,
account_size,
load_program_metrics,
)
}
}

pub fn load_program(
Expand All @@ -4721,19 +4763,16 @@ impl Bank {
..LoadProgramMetrics::default()
};

let mut loaded_program = match self.load_program_accounts(pubkey) {
let mut loaded_program = match self.load_program_accounts(pubkey, environments) {
ProgramAccountLoadResult::AccountNotFound => Ok(LoadedProgram::new_tombstone(
self.slot,
LoadedProgramType::Closed,
)),

ProgramAccountLoadResult::InvalidAccountData => {
Err(InstructionError::InvalidAccountData)
}
ProgramAccountLoadResult::InvalidAccountData(env) => Err((self.slot, env)),

ProgramAccountLoadResult::ProgramOfLoaderV1orV2(program_account) => {
solana_bpf_loader_program::load_program_from_bytes(
None,
Self::load_program_from_bytes(
&mut load_program_metrics,
program_account.data(),
program_account.owner(),
Expand All @@ -4742,6 +4781,7 @@ impl Bank {
environments.program_runtime_v1.clone(),
reload,
)
.map_err(|_| (0, environments.program_runtime_v1.clone()))
}

ProgramAccountLoadResult::ProgramOfLoaderV3(
Expand All @@ -4751,10 +4791,9 @@ impl Bank {
) => programdata_account
.data()
.get(UpgradeableLoaderState::size_of_programdata_metadata()..)
.ok_or(InstructionError::InvalidAccountData)
.ok_or(Box::new(InstructionError::InvalidAccountData).into())
.and_then(|programdata| {
solana_bpf_loader_program::load_program_from_bytes(
None,
Self::load_program_from_bytes(
&mut load_program_metrics,
programdata,
program_account.owner(),
Expand All @@ -4766,60 +4805,28 @@ impl Bank {
environments.program_runtime_v1.clone(),
reload,
)
}),

ProgramAccountLoadResult::ProgramOfLoaderV4(program_account, slot) => {
let loaded_program = program_account
.data()
.get(LoaderV4State::program_data_offset()..)
.and_then(|elf_bytes| {
if reload {
// Safety: this is safe because the program is being reloaded in the cache.
unsafe {
LoadedProgram::reload(
&loader_v4::id(),
environments.program_runtime_v2.clone(),
slot,
slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET),
None,
elf_bytes,
program_account.data().len(),
&mut load_program_metrics,
)
}
} else {
LoadedProgram::new(
&loader_v4::id(),
environments.program_runtime_v2.clone(),
slot,
slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET),
None,
elf_bytes,
program_account.data().len(),
&mut load_program_metrics,
)
}
.ok()
})
.unwrap_or(LoadedProgram::new_tombstone(
self.slot,
LoadedProgramType::FailedVerification(
environments.program_runtime_v2.clone(),
),
));
Ok(loaded_program)
}
})
.map_err(|_| (slot, environments.program_runtime_v1.clone())),

ProgramAccountLoadResult::InvalidV4Program => Ok(LoadedProgram::new_tombstone(
self.slot,
LoadedProgramType::FailedVerification(environments.program_runtime_v2.clone()),
)),
ProgramAccountLoadResult::ProgramOfLoaderV4(program_account, slot) => program_account
.data()
.get(LoaderV4State::program_data_offset()..)
.ok_or(Box::new(InstructionError::InvalidAccountData).into())
.and_then(|elf_bytes| {
Self::load_program_from_bytes(
&mut load_program_metrics,
elf_bytes,
&loader_v4::id(),
program_account.data().len(),
slot,
environments.program_runtime_v2.clone(),
reload,
)
})
.map_err(|_| (slot, environments.program_runtime_v2.clone())),
}
.unwrap_or_else(|_| {
LoadedProgram::new_tombstone(
self.slot,
LoadedProgramType::FailedVerification(environments.program_runtime_v1.clone()),
)
.unwrap_or_else(|(slot, env)| {
LoadedProgram::new_tombstone(slot, LoadedProgramType::FailedVerification(env))
});

let mut timings = ExecuteDetailsTimings::default();
Expand Down

0 comments on commit bc2c98b

Please sign in to comment.