2022-03-10 11:48:33 -08:00
|
|
|
#![deny(clippy::integer_arithmetic)]
|
|
|
|
#![deny(clippy::indexing_slicing)]
|
|
|
|
|
2019-05-24 16:21:42 -07:00
|
|
|
pub mod allocator_bump;
|
2020-08-11 16:11:52 -07:00
|
|
|
pub mod deprecated;
|
|
|
|
pub mod serialization;
|
2020-04-30 01:43:11 -07:00
|
|
|
pub mod syscalls;
|
2020-12-14 15:35:10 -08:00
|
|
|
pub mod upgradeable;
|
|
|
|
pub mod upgradeable_with_jit;
|
2020-12-07 00:49:55 -08:00
|
|
|
pub mod with_jit;
|
2018-10-16 16:33:31 -07:00
|
|
|
|
2022-01-08 01:07:15 -08:00
|
|
|
#[macro_use]
|
|
|
|
extern crate solana_metrics;
|
|
|
|
|
2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
crate::{
|
2022-10-06 11:31:58 -07:00
|
|
|
allocator_bump::BpfAllocator,
|
2021-12-03 09:00:31 -08:00
|
|
|
serialization::{deserialize_parameters, serialize_parameters},
|
|
|
|
syscalls::SyscallError,
|
|
|
|
},
|
|
|
|
log::{log_enabled, trace, Level::Trace},
|
|
|
|
solana_measure::measure::Measure,
|
|
|
|
solana_program_runtime::{
|
2022-10-18 01:22:39 -07:00
|
|
|
compute_budget::ComputeBudget,
|
|
|
|
executor_cache::{Executor, TransactionExecutorCache},
|
2021-12-03 09:00:31 -08:00
|
|
|
ic_logger_msg, ic_msg,
|
2022-10-10 06:01:41 -07:00
|
|
|
invoke_context::{ComputeMeter, InvokeContext},
|
2021-12-03 09:00:31 -08:00
|
|
|
log_collector::LogCollector,
|
|
|
|
stable_log,
|
2022-03-16 03:30:01 -07:00
|
|
|
sysvar_cache::get_sysvar_with_account_check,
|
2022-10-18 01:22:39 -07:00
|
|
|
timings::ExecuteDetailsTimings,
|
2021-08-24 10:05:54 -07:00
|
|
|
},
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_rbpf::{
|
|
|
|
aligned_memory::AlignedMemory,
|
2022-10-06 23:45:05 -07:00
|
|
|
ebpf::{HOST_ALIGN, MM_HEAP_START},
|
2021-12-03 09:00:31 -08:00
|
|
|
elf::Executable,
|
|
|
|
error::{EbpfError, UserDefinedError},
|
2022-04-30 01:58:12 -07:00
|
|
|
memory_region::MemoryRegion,
|
2021-12-03 09:00:31 -08:00
|
|
|
static_analysis::Analysis,
|
2022-06-07 04:45:07 -07:00
|
|
|
verifier::{RequisiteVerifier, VerifierError},
|
2022-10-06 11:31:58 -07:00
|
|
|
vm::{Config, EbpfVm, InstructionMeter, ProgramResult, VerifiedExecutable},
|
2021-12-03 09:00:31 -08:00
|
|
|
},
|
|
|
|
solana_sdk::{
|
|
|
|
bpf_loader, bpf_loader_deprecated,
|
|
|
|
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
|
|
|
|
entrypoint::{HEAP_LENGTH, SUCCESS},
|
|
|
|
feature_set::{
|
2022-08-29 11:30:48 -07:00
|
|
|
cap_accounts_data_allocations_per_transaction, cap_bpf_program_instruction_accounts,
|
2022-10-06 11:31:58 -07:00
|
|
|
check_slice_translation_size, disable_deploy_of_alloc_free_syscall,
|
|
|
|
disable_deprecated_loader, enable_bpf_loader_extend_program_ix,
|
|
|
|
error_on_syscall_bpf_function_hash_collisions, limit_max_instruction_trace_length,
|
2022-10-18 01:22:39 -07:00
|
|
|
reject_callx_r10, FeatureSet,
|
2021-12-03 09:00:31 -08:00
|
|
|
},
|
|
|
|
instruction::{AccountMeta, InstructionError},
|
|
|
|
loader_instruction::LoaderInstruction,
|
|
|
|
loader_upgradeable_instruction::UpgradeableLoaderInstruction,
|
2022-09-26 01:47:16 -07:00
|
|
|
program_error::{
|
|
|
|
MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED, MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED,
|
|
|
|
},
|
2021-12-03 09:00:31 -08:00
|
|
|
program_utils::limited_deserialize,
|
|
|
|
pubkey::Pubkey,
|
2022-01-05 16:08:35 -08:00
|
|
|
saturating_add_assign,
|
2021-12-03 09:00:31 -08:00
|
|
|
system_instruction::{self, MAX_PERMITTED_DATA_LENGTH},
|
2022-09-06 02:31:40 -07:00
|
|
|
transaction_context::{
|
|
|
|
BorrowedAccount, IndexOfAccount, InstructionContext, TransactionContext,
|
|
|
|
},
|
2021-12-03 09:00:31 -08:00
|
|
|
},
|
2022-10-18 01:22:39 -07:00
|
|
|
std::{
|
|
|
|
cell::{RefCell, RefMut},
|
|
|
|
fmt::Debug,
|
|
|
|
rc::Rc,
|
|
|
|
sync::Arc,
|
|
|
|
},
|
2021-12-03 09:00:31 -08:00
|
|
|
thiserror::Error,
|
2020-01-02 18:18:56 -08:00
|
|
|
};
|
2019-05-24 16:21:42 -07:00
|
|
|
|
2020-08-14 12:32:45 -07:00
|
|
|
solana_sdk::declare_builtin!(
|
2019-12-03 17:55:18 -08:00
|
|
|
solana_sdk::bpf_loader::ID,
|
2019-11-20 16:32:19 -08:00
|
|
|
solana_bpf_loader_program,
|
2020-08-14 12:32:45 -07:00
|
|
|
solana_bpf_loader_program::process_instruction
|
2019-11-20 16:32:19 -08:00
|
|
|
);
|
|
|
|
|
2020-09-14 17:42:37 -07:00
|
|
|
/// Errors returned by functions the BPF Loader registers with the VM
|
2022-05-22 18:00:42 -07:00
|
|
|
#[derive(Debug, Error, PartialEq, Eq)]
|
2021-02-18 23:42:09 -08:00
|
|
|
pub enum BpfError {
|
2020-03-26 14:00:26 -07:00
|
|
|
#[error("{0}")]
|
|
|
|
VerifierError(#[from] VerifierError),
|
|
|
|
#[error("{0}")]
|
2020-04-30 01:43:11 -07:00
|
|
|
SyscallError(#[from] SyscallError),
|
2020-03-26 14:00:26 -07:00
|
|
|
}
|
2021-02-18 23:42:09 -08:00
|
|
|
impl UserDefinedError for BpfError {}
|
2020-03-26 14:00:26 -07:00
|
|
|
|
2022-01-08 19:06:47 -08:00
|
|
|
mod executor_metrics {
|
2022-10-18 01:22:39 -07:00
|
|
|
use super::*;
|
|
|
|
|
2022-01-08 19:06:47 -08:00
|
|
|
#[derive(Debug, Default)]
|
|
|
|
pub struct CreateMetrics {
|
|
|
|
pub program_id: String,
|
2022-10-18 01:22:39 -07:00
|
|
|
pub register_syscalls_us: u64,
|
2022-01-08 19:06:47 -08:00
|
|
|
pub load_elf_us: u64,
|
|
|
|
pub verify_code_us: u64,
|
|
|
|
pub jit_compile_us: u64,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CreateMetrics {
|
2022-10-18 01:22:39 -07:00
|
|
|
pub fn submit_datapoint(&self, timings: &mut ExecuteDetailsTimings) {
|
|
|
|
saturating_add_assign!(
|
|
|
|
timings.create_executor_register_syscalls_us,
|
|
|
|
self.register_syscalls_us
|
|
|
|
);
|
|
|
|
saturating_add_assign!(timings.create_executor_load_elf_us, self.load_elf_us);
|
|
|
|
saturating_add_assign!(timings.create_executor_verify_code_us, self.verify_code_us);
|
|
|
|
saturating_add_assign!(timings.create_executor_jit_compile_us, self.jit_compile_us);
|
2022-01-08 19:06:47 -08:00
|
|
|
datapoint_trace!(
|
|
|
|
"create_executor_trace",
|
|
|
|
("program_id", self.program_id, String),
|
2022-10-18 01:22:39 -07:00
|
|
|
("register_syscalls_us", self.register_syscalls_us, i64),
|
2022-01-08 19:06:47 -08:00
|
|
|
("load_elf_us", self.load_elf_us, i64),
|
|
|
|
("verify_code_us", self.verify_code_us, i64),
|
|
|
|
("jit_compile_us", self.jit_compile_us, i64),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-16 09:46:17 -07:00
|
|
|
// The BPF loader is special in that it is the only place in the runtime and its built-in programs,
|
|
|
|
// where data comes not only from instruction account but also program accounts.
|
|
|
|
// Thus, these two helper methods have to distinguish the mixed sources via index_in_instruction.
|
|
|
|
|
|
|
|
fn get_index_in_transaction(
|
|
|
|
instruction_context: &InstructionContext,
|
2022-09-06 02:31:40 -07:00
|
|
|
index_in_instruction: IndexOfAccount,
|
|
|
|
) -> Result<IndexOfAccount, InstructionError> {
|
2022-06-16 09:46:17 -07:00
|
|
|
if index_in_instruction < instruction_context.get_number_of_program_accounts() {
|
|
|
|
instruction_context.get_index_of_program_account_in_transaction(index_in_instruction)
|
|
|
|
} else {
|
|
|
|
instruction_context.get_index_of_instruction_account_in_transaction(
|
|
|
|
index_in_instruction
|
|
|
|
.saturating_sub(instruction_context.get_number_of_program_accounts()),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn try_borrow_account<'a>(
|
|
|
|
transaction_context: &'a TransactionContext,
|
|
|
|
instruction_context: &'a InstructionContext,
|
2022-09-06 02:31:40 -07:00
|
|
|
index_in_instruction: IndexOfAccount,
|
2022-06-16 09:46:17 -07:00
|
|
|
) -> Result<BorrowedAccount<'a>, InstructionError> {
|
|
|
|
if index_in_instruction < instruction_context.get_number_of_program_accounts() {
|
|
|
|
instruction_context.try_borrow_program_account(transaction_context, index_in_instruction)
|
|
|
|
} else {
|
|
|
|
instruction_context.try_borrow_instruction_account(
|
|
|
|
transaction_context,
|
|
|
|
index_in_instruction
|
|
|
|
.saturating_sub(instruction_context.get_number_of_program_accounts()),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-18 01:22:39 -07:00
|
|
|
fn create_executor_from_bytes(
|
|
|
|
feature_set: &FeatureSet,
|
|
|
|
compute_budget: &ComputeBudget,
|
|
|
|
log_collector: Option<Rc<RefCell<LogCollector>>>,
|
|
|
|
create_executor_metrics: &mut executor_metrics::CreateMetrics,
|
|
|
|
programdata: &[u8],
|
2020-12-07 00:49:55 -08:00
|
|
|
use_jit: bool,
|
2021-12-03 06:45:25 -08:00
|
|
|
reject_deployment_of_broken_elfs: bool,
|
2021-02-18 23:42:09 -08:00
|
|
|
) -> Result<Arc<BpfExecutor>, InstructionError> {
|
2022-01-04 20:27:22 -08:00
|
|
|
let mut register_syscalls_time = Measure::start("register_syscalls_time");
|
2022-10-18 01:22:39 -07:00
|
|
|
let disable_deploy_of_alloc_free_syscall = reject_deployment_of_broken_elfs
|
|
|
|
&& feature_set.is_active(&disable_deploy_of_alloc_free_syscall::id());
|
2022-05-20 13:19:41 -07:00
|
|
|
let register_syscall_result =
|
2022-10-18 01:22:39 -07:00
|
|
|
syscalls::register_syscalls(feature_set, disable_deploy_of_alloc_free_syscall);
|
2022-01-04 20:27:22 -08:00
|
|
|
register_syscalls_time.stop();
|
2022-10-18 01:22:39 -07:00
|
|
|
create_executor_metrics.register_syscalls_us = register_syscalls_time.as_us();
|
2022-01-04 20:27:22 -08:00
|
|
|
let syscall_registry = register_syscall_result.map_err(|e| {
|
2022-10-18 01:22:39 -07:00
|
|
|
ic_logger_msg!(log_collector, "Failed to register syscalls: {}", e);
|
2021-04-19 09:48:48 -07:00
|
|
|
InstructionError::ProgramEnvironmentSetupFailure
|
|
|
|
})?;
|
|
|
|
let config = Config {
|
2021-07-22 10:18:51 -07:00
|
|
|
max_call_depth: compute_budget.max_call_depth,
|
|
|
|
stack_frame_size: compute_budget.stack_frame_size,
|
2022-04-12 13:54:39 -07:00
|
|
|
enable_stack_frame_gaps: true,
|
|
|
|
instruction_meter_checkpoint_distance: 10000,
|
|
|
|
enable_instruction_meter: true,
|
2021-04-19 09:48:48 -07:00
|
|
|
enable_instruction_tracing: log_enabled!(Trace),
|
2022-04-12 13:54:39 -07:00
|
|
|
enable_symbol_and_section_labels: false,
|
2022-02-04 12:17:49 -08:00
|
|
|
reject_broken_elfs: reject_deployment_of_broken_elfs,
|
2022-06-03 07:22:23 -07:00
|
|
|
noop_instruction_rate: 256,
|
2022-04-12 13:54:39 -07:00
|
|
|
sanitize_user_provided_values: true,
|
|
|
|
encrypt_environment_registers: true,
|
2022-10-18 01:22:39 -07:00
|
|
|
syscall_bpf_function_hash_collision: feature_set
|
2022-04-12 17:52:32 -07:00
|
|
|
.is_active(&error_on_syscall_bpf_function_hash_collisions::id()),
|
2022-10-18 01:22:39 -07:00
|
|
|
reject_callx_r10: feature_set.is_active(&reject_callx_r10::id()),
|
2022-04-26 08:58:55 -07:00
|
|
|
dynamic_stack_frames: false,
|
|
|
|
enable_sdiv: false,
|
|
|
|
optimize_rodata: false,
|
2022-04-30 01:58:12 -07:00
|
|
|
static_syscalls: false,
|
|
|
|
enable_elf_vaddr: false,
|
2022-08-15 07:04:48 -07:00
|
|
|
reject_rodata_stack_overlap: false,
|
|
|
|
new_elf_parser: false,
|
2022-09-28 11:52:19 -07:00
|
|
|
aligned_memory_mapping: true,
|
2022-04-12 13:54:39 -07:00
|
|
|
// Warning, do not use `Config::default()` so that configuration here is explicit.
|
2021-04-19 09:48:48 -07:00
|
|
|
};
|
2022-10-18 01:22:39 -07:00
|
|
|
let mut load_elf_time = Measure::start("load_elf_time");
|
|
|
|
let executable =
|
|
|
|
Executable::<ThisInstructionMeter>::from_elf(programdata, config, syscall_registry)
|
|
|
|
.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();
|
|
|
|
let executable = executable?;
|
2022-01-04 20:27:22 -08:00
|
|
|
let mut verify_code_time = Measure::start("verify_code_time");
|
2022-06-07 04:45:07 -07:00
|
|
|
let mut verified_executable =
|
2022-10-06 11:31:58 -07:00
|
|
|
VerifiedExecutable::<RequisiteVerifier, ThisInstructionMeter>::from_executable(executable)
|
2022-10-18 01:22:39 -07:00
|
|
|
.map_err(|err| {
|
|
|
|
ic_logger_msg!(log_collector, "{}", err);
|
|
|
|
InstructionError::InvalidAccountData
|
|
|
|
})?;
|
2022-01-04 20:27:22 -08:00
|
|
|
verify_code_time.stop();
|
2022-01-08 19:06:47 -08:00
|
|
|
create_executor_metrics.verify_code_us = verify_code_time.as_us();
|
2020-12-15 09:54:07 -08:00
|
|
|
if use_jit {
|
2022-01-04 20:27:22 -08:00
|
|
|
let mut jit_compile_time = Measure::start("jit_compile_time");
|
2022-06-07 04:45:07 -07:00
|
|
|
let jit_compile_result = verified_executable.jit_compile();
|
2022-01-04 20:27:22 -08:00
|
|
|
jit_compile_time.stop();
|
2022-01-08 19:06:47 -08:00
|
|
|
create_executor_metrics.jit_compile_us = jit_compile_time.as_us();
|
2022-01-04 20:27:22 -08:00
|
|
|
if let Err(err) = jit_compile_result {
|
2022-10-18 01:22:39 -07:00
|
|
|
ic_logger_msg!(log_collector, "Failed to compile program {:?}", err);
|
2020-12-15 09:54:07 -08:00
|
|
|
return Err(InstructionError::ProgramFailedToCompile);
|
|
|
|
}
|
2020-11-24 09:00:19 -08:00
|
|
|
}
|
2022-03-14 15:00:00 -07:00
|
|
|
Ok(Arc::new(BpfExecutor {
|
2022-06-07 04:45:07 -07:00
|
|
|
verified_executable,
|
2022-03-14 15:00:00 -07:00
|
|
|
use_jit,
|
|
|
|
}))
|
2020-08-21 15:31:19 -07:00
|
|
|
}
|
2020-09-14 17:42:37 -07:00
|
|
|
|
2022-10-18 01:22:39 -07:00
|
|
|
pub fn create_executor_from_account(
|
|
|
|
feature_set: &FeatureSet,
|
|
|
|
compute_budget: &ComputeBudget,
|
|
|
|
log_collector: Option<Rc<RefCell<LogCollector>>>,
|
|
|
|
tx_executor_cache: Option<RefMut<TransactionExecutorCache>>,
|
|
|
|
program: &BorrowedAccount,
|
|
|
|
programdata: &BorrowedAccount,
|
|
|
|
use_jit: bool,
|
|
|
|
) -> Result<(Arc<dyn Executor>, Option<executor_metrics::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 = 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
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(ref tx_executor_cache) = tx_executor_cache {
|
|
|
|
if let Some(executor) = tx_executor_cache.get(program.get_key()) {
|
|
|
|
return Ok((executor, None));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut create_executor_metrics = executor_metrics::CreateMetrics {
|
|
|
|
program_id: program.get_key().to_string(),
|
|
|
|
..executor_metrics::CreateMetrics::default()
|
|
|
|
};
|
|
|
|
let executor = create_executor_from_bytes(
|
|
|
|
feature_set,
|
|
|
|
compute_budget,
|
|
|
|
log_collector,
|
|
|
|
&mut create_executor_metrics,
|
|
|
|
programdata
|
|
|
|
.get_data()
|
|
|
|
.get(programdata_offset..)
|
|
|
|
.ok_or(InstructionError::AccountDataTooSmall)?,
|
|
|
|
use_jit,
|
|
|
|
false, /* reject_deployment_of_broken_elfs */
|
|
|
|
)?;
|
|
|
|
if let Some(mut tx_executor_cache) = tx_executor_cache {
|
|
|
|
tx_executor_cache.set(*program.get_key(), executor.clone(), false);
|
|
|
|
}
|
|
|
|
Ok((executor, Some(create_executor_metrics)))
|
|
|
|
}
|
|
|
|
|
2022-03-16 03:30:01 -07:00
|
|
|
fn write_program_data(
|
2022-09-06 02:31:40 -07:00
|
|
|
program_account_index: IndexOfAccount,
|
2021-04-19 09:48:48 -07:00
|
|
|
program_data_offset: usize,
|
2020-12-14 15:35:10 -08:00
|
|
|
bytes: &[u8],
|
2022-03-16 03:30:01 -07:00
|
|
|
invoke_context: &mut InvokeContext,
|
2020-12-14 15:35:10 -08:00
|
|
|
) -> Result<(), InstructionError> {
|
2022-03-30 00:17:55 -07:00
|
|
|
let transaction_context = &invoke_context.transaction_context;
|
|
|
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
2022-06-16 09:46:17 -07:00
|
|
|
let mut program = try_borrow_account(
|
|
|
|
transaction_context,
|
|
|
|
instruction_context,
|
|
|
|
program_account_index,
|
|
|
|
)?;
|
2022-05-21 08:47:09 -07:00
|
|
|
let data = program.get_data_mut()?;
|
2022-03-30 00:17:55 -07:00
|
|
|
let write_offset = program_data_offset.saturating_add(bytes.len());
|
|
|
|
if data.len() < write_offset {
|
2022-03-16 03:30:01 -07:00
|
|
|
ic_msg!(
|
|
|
|
invoke_context,
|
2021-01-21 09:57:59 -08:00
|
|
|
"Write overflow: {} < {}",
|
|
|
|
data.len(),
|
2022-03-30 00:17:55 -07:00
|
|
|
write_offset,
|
2021-01-21 09:57:59 -08:00
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
return Err(InstructionError::AccountDataTooSmall);
|
|
|
|
}
|
2022-03-30 00:17:55 -07:00
|
|
|
data.get_mut(program_data_offset..write_offset)
|
2022-03-10 11:48:33 -08:00
|
|
|
.ok_or(InstructionError::AccountDataTooSmall)?
|
|
|
|
.copy_from_slice(bytes);
|
2020-12-14 15:35:10 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-12-23 19:04:48 -08:00
|
|
|
fn check_loader_id(id: &Pubkey) -> bool {
|
|
|
|
bpf_loader::check_id(id)
|
|
|
|
|| bpf_loader_deprecated::check_id(id)
|
|
|
|
|| bpf_loader_upgradeable::check_id(id)
|
|
|
|
}
|
|
|
|
|
2020-09-14 17:42:37 -07:00
|
|
|
/// Create the BPF virtual machine
|
2021-12-02 09:47:16 -08:00
|
|
|
pub fn create_vm<'a, 'b>(
|
2022-10-06 11:31:58 -07:00
|
|
|
program: &'a VerifiedExecutable<RequisiteVerifier, ThisInstructionMeter>,
|
2022-10-06 23:45:05 -07:00
|
|
|
regions: Vec<MemoryRegion>,
|
2022-05-19 15:14:28 -07:00
|
|
|
orig_account_lengths: Vec<usize>,
|
2021-12-02 09:47:16 -08:00
|
|
|
invoke_context: &'a mut InvokeContext<'b>,
|
2022-10-06 11:31:58 -07:00
|
|
|
) -> Result<EbpfVm<'a, RequisiteVerifier, ThisInstructionMeter>, EbpfError> {
|
2021-07-22 10:18:51 -07:00
|
|
|
let compute_budget = invoke_context.get_compute_budget();
|
2021-10-19 21:01:39 -07:00
|
|
|
let heap_size = compute_budget.heap_size.unwrap_or(HEAP_LENGTH);
|
2022-06-29 23:54:45 -07:00
|
|
|
let _ = invoke_context.get_compute_meter().borrow_mut().consume(
|
|
|
|
((heap_size as u64).saturating_div(32_u64.saturating_mul(1024)))
|
|
|
|
.saturating_sub(1)
|
|
|
|
.saturating_mul(compute_budget.heap_cost),
|
|
|
|
);
|
2021-08-04 00:50:28 -07:00
|
|
|
let mut heap =
|
2022-08-15 07:04:48 -07:00
|
|
|
AlignedMemory::<HOST_ALIGN>::zero_filled(compute_budget.heap_size.unwrap_or(HEAP_LENGTH));
|
2022-10-06 23:45:05 -07:00
|
|
|
|
|
|
|
let vm = EbpfVm::new(program, invoke_context, heap.as_slice_mut(), regions)?;
|
2022-10-06 11:31:58 -07:00
|
|
|
let check_aligned = bpf_loader_deprecated::id()
|
|
|
|
!= invoke_context
|
|
|
|
.transaction_context
|
|
|
|
.get_current_instruction_context()
|
|
|
|
.and_then(|instruction_context| {
|
|
|
|
instruction_context
|
|
|
|
.try_borrow_last_program_account(invoke_context.transaction_context)
|
|
|
|
})
|
|
|
|
.map(|program_account| *program_account.get_owner())
|
|
|
|
.map_err(SyscallError::InstructionError)?;
|
|
|
|
let check_size = invoke_context
|
|
|
|
.feature_set
|
|
|
|
.is_active(&check_slice_translation_size::id());
|
|
|
|
invoke_context
|
|
|
|
.set_syscall_context(
|
|
|
|
check_aligned,
|
|
|
|
check_size,
|
|
|
|
orig_account_lengths,
|
|
|
|
Rc::new(RefCell::new(BpfAllocator::new(heap, MM_HEAP_START))),
|
|
|
|
)
|
|
|
|
.map_err(SyscallError::InstructionError)?;
|
2020-11-04 09:46:26 -08:00
|
|
|
Ok(vm)
|
2020-08-21 15:31:19 -07:00
|
|
|
}
|
|
|
|
|
2020-12-14 15:35:10 -08:00
|
|
|
pub fn process_instruction(
|
2022-09-06 02:31:40 -07:00
|
|
|
first_instruction_account: IndexOfAccount,
|
2021-12-02 09:47:16 -08:00
|
|
|
invoke_context: &mut InvokeContext,
|
2020-12-14 15:35:10 -08:00
|
|
|
) -> Result<(), InstructionError> {
|
2022-04-01 06:48:05 -07:00
|
|
|
process_instruction_common(first_instruction_account, invoke_context, false)
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn process_instruction_jit(
|
2022-09-06 02:31:40 -07:00
|
|
|
first_instruction_account: IndexOfAccount,
|
2021-12-02 09:47:16 -08:00
|
|
|
invoke_context: &mut InvokeContext,
|
2019-03-18 09:05:03 -07:00
|
|
|
) -> Result<(), InstructionError> {
|
2022-04-01 06:48:05 -07:00
|
|
|
process_instruction_common(first_instruction_account, invoke_context, true)
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
2020-03-05 10:57:35 -08:00
|
|
|
|
2020-12-14 15:35:10 -08:00
|
|
|
fn process_instruction_common(
|
2022-09-06 02:31:40 -07:00
|
|
|
first_instruction_account: IndexOfAccount,
|
2021-12-02 09:47:16 -08:00
|
|
|
invoke_context: &mut InvokeContext,
|
2020-12-14 15:35:10 -08:00
|
|
|
use_jit: bool,
|
|
|
|
) -> Result<(), InstructionError> {
|
2021-11-23 04:23:40 -08:00
|
|
|
let log_collector = invoke_context.get_log_collector();
|
2022-02-17 01:16:28 -08:00
|
|
|
let transaction_context = &invoke_context.transaction_context;
|
|
|
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
2022-06-16 09:46:17 -07:00
|
|
|
let program_id = instruction_context.get_last_program_key(transaction_context)?;
|
2022-03-30 00:17:55 -07:00
|
|
|
let first_account_key = transaction_context.get_key_of_account_at_index(
|
2022-06-16 09:46:17 -07:00
|
|
|
get_index_in_transaction(instruction_context, first_instruction_account)?,
|
2022-03-30 00:17:55 -07:00
|
|
|
)?;
|
2022-06-16 09:46:17 -07:00
|
|
|
let second_account_key = get_index_in_transaction(
|
|
|
|
instruction_context,
|
|
|
|
first_instruction_account.saturating_add(1),
|
|
|
|
)
|
|
|
|
.and_then(|index_in_transaction| {
|
|
|
|
transaction_context.get_key_of_account_at_index(index_in_transaction)
|
|
|
|
});
|
2022-03-30 00:17:55 -07:00
|
|
|
|
|
|
|
let program_account_index = if first_account_key == program_id {
|
|
|
|
first_instruction_account
|
|
|
|
} else if second_account_key
|
|
|
|
.map(|key| key == program_id)
|
2021-10-12 23:58:20 -07:00
|
|
|
.unwrap_or(false)
|
|
|
|
{
|
2022-03-30 00:17:55 -07:00
|
|
|
first_instruction_account.saturating_add(1)
|
2021-10-12 23:58:20 -07:00
|
|
|
} else {
|
2022-06-16 09:46:17 -07:00
|
|
|
let first_account = try_borrow_account(
|
|
|
|
transaction_context,
|
|
|
|
instruction_context,
|
|
|
|
first_instruction_account,
|
|
|
|
)?;
|
|
|
|
if first_account.is_executable() {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "BPF loader is executable");
|
2021-10-12 23:58:20 -07:00
|
|
|
return Err(InstructionError::IncorrectProgramId);
|
|
|
|
}
|
2022-03-30 00:17:55 -07:00
|
|
|
first_instruction_account
|
2021-10-12 23:58:20 -07:00
|
|
|
};
|
|
|
|
|
2022-06-16 09:46:17 -07:00
|
|
|
let program = try_borrow_account(
|
|
|
|
transaction_context,
|
|
|
|
instruction_context,
|
|
|
|
program_account_index,
|
|
|
|
)?;
|
2022-03-30 00:17:55 -07:00
|
|
|
if program.is_executable() {
|
2022-03-02 14:50:16 -08:00
|
|
|
// First instruction account can only be zero if called from CPI, which
|
|
|
|
// means stack height better be greater than one
|
2021-10-08 02:41:07 -07:00
|
|
|
debug_assert_eq!(
|
2022-03-02 14:50:16 -08:00
|
|
|
first_instruction_account == 0,
|
|
|
|
invoke_context.get_stack_height() > 1
|
2021-10-08 02:41:07 -07:00
|
|
|
);
|
|
|
|
|
2022-10-18 01:22:39 -07:00
|
|
|
let programdata = if program_account_index == first_instruction_account {
|
|
|
|
None
|
2021-10-12 23:58:20 -07:00
|
|
|
} else {
|
2022-10-18 01:22:39 -07:00
|
|
|
Some(try_borrow_account(
|
|
|
|
transaction_context,
|
|
|
|
instruction_context,
|
2022-10-12 09:09:03 -07:00
|
|
|
first_instruction_account,
|
2022-10-18 01:22:39 -07:00
|
|
|
)?)
|
2020-09-14 17:42:37 -07:00
|
|
|
};
|
2022-10-18 01:22:39 -07:00
|
|
|
let mut get_or_create_executor_time = Measure::start("get_or_create_executor_time");
|
|
|
|
let (executor, create_executor_metrics) = create_executor_from_account(
|
|
|
|
&invoke_context.feature_set,
|
|
|
|
invoke_context.get_compute_budget(),
|
|
|
|
log_collector,
|
|
|
|
Some(invoke_context.tx_executor_cache.borrow_mut()),
|
|
|
|
&program,
|
|
|
|
programdata.as_ref().unwrap_or(&program),
|
|
|
|
use_jit,
|
|
|
|
)?;
|
|
|
|
drop(program);
|
|
|
|
drop(programdata);
|
2021-12-20 20:03:20 -08:00
|
|
|
get_or_create_executor_time.stop();
|
2022-01-05 16:08:35 -08:00
|
|
|
saturating_add_assign!(
|
|
|
|
invoke_context.timings.get_or_create_executor_us,
|
|
|
|
get_or_create_executor_time.as_us()
|
|
|
|
);
|
2022-10-18 01:22:39 -07:00
|
|
|
if let Some(create_executor_metrics) = create_executor_metrics {
|
|
|
|
create_executor_metrics.submit_datapoint(&mut invoke_context.timings);
|
|
|
|
}
|
2021-12-20 20:03:20 -08:00
|
|
|
|
2022-04-01 06:48:05 -07:00
|
|
|
executor.execute(program_account_index, invoke_context)
|
2020-12-14 15:35:10 -08:00
|
|
|
} else {
|
2022-03-30 00:17:55 -07:00
|
|
|
drop(program);
|
2021-10-08 02:41:07 -07:00
|
|
|
debug_assert_eq!(first_instruction_account, 1);
|
2022-03-18 14:29:49 -07:00
|
|
|
let disable_deprecated_loader = invoke_context
|
|
|
|
.feature_set
|
|
|
|
.is_active(&disable_deprecated_loader::id());
|
2020-12-23 19:04:48 -08:00
|
|
|
if bpf_loader_upgradeable::check_id(program_id) {
|
|
|
|
process_loader_upgradeable_instruction(
|
2021-10-08 02:41:07 -07:00
|
|
|
first_instruction_account,
|
2020-12-23 19:04:48 -08:00
|
|
|
invoke_context,
|
|
|
|
use_jit,
|
2021-10-12 23:58:20 -07:00
|
|
|
)
|
2022-03-18 14:29:49 -07:00
|
|
|
} else if bpf_loader::check_id(program_id)
|
|
|
|
|| (!disable_deprecated_loader && bpf_loader_deprecated::check_id(program_id))
|
|
|
|
{
|
2022-04-01 06:48:05 -07:00
|
|
|
process_loader_instruction(first_instruction_account, invoke_context, use_jit)
|
2022-03-18 14:29:49 -07:00
|
|
|
} else if disable_deprecated_loader && bpf_loader_deprecated::check_id(program_id) {
|
|
|
|
ic_logger_msg!(log_collector, "Deprecated loader is no longer supported");
|
|
|
|
Err(InstructionError::UnsupportedProgramId)
|
2021-10-12 23:58:20 -07:00
|
|
|
} else {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Invalid BPF loader id");
|
2021-10-12 23:58:20 -07:00
|
|
|
Err(InstructionError::IncorrectProgramId)
|
2020-12-23 19:04:48 -08:00
|
|
|
}
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_loader_upgradeable_instruction(
|
2022-09-06 02:31:40 -07:00
|
|
|
first_instruction_account: IndexOfAccount,
|
2021-12-02 09:47:16 -08:00
|
|
|
invoke_context: &mut InvokeContext,
|
2020-12-14 15:35:10 -08:00
|
|
|
use_jit: bool,
|
|
|
|
) -> Result<(), InstructionError> {
|
2021-11-23 04:23:40 -08:00
|
|
|
let log_collector = invoke_context.get_log_collector();
|
2022-02-17 01:16:28 -08:00
|
|
|
let transaction_context = &invoke_context.transaction_context;
|
|
|
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
2022-04-01 06:48:05 -07:00
|
|
|
let instruction_data = instruction_context.get_instruction_data();
|
2022-06-16 09:46:17 -07:00
|
|
|
let program_id = instruction_context.get_last_program_key(transaction_context)?;
|
2020-12-14 15:35:10 -08:00
|
|
|
|
|
|
|
match limited_deserialize(instruction_data)? {
|
|
|
|
UpgradeableLoaderInstruction::InitializeBuffer => {
|
2022-03-29 10:06:50 -07:00
|
|
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
2022-04-19 02:35:40 -07:00
|
|
|
let mut buffer =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
2022-03-16 03:30:01 -07:00
|
|
|
|
2022-04-19 02:35:40 -07:00
|
|
|
if UpgradeableLoaderState::Uninitialized != buffer.get_state()? {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Buffer account already initialized");
|
2020-12-14 15:35:10 -08:00
|
|
|
return Err(InstructionError::AccountAlreadyInitialized);
|
|
|
|
}
|
2021-01-29 12:43:42 -08:00
|
|
|
|
2022-06-16 09:46:17 -07:00
|
|
|
let authority_key = Some(*transaction_context.get_key_of_account_at_index(
|
|
|
|
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
|
|
|
|
)?);
|
2022-03-16 03:30:01 -07:00
|
|
|
|
|
|
|
buffer.set_state(&UpgradeableLoaderState::Buffer {
|
2022-04-19 02:35:40 -07:00
|
|
|
authority_address: authority_key,
|
2022-03-16 03:30:01 -07:00
|
|
|
})?;
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
|
|
|
UpgradeableLoaderInstruction::Write { offset, bytes } => {
|
2022-03-29 10:06:50 -07:00
|
|
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
2022-04-19 02:35:40 -07:00
|
|
|
let buffer =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
2022-03-16 03:30:01 -07:00
|
|
|
|
2022-04-19 02:35:40 -07:00
|
|
|
if let UpgradeableLoaderState::Buffer { authority_address } = buffer.get_state()? {
|
2022-03-16 03:30:01 -07:00
|
|
|
if authority_address.is_none() {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Buffer is immutable");
|
2021-01-08 09:37:57 -08:00
|
|
|
return Err(InstructionError::Immutable); // TODO better error code
|
|
|
|
}
|
2022-06-16 09:46:17 -07:00
|
|
|
let authority_key = Some(*transaction_context.get_key_of_account_at_index(
|
|
|
|
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
|
|
|
|
)?);
|
2022-04-19 02:35:40 -07:00
|
|
|
if authority_address != authority_key {
|
2022-03-16 03:30:01 -07:00
|
|
|
ic_logger_msg!(log_collector, "Incorrect buffer authority provided");
|
|
|
|
return Err(InstructionError::IncorrectAuthority);
|
|
|
|
}
|
2022-06-16 09:46:17 -07:00
|
|
|
if !instruction_context.is_instruction_account_signer(1)? {
|
2022-03-16 03:30:01 -07:00
|
|
|
ic_logger_msg!(log_collector, "Buffer authority did not sign");
|
|
|
|
return Err(InstructionError::MissingRequiredSignature);
|
|
|
|
}
|
2021-01-08 09:37:57 -08:00
|
|
|
} else {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Invalid Buffer account");
|
2020-12-14 15:35:10 -08:00
|
|
|
return Err(InstructionError::InvalidAccountData);
|
2022-03-01 13:55:26 -08:00
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
drop(buffer);
|
2020-12-14 15:35:10 -08:00
|
|
|
write_program_data(
|
2022-03-16 03:30:01 -07:00
|
|
|
first_instruction_account,
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_buffer_metadata().saturating_add(offset as usize),
|
2020-12-14 15:35:10 -08:00
|
|
|
&bytes,
|
2022-03-16 03:30:01 -07:00
|
|
|
invoke_context,
|
2020-12-14 15:35:10 -08:00
|
|
|
)?;
|
|
|
|
}
|
|
|
|
UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len } => {
|
2022-03-29 10:06:50 -07:00
|
|
|
instruction_context.check_number_of_instruction_accounts(4)?;
|
2022-04-19 02:35:40 -07:00
|
|
|
let payer_key = *transaction_context.get_key_of_account_at_index(
|
2022-06-16 09:46:17 -07:00
|
|
|
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
2022-03-16 03:30:01 -07:00
|
|
|
)?;
|
2022-04-19 02:35:40 -07:00
|
|
|
let programdata_key = *transaction_context.get_key_of_account_at_index(
|
2022-06-16 09:46:17 -07:00
|
|
|
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
|
2022-03-16 03:30:01 -07:00
|
|
|
)?;
|
2022-03-24 11:30:42 -07:00
|
|
|
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 4)?;
|
|
|
|
let clock =
|
|
|
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 5)?;
|
2022-03-29 10:06:50 -07:00
|
|
|
instruction_context.check_number_of_instruction_accounts(8)?;
|
2022-06-16 09:46:17 -07:00
|
|
|
let authority_key = Some(*transaction_context.get_key_of_account_at_index(
|
|
|
|
instruction_context.get_index_of_instruction_account_in_transaction(7)?,
|
|
|
|
)?);
|
2020-12-14 15:35:10 -08:00
|
|
|
|
|
|
|
// Verify Program account
|
2022-03-16 03:30:01 -07:00
|
|
|
|
2022-04-19 02:35:40 -07:00
|
|
|
let program =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
|
|
|
|
if UpgradeableLoaderState::Uninitialized != program.get_state()? {
|
2022-03-16 03:30:01 -07:00
|
|
|
ic_logger_msg!(log_collector, "Program account already initialized");
|
|
|
|
return Err(InstructionError::AccountAlreadyInitialized);
|
|
|
|
}
|
2022-05-11 07:22:59 -07:00
|
|
|
if program.get_data().len() < UpgradeableLoaderState::size_of_program() {
|
2022-03-16 03:30:01 -07:00
|
|
|
ic_logger_msg!(log_collector, "Program account too small");
|
|
|
|
return Err(InstructionError::AccountDataTooSmall);
|
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
if program.get_lamports() < rent.minimum_balance(program.get_data().len()) {
|
2022-03-16 03:30:01 -07:00
|
|
|
ic_logger_msg!(log_collector, "Program account not rent-exempt");
|
|
|
|
return Err(InstructionError::ExecutableAccountNotRentExempt);
|
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
let new_program_id = *program.get_key();
|
|
|
|
drop(program);
|
2021-09-01 17:59:24 -07:00
|
|
|
|
2020-12-14 15:35:10 -08:00
|
|
|
// Verify Buffer account
|
2022-03-16 03:30:01 -07:00
|
|
|
|
2022-04-19 02:35:40 -07:00
|
|
|
let buffer =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
|
|
|
|
if let UpgradeableLoaderState::Buffer { authority_address } = buffer.get_state()? {
|
|
|
|
if authority_address != authority_key {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match");
|
2021-03-10 09:48:41 -08:00
|
|
|
return Err(InstructionError::IncorrectAuthority);
|
|
|
|
}
|
2022-06-16 09:46:17 -07:00
|
|
|
if !instruction_context.is_instruction_account_signer(7)? {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Upgrade authority did not sign");
|
2021-03-10 09:48:41 -08:00
|
|
|
return Err(InstructionError::MissingRequiredSignature);
|
2021-01-29 12:43:42 -08:00
|
|
|
}
|
2021-01-08 09:37:57 -08:00
|
|
|
} else {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Invalid Buffer account");
|
2020-12-14 15:35:10 -08:00
|
|
|
return Err(InstructionError::InvalidArgument);
|
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
let buffer_key = *buffer.get_key();
|
2022-05-11 07:22:59 -07:00
|
|
|
let buffer_data_offset = UpgradeableLoaderState::size_of_buffer_metadata();
|
2022-04-19 02:35:40 -07:00
|
|
|
let buffer_data_len = buffer.get_data().len().saturating_sub(buffer_data_offset);
|
2022-05-11 07:22:59 -07:00
|
|
|
let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
|
|
|
|
let programdata_len = UpgradeableLoaderState::size_of_programdata(max_data_len);
|
|
|
|
if buffer.get_data().len() < UpgradeableLoaderState::size_of_buffer_metadata()
|
2021-01-19 17:56:44 -08:00
|
|
|
|| buffer_data_len == 0
|
|
|
|
{
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Buffer account too small");
|
2021-01-19 17:56:44 -08:00
|
|
|
return Err(InstructionError::InvalidAccountData);
|
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
drop(buffer);
|
2020-12-14 15:35:10 -08:00
|
|
|
if max_data_len < buffer_data_len {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(
|
|
|
|
log_collector,
|
|
|
|
"Max data length is too small to hold Buffer data"
|
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
return Err(InstructionError::AccountDataTooSmall);
|
|
|
|
}
|
2021-02-03 09:16:25 -08:00
|
|
|
if programdata_len > MAX_PERMITTED_DATA_LENGTH as usize {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Max data length is too large");
|
2021-02-03 09:16:25 -08:00
|
|
|
return Err(InstructionError::InvalidArgument);
|
|
|
|
}
|
2020-12-14 15:35:10 -08:00
|
|
|
|
|
|
|
// Create ProgramData account
|
|
|
|
|
|
|
|
let (derived_address, bump_seed) =
|
2021-09-01 17:59:24 -07:00
|
|
|
Pubkey::find_program_address(&[new_program_id.as_ref()], program_id);
|
2022-04-19 02:35:40 -07:00
|
|
|
if derived_address != programdata_key {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "ProgramData address is not derived");
|
2020-12-14 15:35:10 -08:00
|
|
|
return Err(InstructionError::InvalidArgument);
|
|
|
|
}
|
|
|
|
|
2022-07-15 08:08:14 -07:00
|
|
|
// Drain the Buffer account to payer before paying for programdata account
|
|
|
|
{
|
2022-04-19 02:35:40 -07:00
|
|
|
let mut buffer =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
|
2022-09-13 10:58:19 -07:00
|
|
|
let mut payer =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
|
|
|
payer.checked_add_lamports(buffer.get_lamports())?;
|
2022-05-21 08:47:09 -07:00
|
|
|
buffer.set_lamports(0)?;
|
2022-03-16 03:30:01 -07:00
|
|
|
}
|
2021-09-17 17:49:53 -07:00
|
|
|
|
2022-03-16 03:30:01 -07:00
|
|
|
let mut instruction = system_instruction::create_account(
|
2022-04-19 02:35:40 -07:00
|
|
|
&payer_key,
|
|
|
|
&programdata_key,
|
2022-03-16 03:30:01 -07:00
|
|
|
1.max(rent.minimum_balance(programdata_len)),
|
|
|
|
programdata_len as u64,
|
|
|
|
program_id,
|
|
|
|
);
|
2021-09-17 17:49:53 -07:00
|
|
|
|
|
|
|
// pass an extra account to avoid the overly strict UnbalancedInstruction error
|
|
|
|
instruction
|
|
|
|
.accounts
|
2022-04-19 02:35:40 -07:00
|
|
|
.push(AccountMeta::new(buffer_key, false));
|
2021-09-17 17:49:53 -07:00
|
|
|
|
2022-02-17 01:16:28 -08:00
|
|
|
let transaction_context = &invoke_context.transaction_context;
|
|
|
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
2022-06-16 09:46:17 -07:00
|
|
|
let caller_program_id =
|
|
|
|
instruction_context.get_last_program_key(transaction_context)?;
|
2021-09-01 17:59:24 -07:00
|
|
|
let signers = [&[new_program_id.as_ref(), &[bump_seed]]]
|
2021-04-19 09:48:48 -07:00
|
|
|
.iter()
|
|
|
|
.map(|seeds| Pubkey::create_program_address(*seeds, caller_program_id))
|
|
|
|
.collect::<Result<Vec<Pubkey>, solana_sdk::pubkey::PubkeyError>>()?;
|
2021-11-30 23:54:42 -08:00
|
|
|
invoke_context.native_invoke(instruction, signers.as_slice())?;
|
2020-12-14 15:35:10 -08:00
|
|
|
|
|
|
|
// Load and verify the program bits
|
2022-10-18 01:22:39 -07:00
|
|
|
let transaction_context = &invoke_context.transaction_context;
|
|
|
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
|
|
|
let buffer =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
|
|
|
|
let mut create_executor_metrics = executor_metrics::CreateMetrics::default();
|
|
|
|
let executor = create_executor_from_bytes(
|
|
|
|
&invoke_context.feature_set,
|
|
|
|
invoke_context.get_compute_budget(),
|
|
|
|
invoke_context.get_log_collector(),
|
|
|
|
&mut create_executor_metrics,
|
|
|
|
buffer
|
|
|
|
.get_data()
|
|
|
|
.get(buffer_data_offset..)
|
|
|
|
.ok_or(InstructionError::AccountDataTooSmall)?,
|
2021-10-13 23:47:41 -07:00
|
|
|
use_jit,
|
2021-11-16 09:21:16 -08:00
|
|
|
true,
|
2021-10-13 23:47:41 -07:00
|
|
|
)?;
|
2022-10-18 01:22:39 -07:00
|
|
|
drop(buffer);
|
|
|
|
create_executor_metrics.program_id = new_program_id.to_string();
|
|
|
|
create_executor_metrics.submit_datapoint(&mut invoke_context.timings);
|
2022-10-12 09:09:03 -07:00
|
|
|
invoke_context
|
|
|
|
.tx_executor_cache
|
|
|
|
.borrow_mut()
|
|
|
|
.set(new_program_id, executor, true);
|
2021-04-19 09:48:48 -07:00
|
|
|
|
2022-04-19 02:35:40 -07:00
|
|
|
let transaction_context = &invoke_context.transaction_context;
|
|
|
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
2020-12-14 15:35:10 -08:00
|
|
|
|
|
|
|
// Update the ProgramData account and record the program bits
|
2022-04-19 02:35:40 -07:00
|
|
|
{
|
|
|
|
let mut programdata =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
|
|
|
|
programdata.set_state(&UpgradeableLoaderState::ProgramData {
|
|
|
|
slot: clock.slot,
|
|
|
|
upgrade_authority_address: authority_key,
|
|
|
|
})?;
|
|
|
|
let dst_slice = programdata
|
2022-05-21 08:47:09 -07:00
|
|
|
.get_data_mut()?
|
2022-04-19 02:35:40 -07:00
|
|
|
.get_mut(
|
|
|
|
programdata_data_offset
|
|
|
|
..programdata_data_offset.saturating_add(buffer_data_len),
|
|
|
|
)
|
|
|
|
.ok_or(InstructionError::AccountDataTooSmall)?;
|
|
|
|
let buffer =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
|
|
|
|
let src_slice = buffer
|
|
|
|
.get_data()
|
|
|
|
.get(buffer_data_offset..)
|
|
|
|
.ok_or(InstructionError::AccountDataTooSmall)?;
|
|
|
|
dst_slice.copy_from_slice(src_slice);
|
|
|
|
}
|
2020-12-14 15:35:10 -08:00
|
|
|
|
2021-03-02 00:45:53 -08:00
|
|
|
// Update the Program account
|
2022-04-19 02:35:40 -07:00
|
|
|
let mut program =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
|
2022-03-16 03:30:01 -07:00
|
|
|
program.set_state(&UpgradeableLoaderState::Program {
|
2022-04-19 02:35:40 -07:00
|
|
|
programdata_address: programdata_key,
|
2022-03-16 03:30:01 -07:00
|
|
|
})?;
|
2022-05-21 08:47:09 -07:00
|
|
|
program.set_executable(true)?;
|
2022-04-19 02:35:40 -07:00
|
|
|
drop(program);
|
2020-12-14 15:35:10 -08:00
|
|
|
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Deployed program {:?}", new_program_id);
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
|
|
|
UpgradeableLoaderInstruction::Upgrade => {
|
2022-03-29 10:06:50 -07:00
|
|
|
instruction_context.check_number_of_instruction_accounts(3)?;
|
2022-04-19 02:35:40 -07:00
|
|
|
let programdata_key = *transaction_context.get_key_of_account_at_index(
|
2022-06-16 09:46:17 -07:00
|
|
|
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
2022-03-16 03:30:01 -07:00
|
|
|
)?;
|
2022-03-24 11:30:42 -07:00
|
|
|
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 4)?;
|
|
|
|
let clock =
|
|
|
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 5)?;
|
2022-03-29 10:06:50 -07:00
|
|
|
instruction_context.check_number_of_instruction_accounts(7)?;
|
2022-06-16 09:46:17 -07:00
|
|
|
let authority_key = Some(*transaction_context.get_key_of_account_at_index(
|
|
|
|
instruction_context.get_index_of_instruction_account_in_transaction(6)?,
|
|
|
|
)?);
|
2020-12-14 15:35:10 -08:00
|
|
|
|
|
|
|
// Verify Program account
|
2022-03-16 03:30:01 -07:00
|
|
|
|
2022-04-19 02:35:40 -07:00
|
|
|
let program =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
|
|
|
|
if !program.is_executable() {
|
2022-03-16 03:30:01 -07:00
|
|
|
ic_logger_msg!(log_collector, "Program account not executable");
|
|
|
|
return Err(InstructionError::AccountNotExecutable);
|
|
|
|
}
|
|
|
|
if !program.is_writable() {
|
|
|
|
ic_logger_msg!(log_collector, "Program account not writeable");
|
|
|
|
return Err(InstructionError::InvalidArgument);
|
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
if program.get_owner() != program_id {
|
2022-03-16 03:30:01 -07:00
|
|
|
ic_logger_msg!(log_collector, "Program account not owned by loader");
|
|
|
|
return Err(InstructionError::IncorrectProgramId);
|
|
|
|
}
|
|
|
|
if let UpgradeableLoaderState::Program {
|
|
|
|
programdata_address,
|
2022-04-19 02:35:40 -07:00
|
|
|
} = program.get_state()?
|
2022-03-16 03:30:01 -07:00
|
|
|
{
|
2022-04-19 02:35:40 -07:00
|
|
|
if programdata_address != programdata_key {
|
2022-03-16 03:30:01 -07:00
|
|
|
ic_logger_msg!(log_collector, "Program and ProgramData account mismatch");
|
2020-12-14 15:35:10 -08:00
|
|
|
return Err(InstructionError::InvalidArgument);
|
|
|
|
}
|
2022-03-16 03:30:01 -07:00
|
|
|
} else {
|
|
|
|
ic_logger_msg!(log_collector, "Invalid Program account");
|
|
|
|
return Err(InstructionError::InvalidAccountData);
|
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
let new_program_id = *program.get_key();
|
|
|
|
drop(program);
|
2021-09-01 17:59:24 -07:00
|
|
|
|
2020-12-14 15:35:10 -08:00
|
|
|
// Verify Buffer account
|
2022-03-16 03:30:01 -07:00
|
|
|
|
2022-04-19 02:35:40 -07:00
|
|
|
let buffer =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
|
|
|
|
if let UpgradeableLoaderState::Buffer { authority_address } = buffer.get_state()? {
|
|
|
|
if authority_address != authority_key {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match");
|
2021-03-10 09:48:41 -08:00
|
|
|
return Err(InstructionError::IncorrectAuthority);
|
|
|
|
}
|
2022-06-16 09:46:17 -07:00
|
|
|
if !instruction_context.is_instruction_account_signer(6)? {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Upgrade authority did not sign");
|
2021-03-10 09:48:41 -08:00
|
|
|
return Err(InstructionError::MissingRequiredSignature);
|
2021-01-29 12:43:42 -08:00
|
|
|
}
|
2021-01-08 09:37:57 -08:00
|
|
|
} else {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Invalid Buffer account");
|
2021-01-08 09:37:57 -08:00
|
|
|
return Err(InstructionError::InvalidArgument);
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
let buffer_lamports = buffer.get_lamports();
|
2022-05-11 07:22:59 -07:00
|
|
|
let buffer_data_offset = UpgradeableLoaderState::size_of_buffer_metadata();
|
2022-04-19 02:35:40 -07:00
|
|
|
let buffer_data_len = buffer.get_data().len().saturating_sub(buffer_data_offset);
|
2022-05-11 07:22:59 -07:00
|
|
|
if buffer.get_data().len() < UpgradeableLoaderState::size_of_buffer_metadata()
|
2021-01-19 17:56:44 -08:00
|
|
|
|| buffer_data_len == 0
|
|
|
|
{
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Buffer account too small");
|
2021-01-19 17:56:44 -08:00
|
|
|
return Err(InstructionError::InvalidAccountData);
|
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
drop(buffer);
|
2021-01-19 17:56:44 -08:00
|
|
|
|
2020-12-14 15:35:10 -08:00
|
|
|
// Verify ProgramData account
|
2022-03-16 03:30:01 -07:00
|
|
|
|
2022-04-19 02:35:40 -07:00
|
|
|
let programdata =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
2022-05-11 07:22:59 -07:00
|
|
|
let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
|
2022-04-19 02:35:40 -07:00
|
|
|
let programdata_balance_required =
|
|
|
|
1.max(rent.minimum_balance(programdata.get_data().len()));
|
|
|
|
if programdata.get_data().len()
|
2022-05-11 07:22:59 -07:00
|
|
|
< UpgradeableLoaderState::size_of_programdata(buffer_data_len)
|
2022-04-19 02:35:40 -07:00
|
|
|
{
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "ProgramData account not large enough");
|
2020-12-14 15:35:10 -08:00
|
|
|
return Err(InstructionError::AccountDataTooSmall);
|
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
if programdata.get_lamports().saturating_add(buffer_lamports)
|
2022-03-02 14:50:16 -08:00
|
|
|
< programdata_balance_required
|
|
|
|
{
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(
|
|
|
|
log_collector,
|
|
|
|
"Buffer account balance too low to fund upgrade"
|
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
return Err(InstructionError::InsufficientFunds);
|
|
|
|
}
|
|
|
|
if let UpgradeableLoaderState::ProgramData {
|
|
|
|
slot: _,
|
|
|
|
upgrade_authority_address,
|
2022-04-19 02:35:40 -07:00
|
|
|
} = programdata.get_state()?
|
2020-12-14 15:35:10 -08:00
|
|
|
{
|
2021-03-10 09:48:41 -08:00
|
|
|
if upgrade_authority_address.is_none() {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Program not upgradeable");
|
2021-01-08 09:37:57 -08:00
|
|
|
return Err(InstructionError::Immutable);
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
if upgrade_authority_address != authority_key {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Incorrect upgrade authority provided");
|
2021-01-08 09:37:57 -08:00
|
|
|
return Err(InstructionError::IncorrectAuthority);
|
2020-09-14 17:42:37 -07:00
|
|
|
}
|
2022-06-16 09:46:17 -07:00
|
|
|
if !instruction_context.is_instruction_account_signer(6)? {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Upgrade authority did not sign");
|
2020-12-14 15:35:10 -08:00
|
|
|
return Err(InstructionError::MissingRequiredSignature);
|
2020-09-14 17:42:37 -07:00
|
|
|
}
|
2020-12-14 15:35:10 -08:00
|
|
|
} else {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Invalid ProgramData account");
|
2020-12-14 15:35:10 -08:00
|
|
|
return Err(InstructionError::InvalidAccountData);
|
2020-09-14 17:42:37 -07:00
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
drop(programdata);
|
2020-12-14 15:35:10 -08:00
|
|
|
|
|
|
|
// Load and verify the program bits
|
2022-10-18 01:22:39 -07:00
|
|
|
let buffer =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
|
|
|
|
let mut create_executor_metrics = executor_metrics::CreateMetrics::default();
|
|
|
|
let executor = create_executor_from_bytes(
|
|
|
|
&invoke_context.feature_set,
|
|
|
|
invoke_context.get_compute_budget(),
|
|
|
|
invoke_context.get_log_collector(),
|
|
|
|
&mut create_executor_metrics,
|
|
|
|
buffer
|
|
|
|
.get_data()
|
|
|
|
.get(buffer_data_offset..)
|
|
|
|
.ok_or(InstructionError::AccountDataTooSmall)?,
|
2021-10-13 23:47:41 -07:00
|
|
|
use_jit,
|
2021-11-16 09:21:16 -08:00
|
|
|
true,
|
2021-10-13 23:47:41 -07:00
|
|
|
)?;
|
2022-10-18 01:22:39 -07:00
|
|
|
drop(buffer);
|
|
|
|
create_executor_metrics.program_id = new_program_id.to_string();
|
|
|
|
create_executor_metrics.submit_datapoint(&mut invoke_context.timings);
|
2022-10-12 09:09:03 -07:00
|
|
|
invoke_context
|
|
|
|
.tx_executor_cache
|
|
|
|
.borrow_mut()
|
|
|
|
.set(new_program_id, executor, true);
|
2020-12-14 15:35:10 -08:00
|
|
|
|
2022-04-19 02:35:40 -07:00
|
|
|
let transaction_context = &invoke_context.transaction_context;
|
|
|
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
2020-12-14 15:35:10 -08:00
|
|
|
|
2022-03-16 03:30:01 -07:00
|
|
|
// Update the ProgramData account, record the upgraded data, and zero
|
|
|
|
// the rest
|
2022-04-19 02:35:40 -07:00
|
|
|
let mut programdata =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
|
|
|
{
|
|
|
|
programdata.set_state(&UpgradeableLoaderState::ProgramData {
|
|
|
|
slot: clock.slot,
|
|
|
|
upgrade_authority_address: authority_key,
|
|
|
|
})?;
|
|
|
|
let dst_slice = programdata
|
2022-05-21 08:47:09 -07:00
|
|
|
.get_data_mut()?
|
2022-04-19 02:35:40 -07:00
|
|
|
.get_mut(
|
|
|
|
programdata_data_offset
|
|
|
|
..programdata_data_offset.saturating_add(buffer_data_len),
|
|
|
|
)
|
|
|
|
.ok_or(InstructionError::AccountDataTooSmall)?;
|
|
|
|
let buffer =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
|
|
|
|
let src_slice = buffer
|
|
|
|
.get_data()
|
|
|
|
.get(buffer_data_offset..)
|
|
|
|
.ok_or(InstructionError::AccountDataTooSmall)?;
|
|
|
|
dst_slice.copy_from_slice(src_slice);
|
|
|
|
}
|
2022-03-10 11:48:33 -08:00
|
|
|
programdata
|
2022-05-21 08:47:09 -07:00
|
|
|
.get_data_mut()?
|
2022-03-10 11:48:33 -08:00
|
|
|
.get_mut(programdata_data_offset.saturating_add(buffer_data_len)..)
|
|
|
|
.ok_or(InstructionError::AccountDataTooSmall)?
|
2022-03-02 14:50:16 -08:00
|
|
|
.fill(0);
|
2020-12-14 15:35:10 -08:00
|
|
|
|
|
|
|
// Fund ProgramData to rent-exemption, spill the rest
|
2022-04-19 02:35:40 -07:00
|
|
|
let mut buffer =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
|
|
|
|
let mut spill =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
|
|
|
|
spill.checked_add_lamports(
|
2022-09-13 10:58:19 -07:00
|
|
|
programdata
|
|
|
|
.get_lamports()
|
2022-04-19 02:35:40 -07:00
|
|
|
.saturating_add(buffer_lamports)
|
2022-03-02 14:50:16 -08:00
|
|
|
.saturating_sub(programdata_balance_required),
|
2022-03-16 03:30:01 -07:00
|
|
|
)?;
|
2022-09-13 10:58:19 -07:00
|
|
|
buffer.set_lamports(0)?;
|
|
|
|
programdata.set_lamports(programdata_balance_required)?;
|
2020-12-14 15:35:10 -08:00
|
|
|
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Upgraded program {:?}", new_program_id);
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
|
|
|
UpgradeableLoaderInstruction::SetAuthority => {
|
2022-03-29 10:06:50 -07:00
|
|
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
2022-04-19 02:35:40 -07:00
|
|
|
let mut account =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
|
|
|
let present_authority_key = transaction_context.get_key_of_account_at_index(
|
2022-06-16 09:46:17 -07:00
|
|
|
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
|
2022-03-01 13:55:26 -08:00
|
|
|
)?;
|
2022-04-19 02:35:40 -07:00
|
|
|
let new_authority = instruction_context
|
2022-06-16 09:46:17 -07:00
|
|
|
.get_index_of_instruction_account_in_transaction(2)
|
2022-04-19 02:35:40 -07:00
|
|
|
.and_then(|index_in_transaction| {
|
|
|
|
transaction_context.get_key_of_account_at_index(index_in_transaction)
|
|
|
|
})
|
|
|
|
.ok();
|
|
|
|
|
|
|
|
match account.get_state()? {
|
2021-01-08 09:37:57 -08:00
|
|
|
UpgradeableLoaderState::Buffer { authority_address } => {
|
2021-03-10 09:48:41 -08:00
|
|
|
if new_authority.is_none() {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Buffer authority is not optional");
|
2021-01-29 12:43:42 -08:00
|
|
|
return Err(InstructionError::IncorrectAuthority);
|
|
|
|
}
|
2021-03-10 09:48:41 -08:00
|
|
|
if authority_address.is_none() {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Buffer is immutable");
|
2021-01-08 09:37:57 -08:00
|
|
|
return Err(InstructionError::Immutable);
|
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
if authority_address != Some(*present_authority_key) {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Incorrect buffer authority provided");
|
2021-01-08 09:37:57 -08:00
|
|
|
return Err(InstructionError::IncorrectAuthority);
|
|
|
|
}
|
2022-06-16 09:46:17 -07:00
|
|
|
if !instruction_context.is_instruction_account_signer(1)? {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Buffer authority did not sign");
|
2021-01-08 09:37:57 -08:00
|
|
|
return Err(InstructionError::MissingRequiredSignature);
|
|
|
|
}
|
|
|
|
account.set_state(&UpgradeableLoaderState::Buffer {
|
2022-03-16 03:30:01 -07:00
|
|
|
authority_address: new_authority.cloned(),
|
2021-01-08 09:37:57 -08:00
|
|
|
})?;
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
2021-01-08 09:37:57 -08:00
|
|
|
UpgradeableLoaderState::ProgramData {
|
|
|
|
slot,
|
|
|
|
upgrade_authority_address,
|
|
|
|
} => {
|
2021-03-10 09:48:41 -08:00
|
|
|
if upgrade_authority_address.is_none() {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Program not upgradeable");
|
2021-01-08 09:37:57 -08:00
|
|
|
return Err(InstructionError::Immutable);
|
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
if upgrade_authority_address != Some(*present_authority_key) {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Incorrect upgrade authority provided");
|
2021-01-08 09:37:57 -08:00
|
|
|
return Err(InstructionError::IncorrectAuthority);
|
|
|
|
}
|
2022-06-16 09:46:17 -07:00
|
|
|
if !instruction_context.is_instruction_account_signer(1)? {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Upgrade authority did not sign");
|
2021-01-08 09:37:57 -08:00
|
|
|
return Err(InstructionError::MissingRequiredSignature);
|
|
|
|
}
|
|
|
|
account.set_state(&UpgradeableLoaderState::ProgramData {
|
|
|
|
slot,
|
2022-03-16 03:30:01 -07:00
|
|
|
upgrade_authority_address: new_authority.cloned(),
|
2021-01-08 09:37:57 -08:00
|
|
|
})?;
|
2020-09-14 17:42:37 -07:00
|
|
|
}
|
2021-01-08 09:37:57 -08:00
|
|
|
_ => {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Account does not support authorities");
|
2021-03-17 21:39:29 -07:00
|
|
|
return Err(InstructionError::InvalidArgument);
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
2020-09-14 17:42:37 -07:00
|
|
|
}
|
2020-12-14 15:35:10 -08:00
|
|
|
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "New authority {:?}", new_authority);
|
2020-09-14 17:42:37 -07:00
|
|
|
}
|
2021-03-17 21:39:29 -07:00
|
|
|
UpgradeableLoaderInstruction::Close => {
|
2022-03-29 10:06:50 -07:00
|
|
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
2022-06-16 09:46:17 -07:00
|
|
|
if instruction_context.get_index_of_instruction_account_in_transaction(0)?
|
|
|
|
== instruction_context.get_index_of_instruction_account_in_transaction(1)?
|
2022-04-19 02:35:40 -07:00
|
|
|
{
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(
|
|
|
|
log_collector,
|
|
|
|
"Recipient is the same as the account being closed"
|
|
|
|
);
|
2021-03-17 21:39:29 -07:00
|
|
|
return Err(InstructionError::InvalidArgument);
|
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
let mut close_account =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
|
|
|
let close_key = *close_account.get_key();
|
|
|
|
match close_account.get_state()? {
|
2021-08-24 10:05:54 -07:00
|
|
|
UpgradeableLoaderState::Uninitialized => {
|
2022-04-19 02:35:40 -07:00
|
|
|
let mut recipient_account = instruction_context
|
|
|
|
.try_borrow_instruction_account(transaction_context, 1)?;
|
2022-09-13 10:58:19 -07:00
|
|
|
recipient_account.checked_add_lamports(close_account.get_lamports())?;
|
|
|
|
close_account.set_lamports(0)?;
|
2022-04-19 02:35:40 -07:00
|
|
|
|
|
|
|
ic_logger_msg!(log_collector, "Closed Uninitialized {}", close_key);
|
2021-03-17 21:39:29 -07:00
|
|
|
}
|
2021-08-24 10:05:54 -07:00
|
|
|
UpgradeableLoaderState::Buffer { authority_address } => {
|
2022-03-29 10:06:50 -07:00
|
|
|
instruction_context.check_number_of_instruction_accounts(3)?;
|
2022-04-19 02:35:40 -07:00
|
|
|
drop(close_account);
|
2021-08-24 10:05:54 -07:00
|
|
|
common_close_account(
|
|
|
|
&authority_address,
|
2022-03-30 00:17:55 -07:00
|
|
|
transaction_context,
|
|
|
|
instruction_context,
|
2021-11-23 04:23:40 -08:00
|
|
|
&log_collector,
|
2021-08-24 10:05:54 -07:00
|
|
|
)?;
|
|
|
|
|
2022-04-19 02:35:40 -07:00
|
|
|
ic_logger_msg!(log_collector, "Closed Buffer {}", close_key);
|
2021-03-17 21:39:29 -07:00
|
|
|
}
|
2021-08-24 10:05:54 -07:00
|
|
|
UpgradeableLoaderState::ProgramData {
|
|
|
|
slot: _,
|
|
|
|
upgrade_authority_address: authority_address,
|
|
|
|
} => {
|
2022-03-29 10:06:50 -07:00
|
|
|
instruction_context.check_number_of_instruction_accounts(4)?;
|
2022-04-19 02:35:40 -07:00
|
|
|
drop(close_account);
|
|
|
|
let program_account = instruction_context
|
|
|
|
.try_borrow_instruction_account(transaction_context, 3)?;
|
|
|
|
let program_key = *program_account.get_key();
|
2022-03-16 03:30:01 -07:00
|
|
|
|
|
|
|
if !program_account.is_writable() {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Program account is not writable");
|
2021-08-24 10:05:54 -07:00
|
|
|
return Err(InstructionError::InvalidArgument);
|
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
if program_account.get_owner() != program_id {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Program account not owned by loader");
|
2021-08-27 08:44:38 -07:00
|
|
|
return Err(InstructionError::IncorrectProgramId);
|
|
|
|
}
|
2021-08-24 10:05:54 -07:00
|
|
|
|
2022-04-19 02:35:40 -07:00
|
|
|
match program_account.get_state()? {
|
2021-08-24 10:05:54 -07:00
|
|
|
UpgradeableLoaderState::Program {
|
|
|
|
programdata_address,
|
|
|
|
} => {
|
2022-04-19 02:35:40 -07:00
|
|
|
if programdata_address != close_key {
|
2021-08-24 10:05:54 -07:00
|
|
|
ic_logger_msg!(
|
2021-11-23 04:23:40 -08:00
|
|
|
log_collector,
|
2021-08-24 10:05:54 -07:00
|
|
|
"ProgramData account does not match ProgramData account"
|
|
|
|
);
|
|
|
|
return Err(InstructionError::InvalidArgument);
|
|
|
|
}
|
|
|
|
|
2022-04-19 02:35:40 -07:00
|
|
|
drop(program_account);
|
2021-08-24 10:05:54 -07:00
|
|
|
common_close_account(
|
|
|
|
&authority_address,
|
2022-03-30 00:17:55 -07:00
|
|
|
transaction_context,
|
|
|
|
instruction_context,
|
2021-11-23 04:23:40 -08:00
|
|
|
&log_collector,
|
2021-08-24 10:05:54 -07:00
|
|
|
)?;
|
|
|
|
}
|
|
|
|
_ => {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Invalid Program account");
|
2021-08-24 10:05:54 -07:00
|
|
|
return Err(InstructionError::InvalidArgument);
|
|
|
|
}
|
|
|
|
}
|
2021-03-17 21:39:29 -07:00
|
|
|
|
2022-04-19 02:35:40 -07:00
|
|
|
ic_logger_msg!(log_collector, "Closed Program {}", program_key);
|
2021-08-24 10:05:54 -07:00
|
|
|
}
|
|
|
|
_ => {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Account does not support closing");
|
2021-08-24 10:05:54 -07:00
|
|
|
return Err(InstructionError::InvalidArgument);
|
2021-03-19 13:13:20 -07:00
|
|
|
}
|
2021-03-17 21:39:29 -07:00
|
|
|
}
|
|
|
|
}
|
2022-09-21 21:03:06 -07:00
|
|
|
UpgradeableLoaderInstruction::ExtendProgram { additional_bytes } => {
|
2022-07-11 14:46:32 -07:00
|
|
|
if !invoke_context
|
|
|
|
.feature_set
|
2022-09-21 21:03:06 -07:00
|
|
|
.is_active(&enable_bpf_loader_extend_program_ix::ID)
|
2022-07-11 14:46:32 -07:00
|
|
|
{
|
|
|
|
return Err(InstructionError::InvalidInstructionData);
|
|
|
|
}
|
|
|
|
|
|
|
|
if additional_bytes == 0 {
|
|
|
|
ic_logger_msg!(log_collector, "Additional bytes must be greater than 0");
|
|
|
|
return Err(InstructionError::InvalidInstructionData);
|
|
|
|
}
|
|
|
|
|
2022-09-06 02:31:40 -07:00
|
|
|
const PROGRAM_DATA_ACCOUNT_INDEX: IndexOfAccount = 0;
|
2022-09-21 21:03:06 -07:00
|
|
|
const PROGRAM_ACCOUNT_INDEX: IndexOfAccount = 1;
|
2022-07-11 14:46:32 -07:00
|
|
|
#[allow(dead_code)]
|
|
|
|
// System program is only required when a CPI is performed
|
2022-09-21 21:03:06 -07:00
|
|
|
const OPTIONAL_SYSTEM_PROGRAM_ACCOUNT_INDEX: IndexOfAccount = 2;
|
|
|
|
const OPTIONAL_PAYER_ACCOUNT_INDEX: IndexOfAccount = 3;
|
2022-07-11 14:46:32 -07:00
|
|
|
|
|
|
|
let programdata_account = instruction_context
|
|
|
|
.try_borrow_instruction_account(transaction_context, PROGRAM_DATA_ACCOUNT_INDEX)?;
|
|
|
|
let programdata_key = *programdata_account.get_key();
|
|
|
|
|
|
|
|
if program_id != programdata_account.get_owner() {
|
|
|
|
ic_logger_msg!(log_collector, "ProgramData owner is invalid");
|
|
|
|
return Err(InstructionError::InvalidAccountOwner);
|
|
|
|
}
|
|
|
|
if !programdata_account.is_writable() {
|
|
|
|
ic_logger_msg!(log_collector, "ProgramData is not writable");
|
|
|
|
return Err(InstructionError::InvalidArgument);
|
|
|
|
}
|
|
|
|
|
2022-09-21 21:03:06 -07:00
|
|
|
let program_account = instruction_context
|
|
|
|
.try_borrow_instruction_account(transaction_context, PROGRAM_ACCOUNT_INDEX)?;
|
|
|
|
if !program_account.is_writable() {
|
|
|
|
ic_logger_msg!(log_collector, "Program account is not writable");
|
|
|
|
return Err(InstructionError::InvalidArgument);
|
|
|
|
}
|
|
|
|
if program_account.get_owner() != program_id {
|
|
|
|
ic_logger_msg!(log_collector, "Program account not owned by loader");
|
|
|
|
return Err(InstructionError::InvalidAccountOwner);
|
|
|
|
}
|
|
|
|
match program_account.get_state()? {
|
|
|
|
UpgradeableLoaderState::Program {
|
|
|
|
programdata_address,
|
|
|
|
} => {
|
|
|
|
if programdata_address != programdata_key {
|
|
|
|
ic_logger_msg!(
|
|
|
|
log_collector,
|
|
|
|
"Program account does not match ProgramData account"
|
|
|
|
);
|
|
|
|
return Err(InstructionError::InvalidArgument);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
ic_logger_msg!(log_collector, "Invalid Program account");
|
|
|
|
return Err(InstructionError::InvalidAccountData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
drop(program_account);
|
|
|
|
|
2022-07-11 14:46:32 -07:00
|
|
|
let old_len = programdata_account.get_data().len();
|
|
|
|
let new_len = old_len.saturating_add(additional_bytes as usize);
|
|
|
|
if new_len > MAX_PERMITTED_DATA_LENGTH as usize {
|
|
|
|
ic_logger_msg!(
|
|
|
|
log_collector,
|
|
|
|
"Extended ProgramData length of {} bytes exceeds max account data length of {} bytes",
|
|
|
|
new_len,
|
|
|
|
MAX_PERMITTED_DATA_LENGTH
|
|
|
|
);
|
|
|
|
return Err(InstructionError::InvalidRealloc);
|
|
|
|
}
|
|
|
|
|
|
|
|
if let UpgradeableLoaderState::ProgramData {
|
|
|
|
slot: _,
|
|
|
|
upgrade_authority_address,
|
|
|
|
} = programdata_account.get_state()?
|
|
|
|
{
|
|
|
|
if upgrade_authority_address.is_none() {
|
|
|
|
ic_logger_msg!(
|
|
|
|
log_collector,
|
|
|
|
"Cannot extend ProgramData accounts that are not upgradeable"
|
|
|
|
);
|
|
|
|
return Err(InstructionError::Immutable);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ic_logger_msg!(log_collector, "ProgramData state is invalid");
|
|
|
|
return Err(InstructionError::InvalidAccountData);
|
|
|
|
}
|
|
|
|
|
|
|
|
let required_payment = {
|
|
|
|
let balance = programdata_account.get_lamports();
|
|
|
|
let rent = invoke_context.get_sysvar_cache().get_rent()?;
|
|
|
|
let min_balance = rent.minimum_balance(new_len).max(1);
|
|
|
|
min_balance.saturating_sub(balance)
|
|
|
|
};
|
|
|
|
|
|
|
|
// Borrowed accounts need to be dropped before native_invoke
|
|
|
|
drop(programdata_account);
|
|
|
|
|
|
|
|
if required_payment > 0 {
|
|
|
|
let payer_key = *transaction_context.get_key_of_account_at_index(
|
|
|
|
instruction_context.get_index_of_instruction_account_in_transaction(
|
|
|
|
OPTIONAL_PAYER_ACCOUNT_INDEX,
|
|
|
|
)?,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
invoke_context.native_invoke(
|
|
|
|
system_instruction::transfer(&payer_key, &programdata_key, required_payment),
|
|
|
|
&[],
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
let transaction_context = &invoke_context.transaction_context;
|
|
|
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
|
|
|
let mut programdata_account = instruction_context
|
|
|
|
.try_borrow_instruction_account(transaction_context, PROGRAM_DATA_ACCOUNT_INDEX)?;
|
|
|
|
programdata_account.set_data_length(new_len)?;
|
|
|
|
|
|
|
|
ic_logger_msg!(
|
|
|
|
log_collector,
|
|
|
|
"Extended ProgramData account by {} bytes",
|
|
|
|
additional_bytes
|
|
|
|
);
|
|
|
|
}
|
2020-09-14 17:42:37 -07:00
|
|
|
}
|
2020-12-14 15:35:10 -08:00
|
|
|
|
2020-09-14 17:42:37 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-08-24 10:05:54 -07:00
|
|
|
fn common_close_account(
|
|
|
|
authority_address: &Option<Pubkey>,
|
2022-03-30 00:17:55 -07:00
|
|
|
transaction_context: &TransactionContext,
|
|
|
|
instruction_context: &InstructionContext,
|
2021-11-23 04:23:40 -08:00
|
|
|
log_collector: &Option<Rc<RefCell<LogCollector>>>,
|
2021-08-24 10:05:54 -07:00
|
|
|
) -> Result<(), InstructionError> {
|
|
|
|
if authority_address.is_none() {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Account is immutable");
|
2021-08-24 10:05:54 -07:00
|
|
|
return Err(InstructionError::Immutable);
|
|
|
|
}
|
2022-03-30 00:17:55 -07:00
|
|
|
if *authority_address
|
2022-06-16 09:46:17 -07:00
|
|
|
!= Some(*transaction_context.get_key_of_account_at_index(
|
|
|
|
instruction_context.get_index_of_instruction_account_in_transaction(2)?,
|
|
|
|
)?)
|
2022-03-30 00:17:55 -07:00
|
|
|
{
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Incorrect authority provided");
|
2021-08-24 10:05:54 -07:00
|
|
|
return Err(InstructionError::IncorrectAuthority);
|
|
|
|
}
|
2022-06-16 09:46:17 -07:00
|
|
|
if !instruction_context.is_instruction_account_signer(2)? {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Authority did not sign");
|
2021-08-24 10:05:54 -07:00
|
|
|
return Err(InstructionError::MissingRequiredSignature);
|
|
|
|
}
|
2022-03-16 03:30:01 -07:00
|
|
|
|
2022-03-30 00:17:55 -07:00
|
|
|
let mut close_account =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
|
|
|
let mut recipient_account =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
|
|
|
|
recipient_account.checked_add_lamports(close_account.get_lamports())?;
|
2022-05-21 08:47:09 -07:00
|
|
|
close_account.set_lamports(0)?;
|
2021-10-28 09:04:03 -07:00
|
|
|
close_account.set_state(&UpgradeableLoaderState::Uninitialized)?;
|
2021-08-24 10:05:54 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-12-14 15:35:10 -08:00
|
|
|
fn process_loader_instruction(
|
2022-09-06 02:31:40 -07:00
|
|
|
first_instruction_account: IndexOfAccount,
|
2021-12-02 09:47:16 -08:00
|
|
|
invoke_context: &mut InvokeContext,
|
2020-12-14 15:35:10 -08:00
|
|
|
use_jit: bool,
|
2020-12-07 00:49:55 -08:00
|
|
|
) -> Result<(), InstructionError> {
|
2022-02-17 01:16:28 -08:00
|
|
|
let transaction_context = &invoke_context.transaction_context;
|
|
|
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
2022-04-01 06:48:05 -07:00
|
|
|
let instruction_data = instruction_context.get_instruction_data();
|
2022-06-16 09:46:17 -07:00
|
|
|
let program_id = instruction_context.get_last_program_key(transaction_context)?;
|
2022-10-18 01:22:39 -07:00
|
|
|
let mut program = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
2022-04-19 02:35:40 -07:00
|
|
|
if program.get_owner() != program_id {
|
2021-01-21 09:57:59 -08:00
|
|
|
ic_msg!(
|
|
|
|
invoke_context,
|
|
|
|
"Executable account not owned by the BPF loader"
|
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
return Err(InstructionError::IncorrectProgramId);
|
|
|
|
}
|
2022-04-19 02:35:40 -07:00
|
|
|
let is_program_signer = program.is_signer();
|
2020-12-14 15:35:10 -08:00
|
|
|
match limited_deserialize(instruction_data)? {
|
|
|
|
LoaderInstruction::Write { offset, bytes } => {
|
2022-04-19 02:35:40 -07:00
|
|
|
if !is_program_signer {
|
2021-01-21 09:57:59 -08:00
|
|
|
ic_msg!(invoke_context, "Program account did not sign");
|
2021-01-08 09:37:57 -08:00
|
|
|
return Err(InstructionError::MissingRequiredSignature);
|
|
|
|
}
|
2022-10-18 01:22:39 -07:00
|
|
|
drop(program);
|
2021-10-13 23:47:41 -07:00
|
|
|
write_program_data(
|
2022-03-16 03:30:01 -07:00
|
|
|
first_instruction_account,
|
2021-10-13 23:47:41 -07:00
|
|
|
offset as usize,
|
|
|
|
&bytes,
|
2022-03-16 03:30:01 -07:00
|
|
|
invoke_context,
|
2021-10-13 23:47:41 -07:00
|
|
|
)?;
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
|
|
|
LoaderInstruction::Finalize => {
|
2022-04-19 02:35:40 -07:00
|
|
|
if !is_program_signer {
|
2022-03-16 03:30:01 -07:00
|
|
|
ic_msg!(invoke_context, "key[0] did not sign the transaction");
|
2020-12-14 15:35:10 -08:00
|
|
|
return Err(InstructionError::MissingRequiredSignature);
|
|
|
|
}
|
2022-10-18 01:22:39 -07:00
|
|
|
let mut create_executor_metrics = executor_metrics::CreateMetrics::default();
|
|
|
|
let executor = create_executor_from_bytes(
|
|
|
|
&invoke_context.feature_set,
|
|
|
|
invoke_context.get_compute_budget(),
|
|
|
|
invoke_context.get_log_collector(),
|
|
|
|
&mut create_executor_metrics,
|
|
|
|
program.get_data(),
|
2022-05-20 13:19:41 -07:00
|
|
|
use_jit,
|
|
|
|
true,
|
|
|
|
)?;
|
2022-10-18 01:22:39 -07:00
|
|
|
create_executor_metrics.program_id = program.get_key().to_string();
|
|
|
|
create_executor_metrics.submit_datapoint(&mut invoke_context.timings);
|
2022-10-12 09:09:03 -07:00
|
|
|
invoke_context
|
|
|
|
.tx_executor_cache
|
|
|
|
.borrow_mut()
|
|
|
|
.set(*program.get_key(), executor, true);
|
2022-05-21 08:47:09 -07:00
|
|
|
program.set_executable(true)?;
|
2022-04-19 02:35:40 -07:00
|
|
|
ic_msg!(invoke_context, "Finalized account {:?}", program.get_key());
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
2020-12-07 00:49:55 -08:00
|
|
|
}
|
|
|
|
|
2020-09-14 17:42:37 -07:00
|
|
|
/// Passed to the VM to enforce the compute budget
|
2020-11-04 09:46:26 -08:00
|
|
|
pub struct ThisInstructionMeter {
|
2021-11-23 04:23:40 -08:00
|
|
|
pub compute_meter: Rc<RefCell<ComputeMeter>>,
|
2020-09-14 17:42:37 -07:00
|
|
|
}
|
2020-10-15 15:55:37 -07:00
|
|
|
impl ThisInstructionMeter {
|
2021-11-23 04:23:40 -08:00
|
|
|
fn new(compute_meter: Rc<RefCell<ComputeMeter>>) -> Self {
|
2020-10-15 15:55:37 -07:00
|
|
|
Self { compute_meter }
|
|
|
|
}
|
|
|
|
}
|
2020-09-14 17:42:37 -07:00
|
|
|
impl InstructionMeter for ThisInstructionMeter {
|
|
|
|
fn consume(&mut self, amount: u64) {
|
|
|
|
// 1 to 1 instruction to compute unit mapping
|
|
|
|
// ignore error, Ebpf will bail if exceeded
|
|
|
|
let _ = self.compute_meter.borrow_mut().consume(amount);
|
|
|
|
}
|
|
|
|
fn get_remaining(&self) -> u64 {
|
|
|
|
self.compute_meter.borrow().get_remaining()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// BPF Loader's Executor implementation
|
2021-02-18 23:42:09 -08:00
|
|
|
pub struct BpfExecutor {
|
2022-10-06 11:31:58 -07:00
|
|
|
verified_executable: VerifiedExecutable<RequisiteVerifier, ThisInstructionMeter>,
|
2022-03-14 15:00:00 -07:00
|
|
|
use_jit: bool,
|
2020-09-14 17:42:37 -07:00
|
|
|
}
|
2020-10-20 09:05:45 -07:00
|
|
|
|
|
|
|
// Well, implement Debug for solana_rbpf::vm::Executable in solana-rbpf...
|
2021-02-18 23:42:09 -08:00
|
|
|
impl Debug for BpfExecutor {
|
2020-10-20 09:05:45 -07:00
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
2021-02-18 23:42:09 -08:00
|
|
|
write!(f, "BpfExecutor({:p})", self)
|
2020-10-20 09:05:45 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-18 23:42:09 -08:00
|
|
|
impl Executor for BpfExecutor {
|
2022-04-01 06:48:05 -07:00
|
|
|
fn execute(
|
2020-09-14 17:42:37 -07:00
|
|
|
&self,
|
2022-09-06 02:31:40 -07:00
|
|
|
_first_instruction_account: IndexOfAccount,
|
2022-04-01 06:48:05 -07:00
|
|
|
invoke_context: &mut InvokeContext,
|
2020-09-14 17:42:37 -07:00
|
|
|
) -> Result<(), InstructionError> {
|
2021-11-23 04:23:40 -08:00
|
|
|
let log_collector = invoke_context.get_log_collector();
|
2021-12-02 04:12:11 -08:00
|
|
|
let compute_meter = invoke_context.get_compute_meter();
|
2022-02-02 16:45:57 -08:00
|
|
|
let stack_height = invoke_context.get_stack_height();
|
2022-02-17 01:16:28 -08:00
|
|
|
let transaction_context = &invoke_context.transaction_context;
|
|
|
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
2022-06-16 09:46:17 -07:00
|
|
|
let program_id = *instruction_context.get_last_program_key(transaction_context)?;
|
2020-09-14 17:42:37 -07:00
|
|
|
|
2021-03-03 15:07:45 -08:00
|
|
|
let mut serialize_time = Measure::start("serialize");
|
2022-10-06 23:45:05 -07:00
|
|
|
let (parameter_bytes, regions, account_lengths) = serialize_parameters(
|
2022-07-20 05:12:43 -07:00
|
|
|
invoke_context.transaction_context,
|
|
|
|
instruction_context,
|
|
|
|
invoke_context
|
|
|
|
.feature_set
|
|
|
|
.is_active(&cap_bpf_program_instruction_accounts::ID),
|
|
|
|
)?;
|
2021-03-03 15:07:45 -08:00
|
|
|
serialize_time.stop();
|
2022-05-19 15:14:28 -07:00
|
|
|
|
2021-03-03 15:07:45 -08:00
|
|
|
let mut create_vm_time = Measure::start("create_vm");
|
|
|
|
let mut execute_time;
|
2021-12-22 12:07:07 -08:00
|
|
|
let execution_result = {
|
2020-11-04 09:46:26 -08:00
|
|
|
let mut vm = match create_vm(
|
2022-06-07 04:45:07 -07:00
|
|
|
&self.verified_executable,
|
2022-10-06 23:45:05 -07:00
|
|
|
regions,
|
2022-05-19 15:14:28 -07:00
|
|
|
account_lengths,
|
2020-08-24 13:21:34 -07:00
|
|
|
invoke_context,
|
|
|
|
) {
|
|
|
|
Ok(info) => info,
|
|
|
|
Err(e) => {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Failed to create BPF VM: {}", e);
|
2020-12-15 09:54:07 -08:00
|
|
|
return Err(InstructionError::ProgramEnvironmentSetupFailure);
|
2020-08-24 13:21:34 -07:00
|
|
|
}
|
|
|
|
};
|
2021-03-03 15:07:45 -08:00
|
|
|
create_vm_time.stop();
|
2020-03-17 12:06:15 -07:00
|
|
|
|
2021-03-03 15:07:45 -08:00
|
|
|
execute_time = Measure::start("execute");
|
2022-02-02 16:45:57 -08:00
|
|
|
stable_log::program_invoke(&log_collector, &program_id, stack_height);
|
2020-11-04 09:46:26 -08:00
|
|
|
let mut instruction_meter = ThisInstructionMeter::new(compute_meter.clone());
|
2020-10-15 15:55:37 -07:00
|
|
|
let before = compute_meter.borrow().get_remaining();
|
2022-03-14 15:00:00 -07:00
|
|
|
let result = if self.use_jit {
|
2020-11-24 09:00:19 -08:00
|
|
|
vm.execute_program_jit(&mut instruction_meter)
|
2020-11-04 09:46:26 -08:00
|
|
|
} else {
|
|
|
|
vm.execute_program_interpreted(&mut instruction_meter)
|
|
|
|
};
|
2020-10-15 15:55:37 -07:00
|
|
|
let after = compute_meter.borrow().get_remaining();
|
2021-01-21 09:57:59 -08:00
|
|
|
ic_logger_msg!(
|
2021-11-23 04:23:40 -08:00
|
|
|
log_collector,
|
2020-11-12 12:44:37 -08:00
|
|
|
"Program {} consumed {} of {} compute units",
|
2021-12-02 04:12:11 -08:00
|
|
|
&program_id,
|
2022-03-02 14:50:16 -08:00
|
|
|
before.saturating_sub(after),
|
2020-10-15 15:55:37 -07:00
|
|
|
before
|
|
|
|
);
|
2021-03-01 23:11:58 -08:00
|
|
|
if log_enabled!(Trace) {
|
2021-05-25 01:05:35 -07:00
|
|
|
let mut trace_buffer = Vec::<u8>::new();
|
2022-06-07 04:45:07 -07:00
|
|
|
let analysis =
|
|
|
|
Analysis::from_executable(self.verified_executable.get_executable()).unwrap();
|
2022-10-06 11:31:58 -07:00
|
|
|
vm.get_program_environment()
|
|
|
|
.tracer
|
|
|
|
.write(&mut trace_buffer, &analysis)
|
|
|
|
.unwrap();
|
2021-05-25 01:05:35 -07:00
|
|
|
let trace_string = String::from_utf8(trace_buffer).unwrap();
|
|
|
|
trace!("BPF Program Instruction Trace:\n{}", trace_string);
|
2021-03-01 23:11:58 -08:00
|
|
|
}
|
2021-09-01 02:14:01 -07:00
|
|
|
drop(vm);
|
2022-01-10 09:26:51 -08:00
|
|
|
let (_returned_from_program_id, return_data) =
|
|
|
|
invoke_context.transaction_context.get_return_data();
|
2021-09-29 10:11:06 -07:00
|
|
|
if !return_data.is_empty() {
|
2021-11-23 04:23:40 -08:00
|
|
|
stable_log::program_return(&log_collector, &program_id, return_data);
|
2021-09-01 02:14:01 -07:00
|
|
|
}
|
2020-10-15 15:55:37 -07:00
|
|
|
match result {
|
2022-10-06 11:31:58 -07:00
|
|
|
ProgramResult::Ok(status) if status != SUCCESS => {
|
2022-09-26 01:47:16 -07:00
|
|
|
let error: InstructionError = if (status
|
2022-08-29 11:30:48 -07:00
|
|
|
== MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED
|
2021-12-28 03:14:48 -08:00
|
|
|
&& !invoke_context
|
|
|
|
.feature_set
|
2022-09-26 01:47:16 -07:00
|
|
|
.is_active(&cap_accounts_data_allocations_per_transaction::id()))
|
|
|
|
|| (status == MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED
|
|
|
|
&& !invoke_context
|
|
|
|
.feature_set
|
|
|
|
.is_active(&limit_max_instruction_trace_length::id()))
|
2021-12-28 03:14:48 -08:00
|
|
|
{
|
2022-08-29 11:30:48 -07:00
|
|
|
// Until the cap_accounts_data_allocations_per_transaction feature is
|
2022-09-26 01:47:16 -07:00
|
|
|
// enabled, map the `MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED` error to `InvalidError`.
|
|
|
|
// Until the limit_max_instruction_trace_length feature is
|
|
|
|
// enabled, map the `MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED` error to `InvalidError`.
|
2021-12-28 03:14:48 -08:00
|
|
|
InstructionError::InvalidError
|
|
|
|
} else {
|
|
|
|
status.into()
|
|
|
|
};
|
2021-12-22 12:07:07 -08:00
|
|
|
stable_log::program_failure(&log_collector, &program_id, &error);
|
|
|
|
Err(error)
|
2020-03-17 12:06:15 -07:00
|
|
|
}
|
2022-10-06 11:31:58 -07:00
|
|
|
ProgramResult::Err(error) => {
|
2020-11-12 12:44:37 -08:00
|
|
|
let error = match error {
|
2022-10-06 11:31:58 -07:00
|
|
|
/*EbpfError::UserError(user_error) if let BpfError::SyscallError(
|
|
|
|
SyscallError::InstructionError(instruction_error),
|
|
|
|
) = user_error.downcast_ref::<BpfError>().unwrap() => instruction_error.clone(),*/
|
|
|
|
EbpfError::UserError(user_error)
|
|
|
|
if matches!(
|
|
|
|
user_error.downcast_ref::<BpfError>().unwrap(),
|
|
|
|
BpfError::SyscallError(SyscallError::InstructionError(_)),
|
|
|
|
) =>
|
|
|
|
{
|
|
|
|
match user_error.downcast_ref::<BpfError>().unwrap() {
|
|
|
|
BpfError::SyscallError(SyscallError::InstructionError(
|
|
|
|
instruction_error,
|
|
|
|
)) => instruction_error.clone(),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
2020-12-15 09:54:07 -08:00
|
|
|
err => {
|
2021-11-23 04:23:40 -08:00
|
|
|
ic_logger_msg!(log_collector, "Program failed to complete: {}", err);
|
2020-12-15 09:54:07 -08:00
|
|
|
InstructionError::ProgramFailedToComplete
|
|
|
|
}
|
2020-03-26 14:00:26 -07:00
|
|
|
};
|
2021-11-23 04:23:40 -08:00
|
|
|
stable_log::program_failure(&log_collector, &program_id, &error);
|
2021-12-22 12:07:07 -08:00
|
|
|
Err(error)
|
2020-01-10 13:20:15 -08:00
|
|
|
}
|
2021-12-22 12:07:07 -08:00
|
|
|
_ => Ok(()),
|
2020-01-10 13:20:15 -08:00
|
|
|
}
|
2021-12-22 12:07:07 -08:00
|
|
|
};
|
|
|
|
execute_time.stop();
|
|
|
|
|
2021-03-03 15:07:45 -08:00
|
|
|
let mut deserialize_time = Measure::start("deserialize");
|
2021-12-22 12:07:07 -08:00
|
|
|
let execute_or_deserialize_result = execution_result.and_then(|_| {
|
|
|
|
deserialize_parameters(
|
2022-01-03 14:30:56 -08:00
|
|
|
invoke_context.transaction_context,
|
|
|
|
invoke_context
|
|
|
|
.transaction_context
|
|
|
|
.get_current_instruction_context()?,
|
2021-12-22 12:07:07 -08:00
|
|
|
parameter_bytes.as_slice(),
|
2022-04-11 16:05:09 -07:00
|
|
|
invoke_context.get_orig_account_lengths()?,
|
2021-12-22 12:07:07 -08:00
|
|
|
)
|
|
|
|
});
|
2021-03-03 15:07:45 -08:00
|
|
|
deserialize_time.stop();
|
2021-12-22 12:07:07 -08:00
|
|
|
|
|
|
|
// Update the timings
|
2021-12-03 03:15:22 -08:00
|
|
|
let timings = &mut invoke_context.timings;
|
|
|
|
timings.serialize_us = timings.serialize_us.saturating_add(serialize_time.as_us());
|
|
|
|
timings.create_vm_us = timings.create_vm_us.saturating_add(create_vm_time.as_us());
|
|
|
|
timings.execute_us = timings.execute_us.saturating_add(execute_time.as_us());
|
|
|
|
timings.deserialize_us = timings
|
|
|
|
.deserialize_us
|
|
|
|
.saturating_add(deserialize_time.as_us());
|
2021-12-22 12:07:07 -08:00
|
|
|
|
|
|
|
if execute_or_deserialize_result.is_ok() {
|
|
|
|
stable_log::program_success(&log_collector, &program_id);
|
|
|
|
}
|
|
|
|
execute_or_deserialize_result
|
2018-10-16 09:43:49 -07:00
|
|
|
}
|
|
|
|
}
|
2018-10-31 10:59:56 -07:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
super::*,
|
|
|
|
rand::Rng,
|
|
|
|
solana_program_runtime::invoke_context::mock_process_instruction,
|
2022-10-06 23:45:05 -07:00
|
|
|
solana_rbpf::{ebpf::MM_INPUT_START, verifier::Verifier, vm::SyscallRegistry},
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_runtime::{bank::Bank, bank_client::BankClient},
|
|
|
|
solana_sdk::{
|
|
|
|
account::{
|
|
|
|
create_account_shared_data_for_test as create_account_for_test, AccountSharedData,
|
2022-04-19 02:35:40 -07:00
|
|
|
ReadableAccount, WritableAccount,
|
2021-12-03 09:00:31 -08:00
|
|
|
},
|
|
|
|
account_utils::StateMut,
|
|
|
|
client::SyncClient,
|
|
|
|
clock::Clock,
|
|
|
|
feature_set::FeatureSet,
|
|
|
|
genesis_config::create_genesis_config,
|
|
|
|
instruction::{AccountMeta, Instruction, InstructionError},
|
|
|
|
message::Message,
|
|
|
|
native_token::LAMPORTS_PER_SOL,
|
|
|
|
pubkey::Pubkey,
|
|
|
|
rent::Rent,
|
|
|
|
signature::{Keypair, Signer},
|
|
|
|
system_program, sysvar,
|
|
|
|
transaction::TransactionError,
|
2021-03-24 23:23:20 -07:00
|
|
|
},
|
2021-12-17 05:01:12 -08:00
|
|
|
std::{fs::File, io::Read, ops::Range, sync::Arc},
|
2020-04-28 14:33:56 -07:00
|
|
|
};
|
|
|
|
|
2020-08-21 15:31:19 -07:00
|
|
|
struct TestInstructionMeter {
|
|
|
|
remaining: u64,
|
2020-06-13 13:20:08 -07:00
|
|
|
}
|
2020-08-21 15:31:19 -07:00
|
|
|
impl InstructionMeter for TestInstructionMeter {
|
|
|
|
fn consume(&mut self, amount: u64) {
|
|
|
|
self.remaining = self.remaining.saturating_sub(amount);
|
2020-06-06 10:18:28 -07:00
|
|
|
}
|
2020-08-21 15:31:19 -07:00
|
|
|
fn get_remaining(&self) -> u64 {
|
|
|
|
self.remaining
|
2020-06-06 10:18:28 -07:00
|
|
|
}
|
2020-04-28 14:33:56 -07:00
|
|
|
}
|
2018-11-06 14:28:46 -08:00
|
|
|
|
2021-10-08 02:41:07 -07:00
|
|
|
fn process_instruction(
|
2021-11-04 13:47:32 -07:00
|
|
|
loader_id: &Pubkey,
|
2022-09-06 02:31:40 -07:00
|
|
|
program_indices: &[IndexOfAccount],
|
2021-10-08 02:41:07 -07:00
|
|
|
instruction_data: &[u8],
|
2021-12-17 05:01:12 -08:00
|
|
|
transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
|
|
|
|
instruction_accounts: Vec<AccountMeta>,
|
|
|
|
expected_result: Result<(), InstructionError>,
|
|
|
|
) -> Vec<AccountSharedData> {
|
2021-11-04 13:47:32 -07:00
|
|
|
mock_process_instruction(
|
|
|
|
loader_id,
|
|
|
|
program_indices.to_vec(),
|
2021-10-08 02:41:07 -07:00
|
|
|
instruction_data,
|
2021-12-17 05:01:12 -08:00
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2022-03-31 01:46:35 -07:00
|
|
|
None,
|
2022-04-15 11:43:04 -07:00
|
|
|
None,
|
2021-12-17 05:01:12 -08:00
|
|
|
expected_result,
|
2021-11-04 13:47:32 -07:00
|
|
|
super::process_instruction,
|
2021-10-08 02:41:07 -07:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-12-17 05:01:12 -08:00
|
|
|
fn load_program_account_from_elf(loader_id: &Pubkey, path: &str) -> AccountSharedData {
|
2021-10-08 02:41:07 -07:00
|
|
|
let mut file = File::open(path).expect("file open failed");
|
|
|
|
let mut elf = Vec::new();
|
|
|
|
file.read_to_end(&mut elf).unwrap();
|
|
|
|
let rent = Rent::default();
|
2021-12-17 05:01:12 -08:00
|
|
|
let mut program_account =
|
|
|
|
AccountSharedData::new(rent.minimum_balance(elf.len()), 0, loader_id);
|
|
|
|
program_account.set_data(elf);
|
|
|
|
program_account.set_executable(true);
|
2021-10-08 02:41:07 -07:00
|
|
|
program_account
|
|
|
|
}
|
|
|
|
|
2022-06-07 04:45:07 -07:00
|
|
|
struct TautologyVerifier {}
|
|
|
|
impl Verifier for TautologyVerifier {
|
|
|
|
fn verify(_prog: &[u8], _config: &Config) -> std::result::Result<(), VerifierError> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-31 10:59:56 -07:00
|
|
|
#[test]
|
2020-11-04 09:46:26 -08:00
|
|
|
#[should_panic(expected = "ExceededMaxInstructions(31, 10)")]
|
2019-11-08 09:19:19 -08:00
|
|
|
fn test_bpf_loader_non_terminating_program() {
|
2018-10-31 10:59:56 -07:00
|
|
|
#[rustfmt::skip]
|
2019-11-08 09:19:19 -08:00
|
|
|
let program = &[
|
2019-02-22 16:27:19 -08:00
|
|
|
0x07, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // r6 + 1
|
|
|
|
0x05, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, // goto -2
|
2018-10-31 10:59:56 -07:00
|
|
|
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit
|
|
|
|
];
|
2022-04-30 01:58:12 -07:00
|
|
|
let mut input_mem = [0x00];
|
2022-04-11 10:38:47 -07:00
|
|
|
let config = Config::default();
|
|
|
|
let syscall_registry = SyscallRegistry::default();
|
2021-05-25 01:05:35 -07:00
|
|
|
let mut bpf_functions = std::collections::BTreeMap::<u32, (usize, String)>::new();
|
2022-04-11 10:38:47 -07:00
|
|
|
solana_rbpf::elf::register_bpf_function(
|
|
|
|
&config,
|
|
|
|
&mut bpf_functions,
|
|
|
|
&syscall_registry,
|
|
|
|
0,
|
|
|
|
"entrypoint",
|
|
|
|
)
|
|
|
|
.unwrap();
|
2022-10-06 11:31:58 -07:00
|
|
|
let executable = Executable::<TestInstructionMeter>::from_text_bytes(
|
2020-11-24 09:00:19 -08:00
|
|
|
program,
|
2022-04-11 10:38:47 -07:00
|
|
|
config,
|
|
|
|
syscall_registry,
|
2021-07-07 00:50:11 -07:00
|
|
|
bpf_functions,
|
2020-11-04 09:46:26 -08:00
|
|
|
)
|
|
|
|
.unwrap();
|
2022-10-06 11:31:58 -07:00
|
|
|
let verified_executable =
|
|
|
|
VerifiedExecutable::<TautologyVerifier, TestInstructionMeter>::from_executable(
|
|
|
|
executable,
|
|
|
|
)
|
|
|
|
.unwrap();
|
2022-04-30 01:58:12 -07:00
|
|
|
let input_region = MemoryRegion::new_writable(&mut input_mem, MM_INPUT_START);
|
2022-10-06 11:31:58 -07:00
|
|
|
let mut vm =
|
|
|
|
EbpfVm::new(&verified_executable, &mut (), &mut [], vec![input_region]).unwrap();
|
2020-11-04 09:46:26 -08:00
|
|
|
let mut instruction_meter = TestInstructionMeter { remaining: 10 };
|
|
|
|
vm.execute_program_interpreted(&mut instruction_meter)
|
2020-08-21 15:31:19 -07:00
|
|
|
.unwrap();
|
2018-10-31 10:59:56 -07:00
|
|
|
}
|
2019-11-08 09:19:19 -08:00
|
|
|
|
2020-11-12 13:13:42 -08:00
|
|
|
#[test]
|
2021-05-28 14:24:02 -07:00
|
|
|
#[should_panic(expected = "LDDWCannotBeLast")]
|
2020-11-12 13:13:42 -08:00
|
|
|
fn test_bpf_loader_check_load_dw() {
|
|
|
|
let prog = &[
|
|
|
|
0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55, // first half of lddw
|
|
|
|
];
|
2022-06-07 04:45:07 -07:00
|
|
|
RequisiteVerifier::verify(prog, &Config::default()).unwrap();
|
2020-11-12 13:13:42 -08:00
|
|
|
}
|
|
|
|
|
2019-11-08 09:19:19 -08:00
|
|
|
#[test]
|
|
|
|
fn test_bpf_loader_write() {
|
2021-10-08 02:41:07 -07:00
|
|
|
let loader_id = bpf_loader::id();
|
2021-11-04 13:47:32 -07:00
|
|
|
let program_id = Pubkey::new_unique();
|
2021-12-17 05:01:12 -08:00
|
|
|
let mut program_account = AccountSharedData::new(1, 0, &loader_id);
|
2020-01-10 13:20:15 -08:00
|
|
|
let instruction_data = bincode::serialize(&LoaderInstruction::Write {
|
2019-11-08 09:19:19 -08:00
|
|
|
offset: 3,
|
|
|
|
bytes: vec![1, 2, 3],
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-08 02:41:07 -07:00
|
|
|
// Case: No program account
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction_data,
|
|
|
|
Vec::new(),
|
|
|
|
Vec::new(),
|
2019-11-08 09:19:19 -08:00
|
|
|
Err(InstructionError::NotEnoughAccountKeys),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Not signed
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction_data,
|
|
|
|
vec![(program_id, program_account.clone())],
|
|
|
|
vec![AccountMeta {
|
|
|
|
pubkey: program_id,
|
|
|
|
is_signer: false,
|
2022-06-29 10:29:12 -07:00
|
|
|
is_writable: true,
|
2021-12-17 05:01:12 -08:00
|
|
|
}],
|
2019-11-08 09:19:19 -08:00
|
|
|
Err(InstructionError::MissingRequiredSignature),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Write bytes to an offset
|
2021-12-17 05:01:12 -08:00
|
|
|
program_account.set_data(vec![0; 6]);
|
|
|
|
let accounts = process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction_data,
|
|
|
|
vec![(program_id, program_account.clone())],
|
|
|
|
vec![AccountMeta {
|
|
|
|
pubkey: program_id,
|
|
|
|
is_signer: true,
|
2022-06-29 10:29:12 -07:00
|
|
|
is_writable: true,
|
2021-12-17 05:01:12 -08:00
|
|
|
}],
|
2019-11-08 09:19:19 -08:00
|
|
|
Ok(()),
|
2020-01-22 09:11:56 -08:00
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
assert_eq!(&vec![0, 0, 0, 1, 2, 3], accounts.first().unwrap().data());
|
2019-11-08 09:19:19 -08:00
|
|
|
|
|
|
|
// Case: Overflow
|
2021-12-17 05:01:12 -08:00
|
|
|
program_account.set_data(vec![0; 5]);
|
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction_data,
|
|
|
|
vec![(program_id, program_account)],
|
|
|
|
vec![AccountMeta {
|
|
|
|
pubkey: program_id,
|
|
|
|
is_signer: true,
|
2022-06-29 10:29:12 -07:00
|
|
|
is_writable: true,
|
2021-12-17 05:01:12 -08:00
|
|
|
}],
|
2019-11-08 09:19:19 -08:00
|
|
|
Err(InstructionError::AccountDataTooSmall),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bpf_loader_finalize() {
|
2021-10-08 02:41:07 -07:00
|
|
|
let loader_id = bpf_loader::id();
|
2021-11-04 13:47:32 -07:00
|
|
|
let program_id = Pubkey::new_unique();
|
2021-12-17 05:01:12 -08:00
|
|
|
let mut program_account =
|
2022-05-03 17:10:28 -07:00
|
|
|
load_program_account_from_elf(&loader_id, "test_elfs/out/noop_aligned.so");
|
2021-12-17 05:01:12 -08:00
|
|
|
program_account.set_executable(false);
|
|
|
|
let instruction_data = bincode::serialize(&LoaderInstruction::Finalize).unwrap();
|
2019-11-08 09:19:19 -08:00
|
|
|
|
2021-10-08 02:41:07 -07:00
|
|
|
// Case: No program account
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction_data,
|
|
|
|
Vec::new(),
|
|
|
|
Vec::new(),
|
2019-11-08 09:19:19 -08:00
|
|
|
Err(InstructionError::NotEnoughAccountKeys),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Not signed
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction_data,
|
|
|
|
vec![(program_id, program_account.clone())],
|
|
|
|
vec![AccountMeta {
|
|
|
|
pubkey: program_id,
|
|
|
|
is_signer: false,
|
2022-06-29 10:29:12 -07:00
|
|
|
is_writable: true,
|
2021-12-17 05:01:12 -08:00
|
|
|
}],
|
2019-11-08 09:19:19 -08:00
|
|
|
Err(InstructionError::MissingRequiredSignature),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Finalize
|
2021-12-17 05:01:12 -08:00
|
|
|
let accounts = process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction_data,
|
|
|
|
vec![(program_id, program_account.clone())],
|
|
|
|
vec![AccountMeta {
|
|
|
|
pubkey: program_id,
|
|
|
|
is_signer: true,
|
2022-06-29 10:29:12 -07:00
|
|
|
is_writable: true,
|
2021-12-17 05:01:12 -08:00
|
|
|
}],
|
2019-11-08 09:19:19 -08:00
|
|
|
Ok(()),
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
assert!(accounts.first().unwrap().executable());
|
2020-01-22 09:11:56 -08:00
|
|
|
|
2021-12-17 05:01:12 -08:00
|
|
|
// Case: Finalize bad ELF
|
2022-03-10 11:48:33 -08:00
|
|
|
*program_account.data_as_mut_slice().get_mut(0).unwrap() = 0;
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction_data,
|
|
|
|
vec![(program_id, program_account)],
|
|
|
|
vec![AccountMeta {
|
|
|
|
pubkey: program_id,
|
|
|
|
is_signer: true,
|
2022-06-29 10:29:12 -07:00
|
|
|
is_writable: true,
|
2021-12-17 05:01:12 -08:00
|
|
|
}],
|
2019-12-04 12:03:29 -08:00
|
|
|
Err(InstructionError::InvalidAccountData),
|
|
|
|
);
|
2019-11-08 09:19:19 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bpf_loader_invoke_main() {
|
2021-10-08 02:41:07 -07:00
|
|
|
let loader_id = bpf_loader::id();
|
2021-11-04 13:47:32 -07:00
|
|
|
let program_id = Pubkey::new_unique();
|
2021-12-17 05:01:12 -08:00
|
|
|
let mut program_account =
|
2022-05-03 17:10:28 -07:00
|
|
|
load_program_account_from_elf(&loader_id, "test_elfs/out/noop_aligned.so");
|
2021-12-17 05:01:12 -08:00
|
|
|
let parameter_id = Pubkey::new_unique();
|
|
|
|
let parameter_account = AccountSharedData::new(1, 0, &loader_id);
|
|
|
|
let parameter_meta = AccountMeta {
|
|
|
|
pubkey: parameter_id,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: false,
|
|
|
|
};
|
2019-11-08 09:19:19 -08:00
|
|
|
|
2021-10-08 02:41:07 -07:00
|
|
|
// Case: No program account
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&[],
|
|
|
|
Vec::new(),
|
|
|
|
Vec::new(),
|
2019-11-08 09:19:19 -08:00
|
|
|
Err(InstructionError::NotEnoughAccountKeys),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Only a program account
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[0],
|
|
|
|
&[],
|
|
|
|
vec![(program_id, program_account.clone())],
|
|
|
|
Vec::new(),
|
2019-11-08 09:19:19 -08:00
|
|
|
Ok(()),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: With program and parameter account
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[0],
|
|
|
|
&[],
|
|
|
|
vec![
|
|
|
|
(program_id, program_account.clone()),
|
|
|
|
(parameter_id, parameter_account.clone()),
|
|
|
|
],
|
|
|
|
vec![parameter_meta.clone()],
|
2019-11-08 09:19:19 -08:00
|
|
|
Ok(()),
|
2020-08-26 14:48:51 -07:00
|
|
|
);
|
|
|
|
|
2020-01-22 09:11:56 -08:00
|
|
|
// Case: With duplicate accounts
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[0],
|
|
|
|
&[],
|
|
|
|
vec![
|
|
|
|
(program_id, program_account.clone()),
|
|
|
|
(parameter_id, parameter_account),
|
|
|
|
],
|
|
|
|
vec![parameter_meta.clone(), parameter_meta],
|
2020-01-22 09:11:56 -08:00
|
|
|
Ok(()),
|
|
|
|
);
|
2021-04-19 09:48:48 -07:00
|
|
|
|
|
|
|
// Case: limited budget
|
2021-12-17 05:01:12 -08:00
|
|
|
mock_process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
vec![0],
|
|
|
|
&[],
|
|
|
|
vec![(program_id, program_account.clone())],
|
|
|
|
Vec::new(),
|
2022-03-31 01:46:35 -07:00
|
|
|
None,
|
2022-04-15 11:43:04 -07:00
|
|
|
None,
|
2021-04-19 09:48:48 -07:00
|
|
|
Err(InstructionError::ProgramFailedToComplete),
|
2022-09-06 02:31:40 -07:00
|
|
|
|first_instruction_account: IndexOfAccount, invoke_context: &mut InvokeContext| {
|
2021-12-17 05:01:12 -08:00
|
|
|
invoke_context
|
|
|
|
.get_compute_meter()
|
|
|
|
.borrow_mut()
|
|
|
|
.mock_set_remaining(0);
|
2022-04-01 06:48:05 -07:00
|
|
|
super::process_instruction(first_instruction_account, invoke_context)
|
2021-12-17 05:01:12 -08:00
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Account not a program
|
|
|
|
program_account.set_executable(false);
|
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[0],
|
|
|
|
&[],
|
|
|
|
vec![(program_id, program_account)],
|
|
|
|
Vec::new(),
|
|
|
|
Err(InstructionError::IncorrectProgramId),
|
2021-04-19 09:48:48 -07:00
|
|
|
);
|
2019-11-08 09:19:19 -08:00
|
|
|
}
|
2020-05-08 12:37:04 -07:00
|
|
|
|
2020-08-11 16:11:52 -07:00
|
|
|
#[test]
|
|
|
|
fn test_bpf_loader_serialize_unaligned() {
|
2021-10-08 02:41:07 -07:00
|
|
|
let loader_id = bpf_loader_deprecated::id();
|
2021-12-17 05:01:12 -08:00
|
|
|
let program_id = Pubkey::new_unique();
|
2021-10-08 02:41:07 -07:00
|
|
|
let program_account =
|
2022-05-03 17:10:28 -07:00
|
|
|
load_program_account_from_elf(&loader_id, "test_elfs/out/noop_unaligned.so");
|
2021-12-17 05:01:12 -08:00
|
|
|
let parameter_id = Pubkey::new_unique();
|
|
|
|
let parameter_account = AccountSharedData::new(1, 0, &loader_id);
|
|
|
|
let parameter_meta = AccountMeta {
|
|
|
|
pubkey: parameter_id,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: false,
|
|
|
|
};
|
2020-08-11 16:11:52 -07:00
|
|
|
|
|
|
|
// Case: With program and parameter account
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[0],
|
|
|
|
&[],
|
|
|
|
vec![
|
|
|
|
(program_id, program_account.clone()),
|
|
|
|
(parameter_id, parameter_account.clone()),
|
|
|
|
],
|
|
|
|
vec![parameter_meta.clone()],
|
2020-08-11 16:11:52 -07:00
|
|
|
Ok(()),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: With duplicate accounts
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[0],
|
|
|
|
&[],
|
|
|
|
vec![
|
|
|
|
(program_id, program_account),
|
|
|
|
(parameter_id, parameter_account),
|
|
|
|
],
|
|
|
|
vec![parameter_meta.clone(), parameter_meta],
|
2020-08-11 16:11:52 -07:00
|
|
|
Ok(()),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bpf_loader_serialize_aligned() {
|
2021-10-08 02:41:07 -07:00
|
|
|
let loader_id = bpf_loader::id();
|
2021-12-17 05:01:12 -08:00
|
|
|
let program_id = Pubkey::new_unique();
|
2021-10-08 02:41:07 -07:00
|
|
|
let program_account =
|
2022-05-03 17:10:28 -07:00
|
|
|
load_program_account_from_elf(&loader_id, "test_elfs/out/noop_aligned.so");
|
2021-12-17 05:01:12 -08:00
|
|
|
let parameter_id = Pubkey::new_unique();
|
|
|
|
let parameter_account = AccountSharedData::new(1, 0, &loader_id);
|
|
|
|
let parameter_meta = AccountMeta {
|
|
|
|
pubkey: parameter_id,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: false,
|
|
|
|
};
|
2020-08-11 16:11:52 -07:00
|
|
|
|
|
|
|
// Case: With program and parameter account
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[0],
|
|
|
|
&[],
|
|
|
|
vec![
|
|
|
|
(program_id, program_account.clone()),
|
|
|
|
(parameter_id, parameter_account.clone()),
|
|
|
|
],
|
|
|
|
vec![parameter_meta.clone()],
|
2020-08-11 16:11:52 -07:00
|
|
|
Ok(()),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: With duplicate accounts
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[0],
|
|
|
|
&[],
|
|
|
|
vec![
|
|
|
|
(program_id, program_account),
|
|
|
|
(parameter_id, parameter_account),
|
|
|
|
],
|
|
|
|
vec![parameter_meta.clone(), parameter_meta],
|
2020-08-11 16:11:52 -07:00
|
|
|
Ok(()),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bpf_loader_upgradeable_initialize_buffer() {
|
2021-10-08 02:41:07 -07:00
|
|
|
let loader_id = bpf_loader_upgradeable::id();
|
2020-12-14 15:35:10 -08:00
|
|
|
let buffer_address = Pubkey::new_unique();
|
2022-05-11 07:22:59 -07:00
|
|
|
let buffer_account =
|
|
|
|
AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
|
2021-01-29 12:43:42 -08:00
|
|
|
let authority_address = Pubkey::new_unique();
|
2022-05-11 07:22:59 -07:00
|
|
|
let authority_account =
|
|
|
|
AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
|
2021-12-17 05:01:12 -08:00
|
|
|
let instruction_data =
|
|
|
|
bincode::serialize(&UpgradeableLoaderInstruction::InitializeBuffer).unwrap();
|
|
|
|
let instruction_accounts = vec![
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: buffer_address,
|
|
|
|
is_signer: false,
|
2022-06-29 10:29:12 -07:00
|
|
|
is_writable: true,
|
2021-12-17 05:01:12 -08:00
|
|
|
},
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: authority_address,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: false,
|
|
|
|
},
|
|
|
|
];
|
2020-12-14 15:35:10 -08:00
|
|
|
|
|
|
|
// Case: Success
|
2021-12-17 05:01:12 -08:00
|
|
|
let accounts = process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction_data,
|
|
|
|
vec![
|
|
|
|
(buffer_address, buffer_account),
|
|
|
|
(authority_address, authority_account),
|
|
|
|
],
|
|
|
|
instruction_accounts.clone(),
|
2020-12-14 15:35:10 -08:00
|
|
|
Ok(()),
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
|
2021-01-08 09:37:57 -08:00
|
|
|
assert_eq!(
|
|
|
|
state,
|
|
|
|
UpgradeableLoaderState::Buffer {
|
2021-01-29 12:43:42 -08:00
|
|
|
authority_address: Some(authority_address)
|
2021-01-08 09:37:57 -08:00
|
|
|
}
|
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
|
|
|
|
// Case: Already initialized
|
2021-12-17 05:01:12 -08:00
|
|
|
let accounts = process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction_data,
|
|
|
|
vec![
|
2022-03-10 11:48:33 -08:00
|
|
|
(buffer_address, accounts.first().unwrap().clone()),
|
|
|
|
(authority_address, accounts.get(1).unwrap().clone()),
|
2021-12-17 05:01:12 -08:00
|
|
|
],
|
|
|
|
instruction_accounts,
|
2020-12-14 15:35:10 -08:00
|
|
|
Err(InstructionError::AccountAlreadyInitialized),
|
2021-01-08 09:37:57 -08:00
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
|
2021-01-08 09:37:57 -08:00
|
|
|
assert_eq!(
|
|
|
|
state,
|
|
|
|
UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(authority_address)
|
|
|
|
}
|
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bpf_loader_upgradeable_write() {
|
2021-10-08 02:41:07 -07:00
|
|
|
let loader_id = bpf_loader_upgradeable::id();
|
2020-12-14 15:35:10 -08:00
|
|
|
let buffer_address = Pubkey::new_unique();
|
2022-05-11 07:22:59 -07:00
|
|
|
let mut buffer_account =
|
|
|
|
AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
|
2021-12-17 05:01:12 -08:00
|
|
|
let instruction_accounts = vec![
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: buffer_address,
|
|
|
|
is_signer: false,
|
2022-06-29 10:29:12 -07:00
|
|
|
is_writable: true,
|
2021-12-17 05:01:12 -08:00
|
|
|
},
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: buffer_address,
|
|
|
|
is_signer: true,
|
|
|
|
is_writable: false,
|
|
|
|
},
|
|
|
|
];
|
2020-12-14 15:35:10 -08:00
|
|
|
|
|
|
|
// Case: Not initialized
|
|
|
|
let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
|
|
|
|
offset: 0,
|
|
|
|
bytes: vec![42; 9],
|
|
|
|
})
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![(buffer_address, buffer_account.clone())],
|
|
|
|
instruction_accounts.clone(),
|
2020-12-14 15:35:10 -08:00
|
|
|
Err(InstructionError::InvalidAccountData),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Write entire buffer
|
|
|
|
let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
|
|
|
|
offset: 0,
|
|
|
|
bytes: vec![42; 9],
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
buffer_account
|
2021-01-08 09:37:57 -08:00
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(buffer_address),
|
|
|
|
})
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
let accounts = process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![(buffer_address, buffer_account.clone())],
|
|
|
|
instruction_accounts.clone(),
|
2020-12-14 15:35:10 -08:00
|
|
|
Ok(()),
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
|
2021-01-08 09:37:57 -08:00
|
|
|
assert_eq!(
|
|
|
|
state,
|
|
|
|
UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(buffer_address)
|
|
|
|
}
|
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
assert_eq!(
|
2022-03-10 11:48:33 -08:00
|
|
|
&accounts
|
|
|
|
.first()
|
|
|
|
.unwrap()
|
|
|
|
.data()
|
2022-05-11 07:22:59 -07:00
|
|
|
.get(UpgradeableLoaderState::size_of_buffer_metadata()..)
|
2022-03-10 11:48:33 -08:00
|
|
|
.unwrap(),
|
2020-12-14 15:35:10 -08:00
|
|
|
&[42; 9]
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Write portion of the buffer
|
|
|
|
let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
|
|
|
|
offset: 3,
|
|
|
|
bytes: vec![42; 6],
|
|
|
|
})
|
|
|
|
.unwrap();
|
2022-05-11 07:22:59 -07:00
|
|
|
let mut buffer_account =
|
|
|
|
AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
|
2020-12-14 15:35:10 -08:00
|
|
|
buffer_account
|
2021-01-08 09:37:57 -08:00
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(buffer_address),
|
|
|
|
})
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
let accounts = process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![(buffer_address, buffer_account.clone())],
|
|
|
|
instruction_accounts.clone(),
|
2020-12-14 15:35:10 -08:00
|
|
|
Ok(()),
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
|
2021-01-08 09:37:57 -08:00
|
|
|
assert_eq!(
|
|
|
|
state,
|
|
|
|
UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(buffer_address)
|
|
|
|
}
|
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
assert_eq!(
|
2022-03-10 11:48:33 -08:00
|
|
|
&accounts
|
|
|
|
.first()
|
|
|
|
.unwrap()
|
|
|
|
.data()
|
2022-05-11 07:22:59 -07:00
|
|
|
.get(UpgradeableLoaderState::size_of_buffer_metadata()..)
|
2022-03-10 11:48:33 -08:00
|
|
|
.unwrap(),
|
2020-12-14 15:35:10 -08:00
|
|
|
&[0, 0, 0, 42, 42, 42, 42, 42, 42]
|
|
|
|
);
|
|
|
|
|
2021-10-08 02:41:07 -07:00
|
|
|
// Case: overflow size
|
2020-12-14 15:35:10 -08:00
|
|
|
let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
|
|
|
|
offset: 0,
|
2021-10-08 02:41:07 -07:00
|
|
|
bytes: vec![42; 10],
|
2020-12-14 15:35:10 -08:00
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
buffer_account
|
2021-01-08 09:37:57 -08:00
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(buffer_address),
|
|
|
|
})
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![(buffer_address, buffer_account.clone())],
|
|
|
|
instruction_accounts.clone(),
|
2021-10-08 02:41:07 -07:00
|
|
|
Err(InstructionError::AccountDataTooSmall),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
|
2021-10-08 02:41:07 -07:00
|
|
|
// Case: overflow offset
|
2020-12-14 15:35:10 -08:00
|
|
|
let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
|
2021-10-08 02:41:07 -07:00
|
|
|
offset: 1,
|
|
|
|
bytes: vec![42; 9],
|
2020-12-14 15:35:10 -08:00
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
buffer_account
|
2021-01-08 09:37:57 -08:00
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(buffer_address),
|
|
|
|
})
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![(buffer_address, buffer_account.clone())],
|
|
|
|
instruction_accounts.clone(),
|
2020-12-14 15:35:10 -08:00
|
|
|
Err(InstructionError::AccountDataTooSmall),
|
|
|
|
);
|
|
|
|
|
2021-10-08 02:41:07 -07:00
|
|
|
// Case: Not signed
|
2020-12-14 15:35:10 -08:00
|
|
|
let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
|
2021-10-08 02:41:07 -07:00
|
|
|
offset: 0,
|
2020-12-14 15:35:10 -08:00
|
|
|
bytes: vec![42; 9],
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
buffer_account
|
2021-01-08 09:37:57 -08:00
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(buffer_address),
|
|
|
|
})
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![(buffer_address, buffer_account.clone())],
|
|
|
|
vec![
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: buffer_address,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: false,
|
|
|
|
},
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: buffer_address,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: false,
|
|
|
|
},
|
|
|
|
],
|
2021-10-08 02:41:07 -07:00
|
|
|
Err(InstructionError::MissingRequiredSignature),
|
2021-01-08 09:37:57 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
// Case: wrong authority
|
|
|
|
let authority_address = Pubkey::new_unique();
|
|
|
|
let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
|
|
|
|
offset: 1,
|
|
|
|
bytes: vec![42; 9],
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
buffer_account
|
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(buffer_address),
|
|
|
|
})
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![
|
|
|
|
(buffer_address, buffer_account.clone()),
|
|
|
|
(authority_address, buffer_account.clone()),
|
|
|
|
],
|
|
|
|
vec![
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: buffer_address,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: false,
|
|
|
|
},
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: authority_address,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: false,
|
|
|
|
},
|
|
|
|
],
|
2021-01-08 09:37:57 -08:00
|
|
|
Err(InstructionError::IncorrectAuthority),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
2021-01-29 12:43:42 -08:00
|
|
|
|
|
|
|
// Case: None authority
|
|
|
|
let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
|
|
|
|
offset: 1,
|
|
|
|
bytes: vec![42; 9],
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
buffer_account
|
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: None,
|
|
|
|
})
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![(buffer_address, buffer_account.clone())],
|
|
|
|
instruction_accounts,
|
2021-01-29 12:43:42 -08:00
|
|
|
Err(InstructionError::Immutable),
|
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
|
|
|
|
2021-03-17 13:09:26 -07:00
|
|
|
fn truncate_data(account: &mut AccountSharedData, len: usize) {
|
2021-03-25 09:04:20 -07:00
|
|
|
let mut data = account.data().to_vec();
|
2021-03-23 13:19:31 -07:00
|
|
|
data.truncate(len);
|
|
|
|
account.set_data(data);
|
2021-03-17 13:09:26 -07:00
|
|
|
}
|
|
|
|
|
2020-12-14 15:35:10 -08:00
|
|
|
#[test]
|
|
|
|
fn test_bpf_loader_upgradeable_deploy_with_max_len() {
|
|
|
|
let (genesis_config, mint_keypair) = create_genesis_config(1_000_000_000);
|
2021-08-05 06:42:38 -07:00
|
|
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
2021-01-29 12:43:42 -08:00
|
|
|
bank.feature_set = Arc::new(FeatureSet::all_enabled());
|
2020-12-14 15:35:10 -08:00
|
|
|
bank.add_builtin(
|
|
|
|
"solana_bpf_loader_upgradeable_program",
|
2021-09-28 23:25:08 -07:00
|
|
|
&bpf_loader_upgradeable::id(),
|
2021-10-08 02:41:07 -07:00
|
|
|
super::process_instruction,
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
let bank = Arc::new(bank);
|
|
|
|
let bank_client = BankClient::new_shared(&bank);
|
|
|
|
|
2021-09-17 17:49:53 -07:00
|
|
|
// Setup keypairs and addresses
|
|
|
|
let payer_keypair = Keypair::new();
|
2020-12-14 15:35:10 -08:00
|
|
|
let program_keypair = Keypair::new();
|
2021-09-17 17:49:53 -07:00
|
|
|
let buffer_address = Pubkey::new_unique();
|
2020-12-14 15:35:10 -08:00
|
|
|
let (programdata_address, _) = Pubkey::find_program_address(
|
|
|
|
&[program_keypair.pubkey().as_ref()],
|
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
);
|
2021-01-29 12:43:42 -08:00
|
|
|
let upgrade_authority_keypair = Keypair::new();
|
2021-09-17 17:49:53 -07:00
|
|
|
|
|
|
|
// Load program file
|
2022-05-03 17:10:28 -07:00
|
|
|
let mut file = File::open("test_elfs/out/noop_aligned.so").expect("file open failed");
|
2020-12-14 15:35:10 -08:00
|
|
|
let mut elf = Vec::new();
|
|
|
|
file.read_to_end(&mut elf).unwrap();
|
2021-09-17 17:49:53 -07:00
|
|
|
|
|
|
|
// Compute rent exempt balances
|
|
|
|
let program_len = elf.len();
|
2022-05-11 07:22:59 -07:00
|
|
|
let min_program_balance =
|
|
|
|
bank.get_minimum_balance_for_rent_exemption(UpgradeableLoaderState::size_of_program());
|
2021-09-17 17:49:53 -07:00
|
|
|
let min_buffer_balance = bank.get_minimum_balance_for_rent_exemption(
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_buffer(program_len),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
2021-09-17 17:49:53 -07:00
|
|
|
let min_programdata_balance = bank.get_minimum_balance_for_rent_exemption(
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_programdata(program_len),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
2021-09-17 17:49:53 -07:00
|
|
|
|
|
|
|
// Setup accounts
|
|
|
|
let buffer_account = {
|
|
|
|
let mut account = AccountSharedData::new(
|
|
|
|
min_buffer_balance,
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_buffer(elf.len()),
|
2021-09-17 17:49:53 -07:00
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
);
|
|
|
|
account
|
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(upgrade_authority_keypair.pubkey()),
|
|
|
|
})
|
|
|
|
.unwrap();
|
2022-03-10 11:48:33 -08:00
|
|
|
account
|
|
|
|
.data_as_mut_slice()
|
2022-05-11 07:22:59 -07:00
|
|
|
.get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..)
|
2022-03-10 11:48:33 -08:00
|
|
|
.unwrap()
|
2021-09-17 17:49:53 -07:00
|
|
|
.copy_from_slice(&elf);
|
|
|
|
account
|
|
|
|
};
|
2021-03-09 13:06:07 -08:00
|
|
|
let program_account = AccountSharedData::new(
|
2021-01-29 12:43:42 -08:00
|
|
|
min_programdata_balance,
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_program(),
|
2021-01-29 12:43:42 -08:00
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
);
|
2021-03-09 13:06:07 -08:00
|
|
|
let programdata_account = AccountSharedData::new(
|
2021-01-29 12:43:42 -08:00
|
|
|
1,
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_programdata(elf.len()),
|
2021-01-29 12:43:42 -08:00
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
|
|
|
|
// Test successful deploy
|
2021-09-17 17:49:53 -07:00
|
|
|
let payer_base_balance = LAMPORTS_PER_SOL;
|
|
|
|
let deploy_fees = {
|
|
|
|
let fee_calculator = genesis_config.fee_rate_governor.create_fee_calculator();
|
|
|
|
3 * fee_calculator.lamports_per_signature
|
|
|
|
};
|
2022-03-16 03:30:01 -07:00
|
|
|
let min_payer_balance = min_program_balance
|
|
|
|
.saturating_add(min_programdata_balance)
|
|
|
|
.saturating_sub(min_buffer_balance.saturating_add(deploy_fees));
|
2021-09-17 17:49:53 -07:00
|
|
|
bank.store_account(
|
|
|
|
&payer_keypair.pubkey(),
|
|
|
|
&AccountSharedData::new(
|
2022-03-16 03:30:01 -07:00
|
|
|
payer_base_balance.saturating_add(min_payer_balance),
|
2021-09-17 17:49:53 -07:00
|
|
|
0,
|
|
|
|
&system_program::id(),
|
|
|
|
),
|
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
bank.store_account(&buffer_address, &buffer_account);
|
2021-03-09 13:06:07 -08:00
|
|
|
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
|
|
|
|
bank.store_account(&programdata_address, &AccountSharedData::default());
|
2020-12-14 15:35:10 -08:00
|
|
|
let message = Message::new(
|
|
|
|
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
2021-09-17 17:49:53 -07:00
|
|
|
&payer_keypair.pubkey(),
|
2020-12-14 15:35:10 -08:00
|
|
|
&program_keypair.pubkey(),
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_keypair.pubkey(),
|
2020-12-14 15:35:10 -08:00
|
|
|
min_program_balance,
|
|
|
|
elf.len(),
|
|
|
|
)
|
|
|
|
.unwrap(),
|
2021-09-17 17:49:53 -07:00
|
|
|
Some(&payer_keypair.pubkey()),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
assert!(bank_client
|
2021-01-29 12:43:42 -08:00
|
|
|
.send_and_confirm_message(
|
2021-09-17 17:49:53 -07:00
|
|
|
&[&payer_keypair, &program_keypair, &upgrade_authority_keypair],
|
2021-01-29 12:43:42 -08:00
|
|
|
message
|
|
|
|
)
|
2020-12-14 15:35:10 -08:00
|
|
|
.is_ok());
|
|
|
|
assert_eq!(
|
2021-09-17 17:49:53 -07:00
|
|
|
bank.get_balance(&payer_keypair.pubkey()),
|
|
|
|
payer_base_balance
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
assert_eq!(bank.get_balance(&buffer_address), 0);
|
|
|
|
assert_eq!(None, bank.get_account(&buffer_address));
|
|
|
|
let post_program_account = bank.get_account(&program_keypair.pubkey()).unwrap();
|
2021-05-03 08:45:54 -07:00
|
|
|
assert_eq!(post_program_account.lamports(), min_program_balance);
|
2021-04-26 08:40:11 -07:00
|
|
|
assert_eq!(post_program_account.owner(), &bpf_loader_upgradeable::id());
|
2020-12-14 15:35:10 -08:00
|
|
|
assert_eq!(
|
2021-03-09 14:31:33 -08:00
|
|
|
post_program_account.data().len(),
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_program()
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
let state: UpgradeableLoaderState = post_program_account.state().unwrap();
|
|
|
|
assert_eq!(
|
|
|
|
state,
|
|
|
|
UpgradeableLoaderState::Program {
|
|
|
|
programdata_address
|
|
|
|
}
|
|
|
|
);
|
|
|
|
let post_programdata_account = bank.get_account(&programdata_address).unwrap();
|
2021-05-03 08:45:54 -07:00
|
|
|
assert_eq!(post_programdata_account.lamports(), min_programdata_balance);
|
2021-04-23 13:59:13 -07:00
|
|
|
assert_eq!(
|
|
|
|
post_programdata_account.owner(),
|
|
|
|
&bpf_loader_upgradeable::id()
|
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
let state: UpgradeableLoaderState = post_programdata_account.state().unwrap();
|
|
|
|
assert_eq!(
|
|
|
|
state,
|
|
|
|
UpgradeableLoaderState::ProgramData {
|
|
|
|
slot: bank_client.get_slot().unwrap(),
|
2021-01-29 12:43:42 -08:00
|
|
|
upgrade_authority_address: Some(upgrade_authority_keypair.pubkey())
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
for (i, byte) in post_programdata_account
|
|
|
|
.data()
|
2022-05-11 07:22:59 -07:00
|
|
|
.get(UpgradeableLoaderState::size_of_programdata_metadata()..)
|
2022-03-10 11:48:33 -08:00
|
|
|
.unwrap()
|
2020-12-14 15:35:10 -08:00
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
{
|
2022-03-10 11:48:33 -08:00
|
|
|
assert_eq!(*elf.get(i).unwrap(), *byte);
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
|
|
|
|
2021-10-18 00:55:31 -07:00
|
|
|
// Invoke deployed program
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
&[0, 1],
|
|
|
|
&[],
|
|
|
|
vec![
|
|
|
|
(programdata_address, post_programdata_account),
|
|
|
|
(program_keypair.pubkey(), post_program_account),
|
|
|
|
],
|
|
|
|
Vec::new(),
|
|
|
|
Ok(()),
|
|
|
|
);
|
2021-10-18 00:55:31 -07:00
|
|
|
|
2020-12-14 15:35:10 -08:00
|
|
|
// Test initialized program account
|
|
|
|
bank.clear_signatures();
|
|
|
|
bank.store_account(&buffer_address, &buffer_account);
|
|
|
|
let message = Message::new(
|
2021-03-03 21:46:48 -08:00
|
|
|
&[Instruction::new_with_bincode(
|
2020-12-14 15:35:10 -08:00
|
|
|
bpf_loader_upgradeable::id(),
|
|
|
|
&UpgradeableLoaderInstruction::DeployWithMaxDataLen {
|
|
|
|
max_data_len: elf.len(),
|
|
|
|
},
|
|
|
|
vec![
|
|
|
|
AccountMeta::new(mint_keypair.pubkey(), true),
|
|
|
|
AccountMeta::new(programdata_address, false),
|
|
|
|
AccountMeta::new(program_keypair.pubkey(), false),
|
|
|
|
AccountMeta::new(buffer_address, false),
|
|
|
|
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
|
|
|
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
|
|
|
AccountMeta::new_readonly(system_program::id(), false),
|
2021-01-29 12:43:42 -08:00
|
|
|
AccountMeta::new_readonly(upgrade_authority_keypair.pubkey(), true),
|
2020-12-14 15:35:10 -08:00
|
|
|
],
|
|
|
|
)],
|
|
|
|
Some(&mint_keypair.pubkey()),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
TransactionError::InstructionError(0, InstructionError::AccountAlreadyInitialized),
|
|
|
|
bank_client
|
2021-01-29 12:43:42 -08:00
|
|
|
.send_and_confirm_message(&[&mint_keypair, &upgrade_authority_keypair], message)
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
|
|
|
);
|
|
|
|
|
2021-01-29 12:43:42 -08:00
|
|
|
// Test initialized ProgramData account
|
2020-12-14 15:35:10 -08:00
|
|
|
bank.clear_signatures();
|
|
|
|
bank.store_account(&buffer_address, &buffer_account);
|
2021-03-09 13:06:07 -08:00
|
|
|
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
|
2020-12-14 15:35:10 -08:00
|
|
|
let message = Message::new(
|
|
|
|
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
|
|
|
&mint_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_keypair.pubkey(),
|
2020-12-14 15:35:10 -08:00
|
|
|
min_program_balance,
|
|
|
|
elf.len(),
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
Some(&mint_keypair.pubkey()),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2021-01-29 12:43:42 -08:00
|
|
|
TransactionError::InstructionError(1, InstructionError::Custom(0)),
|
|
|
|
bank_client
|
|
|
|
.send_and_confirm_message(
|
|
|
|
&[&mint_keypair, &program_keypair, &upgrade_authority_keypair],
|
|
|
|
message
|
|
|
|
)
|
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
2021-01-29 12:43:42 -08:00
|
|
|
|
|
|
|
// Test deploy no authority
|
|
|
|
bank.clear_signatures();
|
|
|
|
bank.store_account(&buffer_address, &buffer_account);
|
|
|
|
bank.store_account(&program_keypair.pubkey(), &program_account);
|
|
|
|
bank.store_account(&programdata_address, &programdata_account);
|
|
|
|
let message = Message::new(
|
2021-03-03 21:46:48 -08:00
|
|
|
&[Instruction::new_with_bincode(
|
2021-01-29 12:43:42 -08:00
|
|
|
bpf_loader_upgradeable::id(),
|
|
|
|
&UpgradeableLoaderInstruction::DeployWithMaxDataLen {
|
|
|
|
max_data_len: elf.len(),
|
|
|
|
},
|
|
|
|
vec![
|
|
|
|
AccountMeta::new(mint_keypair.pubkey(), true),
|
|
|
|
AccountMeta::new(programdata_address, false),
|
|
|
|
AccountMeta::new(program_keypair.pubkey(), false),
|
|
|
|
AccountMeta::new(buffer_address, false),
|
|
|
|
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
|
|
|
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
|
|
|
AccountMeta::new_readonly(system_program::id(), false),
|
|
|
|
],
|
|
|
|
)],
|
|
|
|
Some(&mint_keypair.pubkey()),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
assert_eq!(
|
2021-01-29 12:43:42 -08:00
|
|
|
TransactionError::InstructionError(0, InstructionError::NotEnoughAccountKeys),
|
|
|
|
bank_client
|
|
|
|
.send_and_confirm_message(&[&mint_keypair], message)
|
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
|
2021-01-29 12:43:42 -08:00
|
|
|
// Test deploy authority not a signer
|
2020-12-14 15:35:10 -08:00
|
|
|
bank.clear_signatures();
|
|
|
|
bank.store_account(&buffer_address, &buffer_account);
|
2021-01-29 12:43:42 -08:00
|
|
|
bank.store_account(&program_keypair.pubkey(), &program_account);
|
|
|
|
bank.store_account(&programdata_address, &programdata_account);
|
2020-12-14 15:35:10 -08:00
|
|
|
let message = Message::new(
|
2021-03-03 21:46:48 -08:00
|
|
|
&[Instruction::new_with_bincode(
|
2021-01-29 12:43:42 -08:00
|
|
|
bpf_loader_upgradeable::id(),
|
|
|
|
&UpgradeableLoaderInstruction::DeployWithMaxDataLen {
|
|
|
|
max_data_len: elf.len(),
|
|
|
|
},
|
|
|
|
vec![
|
|
|
|
AccountMeta::new(mint_keypair.pubkey(), true),
|
|
|
|
AccountMeta::new(programdata_address, false),
|
|
|
|
AccountMeta::new(program_keypair.pubkey(), false),
|
|
|
|
AccountMeta::new(buffer_address, false),
|
|
|
|
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
|
|
|
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
|
|
|
AccountMeta::new_readonly(system_program::id(), false),
|
|
|
|
AccountMeta::new_readonly(upgrade_authority_keypair.pubkey(), false),
|
|
|
|
],
|
|
|
|
)],
|
2020-12-14 15:35:10 -08:00
|
|
|
Some(&mint_keypair.pubkey()),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2021-01-29 12:43:42 -08:00
|
|
|
TransactionError::InstructionError(0, InstructionError::MissingRequiredSignature),
|
2020-12-14 15:35:10 -08:00
|
|
|
bank_client
|
2021-01-29 12:43:42 -08:00
|
|
|
.send_and_confirm_message(&[&mint_keypair], message)
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test invalid Buffer account state
|
|
|
|
bank.clear_signatures();
|
2021-03-09 13:06:07 -08:00
|
|
|
bank.store_account(&buffer_address, &AccountSharedData::default());
|
|
|
|
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
|
|
|
|
bank.store_account(&programdata_address, &AccountSharedData::default());
|
2020-12-14 15:35:10 -08:00
|
|
|
let message = Message::new(
|
|
|
|
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
|
|
|
&mint_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_keypair.pubkey(),
|
2020-12-14 15:35:10 -08:00
|
|
|
min_program_balance,
|
|
|
|
elf.len(),
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
Some(&mint_keypair.pubkey()),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
TransactionError::InstructionError(1, InstructionError::InvalidAccountData),
|
|
|
|
bank_client
|
2021-01-29 12:43:42 -08:00
|
|
|
.send_and_confirm_message(
|
|
|
|
&[&mint_keypair, &program_keypair, &upgrade_authority_keypair],
|
|
|
|
message
|
|
|
|
)
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test program account not rent exempt
|
|
|
|
bank.clear_signatures();
|
|
|
|
bank.store_account(&buffer_address, &buffer_account);
|
2021-03-09 13:06:07 -08:00
|
|
|
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
|
|
|
|
bank.store_account(&programdata_address, &AccountSharedData::default());
|
2020-12-14 15:35:10 -08:00
|
|
|
let message = Message::new(
|
|
|
|
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
|
|
|
&mint_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_keypair.pubkey(),
|
2022-03-16 03:30:01 -07:00
|
|
|
min_program_balance.saturating_sub(1),
|
2020-12-14 15:35:10 -08:00
|
|
|
elf.len(),
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
Some(&mint_keypair.pubkey()),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
TransactionError::InstructionError(1, InstructionError::ExecutableAccountNotRentExempt),
|
|
|
|
bank_client
|
2021-01-29 12:43:42 -08:00
|
|
|
.send_and_confirm_message(
|
|
|
|
&[&mint_keypair, &program_keypair, &upgrade_authority_keypair],
|
|
|
|
message
|
|
|
|
)
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
|
|
|
);
|
|
|
|
|
2020-12-17 01:02:31 -08:00
|
|
|
// Test program account not rent exempt because data is larger than needed
|
|
|
|
bank.clear_signatures();
|
|
|
|
bank.store_account(&buffer_address, &buffer_account);
|
2021-03-09 13:06:07 -08:00
|
|
|
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
|
|
|
|
bank.store_account(&programdata_address, &AccountSharedData::default());
|
2020-12-17 01:02:31 -08:00
|
|
|
let mut instructions = bpf_loader_upgradeable::deploy_with_max_program_len(
|
|
|
|
&mint_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_keypair.pubkey(),
|
2020-12-17 01:02:31 -08:00
|
|
|
min_program_balance,
|
|
|
|
elf.len(),
|
|
|
|
)
|
|
|
|
.unwrap();
|
2022-03-10 11:48:33 -08:00
|
|
|
*instructions.get_mut(0).unwrap() = system_instruction::create_account(
|
2020-12-17 01:02:31 -08:00
|
|
|
&mint_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
min_program_balance,
|
2022-05-11 07:22:59 -07:00
|
|
|
(UpgradeableLoaderState::size_of_program() as u64).saturating_add(1),
|
2020-12-17 01:02:31 -08:00
|
|
|
&id(),
|
|
|
|
);
|
|
|
|
let message = Message::new(&instructions, Some(&mint_keypair.pubkey()));
|
|
|
|
assert_eq!(
|
|
|
|
TransactionError::InstructionError(1, InstructionError::ExecutableAccountNotRentExempt),
|
|
|
|
bank_client
|
2021-01-29 12:43:42 -08:00
|
|
|
.send_and_confirm_message(
|
|
|
|
&[&mint_keypair, &program_keypair, &upgrade_authority_keypair],
|
|
|
|
message
|
|
|
|
)
|
2020-12-17 01:02:31 -08:00
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test program account too small
|
|
|
|
bank.clear_signatures();
|
|
|
|
bank.store_account(&buffer_address, &buffer_account);
|
2021-03-09 13:06:07 -08:00
|
|
|
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
|
|
|
|
bank.store_account(&programdata_address, &AccountSharedData::default());
|
2020-12-17 01:02:31 -08:00
|
|
|
let mut instructions = bpf_loader_upgradeable::deploy_with_max_program_len(
|
|
|
|
&mint_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_keypair.pubkey(),
|
2020-12-17 01:02:31 -08:00
|
|
|
min_program_balance,
|
|
|
|
elf.len(),
|
|
|
|
)
|
|
|
|
.unwrap();
|
2022-03-10 11:48:33 -08:00
|
|
|
*instructions.get_mut(0).unwrap() = system_instruction::create_account(
|
2020-12-17 01:02:31 -08:00
|
|
|
&mint_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
min_program_balance,
|
2022-05-11 07:22:59 -07:00
|
|
|
(UpgradeableLoaderState::size_of_program() as u64).saturating_sub(1),
|
2020-12-17 01:02:31 -08:00
|
|
|
&id(),
|
|
|
|
);
|
|
|
|
let message = Message::new(&instructions, Some(&mint_keypair.pubkey()));
|
|
|
|
assert_eq!(
|
|
|
|
TransactionError::InstructionError(1, InstructionError::AccountDataTooSmall),
|
|
|
|
bank_client
|
2021-01-29 12:43:42 -08:00
|
|
|
.send_and_confirm_message(
|
|
|
|
&[&mint_keypair, &program_keypair, &upgrade_authority_keypair],
|
|
|
|
message
|
|
|
|
)
|
2020-12-17 01:02:31 -08:00
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
|
|
|
);
|
|
|
|
|
2021-09-17 17:49:53 -07:00
|
|
|
// Test Insufficient payer funds (need more funds to cover the
|
|
|
|
// difference between buffer lamports and programdata lamports)
|
2020-12-14 15:35:10 -08:00
|
|
|
bank.clear_signatures();
|
|
|
|
bank.store_account(
|
|
|
|
&mint_keypair.pubkey(),
|
2022-03-16 03:30:01 -07:00
|
|
|
&AccountSharedData::new(
|
|
|
|
deploy_fees.saturating_add(min_program_balance),
|
|
|
|
0,
|
|
|
|
&system_program::id(),
|
|
|
|
),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
bank.store_account(&buffer_address, &buffer_account);
|
2021-03-09 13:06:07 -08:00
|
|
|
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
|
|
|
|
bank.store_account(&programdata_address, &AccountSharedData::default());
|
2020-12-14 15:35:10 -08:00
|
|
|
let message = Message::new(
|
|
|
|
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
|
|
|
&mint_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_keypair.pubkey(),
|
2020-12-14 15:35:10 -08:00
|
|
|
min_program_balance,
|
|
|
|
elf.len(),
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
Some(&mint_keypair.pubkey()),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
TransactionError::InstructionError(1, InstructionError::Custom(1)),
|
|
|
|
bank_client
|
2021-01-29 12:43:42 -08:00
|
|
|
.send_and_confirm_message(
|
|
|
|
&[&mint_keypair, &program_keypair, &upgrade_authority_keypair],
|
|
|
|
message
|
|
|
|
)
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
|
|
|
);
|
|
|
|
bank.store_account(
|
|
|
|
&mint_keypair.pubkey(),
|
2021-03-09 13:06:07 -08:00
|
|
|
&AccountSharedData::new(1_000_000_000, 0, &system_program::id()),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
// Test max_data_len
|
|
|
|
bank.clear_signatures();
|
|
|
|
bank.store_account(&buffer_address, &buffer_account);
|
2021-03-09 13:06:07 -08:00
|
|
|
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
|
|
|
|
bank.store_account(&programdata_address, &AccountSharedData::default());
|
2020-12-14 15:35:10 -08:00
|
|
|
let message = Message::new(
|
|
|
|
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
|
|
|
&mint_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_keypair.pubkey(),
|
2020-12-14 15:35:10 -08:00
|
|
|
min_program_balance,
|
2022-03-16 03:30:01 -07:00
|
|
|
elf.len().saturating_sub(1),
|
2020-12-14 15:35:10 -08:00
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
Some(&mint_keypair.pubkey()),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
TransactionError::InstructionError(1, InstructionError::AccountDataTooSmall),
|
|
|
|
bank_client
|
2021-01-29 12:43:42 -08:00
|
|
|
.send_and_confirm_message(
|
|
|
|
&[&mint_keypair, &program_keypair, &upgrade_authority_keypair],
|
|
|
|
message
|
|
|
|
)
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
|
|
|
);
|
|
|
|
|
2021-02-03 09:16:25 -08:00
|
|
|
// Test max_data_len too large
|
|
|
|
bank.clear_signatures();
|
|
|
|
bank.store_account(
|
|
|
|
&mint_keypair.pubkey(),
|
2021-03-09 13:06:07 -08:00
|
|
|
&AccountSharedData::new(u64::MAX / 2, 0, &system_program::id()),
|
2021-02-03 09:16:25 -08:00
|
|
|
);
|
|
|
|
let mut modified_buffer_account = buffer_account.clone();
|
2021-04-30 14:17:05 -07:00
|
|
|
modified_buffer_account.set_lamports(u64::MAX / 2);
|
2021-02-03 09:16:25 -08:00
|
|
|
bank.store_account(&buffer_address, &modified_buffer_account);
|
2021-03-09 13:06:07 -08:00
|
|
|
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
|
|
|
|
bank.store_account(&programdata_address, &AccountSharedData::default());
|
2021-02-03 09:16:25 -08:00
|
|
|
let message = Message::new(
|
|
|
|
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
|
|
|
&mint_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
&buffer_address,
|
|
|
|
&upgrade_authority_keypair.pubkey(),
|
|
|
|
min_program_balance,
|
|
|
|
usize::MAX,
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
Some(&mint_keypair.pubkey()),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
TransactionError::InstructionError(1, InstructionError::InvalidArgument),
|
|
|
|
bank_client
|
|
|
|
.send_and_confirm_message(
|
|
|
|
&[&mint_keypair, &program_keypair, &upgrade_authority_keypair],
|
|
|
|
message
|
|
|
|
)
|
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
|
|
|
);
|
|
|
|
|
2020-12-14 15:35:10 -08:00
|
|
|
// Test not the system account
|
|
|
|
bank.clear_signatures();
|
|
|
|
bank.store_account(&buffer_address, &buffer_account);
|
2021-03-09 13:06:07 -08:00
|
|
|
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
|
|
|
|
bank.store_account(&programdata_address, &AccountSharedData::default());
|
2020-12-14 15:35:10 -08:00
|
|
|
let mut instructions = bpf_loader_upgradeable::deploy_with_max_program_len(
|
|
|
|
&mint_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_keypair.pubkey(),
|
2020-12-14 15:35:10 -08:00
|
|
|
min_program_balance,
|
|
|
|
elf.len(),
|
|
|
|
)
|
|
|
|
.unwrap();
|
2022-03-10 11:48:33 -08:00
|
|
|
*instructions
|
|
|
|
.get_mut(1)
|
|
|
|
.unwrap()
|
|
|
|
.accounts
|
|
|
|
.get_mut(6)
|
|
|
|
.unwrap() = AccountMeta::new_readonly(Pubkey::new_unique(), false);
|
2020-12-14 15:35:10 -08:00
|
|
|
let message = Message::new(&instructions, Some(&mint_keypair.pubkey()));
|
|
|
|
assert_eq!(
|
|
|
|
TransactionError::InstructionError(1, InstructionError::MissingAccount),
|
|
|
|
bank_client
|
2021-01-29 12:43:42 -08:00
|
|
|
.send_and_confirm_message(
|
|
|
|
&[&mint_keypair, &program_keypair, &upgrade_authority_keypair],
|
|
|
|
message
|
|
|
|
)
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test Bad ELF data
|
|
|
|
bank.clear_signatures();
|
|
|
|
let mut modified_buffer_account = buffer_account;
|
2021-03-17 13:09:26 -07:00
|
|
|
truncate_data(
|
|
|
|
&mut modified_buffer_account,
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_buffer(1),
|
2021-03-17 13:09:26 -07:00
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
bank.store_account(&buffer_address, &modified_buffer_account);
|
2021-03-09 13:06:07 -08:00
|
|
|
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
|
|
|
|
bank.store_account(&programdata_address, &AccountSharedData::default());
|
2020-12-14 15:35:10 -08:00
|
|
|
let message = Message::new(
|
|
|
|
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
|
|
|
&mint_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_keypair.pubkey(),
|
2020-12-14 15:35:10 -08:00
|
|
|
min_program_balance,
|
|
|
|
elf.len(),
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
Some(&mint_keypair.pubkey()),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
TransactionError::InstructionError(1, InstructionError::InvalidAccountData),
|
|
|
|
bank_client
|
2021-01-29 12:43:42 -08:00
|
|
|
.send_and_confirm_message(
|
|
|
|
&[&mint_keypair, &program_keypair, &upgrade_authority_keypair],
|
|
|
|
message
|
|
|
|
)
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
|
|
|
);
|
2021-01-19 17:56:44 -08:00
|
|
|
|
|
|
|
// Test small buffer account
|
|
|
|
bank.clear_signatures();
|
2021-03-09 13:06:07 -08:00
|
|
|
let mut modified_buffer_account = AccountSharedData::new(
|
2021-01-19 17:56:44 -08:00
|
|
|
min_programdata_balance,
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_buffer(elf.len()),
|
2021-01-19 17:56:44 -08:00
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
);
|
|
|
|
modified_buffer_account
|
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
2021-01-29 12:43:42 -08:00
|
|
|
authority_address: Some(upgrade_authority_keypair.pubkey()),
|
2021-01-19 17:56:44 -08:00
|
|
|
})
|
|
|
|
.unwrap();
|
2022-03-10 11:48:33 -08:00
|
|
|
modified_buffer_account
|
|
|
|
.data_as_mut_slice()
|
2022-05-11 07:22:59 -07:00
|
|
|
.get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..)
|
2022-03-10 11:48:33 -08:00
|
|
|
.unwrap()
|
2021-01-19 17:56:44 -08:00
|
|
|
.copy_from_slice(&elf);
|
2021-03-17 13:09:26 -07:00
|
|
|
truncate_data(&mut modified_buffer_account, 5);
|
2021-01-19 17:56:44 -08:00
|
|
|
bank.store_account(&buffer_address, &modified_buffer_account);
|
2021-03-09 13:06:07 -08:00
|
|
|
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
|
|
|
|
bank.store_account(&programdata_address, &AccountSharedData::default());
|
2021-01-19 17:56:44 -08:00
|
|
|
let message = Message::new(
|
|
|
|
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
|
|
|
&mint_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_keypair.pubkey(),
|
2021-01-19 17:56:44 -08:00
|
|
|
min_program_balance,
|
|
|
|
elf.len(),
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
Some(&mint_keypair.pubkey()),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
TransactionError::InstructionError(1, InstructionError::InvalidAccountData),
|
|
|
|
bank_client
|
2021-01-29 12:43:42 -08:00
|
|
|
.send_and_confirm_message(
|
|
|
|
&[&mint_keypair, &program_keypair, &upgrade_authority_keypair],
|
|
|
|
message
|
|
|
|
)
|
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
|
|
|
);
|
|
|
|
|
|
|
|
// Mismatched buffer and program authority
|
|
|
|
bank.clear_signatures();
|
2021-03-09 13:06:07 -08:00
|
|
|
let mut modified_buffer_account = AccountSharedData::new(
|
2021-01-29 12:43:42 -08:00
|
|
|
min_programdata_balance,
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_buffer(elf.len()),
|
2021-01-29 12:43:42 -08:00
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
);
|
|
|
|
modified_buffer_account
|
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(buffer_address),
|
|
|
|
})
|
|
|
|
.unwrap();
|
2022-03-10 11:48:33 -08:00
|
|
|
modified_buffer_account
|
|
|
|
.data_as_mut_slice()
|
2022-05-11 07:22:59 -07:00
|
|
|
.get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..)
|
2022-03-10 11:48:33 -08:00
|
|
|
.unwrap()
|
2021-01-29 12:43:42 -08:00
|
|
|
.copy_from_slice(&elf);
|
|
|
|
bank.store_account(&buffer_address, &modified_buffer_account);
|
2021-03-09 13:06:07 -08:00
|
|
|
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
|
|
|
|
bank.store_account(&programdata_address, &AccountSharedData::default());
|
2021-01-29 12:43:42 -08:00
|
|
|
let message = Message::new(
|
|
|
|
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
|
|
|
&mint_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
&buffer_address,
|
|
|
|
&upgrade_authority_keypair.pubkey(),
|
|
|
|
min_program_balance,
|
|
|
|
elf.len(),
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
Some(&mint_keypair.pubkey()),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
TransactionError::InstructionError(1, InstructionError::IncorrectAuthority),
|
|
|
|
bank_client
|
|
|
|
.send_and_confirm_message(
|
|
|
|
&[&mint_keypair, &program_keypair, &upgrade_authority_keypair],
|
|
|
|
message
|
|
|
|
)
|
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
|
|
|
);
|
|
|
|
|
|
|
|
// Deploy buffer with mismatched None authority
|
|
|
|
bank.clear_signatures();
|
2021-03-09 13:06:07 -08:00
|
|
|
let mut modified_buffer_account = AccountSharedData::new(
|
2021-01-29 12:43:42 -08:00
|
|
|
min_programdata_balance,
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_buffer(elf.len()),
|
2021-01-29 12:43:42 -08:00
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
);
|
|
|
|
modified_buffer_account
|
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: None,
|
|
|
|
})
|
|
|
|
.unwrap();
|
2022-03-10 11:48:33 -08:00
|
|
|
modified_buffer_account
|
|
|
|
.data_as_mut_slice()
|
2022-05-11 07:22:59 -07:00
|
|
|
.get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..)
|
2022-03-10 11:48:33 -08:00
|
|
|
.unwrap()
|
2021-01-29 12:43:42 -08:00
|
|
|
.copy_from_slice(&elf);
|
|
|
|
bank.store_account(&buffer_address, &modified_buffer_account);
|
2021-03-09 13:06:07 -08:00
|
|
|
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
|
|
|
|
bank.store_account(&programdata_address, &AccountSharedData::default());
|
2021-01-29 12:43:42 -08:00
|
|
|
let message = Message::new(
|
|
|
|
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
|
|
|
&mint_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
&buffer_address,
|
|
|
|
&upgrade_authority_keypair.pubkey(),
|
|
|
|
min_program_balance,
|
|
|
|
elf.len(),
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
Some(&mint_keypair.pubkey()),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
TransactionError::InstructionError(1, InstructionError::IncorrectAuthority),
|
|
|
|
bank_client
|
|
|
|
.send_and_confirm_message(
|
|
|
|
&[&mint_keypair, &program_keypair, &upgrade_authority_keypair],
|
|
|
|
message
|
|
|
|
)
|
2021-01-19 17:56:44 -08:00
|
|
|
.unwrap_err()
|
|
|
|
.unwrap()
|
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bpf_loader_upgradeable_upgrade() {
|
2022-05-03 17:10:28 -07:00
|
|
|
let mut file = File::open("test_elfs/out/noop_aligned.so").expect("file open failed");
|
2020-12-14 15:35:10 -08:00
|
|
|
let mut elf_orig = Vec::new();
|
|
|
|
file.read_to_end(&mut elf_orig).unwrap();
|
2022-05-03 17:10:28 -07:00
|
|
|
let mut file = File::open("test_elfs/out/noop_unaligned.so").expect("file open failed");
|
2020-12-14 15:35:10 -08:00
|
|
|
let mut elf_new = Vec::new();
|
|
|
|
file.read_to_end(&mut elf_new).unwrap();
|
|
|
|
assert_ne!(elf_orig.len(), elf_new.len());
|
2022-01-31 08:53:50 -08:00
|
|
|
const SLOT: u64 = 42;
|
2020-12-14 15:35:10 -08:00
|
|
|
let buffer_address = Pubkey::new_unique();
|
2021-12-17 05:01:12 -08:00
|
|
|
let upgrade_authority_address = Pubkey::new_unique();
|
|
|
|
|
2020-12-14 15:35:10 -08:00
|
|
|
fn get_accounts(
|
2021-12-17 05:01:12 -08:00
|
|
|
buffer_address: &Pubkey,
|
2021-01-08 09:37:57 -08:00
|
|
|
buffer_authority: &Pubkey,
|
2020-12-14 15:35:10 -08:00
|
|
|
upgrade_authority_address: &Pubkey,
|
|
|
|
elf_orig: &[u8],
|
|
|
|
elf_new: &[u8],
|
2021-12-17 05:01:12 -08:00
|
|
|
) -> (Vec<(Pubkey, AccountSharedData)>, Vec<AccountMeta>) {
|
|
|
|
let loader_id = bpf_loader_upgradeable::id();
|
|
|
|
let program_address = Pubkey::new_unique();
|
|
|
|
let spill_address = Pubkey::new_unique();
|
|
|
|
let rent = Rent::default();
|
|
|
|
let min_program_balance =
|
2022-05-11 07:22:59 -07:00
|
|
|
1.max(rent.minimum_balance(UpgradeableLoaderState::size_of_program()));
|
2021-12-17 05:01:12 -08:00
|
|
|
let min_programdata_balance = 1.max(rent.minimum_balance(
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_programdata(elf_orig.len().max(elf_new.len())),
|
2021-12-17 05:01:12 -08:00
|
|
|
));
|
|
|
|
let (programdata_address, _) =
|
|
|
|
Pubkey::find_program_address(&[program_address.as_ref()], &loader_id);
|
|
|
|
let mut buffer_account = AccountSharedData::new(
|
2020-12-14 15:35:10 -08:00
|
|
|
1,
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_buffer(elf_new.len()),
|
2020-12-14 15:35:10 -08:00
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
);
|
|
|
|
buffer_account
|
2021-01-08 09:37:57 -08:00
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(*buffer_authority),
|
|
|
|
})
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap();
|
2022-03-10 11:48:33 -08:00
|
|
|
buffer_account
|
|
|
|
.data_as_mut_slice()
|
2022-05-11 07:22:59 -07:00
|
|
|
.get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..)
|
2022-03-10 11:48:33 -08:00
|
|
|
.unwrap()
|
2021-06-18 06:34:46 -07:00
|
|
|
.copy_from_slice(elf_new);
|
2021-12-17 05:01:12 -08:00
|
|
|
let mut programdata_account = AccountSharedData::new(
|
2020-12-14 15:35:10 -08:00
|
|
|
min_programdata_balance,
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_programdata(elf_orig.len().max(elf_new.len())),
|
2020-12-14 15:35:10 -08:00
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
);
|
|
|
|
programdata_account
|
|
|
|
.set_state(&UpgradeableLoaderState::ProgramData {
|
2022-01-31 08:53:50 -08:00
|
|
|
slot: SLOT,
|
2020-12-14 15:35:10 -08:00
|
|
|
upgrade_authority_address: Some(*upgrade_authority_address),
|
|
|
|
})
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
let mut program_account = AccountSharedData::new(
|
2020-12-14 15:35:10 -08:00
|
|
|
min_program_balance,
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_program(),
|
2020-12-14 15:35:10 -08:00
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
);
|
2021-12-17 05:01:12 -08:00
|
|
|
program_account.set_executable(true);
|
2020-12-14 15:35:10 -08:00
|
|
|
program_account
|
|
|
|
.set_state(&UpgradeableLoaderState::Program {
|
2021-12-17 05:01:12 -08:00
|
|
|
programdata_address,
|
2020-12-14 15:35:10 -08:00
|
|
|
})
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
let spill_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
|
|
|
|
let rent_account = create_account_for_test(&rent);
|
|
|
|
let clock_account = create_account_for_test(&Clock {
|
2022-01-31 08:53:50 -08:00
|
|
|
slot: SLOT,
|
2021-12-17 05:01:12 -08:00
|
|
|
..Clock::default()
|
|
|
|
});
|
|
|
|
let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
|
|
|
|
let transaction_accounts = vec![
|
|
|
|
(programdata_address, programdata_account),
|
|
|
|
(program_address, program_account),
|
|
|
|
(*buffer_address, buffer_account),
|
|
|
|
(spill_address, spill_account),
|
|
|
|
(sysvar::rent::id(), rent_account),
|
|
|
|
(sysvar::clock::id(), clock_account),
|
|
|
|
(*upgrade_authority_address, upgrade_authority_account),
|
|
|
|
];
|
|
|
|
let instruction_accounts = vec![
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: programdata_address,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: true,
|
|
|
|
},
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: program_address,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: true,
|
|
|
|
},
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: *buffer_address,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: true,
|
|
|
|
},
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: spill_address,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: true,
|
|
|
|
},
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: sysvar::rent::id(),
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: false,
|
|
|
|
},
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: sysvar::clock::id(),
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: false,
|
|
|
|
},
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: *upgrade_authority_address,
|
|
|
|
is_signer: true,
|
|
|
|
is_writable: false,
|
|
|
|
},
|
|
|
|
];
|
|
|
|
(transaction_accounts, instruction_accounts)
|
|
|
|
}
|
2020-12-14 15:35:10 -08:00
|
|
|
|
2021-12-17 05:01:12 -08:00
|
|
|
fn process_instruction(
|
|
|
|
transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
|
|
|
|
instruction_accounts: Vec<AccountMeta>,
|
|
|
|
expected_result: Result<(), InstructionError>,
|
|
|
|
) -> Vec<AccountSharedData> {
|
|
|
|
let instruction_data =
|
|
|
|
bincode::serialize(&UpgradeableLoaderInstruction::Upgrade).unwrap();
|
|
|
|
mock_process_instruction(
|
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
Vec::new(),
|
|
|
|
&instruction_data,
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2022-03-31 01:46:35 -07:00
|
|
|
None,
|
2022-04-15 11:43:04 -07:00
|
|
|
None,
|
2021-12-17 05:01:12 -08:00
|
|
|
expected_result,
|
|
|
|
super::process_instruction,
|
2020-12-14 15:35:10 -08:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Case: Success
|
2021-12-17 05:01:12 -08:00
|
|
|
let (transaction_accounts, instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_address,
|
2020-12-14 15:35:10 -08:00
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
2021-12-17 05:01:12 -08:00
|
|
|
let accounts = process_instruction(transaction_accounts, instruction_accounts, Ok(()));
|
|
|
|
let min_programdata_balance = Rent::default().minimum_balance(
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_programdata(elf_orig.len().max(elf_new.len())),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
assert_eq!(
|
|
|
|
min_programdata_balance,
|
|
|
|
accounts.first().unwrap().lamports()
|
|
|
|
);
|
|
|
|
assert_eq!(0, accounts.get(2).unwrap().lamports());
|
|
|
|
assert_eq!(1, accounts.get(3).unwrap().lamports());
|
|
|
|
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
|
2020-12-14 15:35:10 -08:00
|
|
|
assert_eq!(
|
|
|
|
state,
|
|
|
|
UpgradeableLoaderState::ProgramData {
|
2022-01-31 08:53:50 -08:00
|
|
|
slot: SLOT,
|
2020-12-14 15:35:10 -08:00
|
|
|
upgrade_authority_address: Some(upgrade_authority_address)
|
|
|
|
}
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
for (i, byte) in accounts
|
|
|
|
.first()
|
|
|
|
.unwrap()
|
|
|
|
.data()
|
|
|
|
.get(
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_programdata_metadata()
|
|
|
|
..UpgradeableLoaderState::size_of_programdata(elf_new.len()),
|
2022-03-10 11:48:33 -08:00
|
|
|
)
|
2021-12-17 05:01:12 -08:00
|
|
|
.unwrap()
|
2020-12-14 15:35:10 -08:00
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
{
|
2022-03-10 11:48:33 -08:00
|
|
|
assert_eq!(*elf_new.get(i).unwrap(), *byte);
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Case: not upgradable
|
2021-12-17 05:01:12 -08:00
|
|
|
let (mut transaction_accounts, instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_address,
|
2020-12-14 15:35:10 -08:00
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
transaction_accounts
|
|
|
|
.get_mut(0)
|
|
|
|
.unwrap()
|
2021-12-17 05:01:12 -08:00
|
|
|
.1
|
2020-12-14 15:35:10 -08:00
|
|
|
.set_state(&UpgradeableLoaderState::ProgramData {
|
2022-01-31 08:53:50 -08:00
|
|
|
slot: SLOT,
|
2020-12-14 15:35:10 -08:00
|
|
|
upgrade_authority_address: None,
|
|
|
|
})
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2021-01-08 09:37:57 -08:00
|
|
|
Err(InstructionError::Immutable),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
// Case: wrong authority
|
2021-12-17 05:01:12 -08:00
|
|
|
let (mut transaction_accounts, mut instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_address,
|
2020-12-14 15:35:10 -08:00
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
2021-04-19 09:48:48 -07:00
|
|
|
let invalid_upgrade_authority_address = Pubkey::new_unique();
|
2022-03-10 11:48:33 -08:00
|
|
|
transaction_accounts.get_mut(6).unwrap().0 = invalid_upgrade_authority_address;
|
|
|
|
instruction_accounts.get_mut(6).unwrap().pubkey = invalid_upgrade_authority_address;
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2021-01-08 09:37:57 -08:00
|
|
|
Err(InstructionError::IncorrectAuthority),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
// Case: authority did not sign
|
2021-12-17 05:01:12 -08:00
|
|
|
let (transaction_accounts, mut instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_address,
|
2020-12-14 15:35:10 -08:00
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
instruction_accounts.get_mut(6).unwrap().is_signer = false;
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2020-12-14 15:35:10 -08:00
|
|
|
Err(InstructionError::MissingRequiredSignature),
|
|
|
|
);
|
|
|
|
|
2022-09-16 01:54:20 -07:00
|
|
|
// Case: Buffer account and spill account alias
|
|
|
|
let (transaction_accounts, mut instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
|
|
|
&upgrade_authority_address,
|
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
|
|
|
*instruction_accounts.get_mut(3).unwrap() = instruction_accounts.get(2).unwrap().clone();
|
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
|
|
|
Err(InstructionError::AccountBorrowFailed),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Programdata account and spill account alias
|
|
|
|
let (transaction_accounts, mut instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
|
|
|
&upgrade_authority_address,
|
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
|
|
|
*instruction_accounts.get_mut(3).unwrap() = instruction_accounts.get(0).unwrap().clone();
|
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
|
|
|
Err(InstructionError::AccountBorrowFailed),
|
|
|
|
);
|
|
|
|
|
2020-12-14 15:35:10 -08:00
|
|
|
// Case: Program account not executable
|
2021-12-17 05:01:12 -08:00
|
|
|
let (mut transaction_accounts, instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_address,
|
2020-12-14 15:35:10 -08:00
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
transaction_accounts
|
|
|
|
.get_mut(1)
|
|
|
|
.unwrap()
|
|
|
|
.1
|
|
|
|
.set_executable(false);
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2020-12-14 15:35:10 -08:00
|
|
|
Err(InstructionError::AccountNotExecutable),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Program account now owned by loader
|
2021-12-17 05:01:12 -08:00
|
|
|
let (mut transaction_accounts, instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_address,
|
2020-12-14 15:35:10 -08:00
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
transaction_accounts
|
|
|
|
.get_mut(1)
|
|
|
|
.unwrap()
|
|
|
|
.1
|
|
|
|
.set_owner(Pubkey::new_unique());
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2020-12-14 15:35:10 -08:00
|
|
|
Err(InstructionError::IncorrectProgramId),
|
2021-01-19 16:24:44 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Program account not writable
|
2021-12-17 05:01:12 -08:00
|
|
|
let (transaction_accounts, mut instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_address,
|
2021-01-19 16:24:44 -08:00
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
instruction_accounts.get_mut(1).unwrap().is_writable = false;
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2021-01-19 16:24:44 -08:00
|
|
|
Err(InstructionError::InvalidArgument),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Program account not initialized
|
2021-12-17 05:01:12 -08:00
|
|
|
let (mut transaction_accounts, instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_address,
|
2020-12-14 15:35:10 -08:00
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
transaction_accounts
|
|
|
|
.get_mut(1)
|
|
|
|
.unwrap()
|
2021-12-17 05:01:12 -08:00
|
|
|
.1
|
2020-12-14 15:35:10 -08:00
|
|
|
.set_state(&UpgradeableLoaderState::Uninitialized)
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2020-12-14 15:35:10 -08:00
|
|
|
Err(InstructionError::InvalidAccountData),
|
|
|
|
);
|
|
|
|
|
2021-01-29 12:43:42 -08:00
|
|
|
// Case: Program ProgramData account mismatch
|
2021-12-17 05:01:12 -08:00
|
|
|
let (mut transaction_accounts, mut instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_address,
|
2020-12-14 15:35:10 -08:00
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
2021-04-19 09:48:48 -07:00
|
|
|
let invalid_programdata_address = Pubkey::new_unique();
|
2022-03-10 11:48:33 -08:00
|
|
|
transaction_accounts.get_mut(0).unwrap().0 = invalid_programdata_address;
|
|
|
|
instruction_accounts.get_mut(0).unwrap().pubkey = invalid_programdata_address;
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2021-01-29 12:43:42 -08:00
|
|
|
Err(InstructionError::InvalidArgument),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Buffer account not initialized
|
2021-12-17 05:01:12 -08:00
|
|
|
let (mut transaction_accounts, instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_address,
|
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
transaction_accounts
|
|
|
|
.get_mut(2)
|
|
|
|
.unwrap()
|
2021-12-17 05:01:12 -08:00
|
|
|
.1
|
2020-12-14 15:35:10 -08:00
|
|
|
.set_state(&UpgradeableLoaderState::Uninitialized)
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2021-01-29 12:43:42 -08:00
|
|
|
Err(InstructionError::InvalidArgument),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
|
2021-01-29 12:43:42 -08:00
|
|
|
// Case: Buffer account too big
|
2021-12-17 05:01:12 -08:00
|
|
|
let (mut transaction_accounts, instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_address,
|
2020-12-14 15:35:10 -08:00
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
transaction_accounts.get_mut(2).unwrap().1 = AccountSharedData::new(
|
2021-01-29 12:43:42 -08:00
|
|
|
1,
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_buffer(
|
|
|
|
elf_orig.len().max(elf_new.len()).saturating_add(1),
|
|
|
|
),
|
2021-12-17 05:01:12 -08:00
|
|
|
&bpf_loader_upgradeable::id(),
|
2021-01-29 12:43:42 -08:00
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
transaction_accounts
|
|
|
|
.get_mut(2)
|
|
|
|
.unwrap()
|
2021-12-17 05:01:12 -08:00
|
|
|
.1
|
2021-01-29 12:43:42 -08:00
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(upgrade_authority_address),
|
|
|
|
})
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2021-01-29 12:43:42 -08:00
|
|
|
Err(InstructionError::AccountDataTooSmall),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
|
2022-09-16 01:54:20 -07:00
|
|
|
// Case: Buffer account too small
|
2021-12-17 05:01:12 -08:00
|
|
|
let (mut transaction_accounts, instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&upgrade_authority_address,
|
2020-12-14 15:35:10 -08:00
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
transaction_accounts
|
|
|
|
.get_mut(2)
|
|
|
|
.unwrap()
|
2021-12-17 05:01:12 -08:00
|
|
|
.1
|
2021-01-29 12:43:42 -08:00
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(upgrade_authority_address),
|
|
|
|
})
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap();
|
2022-03-10 11:48:33 -08:00
|
|
|
truncate_data(&mut transaction_accounts.get_mut(2).unwrap().1, 5);
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2021-01-29 12:43:42 -08:00
|
|
|
Err(InstructionError::InvalidAccountData),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
|
2021-01-29 12:43:42 -08:00
|
|
|
// Case: Mismatched buffer and program authority
|
2021-12-17 05:01:12 -08:00
|
|
|
let (transaction_accounts, instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
2021-01-08 09:37:57 -08:00
|
|
|
&buffer_address,
|
2020-12-14 15:35:10 -08:00
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2021-01-29 12:43:42 -08:00
|
|
|
Err(InstructionError::IncorrectAuthority),
|
|
|
|
);
|
|
|
|
|
2022-09-16 01:54:20 -07:00
|
|
|
// Case: No buffer authority
|
2021-12-17 05:01:12 -08:00
|
|
|
let (mut transaction_accounts, instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
2021-01-29 12:43:42 -08:00
|
|
|
&buffer_address,
|
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
transaction_accounts
|
|
|
|
.get_mut(2)
|
|
|
|
.unwrap()
|
2021-12-17 05:01:12 -08:00
|
|
|
.1
|
2021-01-08 09:37:57 -08:00
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
2021-01-29 12:43:42 -08:00
|
|
|
authority_address: None,
|
2021-01-08 09:37:57 -08:00
|
|
|
})
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2021-01-29 12:43:42 -08:00
|
|
|
Err(InstructionError::IncorrectAuthority),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
|
2022-09-16 01:54:20 -07:00
|
|
|
// Case: No buffer and program authority
|
2021-12-17 05:01:12 -08:00
|
|
|
let (mut transaction_accounts, instruction_accounts) = get_accounts(
|
|
|
|
&buffer_address,
|
2021-01-08 09:37:57 -08:00
|
|
|
&buffer_address,
|
2020-12-14 15:35:10 -08:00
|
|
|
&upgrade_authority_address,
|
|
|
|
&elf_orig,
|
|
|
|
&elf_new,
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
transaction_accounts
|
|
|
|
.get_mut(0)
|
|
|
|
.unwrap()
|
2021-12-17 05:01:12 -08:00
|
|
|
.1
|
2021-01-29 12:43:42 -08:00
|
|
|
.set_state(&UpgradeableLoaderState::ProgramData {
|
2022-01-31 08:53:50 -08:00
|
|
|
slot: SLOT,
|
2021-01-29 12:43:42 -08:00
|
|
|
upgrade_authority_address: None,
|
|
|
|
})
|
|
|
|
.unwrap();
|
2022-03-10 11:48:33 -08:00
|
|
|
transaction_accounts
|
|
|
|
.get_mut(2)
|
|
|
|
.unwrap()
|
2021-12-17 05:01:12 -08:00
|
|
|
.1
|
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: None,
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
process_instruction(
|
|
|
|
transaction_accounts,
|
|
|
|
instruction_accounts,
|
2021-01-29 12:43:42 -08:00
|
|
|
Err(InstructionError::IncorrectAuthority),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bpf_loader_upgradeable_set_upgrade_authority() {
|
|
|
|
let instruction = bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap();
|
2021-10-08 02:41:07 -07:00
|
|
|
let loader_id = bpf_loader_upgradeable::id();
|
2020-12-14 15:35:10 -08:00
|
|
|
let slot = 0;
|
|
|
|
let upgrade_authority_address = Pubkey::new_unique();
|
2021-12-17 05:01:12 -08:00
|
|
|
let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
|
2020-12-14 15:35:10 -08:00
|
|
|
let new_upgrade_authority_address = Pubkey::new_unique();
|
2021-12-17 05:01:12 -08:00
|
|
|
let new_upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
|
2020-12-14 15:35:10 -08:00
|
|
|
let program_address = Pubkey::new_unique();
|
2021-06-18 00:03:58 -07:00
|
|
|
let (programdata_address, _) = Pubkey::find_program_address(
|
|
|
|
&[program_address.as_ref()],
|
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
);
|
2021-12-17 05:01:12 -08:00
|
|
|
let mut programdata_account = AccountSharedData::new(
|
2020-12-14 15:35:10 -08:00
|
|
|
1,
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_programdata(0),
|
2020-12-14 15:35:10 -08:00
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
);
|
|
|
|
programdata_account
|
|
|
|
.set_state(&UpgradeableLoaderState::ProgramData {
|
|
|
|
slot,
|
|
|
|
upgrade_authority_address: Some(upgrade_authority_address),
|
|
|
|
})
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
let programdata_meta = AccountMeta {
|
|
|
|
pubkey: programdata_address,
|
|
|
|
is_signer: false,
|
2022-06-29 10:29:12 -07:00
|
|
|
is_writable: true,
|
2021-12-17 05:01:12 -08:00
|
|
|
};
|
|
|
|
let upgrade_authority_meta = AccountMeta {
|
|
|
|
pubkey: upgrade_authority_address,
|
|
|
|
is_signer: true,
|
|
|
|
is_writable: false,
|
|
|
|
};
|
|
|
|
let new_upgrade_authority_meta = AccountMeta {
|
|
|
|
pubkey: new_upgrade_authority_address,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Case: Set to new authority
|
|
|
|
let accounts = process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![
|
|
|
|
(programdata_address, programdata_account.clone()),
|
|
|
|
(upgrade_authority_address, upgrade_authority_account.clone()),
|
|
|
|
(
|
|
|
|
new_upgrade_authority_address,
|
|
|
|
new_upgrade_authority_account.clone(),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
vec![
|
|
|
|
programdata_meta.clone(),
|
|
|
|
upgrade_authority_meta.clone(),
|
|
|
|
new_upgrade_authority_meta.clone(),
|
|
|
|
],
|
2020-12-14 15:35:10 -08:00
|
|
|
Ok(()),
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
|
2020-12-14 15:35:10 -08:00
|
|
|
assert_eq!(
|
|
|
|
state,
|
|
|
|
UpgradeableLoaderState::ProgramData {
|
|
|
|
slot,
|
|
|
|
upgrade_authority_address: Some(new_upgrade_authority_address),
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Not upgradeable
|
2021-12-17 05:01:12 -08:00
|
|
|
let accounts = process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![
|
|
|
|
(programdata_address, programdata_account.clone()),
|
|
|
|
(upgrade_authority_address, upgrade_authority_account.clone()),
|
|
|
|
],
|
|
|
|
vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
|
2020-12-14 15:35:10 -08:00
|
|
|
Ok(()),
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
|
2020-12-14 15:35:10 -08:00
|
|
|
assert_eq!(
|
|
|
|
state,
|
|
|
|
UpgradeableLoaderState::ProgramData {
|
|
|
|
slot,
|
|
|
|
upgrade_authority_address: None,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Authority did not sign
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![
|
|
|
|
(programdata_address, programdata_account.clone()),
|
|
|
|
(upgrade_authority_address, upgrade_authority_account.clone()),
|
|
|
|
],
|
|
|
|
vec![
|
|
|
|
programdata_meta.clone(),
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: upgrade_authority_address,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: false,
|
|
|
|
},
|
|
|
|
],
|
2020-12-14 15:35:10 -08:00
|
|
|
Err(InstructionError::MissingRequiredSignature),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: wrong authority
|
2021-04-19 09:48:48 -07:00
|
|
|
let invalid_upgrade_authority_address = Pubkey::new_unique();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![
|
|
|
|
(programdata_address, programdata_account.clone()),
|
|
|
|
(
|
|
|
|
invalid_upgrade_authority_address,
|
|
|
|
upgrade_authority_account.clone(),
|
|
|
|
),
|
|
|
|
(new_upgrade_authority_address, new_upgrade_authority_account),
|
|
|
|
],
|
|
|
|
vec![
|
|
|
|
programdata_meta.clone(),
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: invalid_upgrade_authority_address,
|
|
|
|
is_signer: true,
|
|
|
|
is_writable: false,
|
|
|
|
},
|
|
|
|
new_upgrade_authority_meta,
|
|
|
|
],
|
2021-01-08 09:37:57 -08:00
|
|
|
Err(InstructionError::IncorrectAuthority),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
// Case: No authority
|
|
|
|
programdata_account
|
|
|
|
.set_state(&UpgradeableLoaderState::ProgramData {
|
|
|
|
slot,
|
|
|
|
upgrade_authority_address: None,
|
|
|
|
})
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![
|
|
|
|
(programdata_address, programdata_account.clone()),
|
|
|
|
(upgrade_authority_address, upgrade_authority_account.clone()),
|
|
|
|
],
|
|
|
|
vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
|
2021-01-08 09:37:57 -08:00
|
|
|
Err(InstructionError::Immutable),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Not a ProgramData account
|
|
|
|
programdata_account
|
|
|
|
.set_state(&UpgradeableLoaderState::Program {
|
|
|
|
programdata_address: Pubkey::new_unique(),
|
|
|
|
})
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![
|
|
|
|
(programdata_address, programdata_account.clone()),
|
|
|
|
(upgrade_authority_address, upgrade_authority_account),
|
|
|
|
],
|
|
|
|
vec![programdata_meta, upgrade_authority_meta],
|
2021-03-17 21:39:29 -07:00
|
|
|
Err(InstructionError::InvalidArgument),
|
2021-01-08 09:37:57 -08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bpf_loader_upgradeable_set_buffer_authority() {
|
|
|
|
let instruction = bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap();
|
2021-10-08 02:41:07 -07:00
|
|
|
let loader_id = bpf_loader_upgradeable::id();
|
2021-12-17 05:01:12 -08:00
|
|
|
let invalid_authority_address = Pubkey::new_unique();
|
2021-01-08 09:37:57 -08:00
|
|
|
let authority_address = Pubkey::new_unique();
|
2021-12-17 05:01:12 -08:00
|
|
|
let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
|
2021-01-08 09:37:57 -08:00
|
|
|
let new_authority_address = Pubkey::new_unique();
|
2021-12-17 05:01:12 -08:00
|
|
|
let new_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
|
2021-01-08 09:37:57 -08:00
|
|
|
let buffer_address = Pubkey::new_unique();
|
2022-05-11 07:22:59 -07:00
|
|
|
let mut buffer_account =
|
|
|
|
AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(0), &loader_id);
|
2021-01-08 09:37:57 -08:00
|
|
|
buffer_account
|
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(authority_address),
|
|
|
|
})
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
let mut transaction_accounts = vec![
|
|
|
|
(buffer_address, buffer_account.clone()),
|
|
|
|
(authority_address, authority_account.clone()),
|
|
|
|
(new_authority_address, new_authority_account.clone()),
|
2021-04-19 09:48:48 -07:00
|
|
|
];
|
2021-12-17 05:01:12 -08:00
|
|
|
let buffer_meta = AccountMeta {
|
|
|
|
pubkey: buffer_address,
|
|
|
|
is_signer: false,
|
2022-06-29 10:29:12 -07:00
|
|
|
is_writable: true,
|
2021-12-17 05:01:12 -08:00
|
|
|
};
|
|
|
|
let authority_meta = AccountMeta {
|
|
|
|
pubkey: authority_address,
|
|
|
|
is_signer: true,
|
|
|
|
is_writable: false,
|
|
|
|
};
|
|
|
|
let new_authority_meta = AccountMeta {
|
|
|
|
pubkey: new_authority_address,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Case: New authority required
|
|
|
|
let accounts = process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
transaction_accounts.clone(),
|
|
|
|
vec![buffer_meta.clone(), authority_meta.clone()],
|
2021-10-08 02:41:07 -07:00
|
|
|
Err(InstructionError::IncorrectAuthority),
|
2021-01-08 09:37:57 -08:00
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
|
2021-01-08 09:37:57 -08:00
|
|
|
assert_eq!(
|
|
|
|
state,
|
|
|
|
UpgradeableLoaderState::Buffer {
|
2021-10-08 02:41:07 -07:00
|
|
|
authority_address: Some(authority_address),
|
2021-01-08 09:37:57 -08:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2021-10-08 02:41:07 -07:00
|
|
|
// Case: Set to new authority
|
2021-01-08 09:37:57 -08:00
|
|
|
buffer_account
|
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(authority_address),
|
|
|
|
})
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
let accounts = process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
transaction_accounts.clone(),
|
|
|
|
vec![
|
|
|
|
buffer_meta.clone(),
|
|
|
|
authority_meta.clone(),
|
|
|
|
new_authority_meta.clone(),
|
|
|
|
],
|
2021-10-08 02:41:07 -07:00
|
|
|
Ok(()),
|
2021-01-08 09:37:57 -08:00
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
|
2021-01-08 09:37:57 -08:00
|
|
|
assert_eq!(
|
|
|
|
state,
|
|
|
|
UpgradeableLoaderState::Buffer {
|
2021-10-08 02:41:07 -07:00
|
|
|
authority_address: Some(new_authority_address),
|
2021-01-08 09:37:57 -08:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Authority did not sign
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
transaction_accounts.clone(),
|
|
|
|
vec![
|
|
|
|
buffer_meta.clone(),
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: authority_address,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: false,
|
|
|
|
},
|
|
|
|
new_authority_meta.clone(),
|
|
|
|
],
|
2021-01-08 09:37:57 -08:00
|
|
|
Err(InstructionError::MissingRequiredSignature),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: wrong authority
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![
|
|
|
|
(buffer_address, buffer_account.clone()),
|
|
|
|
(invalid_authority_address, authority_account),
|
|
|
|
(new_authority_address, new_authority_account),
|
|
|
|
],
|
|
|
|
vec![
|
|
|
|
buffer_meta.clone(),
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: invalid_authority_address,
|
|
|
|
is_signer: true,
|
|
|
|
is_writable: false,
|
|
|
|
},
|
|
|
|
new_authority_meta.clone(),
|
|
|
|
],
|
2021-01-08 09:37:57 -08:00
|
|
|
Err(InstructionError::IncorrectAuthority),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: No authority
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
transaction_accounts.clone(),
|
|
|
|
vec![buffer_meta.clone(), authority_meta.clone()],
|
|
|
|
Err(InstructionError::IncorrectAuthority),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Set to no authority
|
2022-03-10 11:48:33 -08:00
|
|
|
transaction_accounts
|
|
|
|
.get_mut(0)
|
|
|
|
.unwrap()
|
2021-12-17 05:01:12 -08:00
|
|
|
.1
|
2021-01-08 09:37:57 -08:00
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: None,
|
|
|
|
})
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
transaction_accounts.clone(),
|
|
|
|
vec![
|
|
|
|
buffer_meta.clone(),
|
|
|
|
authority_meta.clone(),
|
|
|
|
new_authority_meta.clone(),
|
|
|
|
],
|
2021-01-08 09:37:57 -08:00
|
|
|
Err(InstructionError::Immutable),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: Not a Buffer account
|
2022-03-10 11:48:33 -08:00
|
|
|
transaction_accounts
|
|
|
|
.get_mut(0)
|
|
|
|
.unwrap()
|
2021-12-17 05:01:12 -08:00
|
|
|
.1
|
2021-01-08 09:37:57 -08:00
|
|
|
.set_state(&UpgradeableLoaderState::Program {
|
|
|
|
programdata_address: Pubkey::new_unique(),
|
|
|
|
})
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
transaction_accounts.clone(),
|
|
|
|
vec![buffer_meta, authority_meta, new_authority_meta],
|
2021-03-17 21:39:29 -07:00
|
|
|
Err(InstructionError::InvalidArgument),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bpf_loader_upgradeable_close() {
|
|
|
|
let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Close).unwrap();
|
2021-10-08 02:41:07 -07:00
|
|
|
let loader_id = bpf_loader_upgradeable::id();
|
2021-12-17 05:01:12 -08:00
|
|
|
let invalid_authority_address = Pubkey::new_unique();
|
2021-03-17 21:39:29 -07:00
|
|
|
let authority_address = Pubkey::new_unique();
|
2021-12-17 05:01:12 -08:00
|
|
|
let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
|
2021-03-17 21:39:29 -07:00
|
|
|
let recipient_address = Pubkey::new_unique();
|
2021-12-17 05:01:12 -08:00
|
|
|
let recipient_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
|
2021-03-17 21:39:29 -07:00
|
|
|
let buffer_address = Pubkey::new_unique();
|
2022-05-11 07:22:59 -07:00
|
|
|
let mut buffer_account =
|
|
|
|
AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(0), &loader_id);
|
2021-03-17 21:39:29 -07:00
|
|
|
buffer_account
|
|
|
|
.set_state(&UpgradeableLoaderState::Buffer {
|
|
|
|
authority_address: Some(authority_address),
|
|
|
|
})
|
|
|
|
.unwrap();
|
2021-08-24 10:05:54 -07:00
|
|
|
let uninitialized_address = Pubkey::new_unique();
|
2021-12-17 05:01:12 -08:00
|
|
|
let mut uninitialized_account = AccountSharedData::new(
|
2021-08-24 10:05:54 -07:00
|
|
|
1,
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_programdata(0),
|
2021-12-17 05:01:12 -08:00
|
|
|
&loader_id,
|
2021-08-24 10:05:54 -07:00
|
|
|
);
|
|
|
|
uninitialized_account
|
|
|
|
.set_state(&UpgradeableLoaderState::Uninitialized)
|
|
|
|
.unwrap();
|
|
|
|
let programdata_address = Pubkey::new_unique();
|
2021-12-17 05:01:12 -08:00
|
|
|
let mut programdata_account = AccountSharedData::new(
|
2021-08-24 10:05:54 -07:00
|
|
|
1,
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_programdata(0),
|
2021-12-17 05:01:12 -08:00
|
|
|
&loader_id,
|
2021-08-24 10:05:54 -07:00
|
|
|
);
|
|
|
|
programdata_account
|
|
|
|
.set_state(&UpgradeableLoaderState::ProgramData {
|
|
|
|
slot: 0,
|
|
|
|
upgrade_authority_address: Some(authority_address),
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
let program_address = Pubkey::new_unique();
|
2022-05-11 07:22:59 -07:00
|
|
|
let mut program_account =
|
|
|
|
AccountSharedData::new(1, UpgradeableLoaderState::size_of_program(), &loader_id);
|
2021-12-17 05:01:12 -08:00
|
|
|
program_account.set_executable(true);
|
2021-08-24 10:05:54 -07:00
|
|
|
program_account
|
2021-03-17 21:39:29 -07:00
|
|
|
.set_state(&UpgradeableLoaderState::Program {
|
2021-08-24 10:05:54 -07:00
|
|
|
programdata_address,
|
2021-03-17 21:39:29 -07:00
|
|
|
})
|
|
|
|
.unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
let transaction_accounts = vec![
|
|
|
|
(buffer_address, buffer_account.clone()),
|
|
|
|
(recipient_address, recipient_account.clone()),
|
|
|
|
(authority_address, authority_account.clone()),
|
2021-04-19 09:48:48 -07:00
|
|
|
];
|
2021-12-17 05:01:12 -08:00
|
|
|
let buffer_meta = AccountMeta {
|
|
|
|
pubkey: buffer_address,
|
|
|
|
is_signer: false,
|
2022-06-29 10:29:12 -07:00
|
|
|
is_writable: true,
|
2021-12-17 05:01:12 -08:00
|
|
|
};
|
|
|
|
let recipient_meta = AccountMeta {
|
|
|
|
pubkey: recipient_address,
|
|
|
|
is_signer: false,
|
2022-06-29 10:29:12 -07:00
|
|
|
is_writable: true,
|
2021-12-17 05:01:12 -08:00
|
|
|
};
|
|
|
|
let authority_meta = AccountMeta {
|
|
|
|
pubkey: authority_address,
|
|
|
|
is_signer: true,
|
|
|
|
is_writable: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Case: close a buffer account
|
|
|
|
let accounts = process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
transaction_accounts,
|
|
|
|
vec![
|
|
|
|
buffer_meta.clone(),
|
|
|
|
recipient_meta.clone(),
|
|
|
|
authority_meta.clone(),
|
|
|
|
],
|
2021-08-24 10:05:54 -07:00
|
|
|
Ok(()),
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
assert_eq!(0, accounts.first().unwrap().lamports());
|
|
|
|
assert_eq!(2, accounts.get(1).unwrap().lamports());
|
|
|
|
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
assert_eq!(state, UpgradeableLoaderState::Uninitialized);
|
|
|
|
|
|
|
|
// Case: close with wrong authority
|
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![
|
|
|
|
(buffer_address, buffer_account.clone()),
|
|
|
|
(recipient_address, recipient_account.clone()),
|
|
|
|
(invalid_authority_address, authority_account.clone()),
|
|
|
|
],
|
|
|
|
vec![
|
|
|
|
buffer_meta,
|
|
|
|
recipient_meta.clone(),
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: invalid_authority_address,
|
|
|
|
is_signer: true,
|
|
|
|
is_writable: false,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
Err(InstructionError::IncorrectAuthority),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Case: close an uninitialized account
|
|
|
|
let accounts = process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![
|
|
|
|
(uninitialized_address, uninitialized_account.clone()),
|
|
|
|
(recipient_address, recipient_account.clone()),
|
|
|
|
(invalid_authority_address, authority_account.clone()),
|
|
|
|
],
|
|
|
|
vec![
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: uninitialized_address,
|
|
|
|
is_signer: false,
|
2022-06-29 10:29:12 -07:00
|
|
|
is_writable: true,
|
2021-12-17 05:01:12 -08:00
|
|
|
},
|
|
|
|
recipient_meta.clone(),
|
|
|
|
authority_meta.clone(),
|
|
|
|
],
|
|
|
|
Ok(()),
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
assert_eq!(0, accounts.first().unwrap().lamports());
|
|
|
|
assert_eq!(2, accounts.get(1).unwrap().lamports());
|
|
|
|
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
|
2021-12-17 05:01:12 -08:00
|
|
|
assert_eq!(state, UpgradeableLoaderState::Uninitialized);
|
|
|
|
|
|
|
|
// Case: close a program account
|
|
|
|
let accounts = process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&instruction,
|
|
|
|
vec![
|
|
|
|
(programdata_address, programdata_account.clone()),
|
|
|
|
(recipient_address, recipient_account),
|
|
|
|
(authority_address, authority_account),
|
|
|
|
(program_address, program_account.clone()),
|
|
|
|
],
|
|
|
|
vec![
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: programdata_address,
|
|
|
|
is_signer: false,
|
2022-06-29 10:29:12 -07:00
|
|
|
is_writable: true,
|
2021-12-17 05:01:12 -08:00
|
|
|
},
|
|
|
|
recipient_meta,
|
|
|
|
authority_meta,
|
|
|
|
AccountMeta {
|
|
|
|
pubkey: program_address,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: true,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
Ok(()),
|
|
|
|
);
|
2022-03-10 11:48:33 -08:00
|
|
|
assert_eq!(0, accounts.first().unwrap().lamports());
|
|
|
|
assert_eq!(2, accounts.get(1).unwrap().lamports());
|
|
|
|
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
|
2021-08-24 10:05:54 -07:00
|
|
|
assert_eq!(state, UpgradeableLoaderState::Uninitialized);
|
|
|
|
|
|
|
|
// Try to invoke closed account
|
2021-12-17 05:01:12 -08:00
|
|
|
process_instruction(
|
|
|
|
&program_address,
|
|
|
|
&[0, 1],
|
|
|
|
&[],
|
|
|
|
vec![
|
|
|
|
(programdata_address, programdata_account.clone()),
|
|
|
|
(program_address, program_account.clone()),
|
|
|
|
],
|
|
|
|
Vec::new(),
|
2021-08-24 10:05:54 -07:00
|
|
|
Err(InstructionError::InvalidAccountData),
|
2020-08-11 16:11:52 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-05-08 12:37:04 -07:00
|
|
|
/// fuzzing utility function
|
|
|
|
fn fuzz<F>(
|
|
|
|
bytes: &[u8],
|
|
|
|
outer_iters: usize,
|
|
|
|
inner_iters: usize,
|
|
|
|
offset: Range<usize>,
|
|
|
|
value: Range<u8>,
|
|
|
|
work: F,
|
|
|
|
) where
|
|
|
|
F: Fn(&mut [u8]),
|
|
|
|
{
|
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
for _ in 0..outer_iters {
|
|
|
|
let mut mangled_bytes = bytes.to_vec();
|
|
|
|
for _ in 0..inner_iters {
|
|
|
|
let offset = rng.gen_range(offset.start, offset.end);
|
|
|
|
let value = rng.gen_range(value.start, value.end);
|
2022-03-10 11:48:33 -08:00
|
|
|
*mangled_bytes.get_mut(offset).unwrap() = value;
|
2020-05-08 12:37:04 -07:00
|
|
|
work(&mut mangled_bytes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[ignore]
|
|
|
|
fn test_fuzz() {
|
2021-11-04 13:47:32 -07:00
|
|
|
let loader_id = bpf_loader::id();
|
|
|
|
let program_id = Pubkey::new_unique();
|
2020-05-08 12:37:04 -07:00
|
|
|
|
|
|
|
// Create program account
|
2022-05-03 17:10:28 -07:00
|
|
|
let mut file = File::open("test_elfs/out/noop_aligned.so").expect("file open failed");
|
2020-05-08 12:37:04 -07:00
|
|
|
let mut elf = Vec::new();
|
|
|
|
file.read_to_end(&mut elf).unwrap();
|
|
|
|
|
2020-06-13 13:20:08 -07:00
|
|
|
// Mangle the whole file
|
2020-05-08 12:37:04 -07:00
|
|
|
fuzz(
|
|
|
|
&elf,
|
|
|
|
1_000_000_000,
|
|
|
|
100,
|
|
|
|
0..elf.len(),
|
|
|
|
0..255,
|
|
|
|
|bytes: &mut [u8]| {
|
2021-12-17 05:01:12 -08:00
|
|
|
let mut program_account = AccountSharedData::new(1, 0, &loader_id);
|
|
|
|
program_account.set_data(bytes.to_vec());
|
|
|
|
program_account.set_executable(true);
|
|
|
|
process_instruction(
|
|
|
|
&loader_id,
|
|
|
|
&[],
|
|
|
|
&[],
|
|
|
|
vec![(program_id, program_account)],
|
|
|
|
Vec::new(),
|
|
|
|
Ok(()),
|
|
|
|
);
|
2020-05-08 12:37:04 -07:00
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2018-10-31 10:59:56 -07:00
|
|
|
}
|