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

Code to load a program from its account #30282

Merged
merged 3 commits into from
Feb 15, 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
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