Skip to content

Commit

Permalink
Code to load a program from its account (solana-labs#30282)
Browse files Browse the repository at this point in the history
  • Loading branch information
pgarg66 authored and nickfrosty committed Mar 12, 2023
1 parent f7aa02f commit 8b718f5
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 30 deletions.
6 changes: 6 additions & 0 deletions program-runtime/src/loaded_programs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ impl Debug for LoadedProgramType {
pub struct LoadedProgram {
/// The program of this entry
pub program: LoadedProgramType,
/// Size of account that stores the program and program data
pub account_size: usize,
/// Slot in which the program was (re)deployed
pub deployment_slot: Slot,
/// Slot in which this entry will become active (can be in the future)
Expand All @@ -85,6 +87,7 @@ impl LoadedProgram {
loader: Arc<BuiltInProgram<InvokeContext<'static>>>,
deployment_slot: Slot,
elf_bytes: &[u8],
account_size: usize,
) -> Result<Self, EbpfError> {
let program = if bpf_loader_deprecated::check_id(loader_key) {
let executable = Executable::load(elf_bytes, loader.clone())?;
Expand All @@ -97,6 +100,7 @@ impl LoadedProgram {
};
Ok(Self {
deployment_slot,
account_size,
effective_slot: deployment_slot.saturating_add(1),
usage_counter: AtomicU64::new(0),
program,
Expand All @@ -110,6 +114,7 @@ impl LoadedProgram {
) -> Self {
Self {
deployment_slot,
account_size: 0,
effective_slot: deployment_slot.saturating_add(1),
usage_counter: AtomicU64::new(0),
program: LoadedProgramType::BuiltIn(program),
Expand Down Expand Up @@ -375,6 +380,7 @@ mod tests {
fn new_test_loaded_program(deployment_slot: Slot, effective_slot: Slot) -> Arc<LoadedProgram> {
Arc::new(LoadedProgram {
program: LoadedProgramType::Invalid,
account_size: 0,
deployment_slot,
effective_slot,
usage_counter: AtomicU64::default(),
Expand Down
121 changes: 91 additions & 30 deletions programs/bpf_loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use {
executor_cache::TransactionExecutorCache,
ic_logger_msg, ic_msg,
invoke_context::InvokeContext,
loaded_programs::LoadedProgram,
log_collector::LogCollector,
stable_log,
sysvar_cache::get_sysvar_with_account_check,
Expand All @@ -38,6 +39,7 @@ use {
solana_sdk::{
bpf_loader, bpf_loader_deprecated,
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
clock::Slot,
entrypoint::{HEAP_LENGTH, SUCCESS},
feature_set::{
cap_accounts_data_allocations_per_transaction, cap_bpf_program_instruction_accounts,
Expand Down Expand Up @@ -180,6 +182,93 @@ fn create_executor_from_bytes(
}))
}

fn get_programdata_offset_and_depoyment_offset(
log_collector: &Option<Rc<RefCell<LogCollector>>>,
program: &BorrowedAccount,
programdata: &BorrowedAccount,
) -> Result<(usize, Slot), InstructionError> {
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()?
{
Ok((UpgradeableLoaderState::size_of_programdata_metadata(), slot))
} else {
ic_logger_msg!(log_collector, "Program has been closed");
Err(InstructionError::InvalidAccountData)
}
} else {
ic_logger_msg!(log_collector, "Invalid Program account");
Err(InstructionError::InvalidAccountData)
}
} else {
Ok((0, 0))
}
}

pub fn load_program_from_account(
feature_set: &FeatureSet,
compute_budget: &ComputeBudget,
log_collector: Option<Rc<RefCell<LogCollector>>>,
program: &BorrowedAccount,
programdata: &BorrowedAccount,
) -> Result<(LoadedProgram, Option<CreateMetrics>), 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) =
get_programdata_offset_and_depoyment_offset(&log_collector, program, programdata)?;
let programdata_size = if programdata_offset != 0 {
programdata.get_data().len()
} else {
0
};

let mut create_executor_metrics = CreateMetrics {
program_id: program.get_key().to_string(),
..CreateMetrics::default()
};

let mut register_syscalls_time = Measure::start("register_syscalls_time");
let loader = syscalls::create_loader(feature_set, compute_budget, false, false, false)
.map_err(|e| {
ic_logger_msg!(log_collector, "Failed to register syscalls: {}", e);
InstructionError::ProgramEnvironmentSetupFailure
})?;
register_syscalls_time.stop();
create_executor_metrics.register_syscalls_us = register_syscalls_time.as_us();

let mut load_elf_time = Measure::start("load_elf_time");
let loaded_program = LoadedProgram::new(
program.get_owner(),
loader,
deployment_slot,
programdata
.get_data()
.get(programdata_offset..)
.ok_or(InstructionError::AccountDataTooSmall)?,
program.get_data().len().saturating_add(programdata_size),
)
.map_err(|err| {
ic_logger_msg!(log_collector, "{}", err);
InstructionError::InvalidAccountData
})?;
load_elf_time.stop();
create_executor_metrics.load_elf_us = load_elf_time.as_us();

Ok((loaded_program, Some(create_executor_metrics)))
}

pub fn create_executor_from_account(
feature_set: &FeatureSet,
compute_budget: &ComputeBudget,
Expand All @@ -197,36 +286,8 @@ pub fn create_executor_from_account(
return Err(InstructionError::IncorrectProgramId);
}

let programdata_offset = if bpf_loader_upgradeable::check_id(program.get_owner()) {
if let UpgradeableLoaderState::Program {
programdata_address,
} = program.get_state()?
{
if &programdata_address != programdata.get_key() {
ic_logger_msg!(
log_collector,
"Wrong ProgramData account for this Program account"
);
return Err(InstructionError::InvalidArgument);
}
if !matches!(
programdata.get_state()?,
UpgradeableLoaderState::ProgramData {
slot: _,
upgrade_authority_address: _,
}
) {
ic_logger_msg!(log_collector, "Program has been closed");
return Err(InstructionError::InvalidAccountData);
}
UpgradeableLoaderState::size_of_programdata_metadata()
} else {
ic_logger_msg!(log_collector, "Invalid Program account");
return Err(InstructionError::InvalidAccountData);
}
} else {
0
};
let (programdata_offset, _) =
get_programdata_offset_and_depoyment_offset(&log_collector, program, programdata)?;

if let Some(ref tx_executor_cache) = tx_executor_cache {
match tx_executor_cache.get(program.get_key()) {
Expand Down

0 comments on commit 8b718f5

Please sign in to comment.