Code to load a program from its account (#30282)
This commit is contained in:
parent
a020f3eb60
commit
a9ad0f2b5a
|
@ -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)
|
||||
|
@ -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())?;
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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(),
|
||||
|
|
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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()) {
|
||||
|
|
Loading…
Reference in New Issue