1#![allow(unsafe_code)]
6#![allow(clippy::ptr_as_ptr)]
7#![deny(clippy::arithmetic_side_effects)]
8#![deny(clippy::indexing_slicing)]
9
10pub mod serialization;
11pub mod syscalls;
12
13use std::{cell::RefCell, mem, rc::Rc};
14
15#[cfg(feature = "svm-internal")]
16use qualifier_attr::qualifiers;
17use rialo_s_bincode::limited_deserialize;
18use rialo_s_clock::Slot;
19use rialo_s_compute_budget::compute_budget::MAX_INSTRUCTION_STACK_DEPTH;
20use rialo_s_feature_set::{
21 bpf_account_data_direct_mapping, disable_new_loader_v3_deployments,
22 enable_bpf_loader_set_authority_checked_ix, enable_loader_v4,
23 remove_accounts_executable_flag_checks,
24};
25use rialo_s_instruction::{error::InstructionError, AccountMeta};
26use rialo_s_loader_v3_interface::{
27 instruction::UpgradeableLoaderInstruction, state::UpgradeableLoaderState,
28};
29use rialo_s_log_collector::{ic_logger_msg, ic_msg, LogCollector};
30use rialo_s_measure::measure::Measure;
31use rialo_s_program_entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS};
32use rialo_s_program_runtime::{
33 invoke_context::{BpfAllocator, InvokeContext, SerializedAccountMetadata, SyscallContext},
34 loaded_programs::{
35 ExecutableKind, LoadProgramMetrics, ProgramCacheEntry, ProgramCacheEntryOwner,
36 ProgramCacheEntryType, ProgramCacheForTxBatch, ProgramRuntimeEnvironment,
37 DELAY_VISIBILITY_SLOT_OFFSET,
38 },
39 mem_pool::VmMemoryPool,
40 stable_log,
41 sysvar_cache::get_sysvar_with_account_check,
42};
43use rialo_s_pubkey::Pubkey;
44use rialo_s_sdk_ids::{
45 bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, loader_v4, native_loader,
46 system_program,
47};
48use rialo_s_system_interface::{instruction as system_instruction, MAX_PERMITTED_DATA_LENGTH};
49use rialo_s_transaction_context::{IndexOfAccount, InstructionContext, TransactionContext};
50use rialo_s_type_overrides::sync::{atomic::Ordering, Arc};
51use solana_sbpf::{
52 declare_builtin_function,
53 ebpf::{self, MM_HEAP_START},
54 elf::Executable,
55 error::{EbpfError, ProgramResult},
56 memory_region::{AccessType, MemoryCowCallback, MemoryMapping, MemoryRegion},
57 program::BuiltinProgram,
58 verifier::RequisiteVerifier,
59 vm::{ContextObject, EbpfVm},
60};
61use syscalls::morph_into_deployment_environment_v1;
62
63#[cfg_attr(feature = "svm-internal", qualifiers(pub))]
64const DEFAULT_LOADER_COMPUTE_UNITS: u64 = 570;
65#[cfg_attr(feature = "svm-internal", qualifiers(pub))]
66const DEPRECATED_LOADER_COMPUTE_UNITS: u64 = 1_140;
67#[cfg_attr(feature = "svm-internal", qualifiers(pub))]
68const UPGRADEABLE_LOADER_COMPUTE_UNITS: u64 = 2_370;
69
70thread_local! {
71 pub static MEMORY_POOL: RefCell<VmMemoryPool> = RefCell::new(VmMemoryPool::new());
72}
73
74#[allow(clippy::too_many_arguments)]
75pub fn load_program_from_bytes(
76 log_collector: Option<Rc<RefCell<LogCollector>>>,
77 load_program_metrics: &mut LoadProgramMetrics,
78 programdata: &[u8],
79 loader_key: &Pubkey,
80 account_size: usize,
81 deployment_slot: Slot,
82 program_runtime_environment: Arc<BuiltinProgram<InvokeContext<'static>>>,
83 reloading: bool,
84) -> Result<ProgramCacheEntry, InstructionError> {
85 let effective_slot = deployment_slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET);
86 let loaded_program = if reloading {
87 unsafe {
89 ProgramCacheEntry::reload(
90 loader_key,
91 program_runtime_environment,
92 deployment_slot,
93 effective_slot,
94 programdata,
95 account_size,
96 load_program_metrics,
97 )
98 }
99 } else {
100 ProgramCacheEntry::new(
101 loader_key,
102 program_runtime_environment,
103 deployment_slot,
104 effective_slot,
105 programdata,
106 account_size,
107 load_program_metrics,
108 )
109 }
110 .map_err(|err| {
111 ic_logger_msg!(log_collector, "{}", err);
112 InstructionError::InvalidAccountData
113 })?;
114 Ok(loaded_program)
115}
116
117pub fn deploy_program(
121 log_collector: Option<Rc<RefCell<LogCollector>>>,
122 program_cache_for_tx_batch: &mut ProgramCacheForTxBatch,
123 program_runtime_environment: ProgramRuntimeEnvironment,
124 program_id: &Pubkey,
125 loader_key: &Pubkey,
126 account_size: usize,
127 programdata: &[u8],
128 deployment_slot: Slot,
129) -> Result<LoadProgramMetrics, InstructionError> {
130 let mut load_program_metrics = LoadProgramMetrics::default();
131 let mut register_syscalls_time = Measure::start("register_syscalls_time");
132 let deployment_program_runtime_environment =
133 morph_into_deployment_environment_v1(program_runtime_environment.clone()).map_err(|e| {
134 ic_logger_msg!(log_collector, "Failed to register syscalls: {}", e);
135 InstructionError::ProgramEnvironmentSetupFailure
136 })?;
137 register_syscalls_time.stop();
138 load_program_metrics.register_syscalls_us = register_syscalls_time.as_us();
139 let mut load_elf_time = Measure::start("load_elf_time");
141 let executable = Executable::<InvokeContext<'_>>::load(
142 programdata,
143 Arc::new(deployment_program_runtime_environment),
144 )
145 .map_err(|err| {
146 ic_logger_msg!(log_collector, "{}", err);
147 InstructionError::InvalidAccountData
148 })?;
149 load_elf_time.stop();
150 load_program_metrics.load_elf_us = load_elf_time.as_us();
151 let mut verify_code_time = Measure::start("verify_code_time");
152 executable.verify::<RequisiteVerifier>().map_err(|err| {
153 ic_logger_msg!(log_collector, "{}", err);
154 InstructionError::InvalidAccountData
155 })?;
156 verify_code_time.stop();
157 load_program_metrics.verify_code_us = verify_code_time.as_us();
158 let executor = load_program_from_bytes(
160 log_collector,
161 &mut load_program_metrics,
162 programdata,
163 loader_key,
164 account_size,
165 deployment_slot,
166 program_runtime_environment,
167 true,
168 )?;
169 if let Some(old_entry) = program_cache_for_tx_batch.find(program_id) {
170 executor.tx_usage_counter.store(
171 old_entry.tx_usage_counter.load(Ordering::Relaxed),
172 Ordering::Relaxed,
173 );
174 executor.ix_usage_counter.store(
175 old_entry.ix_usage_counter.load(Ordering::Relaxed),
176 Ordering::Relaxed,
177 );
178 }
179 load_program_metrics.program_id = program_id.to_string();
180 program_cache_for_tx_batch.store_modified_entry(*program_id, Arc::new(executor));
181 Ok(load_program_metrics)
182}
183
184#[macro_export]
185macro_rules! deploy_program {
186 ($invoke_context:expr, $program_id:expr, $loader_key:expr, $account_size:expr, $programdata:expr, $deployment_slot:expr $(,)?) => {
187 let environments = $invoke_context
188 .get_environments_for_slot($deployment_slot.saturating_add(
189 rialo_s_program_runtime::loaded_programs::DELAY_VISIBILITY_SLOT_OFFSET,
190 ))
191 .map_err(|_err| {
192 InstructionError::ProgramEnvironmentSetupFailure
194 })?;
195 let load_program_metrics = $crate::deploy_program(
196 $invoke_context.get_log_collector(),
197 $invoke_context.program_cache_for_tx_batch,
198 environments.program_runtime_v1.clone(),
199 $program_id,
200 $loader_key,
201 $account_size,
202 $programdata,
203 $deployment_slot,
204 )?;
205 load_program_metrics.submit_datapoint(&mut $invoke_context.timings);
206 };
207}
208
209fn write_program_data(
210 program_data_offset: usize,
211 bytes: &[u8],
212 invoke_context: &mut InvokeContext<'_>,
213) -> Result<(), InstructionError> {
214 let transaction_context = &invoke_context.transaction_context;
215 let instruction_context = transaction_context.get_current_instruction_context()?;
216 let mut program = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
217 let data = program.get_data_mut()?;
218 let write_offset = program_data_offset.saturating_add(bytes.len());
219 if data.len() < write_offset {
220 ic_msg!(
221 invoke_context,
222 "Write overflow: {} < {}",
223 data.len(),
224 write_offset,
225 );
226 return Err(InstructionError::AccountDataTooSmall);
227 }
228 data.get_mut(program_data_offset..write_offset)
229 .ok_or(InstructionError::AccountDataTooSmall)?
230 .copy_from_slice(bytes);
231 Ok(())
232}
233
234pub fn calculate_heap_cost(heap_size: u32, heap_cost: u64) -> u64 {
236 const KIBIBYTE: u64 = 1024;
237 const PAGE_SIZE_KB: u64 = 32;
238 let mut rounded_heap_size = u64::from(heap_size);
239 rounded_heap_size =
240 rounded_heap_size.saturating_add(PAGE_SIZE_KB.saturating_mul(KIBIBYTE).saturating_sub(1));
241 rounded_heap_size
242 .checked_div(PAGE_SIZE_KB.saturating_mul(KIBIBYTE))
243 .expect("PAGE_SIZE_KB * KIBIBYTE > 0")
244 .saturating_sub(1)
245 .saturating_mul(heap_cost)
246}
247
248#[cfg_attr(feature = "svm-internal", qualifiers(pub))]
250fn create_vm<'a, 'b>(
251 program: &'a Executable<InvokeContext<'b>>,
252 regions: Vec<MemoryRegion>,
253 accounts_metadata: Vec<SerializedAccountMetadata>,
254 invoke_context: &'a mut InvokeContext<'b>,
255 stack: &mut [u8],
256 heap: &mut [u8],
257) -> Result<EbpfVm<'a, InvokeContext<'b>>, Box<dyn std::error::Error>> {
258 let stack_size = stack.len();
259 let heap_size = heap.len();
260 let accounts = Rc::clone(invoke_context.transaction_context.accounts());
261 let memory_mapping = create_memory_mapping(
262 program,
263 stack,
264 heap,
265 regions,
266 Some(Box::new(move |index_in_transaction| {
267 let mut account = accounts
271 .try_borrow_mut(index_in_transaction as IndexOfAccount)
272 .map_err(|_| ())?;
273 accounts
274 .touch(index_in_transaction as IndexOfAccount)
275 .map_err(|_| ())?;
276
277 if account.is_shared() {
278 account.reserve(MAX_PERMITTED_DATA_INCREASE);
281 }
282 Ok(account
283 .try_data_as_mut_slice()
284 .map_err(|_| ())?
285 .as_mut_ptr() as u64)
286 })),
287 )?;
288 invoke_context.set_syscall_context(SyscallContext {
289 allocator: BpfAllocator::new(heap_size as u64),
290 accounts_metadata,
291 trace_log: Vec::new(),
292 })?;
293 Ok(EbpfVm::new(
294 program.get_loader().clone(),
295 program.get_sbpf_version(),
296 invoke_context,
297 memory_mapping,
298 stack_size,
299 ))
300}
301
302#[macro_export]
304macro_rules! create_vm {
305 ($vm:ident, $program:expr, $regions:expr, $accounts_metadata:expr, $invoke_context:expr $(,)?) => {
306 let invoke_context = &*$invoke_context;
307 let stack_size = $program.get_config().stack_size();
308 let heap_size = invoke_context.get_compute_budget().heap_size;
309 let heap_cost_result = invoke_context.consume_checked($crate::calculate_heap_cost(
310 heap_size,
311 invoke_context.get_compute_budget().heap_cost,
312 ));
313 let $vm = heap_cost_result.and_then(|_| {
314 let (mut stack, mut heap) = $crate::MEMORY_POOL
315 .with_borrow_mut(|pool| (pool.get_stack(stack_size), pool.get_heap(heap_size)));
316 let vm = $crate::create_vm(
317 $program,
318 $regions,
319 $accounts_metadata,
320 $invoke_context,
321 stack
322 .as_slice_mut()
323 .get_mut(..stack_size)
324 .expect("invalid stack size"),
325 heap.as_slice_mut()
326 .get_mut(..heap_size as usize)
327 .expect("invalid heap size"),
328 );
329 vm.map(|vm| (vm, stack, heap))
330 });
331 };
332}
333
334#[macro_export]
335macro_rules! mock_create_vm {
336 ($vm:ident, $additional_regions:expr, $accounts_metadata:expr, $invoke_context:expr $(,)?) => {
337 let loader = rialo_s_type_overrides::sync::Arc::new(BuiltinProgram::new_mock());
338 let function_registry = solana_sbpf::program::FunctionRegistry::default();
339 let executable = solana_sbpf::elf::Executable::<InvokeContext<'_>>::from_text_bytes(
340 &[0x9D, 0, 0, 0, 0, 0, 0, 0],
341 loader,
342 SBPFVersion::V3,
343 function_registry,
344 )
345 .unwrap();
346 executable
347 .verify::<solana_sbpf::verifier::RequisiteVerifier>()
348 .unwrap();
349 $crate::create_vm!(
350 $vm,
351 &executable,
352 $additional_regions,
353 $accounts_metadata,
354 $invoke_context,
355 );
356 let $vm = $vm.map(|(vm, _, _)| vm);
357 };
358}
359
360fn create_memory_mapping<'a, 'b, C: ContextObject>(
361 executable: &'a Executable<C>,
362 stack: &'b mut [u8],
363 heap: &'b mut [u8],
364 additional_regions: Vec<MemoryRegion>,
365 cow_cb: Option<MemoryCowCallback>,
366) -> Result<MemoryMapping<'a>, Box<dyn std::error::Error>> {
367 let config = executable.get_config();
368 let sbpf_version = executable.get_sbpf_version();
369 let regions: Vec<MemoryRegion> = vec![
370 executable.get_ro_region(),
371 MemoryRegion::new_writable_gapped(
372 stack,
373 ebpf::MM_STACK_START,
374 if !sbpf_version.dynamic_stack_frames() && config.enable_stack_frame_gaps {
375 config.stack_frame_size as u64
376 } else {
377 0
378 },
379 ),
380 MemoryRegion::new_writable(heap, MM_HEAP_START),
381 ]
382 .into_iter()
383 .chain(additional_regions)
384 .collect();
385
386 Ok(if let Some(cow_cb) = cow_cb {
387 MemoryMapping::new_with_cow(regions, cow_cb, config, sbpf_version)?
388 } else {
389 MemoryMapping::new(regions, config, sbpf_version)?
390 })
391}
392
393declare_builtin_function!(
394 Entrypoint,
395 fn rust(
396 invoke_context: &mut InvokeContext<'_>,
397 _arg0: u64,
398 _arg1: u64,
399 _arg2: u64,
400 _arg3: u64,
401 _arg4: u64,
402 _memory_mapping: &mut MemoryMapping<'_>,
403 ) -> Result<u64, Box<dyn std::error::Error>> {
404 process_instruction_inner(invoke_context)
405 }
406);
407
408mod migration_authority {
409 rialo_s_pubkey::declare_id!("3Scf35jMNk2xXBD6areNjgMtXgp5ZspDhms8vdcbzC42");
410}
411
412#[cfg_attr(feature = "svm-internal", qualifiers(pub))]
413pub(crate) fn process_instruction_inner(
414 invoke_context: &mut InvokeContext<'_>,
415) -> Result<u64, Box<dyn std::error::Error>> {
416 let log_collector = invoke_context.get_log_collector();
417 let transaction_context = &invoke_context.transaction_context;
418 let instruction_context = transaction_context.get_current_instruction_context()?;
419 let program_account =
420 instruction_context.try_borrow_last_program_account(transaction_context)?;
421
422 if native_loader::check_id(program_account.get_owner()) {
424 drop(program_account);
425 let program_id = instruction_context.get_last_program_key(transaction_context)?;
426 return if bpf_loader_upgradeable::check_id(program_id) {
427 invoke_context.consume_checked(UPGRADEABLE_LOADER_COMPUTE_UNITS)?;
428 process_loader_upgradeable_instruction(invoke_context)
429 } else if bpf_loader::check_id(program_id) {
430 invoke_context.consume_checked(DEFAULT_LOADER_COMPUTE_UNITS)?;
431 ic_logger_msg!(
432 log_collector,
433 "BPF loader management instructions are no longer supported",
434 );
435 Err(InstructionError::UnsupportedProgramId)
436 } else if bpf_loader_deprecated::check_id(program_id) {
437 invoke_context.consume_checked(DEPRECATED_LOADER_COMPUTE_UNITS)?;
438 ic_logger_msg!(log_collector, "Deprecated loader is no longer supported");
439 Err(InstructionError::UnsupportedProgramId)
440 } else {
441 ic_logger_msg!(log_collector, "Invalid BPF loader id");
442 Err(
443 if invoke_context
444 .get_feature_set()
445 .is_active(&remove_accounts_executable_flag_checks::id())
446 {
447 InstructionError::UnsupportedProgramId
448 } else {
449 InstructionError::IncorrectProgramId
450 },
451 )
452 }
453 .map(|_| 0)
454 .map_err(|error| Box::new(error) as Box<dyn std::error::Error>);
455 }
456
457 #[allow(deprecated)]
459 if !invoke_context
460 .get_feature_set()
461 .is_active(&remove_accounts_executable_flag_checks::id())
462 && !program_account.is_executable()
463 {
464 ic_logger_msg!(log_collector, "Program is not executable");
465 return Err(Box::new(InstructionError::IncorrectProgramId));
466 }
467
468 let mut get_or_create_executor_time = Measure::start("get_or_create_executor_time");
469 let executor = invoke_context
470 .program_cache_for_tx_batch
471 .find(program_account.get_key())
472 .ok_or_else(|| {
473 ic_logger_msg!(log_collector, "Program is not cached");
474 if invoke_context
475 .get_feature_set()
476 .is_active(&remove_accounts_executable_flag_checks::id())
477 {
478 InstructionError::UnsupportedProgramId
479 } else {
480 InstructionError::InvalidAccountData
481 }
482 })?;
483 drop(program_account);
484 get_or_create_executor_time.stop();
485 invoke_context.timings.get_or_create_executor_us += get_or_create_executor_time.as_us();
486
487 executor.ix_usage_counter.fetch_add(1, Ordering::Relaxed);
488 match &executor.program {
489 ProgramCacheEntryType::FailedVerification(_)
490 | ProgramCacheEntryType::Closed
491 | ProgramCacheEntryType::DelayVisibility => {
492 ic_logger_msg!(log_collector, "Program is not deployed");
493 let instruction_error = if invoke_context
494 .get_feature_set()
495 .is_active(&remove_accounts_executable_flag_checks::id())
496 {
497 InstructionError::UnsupportedProgramId
498 } else {
499 InstructionError::InvalidAccountData
500 };
501 Err(Box::new(instruction_error) as Box<dyn std::error::Error>)
502 }
503 ProgramCacheEntryType::Loaded(ExecutableKind::Ebpf(executable)) => {
504 execute(executable, invoke_context)
505 }
506 _ => {
507 let instruction_error = if invoke_context
508 .get_feature_set()
509 .is_active(&remove_accounts_executable_flag_checks::id())
510 {
511 InstructionError::UnsupportedProgramId
512 } else {
513 InstructionError::IncorrectProgramId
514 };
515 Err(Box::new(instruction_error) as Box<dyn std::error::Error>)
516 }
517 }
518 .map(|_| 0)
519}
520
521fn process_loader_upgradeable_instruction(
522 invoke_context: &mut InvokeContext<'_>,
523) -> Result<(), InstructionError> {
524 let log_collector = invoke_context.get_log_collector();
525 let transaction_context = &invoke_context.transaction_context;
526 let instruction_context = transaction_context.get_current_instruction_context()?;
527 let instruction_data = instruction_context.get_instruction_data();
528 let program_id = instruction_context.get_last_program_key(transaction_context)?;
529
530 match limited_deserialize(instruction_data, rialo_s_packet::PACKET_DATA_SIZE as u64)? {
531 UpgradeableLoaderInstruction::InitializeBuffer => {
532 instruction_context.check_number_of_instruction_accounts(2)?;
533 let mut buffer =
534 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
535
536 if UpgradeableLoaderState::Uninitialized != buffer.get_state()? {
537 ic_logger_msg!(log_collector, "Buffer account already initialized");
538 return Err(InstructionError::AccountAlreadyInitialized);
539 }
540
541 let authority_key = Some(*transaction_context.get_key_of_account_at_index(
542 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
543 )?);
544
545 buffer.set_state(&UpgradeableLoaderState::Buffer {
546 authority_address: authority_key,
547 })?;
548 }
549 UpgradeableLoaderInstruction::Write { offset, bytes } => {
550 instruction_context.check_number_of_instruction_accounts(2)?;
551 let buffer =
552 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
553
554 if let UpgradeableLoaderState::Buffer { authority_address } = buffer.get_state()? {
555 if authority_address.is_none() {
556 ic_logger_msg!(log_collector, "Buffer is immutable");
557 return Err(InstructionError::Immutable); }
559 let authority_key = Some(*transaction_context.get_key_of_account_at_index(
560 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
561 )?);
562 if authority_address != authority_key {
563 ic_logger_msg!(log_collector, "Incorrect buffer authority provided");
564 return Err(InstructionError::IncorrectAuthority);
565 }
566 if !instruction_context.is_instruction_account_signer(1)? {
567 ic_logger_msg!(log_collector, "Buffer authority did not sign");
568 return Err(InstructionError::MissingRequiredSignature);
569 }
570 } else {
571 ic_logger_msg!(log_collector, "Invalid Buffer account");
572 return Err(InstructionError::InvalidAccountData);
573 }
574 drop(buffer);
575 write_program_data(
576 UpgradeableLoaderState::size_of_buffer_metadata().saturating_add(offset as usize),
577 &bytes,
578 invoke_context,
579 )?;
580 }
581 UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len } => {
582 if invoke_context
583 .get_feature_set()
584 .is_active(&disable_new_loader_v3_deployments::id())
585 {
586 ic_logger_msg!(log_collector, "Unsupported instruction");
587 return Err(InstructionError::InvalidInstructionData);
588 }
589
590 instruction_context.check_number_of_instruction_accounts(4)?;
591 let payer_key = *transaction_context.get_key_of_account_at_index(
592 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
593 )?;
594 let programdata_key = *transaction_context.get_key_of_account_at_index(
595 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
596 )?;
597 let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 4)?;
598 let clock =
599 get_sysvar_with_account_check::clock(invoke_context, instruction_context, 5)?;
600 instruction_context.check_number_of_instruction_accounts(8)?;
601 let authority_key = Some(*transaction_context.get_key_of_account_at_index(
602 instruction_context.get_index_of_instruction_account_in_transaction(7)?,
603 )?);
604
605 let program =
608 instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
609 if UpgradeableLoaderState::Uninitialized != program.get_state()? {
610 ic_logger_msg!(log_collector, "Program account already initialized");
611 return Err(InstructionError::AccountAlreadyInitialized);
612 }
613 if program.get_data().len() < UpgradeableLoaderState::size_of_program() {
614 ic_logger_msg!(log_collector, "Program account too small");
615 return Err(InstructionError::AccountDataTooSmall);
616 }
617 if program.get_kelvins() < rent.minimum_balance(program.get_data().len()) {
618 ic_logger_msg!(log_collector, "Program account not rent-exempt");
619 return Err(InstructionError::ExecutableAccountNotRentExempt);
620 }
621 let new_program_id = *program.get_key();
622 drop(program);
623
624 let buffer =
627 instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
628 if let UpgradeableLoaderState::Buffer { authority_address } = buffer.get_state()? {
629 if authority_address != authority_key {
630 ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match");
631 return Err(InstructionError::IncorrectAuthority);
632 }
633 if !instruction_context.is_instruction_account_signer(7)? {
634 ic_logger_msg!(log_collector, "Upgrade authority did not sign");
635 return Err(InstructionError::MissingRequiredSignature);
636 }
637 } else {
638 ic_logger_msg!(log_collector, "Invalid Buffer account");
639 return Err(InstructionError::InvalidArgument);
640 }
641 let buffer_key = *buffer.get_key();
642 let buffer_data_offset = UpgradeableLoaderState::size_of_buffer_metadata();
643 let buffer_data_len = buffer.get_data().len().saturating_sub(buffer_data_offset);
644 let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
645 let programdata_len = UpgradeableLoaderState::size_of_programdata(max_data_len);
646 if buffer.get_data().len() < UpgradeableLoaderState::size_of_buffer_metadata()
647 || buffer_data_len == 0
648 {
649 ic_logger_msg!(log_collector, "Buffer account too small");
650 return Err(InstructionError::InvalidAccountData);
651 }
652 drop(buffer);
653 if max_data_len < buffer_data_len {
654 ic_logger_msg!(
655 log_collector,
656 "Max data length is too small to hold Buffer data"
657 );
658 return Err(InstructionError::AccountDataTooSmall);
659 }
660 if programdata_len > MAX_PERMITTED_DATA_LENGTH as usize {
661 ic_logger_msg!(log_collector, "Max data length is too large");
662 return Err(InstructionError::InvalidArgument);
663 }
664
665 let (derived_address, bump_seed) =
667 Pubkey::find_program_address(&[new_program_id.as_ref()], program_id);
668 if derived_address != programdata_key {
669 ic_logger_msg!(log_collector, "ProgramData address is not derived");
670 return Err(InstructionError::InvalidArgument);
671 }
672
673 {
675 let mut buffer =
676 instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
677 let mut payer =
678 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
679 payer.checked_add_kelvins(buffer.get_kelvins())?;
680 buffer.set_kelvins(0)?;
681 }
682
683 let owner_id = *program_id;
684 let mut instruction = system_instruction::create_account(
685 &payer_key,
686 &programdata_key,
687 1.max(rent.minimum_balance(programdata_len)),
688 programdata_len as u64,
689 program_id,
690 );
691
692 instruction
694 .accounts
695 .push(AccountMeta::new(buffer_key, false));
696
697 let transaction_context = &invoke_context.transaction_context;
698 let instruction_context = transaction_context.get_current_instruction_context()?;
699 let caller_program_id =
700 instruction_context.get_last_program_key(transaction_context)?;
701 let signers = [[new_program_id.as_ref(), &[bump_seed]]]
702 .iter()
703 .map(|seeds| Pubkey::create_program_address(seeds, caller_program_id))
704 .collect::<Result<Vec<Pubkey>, rialo_s_pubkey::PubkeyError>>()?;
705 invoke_context.native_invoke(instruction.into(), signers.as_slice())?;
706
707 let transaction_context = &invoke_context.transaction_context;
709 let instruction_context = transaction_context.get_current_instruction_context()?;
710 let buffer =
711 instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
712 deploy_program!(
713 invoke_context,
714 &new_program_id,
715 &owner_id,
716 UpgradeableLoaderState::size_of_program().saturating_add(programdata_len),
717 buffer
718 .get_data()
719 .get(buffer_data_offset..)
720 .ok_or(InstructionError::AccountDataTooSmall)?,
721 clock.slot,
722 );
723 drop(buffer);
724
725 let transaction_context = &invoke_context.transaction_context;
726 let instruction_context = transaction_context.get_current_instruction_context()?;
727
728 {
730 let mut programdata =
731 instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
732 programdata.set_state(&UpgradeableLoaderState::ProgramData {
733 slot: clock.slot,
734 upgrade_authority_address: authority_key,
735 })?;
736 let dst_slice = programdata
737 .get_data_mut()?
738 .get_mut(
739 programdata_data_offset
740 ..programdata_data_offset.saturating_add(buffer_data_len),
741 )
742 .ok_or(InstructionError::AccountDataTooSmall)?;
743 let mut buffer =
744 instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
745 let src_slice = buffer
746 .get_data()
747 .get(buffer_data_offset..)
748 .ok_or(InstructionError::AccountDataTooSmall)?;
749 dst_slice.copy_from_slice(src_slice);
750 buffer.set_data_length(UpgradeableLoaderState::size_of_buffer(0))?;
751 }
752
753 let mut program =
755 instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
756 program.set_state(&UpgradeableLoaderState::Program {
757 programdata_address: programdata_key,
758 })?;
759 program.set_executable(true)?;
760 drop(program);
761
762 ic_logger_msg!(log_collector, "Deployed program {:?}", new_program_id);
763 }
764 UpgradeableLoaderInstruction::Upgrade => {
765 instruction_context.check_number_of_instruction_accounts(3)?;
766 let programdata_key = *transaction_context.get_key_of_account_at_index(
767 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
768 )?;
769 let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 4)?;
770 let clock =
771 get_sysvar_with_account_check::clock(invoke_context, instruction_context, 5)?;
772 instruction_context.check_number_of_instruction_accounts(7)?;
773 let authority_key = Some(*transaction_context.get_key_of_account_at_index(
774 instruction_context.get_index_of_instruction_account_in_transaction(6)?,
775 )?);
776
777 let program =
780 instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
781 #[allow(deprecated)]
782 if !invoke_context
783 .get_feature_set()
784 .is_active(&remove_accounts_executable_flag_checks::id())
785 && !program.is_executable()
786 {
787 ic_logger_msg!(log_collector, "Program account not executable");
788 return Err(InstructionError::AccountNotExecutable);
789 }
790 if !program.is_writable() {
791 ic_logger_msg!(log_collector, "Program account not writeable");
792 return Err(InstructionError::InvalidArgument);
793 }
794 if program.get_owner() != program_id {
795 ic_logger_msg!(log_collector, "Program account not owned by loader");
796 return Err(InstructionError::IncorrectProgramId);
797 }
798 if let UpgradeableLoaderState::Program {
799 programdata_address,
800 } = program.get_state()?
801 {
802 if programdata_address != programdata_key {
803 ic_logger_msg!(log_collector, "Program and ProgramData account mismatch");
804 return Err(InstructionError::InvalidArgument);
805 }
806 } else {
807 ic_logger_msg!(log_collector, "Invalid Program account");
808 return Err(InstructionError::InvalidAccountData);
809 }
810 let new_program_id = *program.get_key();
811 drop(program);
812
813 let buffer =
816 instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
817 if let UpgradeableLoaderState::Buffer { authority_address } = buffer.get_state()? {
818 if authority_address != authority_key {
819 ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match");
820 return Err(InstructionError::IncorrectAuthority);
821 }
822 if !instruction_context.is_instruction_account_signer(6)? {
823 ic_logger_msg!(log_collector, "Upgrade authority did not sign");
824 return Err(InstructionError::MissingRequiredSignature);
825 }
826 } else {
827 ic_logger_msg!(log_collector, "Invalid Buffer account");
828 return Err(InstructionError::InvalidArgument);
829 }
830 let buffer_kelvins = buffer.get_kelvins();
831 let buffer_data_offset = UpgradeableLoaderState::size_of_buffer_metadata();
832 let buffer_data_len = buffer.get_data().len().saturating_sub(buffer_data_offset);
833 if buffer.get_data().len() < UpgradeableLoaderState::size_of_buffer_metadata()
834 || buffer_data_len == 0
835 {
836 ic_logger_msg!(log_collector, "Buffer account too small");
837 return Err(InstructionError::InvalidAccountData);
838 }
839 drop(buffer);
840
841 let programdata =
844 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
845 let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
846 let programdata_balance_required =
847 1.max(rent.minimum_balance(programdata.get_data().len()));
848 if programdata.get_data().len()
849 < UpgradeableLoaderState::size_of_programdata(buffer_data_len)
850 {
851 ic_logger_msg!(log_collector, "ProgramData account not large enough");
852 return Err(InstructionError::AccountDataTooSmall);
853 }
854 if programdata.get_kelvins().saturating_add(buffer_kelvins)
855 < programdata_balance_required
856 {
857 ic_logger_msg!(
858 log_collector,
859 "Buffer account balance too low to fund upgrade"
860 );
861 return Err(InstructionError::InsufficientFunds);
862 }
863 if let UpgradeableLoaderState::ProgramData {
864 slot,
865 upgrade_authority_address,
866 } = programdata.get_state()?
867 {
868 if clock.slot == slot {
869 ic_logger_msg!(log_collector, "Program was deployed in this block already");
870 return Err(InstructionError::InvalidArgument);
871 }
872 if upgrade_authority_address.is_none() {
873 ic_logger_msg!(log_collector, "Program not upgradeable");
874 return Err(InstructionError::Immutable);
875 }
876 if upgrade_authority_address != authority_key {
877 ic_logger_msg!(log_collector, "Incorrect upgrade authority provided");
878 return Err(InstructionError::IncorrectAuthority);
879 }
880 if !instruction_context.is_instruction_account_signer(6)? {
881 ic_logger_msg!(log_collector, "Upgrade authority did not sign");
882 return Err(InstructionError::MissingRequiredSignature);
883 }
884 } else {
885 ic_logger_msg!(log_collector, "Invalid ProgramData account");
886 return Err(InstructionError::InvalidAccountData);
887 };
888 let programdata_len = programdata.get_data().len();
889 drop(programdata);
890
891 let buffer =
893 instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
894 deploy_program!(
895 invoke_context,
896 &new_program_id,
897 program_id,
898 UpgradeableLoaderState::size_of_program().saturating_add(programdata_len),
899 buffer
900 .get_data()
901 .get(buffer_data_offset..)
902 .ok_or(InstructionError::AccountDataTooSmall)?,
903 clock.slot,
904 );
905 drop(buffer);
906
907 let transaction_context = &invoke_context.transaction_context;
908 let instruction_context = transaction_context.get_current_instruction_context()?;
909
910 let mut programdata =
913 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
914 {
915 programdata.set_state(&UpgradeableLoaderState::ProgramData {
916 slot: clock.slot,
917 upgrade_authority_address: authority_key,
918 })?;
919 let dst_slice = programdata
920 .get_data_mut()?
921 .get_mut(
922 programdata_data_offset
923 ..programdata_data_offset.saturating_add(buffer_data_len),
924 )
925 .ok_or(InstructionError::AccountDataTooSmall)?;
926 let buffer =
927 instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
928 let src_slice = buffer
929 .get_data()
930 .get(buffer_data_offset..)
931 .ok_or(InstructionError::AccountDataTooSmall)?;
932 dst_slice.copy_from_slice(src_slice);
933 }
934 programdata
935 .get_data_mut()?
936 .get_mut(programdata_data_offset.saturating_add(buffer_data_len)..)
937 .ok_or(InstructionError::AccountDataTooSmall)?
938 .fill(0);
939
940 let mut buffer =
942 instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
943 let mut spill =
944 instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
945 spill.checked_add_kelvins(
946 programdata
947 .get_kelvins()
948 .saturating_add(buffer_kelvins)
949 .saturating_sub(programdata_balance_required),
950 )?;
951 buffer.set_kelvins(0)?;
952 programdata.set_kelvins(programdata_balance_required)?;
953 buffer.set_data_length(UpgradeableLoaderState::size_of_buffer(0))?;
954
955 ic_logger_msg!(log_collector, "Upgraded program {:?}", new_program_id);
956 }
957 UpgradeableLoaderInstruction::SetAuthority => {
958 instruction_context.check_number_of_instruction_accounts(2)?;
959 let mut account =
960 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
961 let present_authority_key = transaction_context.get_key_of_account_at_index(
962 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
963 )?;
964 let new_authority = instruction_context
965 .get_index_of_instruction_account_in_transaction(2)
966 .and_then(|index_in_transaction| {
967 transaction_context.get_key_of_account_at_index(index_in_transaction)
968 })
969 .ok();
970
971 match account.get_state()? {
972 UpgradeableLoaderState::Buffer { authority_address } => {
973 if new_authority.is_none() {
974 ic_logger_msg!(log_collector, "Buffer authority is not optional");
975 return Err(InstructionError::IncorrectAuthority);
976 }
977 if authority_address.is_none() {
978 ic_logger_msg!(log_collector, "Buffer is immutable");
979 return Err(InstructionError::Immutable);
980 }
981 if authority_address != Some(*present_authority_key) {
982 ic_logger_msg!(log_collector, "Incorrect buffer authority provided");
983 return Err(InstructionError::IncorrectAuthority);
984 }
985 if !instruction_context.is_instruction_account_signer(1)? {
986 ic_logger_msg!(log_collector, "Buffer authority did not sign");
987 return Err(InstructionError::MissingRequiredSignature);
988 }
989 account.set_state(&UpgradeableLoaderState::Buffer {
990 authority_address: new_authority.cloned(),
991 })?;
992 }
993 UpgradeableLoaderState::ProgramData {
994 slot,
995 upgrade_authority_address,
996 } => {
997 if upgrade_authority_address.is_none() {
998 ic_logger_msg!(log_collector, "Program not upgradeable");
999 return Err(InstructionError::Immutable);
1000 }
1001 if upgrade_authority_address != Some(*present_authority_key) {
1002 ic_logger_msg!(log_collector, "Incorrect upgrade authority provided");
1003 return Err(InstructionError::IncorrectAuthority);
1004 }
1005 if !instruction_context.is_instruction_account_signer(1)? {
1006 ic_logger_msg!(log_collector, "Upgrade authority did not sign");
1007 return Err(InstructionError::MissingRequiredSignature);
1008 }
1009 account.set_state(&UpgradeableLoaderState::ProgramData {
1010 slot,
1011 upgrade_authority_address: new_authority.cloned(),
1012 })?;
1013 }
1014 _ => {
1015 ic_logger_msg!(log_collector, "Account does not support authorities");
1016 return Err(InstructionError::InvalidArgument);
1017 }
1018 }
1019
1020 ic_logger_msg!(log_collector, "New authority {:?}", new_authority);
1021 }
1022 UpgradeableLoaderInstruction::SetAuthorityChecked => {
1023 if !invoke_context
1024 .get_feature_set()
1025 .is_active(&enable_bpf_loader_set_authority_checked_ix::id())
1026 {
1027 return Err(InstructionError::InvalidInstructionData);
1028 }
1029
1030 instruction_context.check_number_of_instruction_accounts(3)?;
1031 let mut account =
1032 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
1033 let present_authority_key = transaction_context.get_key_of_account_at_index(
1034 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
1035 )?;
1036 let new_authority_key = transaction_context.get_key_of_account_at_index(
1037 instruction_context.get_index_of_instruction_account_in_transaction(2)?,
1038 )?;
1039
1040 match account.get_state()? {
1041 UpgradeableLoaderState::Buffer { authority_address } => {
1042 if authority_address.is_none() {
1043 ic_logger_msg!(log_collector, "Buffer is immutable");
1044 return Err(InstructionError::Immutable);
1045 }
1046 if authority_address != Some(*present_authority_key) {
1047 ic_logger_msg!(log_collector, "Incorrect buffer authority provided");
1048 return Err(InstructionError::IncorrectAuthority);
1049 }
1050 if !instruction_context.is_instruction_account_signer(1)? {
1051 ic_logger_msg!(log_collector, "Buffer authority did not sign");
1052 return Err(InstructionError::MissingRequiredSignature);
1053 }
1054 if !instruction_context.is_instruction_account_signer(2)? {
1055 ic_logger_msg!(log_collector, "New authority did not sign");
1056 return Err(InstructionError::MissingRequiredSignature);
1057 }
1058 account.set_state(&UpgradeableLoaderState::Buffer {
1059 authority_address: Some(*new_authority_key),
1060 })?;
1061 }
1062 UpgradeableLoaderState::ProgramData {
1063 slot,
1064 upgrade_authority_address,
1065 } => {
1066 if upgrade_authority_address.is_none() {
1067 ic_logger_msg!(log_collector, "Program not upgradeable");
1068 return Err(InstructionError::Immutable);
1069 }
1070 if upgrade_authority_address != Some(*present_authority_key) {
1071 ic_logger_msg!(log_collector, "Incorrect upgrade authority provided");
1072 return Err(InstructionError::IncorrectAuthority);
1073 }
1074 if !instruction_context.is_instruction_account_signer(1)? {
1075 ic_logger_msg!(log_collector, "Upgrade authority did not sign");
1076 return Err(InstructionError::MissingRequiredSignature);
1077 }
1078 if !instruction_context.is_instruction_account_signer(2)? {
1079 ic_logger_msg!(log_collector, "New authority did not sign");
1080 return Err(InstructionError::MissingRequiredSignature);
1081 }
1082 account.set_state(&UpgradeableLoaderState::ProgramData {
1083 slot,
1084 upgrade_authority_address: Some(*new_authority_key),
1085 })?;
1086 }
1087 _ => {
1088 ic_logger_msg!(log_collector, "Account does not support authorities");
1089 return Err(InstructionError::InvalidArgument);
1090 }
1091 }
1092
1093 ic_logger_msg!(log_collector, "New authority {:?}", new_authority_key);
1094 }
1095 UpgradeableLoaderInstruction::Close => {
1096 instruction_context.check_number_of_instruction_accounts(2)?;
1097 if instruction_context.get_index_of_instruction_account_in_transaction(0)?
1098 == instruction_context.get_index_of_instruction_account_in_transaction(1)?
1099 {
1100 ic_logger_msg!(
1101 log_collector,
1102 "Recipient is the same as the account being closed"
1103 );
1104 return Err(InstructionError::InvalidArgument);
1105 }
1106 let mut close_account =
1107 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
1108 let close_key = *close_account.get_key();
1109 let close_account_state = close_account.get_state()?;
1110 close_account.set_data_length(UpgradeableLoaderState::size_of_uninitialized())?;
1111 match close_account_state {
1112 UpgradeableLoaderState::Uninitialized => {
1113 let mut recipient_account = instruction_context
1114 .try_borrow_instruction_account(transaction_context, 1)?;
1115 recipient_account.checked_add_kelvins(close_account.get_kelvins())?;
1116 close_account.set_kelvins(0)?;
1117
1118 ic_logger_msg!(log_collector, "Closed Uninitialized {}", close_key);
1119 }
1120 UpgradeableLoaderState::Buffer { authority_address } => {
1121 instruction_context.check_number_of_instruction_accounts(3)?;
1122 drop(close_account);
1123 common_close_account(
1124 &authority_address,
1125 transaction_context,
1126 instruction_context,
1127 &log_collector,
1128 )?;
1129
1130 ic_logger_msg!(log_collector, "Closed Buffer {}", close_key);
1131 }
1132 UpgradeableLoaderState::ProgramData {
1133 slot,
1134 upgrade_authority_address: authority_address,
1135 } => {
1136 instruction_context.check_number_of_instruction_accounts(4)?;
1137 drop(close_account);
1138 let program_account = instruction_context
1139 .try_borrow_instruction_account(transaction_context, 3)?;
1140 let program_key = *program_account.get_key();
1141
1142 if !program_account.is_writable() {
1143 ic_logger_msg!(log_collector, "Program account is not writable");
1144 return Err(InstructionError::InvalidArgument);
1145 }
1146 if program_account.get_owner() != program_id {
1147 ic_logger_msg!(log_collector, "Program account not owned by loader");
1148 return Err(InstructionError::IncorrectProgramId);
1149 }
1150 let clock = invoke_context.get_sysvar_cache().get_clock()?;
1151 if clock.slot == slot {
1152 ic_logger_msg!(log_collector, "Program was deployed in this block already");
1153 return Err(InstructionError::InvalidArgument);
1154 }
1155
1156 match program_account.get_state()? {
1157 UpgradeableLoaderState::Program {
1158 programdata_address,
1159 } => {
1160 if programdata_address != close_key {
1161 ic_logger_msg!(
1162 log_collector,
1163 "ProgramData account does not match ProgramData account"
1164 );
1165 return Err(InstructionError::InvalidArgument);
1166 }
1167
1168 drop(program_account);
1169 common_close_account(
1170 &authority_address,
1171 transaction_context,
1172 instruction_context,
1173 &log_collector,
1174 )?;
1175 let clock = invoke_context.get_sysvar_cache().get_clock()?;
1176 invoke_context
1177 .program_cache_for_tx_batch
1178 .store_modified_entry(
1179 program_key,
1180 Arc::new(ProgramCacheEntry::new_tombstone(
1181 clock.slot,
1182 ProgramCacheEntryOwner::LoaderV3,
1183 ProgramCacheEntryType::Closed,
1184 )),
1185 );
1186 }
1187 _ => {
1188 ic_logger_msg!(log_collector, "Invalid Program account");
1189 return Err(InstructionError::InvalidArgument);
1190 }
1191 }
1192
1193 ic_logger_msg!(log_collector, "Closed Program {}", program_key);
1194 }
1195 _ => {
1196 ic_logger_msg!(log_collector, "Account does not support closing");
1197 return Err(InstructionError::InvalidArgument);
1198 }
1199 }
1200 }
1201 UpgradeableLoaderInstruction::ExtendProgram { additional_bytes } => {
1202 if additional_bytes == 0 {
1203 ic_logger_msg!(log_collector, "Additional bytes must be greater than 0");
1204 return Err(InstructionError::InvalidInstructionData);
1205 }
1206
1207 const PROGRAM_DATA_ACCOUNT_INDEX: IndexOfAccount = 0;
1208 const PROGRAM_ACCOUNT_INDEX: IndexOfAccount = 1;
1209 #[allow(dead_code)]
1210 const OPTIONAL_SYSTEM_PROGRAM_ACCOUNT_INDEX: IndexOfAccount = 2;
1212 const OPTIONAL_PAYER_ACCOUNT_INDEX: IndexOfAccount = 3;
1213
1214 let programdata_account = instruction_context
1215 .try_borrow_instruction_account(transaction_context, PROGRAM_DATA_ACCOUNT_INDEX)?;
1216 let programdata_key = *programdata_account.get_key();
1217
1218 if program_id != programdata_account.get_owner() {
1219 ic_logger_msg!(log_collector, "ProgramData owner is invalid");
1220 return Err(InstructionError::InvalidAccountOwner);
1221 }
1222 if !programdata_account.is_writable() {
1223 ic_logger_msg!(log_collector, "ProgramData is not writable");
1224 return Err(InstructionError::InvalidArgument);
1225 }
1226
1227 let program_account = instruction_context
1228 .try_borrow_instruction_account(transaction_context, PROGRAM_ACCOUNT_INDEX)?;
1229 if !program_account.is_writable() {
1230 ic_logger_msg!(log_collector, "Program account is not writable");
1231 return Err(InstructionError::InvalidArgument);
1232 }
1233 if program_account.get_owner() != program_id {
1234 ic_logger_msg!(log_collector, "Program account not owned by loader");
1235 return Err(InstructionError::InvalidAccountOwner);
1236 }
1237 let program_key = *program_account.get_key();
1238 match program_account.get_state()? {
1239 UpgradeableLoaderState::Program {
1240 programdata_address,
1241 } => {
1242 if programdata_address != programdata_key {
1243 ic_logger_msg!(
1244 log_collector,
1245 "Program account does not match ProgramData account"
1246 );
1247 return Err(InstructionError::InvalidArgument);
1248 }
1249 }
1250 _ => {
1251 ic_logger_msg!(log_collector, "Invalid Program account");
1252 return Err(InstructionError::InvalidAccountData);
1253 }
1254 }
1255 drop(program_account);
1256
1257 let old_len = programdata_account.get_data().len();
1258 let new_len = old_len.saturating_add(additional_bytes as usize);
1259 if new_len > MAX_PERMITTED_DATA_LENGTH as usize {
1260 ic_logger_msg!(
1261 log_collector,
1262 "Extended ProgramData length of {} bytes exceeds max account data length of {} bytes",
1263 new_len,
1264 MAX_PERMITTED_DATA_LENGTH
1265 );
1266 return Err(InstructionError::InvalidRealloc);
1267 }
1268
1269 let clock_slot = invoke_context
1270 .get_sysvar_cache()
1271 .get_clock()
1272 .map(|clock| clock.slot)?;
1273
1274 let upgrade_authority_address = if let UpgradeableLoaderState::ProgramData {
1275 slot,
1276 upgrade_authority_address,
1277 } = programdata_account.get_state()?
1278 {
1279 if clock_slot == slot {
1280 ic_logger_msg!(log_collector, "Program was extended in this block already");
1281 return Err(InstructionError::InvalidArgument);
1282 }
1283
1284 if upgrade_authority_address.is_none() {
1285 ic_logger_msg!(
1286 log_collector,
1287 "Cannot extend ProgramData accounts that are not upgradeable"
1288 );
1289 return Err(InstructionError::Immutable);
1290 }
1291 upgrade_authority_address
1292 } else {
1293 ic_logger_msg!(log_collector, "ProgramData state is invalid");
1294 return Err(InstructionError::InvalidAccountData);
1295 };
1296
1297 let required_payment = {
1298 let balance = programdata_account.get_kelvins();
1299 let rent = invoke_context.get_sysvar_cache().get_rent()?;
1300 let min_balance = rent.minimum_balance(new_len).max(1);
1301 min_balance.saturating_sub(balance)
1302 };
1303
1304 drop(programdata_account);
1306
1307 let program_id = *program_id;
1309 if required_payment > 0 {
1310 let payer_key = *transaction_context.get_key_of_account_at_index(
1311 instruction_context.get_index_of_instruction_account_in_transaction(
1312 OPTIONAL_PAYER_ACCOUNT_INDEX,
1313 )?,
1314 )?;
1315
1316 invoke_context.native_invoke(
1317 system_instruction::transfer(&payer_key, &programdata_key, required_payment)
1318 .into(),
1319 &[],
1320 )?;
1321 }
1322
1323 let transaction_context = &invoke_context.transaction_context;
1324 let instruction_context = transaction_context.get_current_instruction_context()?;
1325 let mut programdata_account = instruction_context
1326 .try_borrow_instruction_account(transaction_context, PROGRAM_DATA_ACCOUNT_INDEX)?;
1327 programdata_account.set_data_length(new_len)?;
1328
1329 let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
1330
1331 deploy_program!(
1332 invoke_context,
1333 &program_key,
1334 &program_id,
1335 UpgradeableLoaderState::size_of_program().saturating_add(new_len),
1336 programdata_account
1337 .get_data()
1338 .get(programdata_data_offset..)
1339 .ok_or(InstructionError::AccountDataTooSmall)?,
1340 clock_slot,
1341 );
1342 drop(programdata_account);
1343
1344 let mut programdata_account = instruction_context
1345 .try_borrow_instruction_account(transaction_context, PROGRAM_DATA_ACCOUNT_INDEX)?;
1346 programdata_account.set_state(&UpgradeableLoaderState::ProgramData {
1347 slot: clock_slot,
1348 upgrade_authority_address,
1349 })?;
1350
1351 ic_logger_msg!(
1352 log_collector,
1353 "Extended ProgramData account by {} bytes",
1354 additional_bytes
1355 );
1356 }
1357 UpgradeableLoaderInstruction::Migrate => {
1358 if !invoke_context
1359 .get_feature_set()
1360 .is_active(&enable_loader_v4::id())
1361 {
1362 return Err(InstructionError::InvalidInstructionData);
1363 }
1364
1365 instruction_context.check_number_of_instruction_accounts(3)?;
1366 let programdata_address = *transaction_context.get_key_of_account_at_index(
1367 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
1368 )?;
1369 let program_address = *transaction_context.get_key_of_account_at_index(
1370 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
1371 )?;
1372 let provided_authority_address = *transaction_context.get_key_of_account_at_index(
1373 instruction_context.get_index_of_instruction_account_in_transaction(2)?,
1374 )?;
1375 let clock_slot = invoke_context
1376 .get_sysvar_cache()
1377 .get_clock()
1378 .map(|clock| clock.slot)?;
1379
1380 let programdata =
1382 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
1383 if !programdata.is_writable() {
1384 ic_logger_msg!(log_collector, "ProgramData account not writeable");
1385 return Err(InstructionError::InvalidArgument);
1386 }
1387 let (program_len, upgrade_authority_address) =
1388 if let Ok(UpgradeableLoaderState::ProgramData {
1389 slot,
1390 upgrade_authority_address,
1391 }) = programdata.get_state()
1392 {
1393 if clock_slot == slot {
1394 ic_logger_msg!(log_collector, "Program was deployed in this block already");
1395 return Err(InstructionError::InvalidArgument);
1396 }
1397 (
1398 programdata
1399 .get_data()
1400 .len()
1401 .saturating_sub(UpgradeableLoaderState::size_of_programdata_metadata()),
1402 upgrade_authority_address,
1403 )
1404 } else {
1405 (0, None)
1406 };
1407 let programdata_funds = programdata.get_kelvins();
1408 drop(programdata);
1409
1410 if !migration_authority::check_id(&provided_authority_address)
1412 && provided_authority_address
1413 != upgrade_authority_address.unwrap_or(program_address)
1414 {
1415 ic_logger_msg!(log_collector, "Incorrect migration authority provided");
1416 return Err(InstructionError::IncorrectAuthority);
1417 }
1418 if !instruction_context.is_instruction_account_signer(2)? {
1419 ic_logger_msg!(log_collector, "Migration authority did not sign");
1420 return Err(InstructionError::MissingRequiredSignature);
1421 }
1422
1423 let mut program =
1425 instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
1426 if !program.is_writable() {
1427 ic_logger_msg!(log_collector, "Program account not writeable");
1428 return Err(InstructionError::InvalidArgument);
1429 }
1430 if program.get_owner() != program_id {
1431 ic_logger_msg!(log_collector, "Program account not owned by loader");
1432 return Err(InstructionError::IncorrectProgramId);
1433 }
1434 if let UpgradeableLoaderState::Program {
1435 programdata_address: stored_programdata_address,
1436 } = program.get_state()?
1437 {
1438 if programdata_address != stored_programdata_address {
1439 ic_logger_msg!(log_collector, "Program and ProgramData account mismatch");
1440 return Err(InstructionError::InvalidArgument);
1441 }
1442 } else {
1443 ic_logger_msg!(log_collector, "Invalid Program account");
1444 return Err(InstructionError::InvalidAccountData);
1445 }
1446 program.set_data_from_slice(&[])?;
1447 program.checked_add_kelvins(programdata_funds)?;
1448 if program_len == 0 {
1449 program.set_owner(&system_program::id().to_bytes())?;
1450 } else {
1451 program.set_owner(&loader_v4::id().to_bytes())?;
1452 }
1453 drop(program);
1454
1455 let mut programdata =
1456 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
1457 programdata.set_kelvins(0)?;
1458 drop(programdata);
1459
1460 if program_len > 0 {
1461 invoke_context.native_invoke(
1462 rialo_s_loader_v4_interface::instruction::set_program_length(
1463 &program_address,
1464 &provided_authority_address,
1465 program_len as u32,
1466 &program_address,
1467 )
1468 .into(),
1469 &[],
1470 )?;
1471
1472 invoke_context.native_invoke(
1473 rialo_s_loader_v4_interface::instruction::copy(
1474 &program_address,
1475 &provided_authority_address,
1476 &programdata_address,
1477 0,
1478 0,
1479 program_len as u32,
1480 )
1481 .into(),
1482 &[],
1483 )?;
1484
1485 invoke_context.native_invoke(
1486 rialo_s_loader_v4_interface::instruction::deploy(
1487 &program_address,
1488 &provided_authority_address,
1489 )
1490 .into(),
1491 &[],
1492 )?;
1493
1494 match upgrade_authority_address {
1495 None => {
1496 invoke_context.native_invoke(
1497 rialo_s_loader_v4_interface::instruction::finalize(
1498 &program_address,
1499 &provided_authority_address,
1500 &program_address,
1501 )
1502 .into(),
1503 &[],
1504 )?;
1505 }
1506 Some(authority)
1507 if migration_authority::check_id(&provided_authority_address) =>
1508 {
1509 invoke_context.native_invoke(
1510 rialo_s_loader_v4_interface::instruction::transfer_authority(
1511 &program_address,
1512 &provided_authority_address,
1513 &authority,
1514 )
1515 .into(),
1516 &[],
1517 )?;
1518 }
1519 Some(_) => {}
1520 }
1521 }
1522
1523 let transaction_context = &invoke_context.transaction_context;
1524 let instruction_context = transaction_context.get_current_instruction_context()?;
1525 let mut programdata =
1526 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
1527 programdata.set_data_from_slice(&[])?;
1528 programdata.set_owner(&system_program::id().to_bytes())?;
1529 drop(programdata);
1530
1531 ic_logger_msg!(log_collector, "Migrated program {:?}", &program_address);
1532 }
1533 }
1534
1535 Ok(())
1536}
1537
1538fn common_close_account(
1539 authority_address: &Option<Pubkey>,
1540 transaction_context: &TransactionContext,
1541 instruction_context: &InstructionContext,
1542 log_collector: &Option<Rc<RefCell<LogCollector>>>,
1543) -> Result<(), InstructionError> {
1544 if authority_address.is_none() {
1545 ic_logger_msg!(log_collector, "Account is immutable");
1546 return Err(InstructionError::Immutable);
1547 }
1548 if *authority_address
1549 != Some(*transaction_context.get_key_of_account_at_index(
1550 instruction_context.get_index_of_instruction_account_in_transaction(2)?,
1551 )?)
1552 {
1553 ic_logger_msg!(log_collector, "Incorrect authority provided");
1554 return Err(InstructionError::IncorrectAuthority);
1555 }
1556 if !instruction_context.is_instruction_account_signer(2)? {
1557 ic_logger_msg!(log_collector, "Authority did not sign");
1558 return Err(InstructionError::MissingRequiredSignature);
1559 }
1560
1561 let mut close_account =
1562 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
1563 let mut recipient_account =
1564 instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
1565
1566 recipient_account.checked_add_kelvins(close_account.get_kelvins())?;
1567 close_account.set_kelvins(0)?;
1568 close_account.set_state(&UpgradeableLoaderState::Uninitialized)?;
1569 Ok(())
1570}
1571
1572#[cfg_attr(feature = "svm-internal", qualifiers(pub))]
1573fn execute<'a, 'b: 'a>(
1574 executable: &'a Executable<InvokeContext<'static>>,
1575 invoke_context: &'a mut InvokeContext<'b>,
1576) -> Result<(), Box<dyn std::error::Error>> {
1577 let executable = unsafe {
1580 mem::transmute::<&'a Executable<InvokeContext<'static>>, &'a Executable<InvokeContext<'b>>>(
1581 executable,
1582 )
1583 };
1584 let log_collector = invoke_context.get_log_collector();
1585 let transaction_context = &invoke_context.transaction_context;
1586 let instruction_context = transaction_context.get_current_instruction_context()?;
1587 let (program_id, is_loader_deprecated) = {
1588 let program_account =
1589 instruction_context.try_borrow_last_program_account(transaction_context)?;
1590 (
1591 *program_account.get_key(),
1592 *program_account.get_owner() == bpf_loader_deprecated::id(),
1593 )
1594 };
1595 #[cfg(any(target_os = "windows", not(target_arch = "x86_64")))]
1596 let use_jit = false;
1597 #[cfg(all(not(target_os = "windows"), target_arch = "x86_64"))]
1598 let use_jit = executable.get_compiled_program().is_some();
1599 let direct_mapping = invoke_context
1600 .get_feature_set()
1601 .is_active(&bpf_account_data_direct_mapping::id());
1602
1603 let mut serialize_time = Measure::start("serialize");
1604 let (parameter_bytes, regions, accounts_metadata) = serialization::serialize_parameters(
1605 invoke_context.transaction_context,
1606 instruction_context,
1607 !direct_mapping,
1608 )?;
1609 serialize_time.stop();
1610
1611 let account_region_addrs = accounts_metadata
1614 .iter()
1615 .map(|m| {
1616 let vm_end = m
1617 .vm_data_addr
1618 .saturating_add(m.original_data_len as u64)
1619 .saturating_add(if !is_loader_deprecated {
1620 MAX_PERMITTED_DATA_INCREASE as u64
1621 } else {
1622 0
1623 });
1624 m.vm_data_addr..vm_end
1625 })
1626 .collect::<Vec<_>>();
1627
1628 let mut create_vm_time = Measure::start("create_vm");
1629 let execution_result = {
1630 let compute_meter_prev = invoke_context.get_remaining();
1631 create_vm!(vm, executable, regions, accounts_metadata, invoke_context);
1632 let (mut vm, stack, heap) = match vm {
1633 Ok(info) => info,
1634 Err(e) => {
1635 ic_logger_msg!(log_collector, "Failed to create SBF VM: {}", e);
1636 return Err(Box::new(InstructionError::ProgramEnvironmentSetupFailure));
1637 }
1638 };
1639 create_vm_time.stop();
1640
1641 vm.context_object_pointer.execute_time = Some(Measure::start("execute"));
1642 let (compute_units_consumed, result) = vm.execute_program(executable, !use_jit);
1643 MEMORY_POOL.with_borrow_mut(|memory_pool| {
1644 memory_pool.put_stack(stack);
1645 memory_pool.put_heap(heap);
1646 debug_assert!(memory_pool.stack_len() <= MAX_INSTRUCTION_STACK_DEPTH);
1647 debug_assert!(memory_pool.heap_len() <= MAX_INSTRUCTION_STACK_DEPTH);
1648 });
1649 drop(vm);
1650 if let Some(execute_time) = invoke_context.execute_time.as_mut() {
1651 execute_time.stop();
1652 invoke_context.timings.execute_us += execute_time.as_us();
1653 }
1654
1655 ic_logger_msg!(
1656 log_collector,
1657 "Program {} consumed {} of {} compute units",
1658 &program_id,
1659 compute_units_consumed,
1660 compute_meter_prev
1661 );
1662 let (_returned_from_program_id, return_data) =
1663 invoke_context.transaction_context.get_return_data();
1664 if !return_data.is_empty() {
1665 stable_log::program_return(&log_collector, &program_id, return_data);
1666 }
1667 match result {
1668 ProgramResult::Ok(status) if status != SUCCESS => {
1669 let error: InstructionError = status.into();
1670 Err(Box::new(error) as Box<dyn std::error::Error>)
1671 }
1672 ProgramResult::Err(mut error) => {
1673 if invoke_context
1674 .get_feature_set()
1675 .is_active(&rialo_s_feature_set::deplete_cu_meter_on_vm_failure::id())
1676 && !matches!(error, EbpfError::SyscallError(_))
1677 {
1678 invoke_context.consume(invoke_context.get_remaining());
1689 }
1690
1691 if direct_mapping {
1692 if let EbpfError::AccessViolation(
1693 AccessType::Store,
1694 address,
1695 _size,
1696 _section_name,
1697 ) = error
1698 {
1699 if let Some((instruction_account_index, _)) = account_region_addrs
1703 .iter()
1704 .enumerate()
1705 .find(|(_, vm_region)| vm_region.contains(&address))
1706 {
1707 let transaction_context = &invoke_context.transaction_context;
1708 let instruction_context =
1709 transaction_context.get_current_instruction_context()?;
1710
1711 let account = instruction_context.try_borrow_instruction_account(
1712 transaction_context,
1713 instruction_account_index as IndexOfAccount,
1714 )?;
1715
1716 error = EbpfError::SyscallError(Box::new(
1717 #[allow(deprecated)]
1718 if !invoke_context
1719 .get_feature_set()
1720 .is_active(&remove_accounts_executable_flag_checks::id())
1721 && account.is_executable()
1722 {
1723 InstructionError::ExecutableDataModified
1724 } else if account.is_writable() {
1725 InstructionError::ExternalAccountDataModified
1726 } else {
1727 InstructionError::ReadonlyDataModified
1728 },
1729 ));
1730 }
1731 }
1732 }
1733 Err(if let EbpfError::SyscallError(err) = error {
1734 err
1735 } else {
1736 error.into()
1737 })
1738 }
1739 _ => Ok(()),
1740 }
1741 };
1742
1743 fn deserialize_parameters(
1744 invoke_context: &mut InvokeContext<'_>,
1745 parameter_bytes: &[u8],
1746 copy_account_data: bool,
1747 ) -> Result<(), InstructionError> {
1748 serialization::deserialize_parameters(
1749 invoke_context.transaction_context,
1750 invoke_context
1751 .transaction_context
1752 .get_current_instruction_context()?,
1753 copy_account_data,
1754 parameter_bytes,
1755 &invoke_context.get_syscall_context()?.accounts_metadata,
1756 )
1757 }
1758
1759 let mut deserialize_time = Measure::start("deserialize");
1760 let execute_or_deserialize_result = execution_result.and_then(|_| {
1761 deserialize_parameters(invoke_context, parameter_bytes.as_slice(), !direct_mapping)
1762 .map_err(|error| Box::new(error) as Box<dyn std::error::Error>)
1763 });
1764 deserialize_time.stop();
1765
1766 invoke_context.timings.serialize_us += serialize_time.as_us();
1768 invoke_context.timings.create_vm_us += create_vm_time.as_us();
1769 invoke_context.timings.deserialize_us += deserialize_time.as_us();
1770
1771 execute_or_deserialize_result
1772}
1773
1774#[cfg_attr(feature = "svm-internal", qualifiers(pub))]
1775mod test_utils {
1776 #[cfg(any(test, feature = "svm-internal"))]
1777 use {
1778 super::*, crate::syscalls::create_program_runtime_environment_v1,
1779 rialo_s_account::ReadableAccount, rialo_s_loader_v4_interface::state::LoaderV4State,
1780 rialo_s_program_runtime::loaded_programs::DELAY_VISIBILITY_SLOT_OFFSET,
1781 rialo_s_sdk_ids::loader_v4,
1782 };
1783
1784 #[cfg(any(test, feature = "svm-internal"))]
1785 fn check_loader_id(id: &Pubkey) -> bool {
1786 bpf_loader::check_id(id)
1787 || bpf_loader_deprecated::check_id(id)
1788 || bpf_loader_upgradeable::check_id(id)
1789 || loader_v4::check_id(id)
1790 }
1791
1792 #[cfg(any(test, feature = "svm-internal"))]
1793 pub fn load_all_invoked_programs(invoke_context: &mut InvokeContext<'_>) {
1794 let mut load_program_metrics = LoadProgramMetrics::default();
1795 let program_runtime_environment = create_program_runtime_environment_v1(
1796 invoke_context.get_feature_set(),
1797 invoke_context.get_compute_budget(),
1798 false, false, );
1801 let program_runtime_environment = Arc::new(program_runtime_environment.unwrap());
1802 let num_accounts = invoke_context.transaction_context.get_number_of_accounts();
1803 for index in 0..num_accounts {
1804 let account = invoke_context
1805 .transaction_context
1806 .get_account_at_index(index)
1807 .expect("Failed to get the account")
1808 .borrow();
1809
1810 let owner = account.owner();
1811 if check_loader_id(owner) {
1812 let programdata_data_offset = if loader_v4::check_id(owner) {
1813 LoaderV4State::program_data_offset()
1814 } else {
1815 0
1816 };
1817 let pubkey = invoke_context
1818 .transaction_context
1819 .get_key_of_account_at_index(index)
1820 .expect("Failed to get account key");
1821
1822 if let Ok(loaded_program) = load_program_from_bytes(
1823 None,
1824 &mut load_program_metrics,
1825 account
1826 .data()
1827 .get(programdata_data_offset.min(account.data().len())..)
1828 .unwrap(),
1829 owner,
1830 account.data().len(),
1831 0,
1832 program_runtime_environment.clone(),
1833 false,
1834 ) {
1835 invoke_context
1836 .program_cache_for_tx_batch
1837 .set_slot_for_tests(DELAY_VISIBILITY_SLOT_OFFSET);
1838 invoke_context
1839 .program_cache_for_tx_batch
1840 .store_modified_entry(*pubkey, Arc::new(loaded_program));
1841 }
1842 }
1843 }
1844 }
1845}
1846
1847#[cfg(test)]
1848mod tests {
1849 use std::{fs::File, io::Read, ops::Range, sync::atomic::AtomicU64};
1850
1851 use assert_matches::assert_matches;
1852 use rand::Rng;
1853 use rialo_s_account::{
1854 create_account_shared_data_for_test as create_account_for_test, state_traits::StateMut,
1855 AccountSharedData, ReadableAccount, StoredAccount, WritableAccount,
1856 };
1857 use rialo_s_clock::Clock;
1858 use rialo_s_epoch_schedule::EpochSchedule;
1859 use rialo_s_instruction::{error::InstructionError, AccountMeta};
1860 use rialo_s_program_runtime::{
1861 invoke_context::mock_process_instruction, with_mock_invoke_context,
1862 };
1863 use rialo_s_pubkey::Pubkey;
1864 use rialo_s_rent::Rent;
1865 use rialo_s_sdk_ids::sysvar;
1866
1867 use super::*;
1868
1869 fn process_instruction(
1870 loader_id: &Pubkey,
1871 program_indices: &[IndexOfAccount],
1872 instruction_data: &[u8],
1873 transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
1874 instruction_accounts: Vec<AccountMeta>,
1875 expected_result: Result<(), InstructionError>,
1876 ) -> Vec<StoredAccount> {
1877 mock_process_instruction(
1878 loader_id,
1879 program_indices.to_vec(),
1880 instruction_data,
1881 transaction_accounts
1882 .into_iter()
1883 .map(|(k, v)| (k, StoredAccount::from(v)))
1884 .collect(),
1885 instruction_accounts,
1886 expected_result,
1887 Entrypoint::vm,
1888 |invoke_context| {
1889 let mut feature_set = invoke_context.get_feature_set().clone();
1890 feature_set.deactivate(&disable_new_loader_v3_deployments::id());
1891 invoke_context.mock_set_feature_set(Arc::new(feature_set));
1892 test_utils::load_all_invoked_programs(invoke_context);
1893 },
1894 |_invoke_context| {},
1895 )
1896 }
1897
1898 fn load_program_account_from_elf(loader_id: &Pubkey, path: &str) -> AccountSharedData {
1899 let mut file = File::open(path).expect("file open failed");
1900 let mut elf = Vec::new();
1901 file.read_to_end(&mut elf).unwrap();
1902 let rent = Rent::default();
1903 let mut program_account =
1904 AccountSharedData::new(rent.minimum_balance(elf.len()), 0, loader_id);
1905 program_account.set_data(elf);
1906 program_account
1907 }
1908
1909 #[test]
1910 fn test_bpf_loader_invoke_main() {
1911 let loader_id = bpf_loader::id();
1912 let program_id = Pubkey::new_unique();
1913 let program_account =
1914 load_program_account_from_elf(&loader_id, "test_elfs/out/sbpfv3_return_ok.so");
1915 let parameter_id = Pubkey::new_unique();
1916 let parameter_account = AccountSharedData::new(1, 0, &loader_id);
1917 let parameter_meta = AccountMeta {
1918 pubkey: parameter_id,
1919 is_signer: false,
1920 is_writable: false,
1921 };
1922
1923 process_instruction(
1925 &loader_id,
1926 &[],
1927 &[],
1928 Vec::new(),
1929 Vec::new(),
1930 Err(InstructionError::UnsupportedProgramId),
1931 );
1932
1933 process_instruction(
1935 &loader_id,
1936 &[0],
1937 &[],
1938 vec![(program_id, program_account.clone())],
1939 Vec::new(),
1940 Ok(()),
1941 );
1942
1943 process_instruction(
1945 &loader_id,
1946 &[0],
1947 &[],
1948 vec![
1949 (program_id, program_account.clone()),
1950 (parameter_id, parameter_account.clone()),
1951 ],
1952 vec![parameter_meta.clone()],
1953 Ok(()),
1954 );
1955
1956 process_instruction(
1958 &loader_id,
1959 &[0],
1960 &[],
1961 vec![
1962 (program_id, program_account.clone()),
1963 (parameter_id, parameter_account.clone()),
1964 ],
1965 vec![parameter_meta.clone(), parameter_meta],
1966 Ok(()),
1967 );
1968
1969 mock_process_instruction(
1971 &loader_id,
1972 vec![0],
1973 &[],
1974 vec![(program_id, StoredAccount::from(program_account))],
1975 Vec::new(),
1976 Err(InstructionError::ProgramFailedToComplete),
1977 Entrypoint::vm,
1978 |invoke_context| {
1979 invoke_context.mock_set_remaining(0);
1980 test_utils::load_all_invoked_programs(invoke_context);
1981 },
1982 |_invoke_context| {},
1983 );
1984
1985 mock_process_instruction(
1987 &loader_id,
1988 vec![0],
1989 &[],
1990 vec![(program_id, StoredAccount::from(parameter_account.clone()))],
1991 Vec::new(),
1992 Err(InstructionError::IncorrectProgramId),
1993 Entrypoint::vm,
1994 |invoke_context| {
1995 let mut feature_set = invoke_context.get_feature_set().clone();
1996 feature_set.deactivate(&remove_accounts_executable_flag_checks::id());
1997 invoke_context.mock_set_feature_set(Arc::new(feature_set));
1998 test_utils::load_all_invoked_programs(invoke_context);
1999 },
2000 |_invoke_context| {},
2001 );
2002 process_instruction(
2003 &loader_id,
2004 &[0],
2005 &[],
2006 vec![(program_id, parameter_account)],
2007 Vec::new(),
2008 Err(InstructionError::UnsupportedProgramId),
2009 );
2010 }
2011
2012 #[test]
2013 fn test_bpf_loader_serialize_unaligned() {
2014 let loader_id = bpf_loader_deprecated::id();
2015 let program_id = Pubkey::new_unique();
2016 let program_account =
2017 load_program_account_from_elf(&loader_id, "test_elfs/out/noop_unaligned.so");
2018 let parameter_id = Pubkey::new_unique();
2019 let parameter_account = AccountSharedData::new(1, 0, &loader_id);
2020 let parameter_meta = AccountMeta {
2021 pubkey: parameter_id,
2022 is_signer: false,
2023 is_writable: false,
2024 };
2025
2026 process_instruction(
2028 &loader_id,
2029 &[0],
2030 &[],
2031 vec![
2032 (program_id, program_account.clone()),
2033 (parameter_id, parameter_account.clone()),
2034 ],
2035 vec![parameter_meta.clone()],
2036 Ok(()),
2037 );
2038
2039 process_instruction(
2041 &loader_id,
2042 &[0],
2043 &[],
2044 vec![
2045 (program_id, program_account),
2046 (parameter_id, parameter_account),
2047 ],
2048 vec![parameter_meta.clone(), parameter_meta],
2049 Ok(()),
2050 );
2051 }
2052
2053 #[test]
2054 fn test_bpf_loader_serialize_aligned() {
2055 let loader_id = bpf_loader::id();
2056 let program_id = Pubkey::new_unique();
2057 let program_account =
2058 load_program_account_from_elf(&loader_id, "test_elfs/out/noop_aligned.so");
2059 let parameter_id = Pubkey::new_unique();
2060 let parameter_account = AccountSharedData::new(1, 0, &loader_id);
2061 let parameter_meta = AccountMeta {
2062 pubkey: parameter_id,
2063 is_signer: false,
2064 is_writable: false,
2065 };
2066
2067 process_instruction(
2069 &loader_id,
2070 &[0],
2071 &[],
2072 vec![
2073 (program_id, program_account.clone()),
2074 (parameter_id, parameter_account.clone()),
2075 ],
2076 vec![parameter_meta.clone()],
2077 Ok(()),
2078 );
2079
2080 process_instruction(
2082 &loader_id,
2083 &[0],
2084 &[],
2085 vec![
2086 (program_id, program_account),
2087 (parameter_id, parameter_account),
2088 ],
2089 vec![parameter_meta.clone(), parameter_meta],
2090 Ok(()),
2091 );
2092 }
2093
2094 #[test]
2095 fn test_bpf_loader_upgradeable_initialize_buffer() {
2096 let loader_id = bpf_loader_upgradeable::id();
2097 let buffer_address = Pubkey::new_unique();
2098 let buffer_account =
2099 AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
2100 let authority_address = Pubkey::new_unique();
2101 let authority_account =
2102 AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
2103 let instruction_data =
2104 bincode::serialize(&UpgradeableLoaderInstruction::InitializeBuffer).unwrap();
2105 let instruction_accounts = vec![
2106 AccountMeta {
2107 pubkey: buffer_address,
2108 is_signer: false,
2109 is_writable: true,
2110 },
2111 AccountMeta {
2112 pubkey: authority_address,
2113 is_signer: false,
2114 is_writable: false,
2115 },
2116 ];
2117
2118 let accounts = process_instruction(
2120 &loader_id,
2121 &[],
2122 &instruction_data,
2123 vec![
2124 (buffer_address, buffer_account),
2125 (authority_address, authority_account),
2126 ],
2127 instruction_accounts.clone(),
2128 Ok(()),
2129 );
2130 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
2131 assert_eq!(
2132 state,
2133 UpgradeableLoaderState::Buffer {
2134 authority_address: Some(authority_address)
2135 }
2136 );
2137
2138 let accounts = process_instruction(
2140 &loader_id,
2141 &[],
2142 &instruction_data,
2143 vec![
2144 (buffer_address, accounts.first().unwrap().clone().into()),
2145 (authority_address, accounts.get(1).unwrap().clone().into()),
2146 ],
2147 instruction_accounts,
2148 Err(InstructionError::AccountAlreadyInitialized),
2149 );
2150 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
2151 assert_eq!(
2152 state,
2153 UpgradeableLoaderState::Buffer {
2154 authority_address: Some(authority_address)
2155 }
2156 );
2157 }
2158
2159 #[test]
2160 fn test_bpf_loader_upgradeable_write() {
2161 let loader_id = bpf_loader_upgradeable::id();
2162 let buffer_address = Pubkey::new_unique();
2163 let mut buffer_account =
2164 AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
2165 let instruction_accounts = vec![
2166 AccountMeta {
2167 pubkey: buffer_address,
2168 is_signer: false,
2169 is_writable: true,
2170 },
2171 AccountMeta {
2172 pubkey: buffer_address,
2173 is_signer: true,
2174 is_writable: false,
2175 },
2176 ];
2177
2178 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
2180 offset: 0,
2181 bytes: vec![42; 9],
2182 })
2183 .unwrap();
2184 process_instruction(
2185 &loader_id,
2186 &[],
2187 &instruction,
2188 vec![(buffer_address, buffer_account.clone())],
2189 instruction_accounts.clone(),
2190 Err(InstructionError::InvalidAccountData),
2191 );
2192
2193 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
2195 offset: 0,
2196 bytes: vec![42; 9],
2197 })
2198 .unwrap();
2199 buffer_account
2200 .set_state(&UpgradeableLoaderState::Buffer {
2201 authority_address: Some(buffer_address),
2202 })
2203 .unwrap();
2204 let accounts = process_instruction(
2205 &loader_id,
2206 &[],
2207 &instruction,
2208 vec![(buffer_address, buffer_account.clone())],
2209 instruction_accounts.clone(),
2210 Ok(()),
2211 );
2212 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
2213 assert_eq!(
2214 state,
2215 UpgradeableLoaderState::Buffer {
2216 authority_address: Some(buffer_address)
2217 }
2218 );
2219 assert_eq!(
2220 &accounts
2221 .first()
2222 .unwrap()
2223 .data()
2224 .get(UpgradeableLoaderState::size_of_buffer_metadata()..)
2225 .unwrap(),
2226 &[42; 9]
2227 );
2228
2229 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
2231 offset: 3,
2232 bytes: vec![42; 6],
2233 })
2234 .unwrap();
2235 let mut buffer_account =
2236 AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
2237 buffer_account
2238 .set_state(&UpgradeableLoaderState::Buffer {
2239 authority_address: Some(buffer_address),
2240 })
2241 .unwrap();
2242 let accounts = process_instruction(
2243 &loader_id,
2244 &[],
2245 &instruction,
2246 vec![(buffer_address, buffer_account.clone())],
2247 instruction_accounts.clone(),
2248 Ok(()),
2249 );
2250 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
2251 assert_eq!(
2252 state,
2253 UpgradeableLoaderState::Buffer {
2254 authority_address: Some(buffer_address)
2255 }
2256 );
2257 assert_eq!(
2258 &accounts
2259 .first()
2260 .unwrap()
2261 .data()
2262 .get(UpgradeableLoaderState::size_of_buffer_metadata()..)
2263 .unwrap(),
2264 &[0, 0, 0, 42, 42, 42, 42, 42, 42]
2265 );
2266
2267 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
2269 offset: 0,
2270 bytes: vec![42; 10],
2271 })
2272 .unwrap();
2273 buffer_account
2274 .set_state(&UpgradeableLoaderState::Buffer {
2275 authority_address: Some(buffer_address),
2276 })
2277 .unwrap();
2278 process_instruction(
2279 &loader_id,
2280 &[],
2281 &instruction,
2282 vec![(buffer_address, buffer_account.clone())],
2283 instruction_accounts.clone(),
2284 Err(InstructionError::AccountDataTooSmall),
2285 );
2286
2287 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
2289 offset: 1,
2290 bytes: vec![42; 9],
2291 })
2292 .unwrap();
2293 buffer_account
2294 .set_state(&UpgradeableLoaderState::Buffer {
2295 authority_address: Some(buffer_address),
2296 })
2297 .unwrap();
2298 process_instruction(
2299 &loader_id,
2300 &[],
2301 &instruction,
2302 vec![(buffer_address, buffer_account.clone())],
2303 instruction_accounts.clone(),
2304 Err(InstructionError::AccountDataTooSmall),
2305 );
2306
2307 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
2309 offset: 0,
2310 bytes: vec![42; 9],
2311 })
2312 .unwrap();
2313 buffer_account
2314 .set_state(&UpgradeableLoaderState::Buffer {
2315 authority_address: Some(buffer_address),
2316 })
2317 .unwrap();
2318 process_instruction(
2319 &loader_id,
2320 &[],
2321 &instruction,
2322 vec![(buffer_address, buffer_account.clone())],
2323 vec![
2324 AccountMeta {
2325 pubkey: buffer_address,
2326 is_signer: false,
2327 is_writable: false,
2328 },
2329 AccountMeta {
2330 pubkey: buffer_address,
2331 is_signer: false,
2332 is_writable: false,
2333 },
2334 ],
2335 Err(InstructionError::MissingRequiredSignature),
2336 );
2337
2338 let authority_address = Pubkey::new_unique();
2340 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
2341 offset: 1,
2342 bytes: vec![42; 9],
2343 })
2344 .unwrap();
2345 buffer_account
2346 .set_state(&UpgradeableLoaderState::Buffer {
2347 authority_address: Some(buffer_address),
2348 })
2349 .unwrap();
2350 process_instruction(
2351 &loader_id,
2352 &[],
2353 &instruction,
2354 vec![
2355 (buffer_address, buffer_account.clone()),
2356 (authority_address, buffer_account.clone()),
2357 ],
2358 vec![
2359 AccountMeta {
2360 pubkey: buffer_address,
2361 is_signer: false,
2362 is_writable: false,
2363 },
2364 AccountMeta {
2365 pubkey: authority_address,
2366 is_signer: false,
2367 is_writable: false,
2368 },
2369 ],
2370 Err(InstructionError::IncorrectAuthority),
2371 );
2372
2373 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
2375 offset: 1,
2376 bytes: vec![42; 9],
2377 })
2378 .unwrap();
2379 buffer_account
2380 .set_state(&UpgradeableLoaderState::Buffer {
2381 authority_address: None,
2382 })
2383 .unwrap();
2384 process_instruction(
2385 &loader_id,
2386 &[],
2387 &instruction,
2388 vec![(buffer_address, buffer_account.clone())],
2389 instruction_accounts,
2390 Err(InstructionError::Immutable),
2391 );
2392 }
2393
2394 fn truncate_data(account: &mut AccountSharedData, len: usize) {
2395 let mut data = account.data().to_vec();
2396 data.truncate(len);
2397 account.set_data(data);
2398 }
2399
2400 #[test]
2401 fn test_bpf_loader_upgradeable_upgrade() {
2402 let mut file = File::open("test_elfs/out/sbpfv3_return_ok.so").expect("file open failed");
2403 let mut elf_orig = Vec::new();
2404 file.read_to_end(&mut elf_orig).unwrap();
2405 let mut file = File::open("test_elfs/out/sbpfv3_return_err.so").expect("file open failed");
2406 let mut elf_new = Vec::new();
2407 file.read_to_end(&mut elf_new).unwrap();
2408 assert_ne!(elf_orig.len(), elf_new.len());
2409 const SLOT: u64 = 42;
2410 let buffer_address = Pubkey::new_unique();
2411 let upgrade_authority_address = Pubkey::new_unique();
2412
2413 fn get_accounts(
2414 buffer_address: &Pubkey,
2415 buffer_authority: &Pubkey,
2416 upgrade_authority_address: &Pubkey,
2417 elf_orig: &[u8],
2418 elf_new: &[u8],
2419 ) -> (Vec<(Pubkey, AccountSharedData)>, Vec<AccountMeta>) {
2420 let loader_id = bpf_loader_upgradeable::id();
2421 let program_address = Pubkey::new_unique();
2422 let spill_address = Pubkey::new_unique();
2423 let rent = Rent::default();
2424 let min_program_balance =
2425 1.max(rent.minimum_balance(UpgradeableLoaderState::size_of_program()));
2426 let min_programdata_balance = 1.max(rent.minimum_balance(
2427 UpgradeableLoaderState::size_of_programdata(elf_orig.len().max(elf_new.len())),
2428 ));
2429 let (programdata_address, _) =
2430 Pubkey::find_program_address(&[program_address.as_ref()], &loader_id);
2431 let mut buffer_account = AccountSharedData::new(
2432 1,
2433 UpgradeableLoaderState::size_of_buffer(elf_new.len()),
2434 &bpf_loader_upgradeable::id(),
2435 );
2436 buffer_account
2437 .set_state(&UpgradeableLoaderState::Buffer {
2438 authority_address: Some(*buffer_authority),
2439 })
2440 .unwrap();
2441 buffer_account
2442 .data_as_mut_slice()
2443 .get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..)
2444 .unwrap()
2445 .copy_from_slice(elf_new);
2446 let mut programdata_account = AccountSharedData::new(
2447 min_programdata_balance,
2448 UpgradeableLoaderState::size_of_programdata(elf_orig.len().max(elf_new.len())),
2449 &bpf_loader_upgradeable::id(),
2450 );
2451 programdata_account
2452 .set_state(&UpgradeableLoaderState::ProgramData {
2453 slot: SLOT,
2454 upgrade_authority_address: Some(*upgrade_authority_address),
2455 })
2456 .unwrap();
2457 let mut program_account = AccountSharedData::new(
2458 min_program_balance,
2459 UpgradeableLoaderState::size_of_program(),
2460 &bpf_loader_upgradeable::id(),
2461 );
2462 program_account
2463 .set_state(&UpgradeableLoaderState::Program {
2464 programdata_address,
2465 })
2466 .unwrap();
2467 let spill_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
2468 let rent_account: AccountSharedData = create_account_for_test(&rent).into();
2469 let clock_account: AccountSharedData = create_account_for_test(&Clock {
2470 slot: SLOT.saturating_add(1),
2471 ..Clock::default()
2472 })
2473 .into();
2474 let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
2475 let transaction_accounts = vec![
2476 (programdata_address, programdata_account),
2477 (program_address, program_account),
2478 (*buffer_address, buffer_account),
2479 (spill_address, spill_account),
2480 (sysvar::rent::id(), rent_account),
2481 (sysvar::clock::id(), clock_account),
2482 (*upgrade_authority_address, upgrade_authority_account),
2483 ];
2484 let instruction_accounts = vec![
2485 AccountMeta {
2486 pubkey: programdata_address,
2487 is_signer: false,
2488 is_writable: true,
2489 },
2490 AccountMeta {
2491 pubkey: program_address,
2492 is_signer: false,
2493 is_writable: true,
2494 },
2495 AccountMeta {
2496 pubkey: *buffer_address,
2497 is_signer: false,
2498 is_writable: true,
2499 },
2500 AccountMeta {
2501 pubkey: spill_address,
2502 is_signer: false,
2503 is_writable: true,
2504 },
2505 AccountMeta {
2506 pubkey: sysvar::rent::id(),
2507 is_signer: false,
2508 is_writable: false,
2509 },
2510 AccountMeta {
2511 pubkey: sysvar::clock::id(),
2512 is_signer: false,
2513 is_writable: false,
2514 },
2515 AccountMeta {
2516 pubkey: *upgrade_authority_address,
2517 is_signer: true,
2518 is_writable: false,
2519 },
2520 ];
2521 (transaction_accounts, instruction_accounts)
2522 }
2523
2524 fn process_instruction(
2525 transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
2526 instruction_accounts: Vec<AccountMeta>,
2527 expected_result: Result<(), InstructionError>,
2528 ) -> Vec<StoredAccount> {
2529 let instruction_data =
2530 bincode::serialize(&UpgradeableLoaderInstruction::Upgrade).unwrap();
2531 mock_process_instruction(
2532 &bpf_loader_upgradeable::id(),
2533 Vec::new(),
2534 &instruction_data,
2535 transaction_accounts
2536 .into_iter()
2537 .map(|(k, v)| (k, StoredAccount::from(v)))
2538 .collect(),
2539 instruction_accounts,
2540 expected_result,
2541 Entrypoint::vm,
2542 |_invoke_context| {},
2543 |_invoke_context| {},
2544 )
2545 }
2546
2547 let (transaction_accounts, instruction_accounts) = get_accounts(
2549 &buffer_address,
2550 &upgrade_authority_address,
2551 &upgrade_authority_address,
2552 &elf_orig,
2553 &elf_new,
2554 );
2555 let accounts = process_instruction(transaction_accounts, instruction_accounts, Ok(()));
2556 let min_programdata_balance = Rent::default().minimum_balance(
2557 UpgradeableLoaderState::size_of_programdata(elf_orig.len().max(elf_new.len())),
2558 );
2559 assert_eq!(min_programdata_balance, accounts.first().unwrap().kelvins());
2560 assert_eq!(0, accounts.get(2).unwrap().kelvins());
2561 assert_eq!(1, accounts.get(3).unwrap().kelvins());
2562 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
2563 assert_eq!(
2564 state,
2565 UpgradeableLoaderState::ProgramData {
2566 slot: SLOT.saturating_add(1),
2567 upgrade_authority_address: Some(upgrade_authority_address)
2568 }
2569 );
2570 for (i, byte) in accounts
2571 .first()
2572 .unwrap()
2573 .data()
2574 .get(
2575 UpgradeableLoaderState::size_of_programdata_metadata()
2576 ..UpgradeableLoaderState::size_of_programdata(elf_new.len()),
2577 )
2578 .unwrap()
2579 .iter()
2580 .enumerate()
2581 {
2582 assert_eq!(*elf_new.get(i).unwrap(), *byte);
2583 }
2584
2585 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2587 &buffer_address,
2588 &upgrade_authority_address,
2589 &upgrade_authority_address,
2590 &elf_orig,
2591 &elf_new,
2592 );
2593 transaction_accounts
2594 .get_mut(0)
2595 .unwrap()
2596 .1
2597 .set_state(&UpgradeableLoaderState::ProgramData {
2598 slot: SLOT,
2599 upgrade_authority_address: None,
2600 })
2601 .unwrap();
2602 process_instruction(
2603 transaction_accounts,
2604 instruction_accounts,
2605 Err(InstructionError::Immutable),
2606 );
2607
2608 let (mut transaction_accounts, mut instruction_accounts) = get_accounts(
2610 &buffer_address,
2611 &upgrade_authority_address,
2612 &upgrade_authority_address,
2613 &elf_orig,
2614 &elf_new,
2615 );
2616 let invalid_upgrade_authority_address = Pubkey::new_unique();
2617 transaction_accounts.get_mut(6).unwrap().0 = invalid_upgrade_authority_address;
2618 instruction_accounts.get_mut(6).unwrap().pubkey = invalid_upgrade_authority_address;
2619 process_instruction(
2620 transaction_accounts,
2621 instruction_accounts,
2622 Err(InstructionError::IncorrectAuthority),
2623 );
2624
2625 let (transaction_accounts, mut instruction_accounts) = get_accounts(
2627 &buffer_address,
2628 &upgrade_authority_address,
2629 &upgrade_authority_address,
2630 &elf_orig,
2631 &elf_new,
2632 );
2633 instruction_accounts.get_mut(6).unwrap().is_signer = false;
2634 process_instruction(
2635 transaction_accounts,
2636 instruction_accounts,
2637 Err(InstructionError::MissingRequiredSignature),
2638 );
2639
2640 let (transaction_accounts, mut instruction_accounts) = get_accounts(
2642 &buffer_address,
2643 &upgrade_authority_address,
2644 &upgrade_authority_address,
2645 &elf_orig,
2646 &elf_new,
2647 );
2648 *instruction_accounts.get_mut(3).unwrap() = instruction_accounts.get(2).unwrap().clone();
2649 process_instruction(
2650 transaction_accounts,
2651 instruction_accounts,
2652 Err(InstructionError::AccountBorrowFailed),
2653 );
2654
2655 let (transaction_accounts, mut instruction_accounts) = get_accounts(
2657 &buffer_address,
2658 &upgrade_authority_address,
2659 &upgrade_authority_address,
2660 &elf_orig,
2661 &elf_new,
2662 );
2663 *instruction_accounts.get_mut(3).unwrap() = instruction_accounts.first().unwrap().clone();
2664 process_instruction(
2665 transaction_accounts,
2666 instruction_accounts,
2667 Err(InstructionError::AccountBorrowFailed),
2668 );
2669
2670 let (transaction_accounts, mut instruction_accounts) = get_accounts(
2672 &buffer_address,
2673 &upgrade_authority_address,
2674 &upgrade_authority_address,
2675 &elf_orig,
2676 &elf_new,
2677 );
2678 *instruction_accounts.get_mut(1).unwrap() = instruction_accounts.get(2).unwrap().clone();
2679 let instruction_data = bincode::serialize(&UpgradeableLoaderInstruction::Upgrade).unwrap();
2680 mock_process_instruction(
2681 &bpf_loader_upgradeable::id(),
2682 Vec::new(),
2683 &instruction_data,
2684 transaction_accounts
2685 .clone()
2686 .into_iter()
2687 .map(|(k, v)| (k, StoredAccount::from(v)))
2688 .collect(),
2689 instruction_accounts.clone(),
2690 Err(InstructionError::AccountNotExecutable),
2691 Entrypoint::vm,
2692 |invoke_context| {
2693 let mut feature_set = invoke_context.get_feature_set().clone();
2694 feature_set.deactivate(&remove_accounts_executable_flag_checks::id());
2695 invoke_context.mock_set_feature_set(Arc::new(feature_set));
2696 test_utils::load_all_invoked_programs(invoke_context);
2697 },
2698 |_invoke_context| {},
2699 );
2700 process_instruction(
2701 transaction_accounts.clone(),
2702 instruction_accounts.clone(),
2703 Err(InstructionError::InvalidAccountData),
2704 );
2705
2706 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2708 &buffer_address,
2709 &upgrade_authority_address,
2710 &upgrade_authority_address,
2711 &elf_orig,
2712 &elf_new,
2713 );
2714 transaction_accounts
2715 .get_mut(1)
2716 .unwrap()
2717 .1
2718 .set_owner(Pubkey::new_unique());
2719 process_instruction(
2720 transaction_accounts,
2721 instruction_accounts,
2722 Err(InstructionError::IncorrectProgramId),
2723 );
2724
2725 let (transaction_accounts, mut instruction_accounts) = get_accounts(
2727 &buffer_address,
2728 &upgrade_authority_address,
2729 &upgrade_authority_address,
2730 &elf_orig,
2731 &elf_new,
2732 );
2733 instruction_accounts.get_mut(1).unwrap().is_writable = false;
2734 process_instruction(
2735 transaction_accounts,
2736 instruction_accounts,
2737 Err(InstructionError::InvalidArgument),
2738 );
2739
2740 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2742 &buffer_address,
2743 &upgrade_authority_address,
2744 &upgrade_authority_address,
2745 &elf_orig,
2746 &elf_new,
2747 );
2748 transaction_accounts
2749 .get_mut(1)
2750 .unwrap()
2751 .1
2752 .set_state(&UpgradeableLoaderState::Uninitialized)
2753 .unwrap();
2754 process_instruction(
2755 transaction_accounts,
2756 instruction_accounts,
2757 Err(InstructionError::InvalidAccountData),
2758 );
2759
2760 let (mut transaction_accounts, mut instruction_accounts) = get_accounts(
2762 &buffer_address,
2763 &upgrade_authority_address,
2764 &upgrade_authority_address,
2765 &elf_orig,
2766 &elf_new,
2767 );
2768 let invalid_programdata_address = Pubkey::new_unique();
2769 transaction_accounts.get_mut(0).unwrap().0 = invalid_programdata_address;
2770 instruction_accounts.get_mut(0).unwrap().pubkey = invalid_programdata_address;
2771 process_instruction(
2772 transaction_accounts,
2773 instruction_accounts,
2774 Err(InstructionError::InvalidArgument),
2775 );
2776
2777 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2779 &buffer_address,
2780 &upgrade_authority_address,
2781 &upgrade_authority_address,
2782 &elf_orig,
2783 &elf_new,
2784 );
2785 transaction_accounts
2786 .get_mut(2)
2787 .unwrap()
2788 .1
2789 .set_state(&UpgradeableLoaderState::Uninitialized)
2790 .unwrap();
2791 process_instruction(
2792 transaction_accounts,
2793 instruction_accounts,
2794 Err(InstructionError::InvalidArgument),
2795 );
2796
2797 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2799 &buffer_address,
2800 &upgrade_authority_address,
2801 &upgrade_authority_address,
2802 &elf_orig,
2803 &elf_new,
2804 );
2805 transaction_accounts.get_mut(2).unwrap().1 = AccountSharedData::new(
2806 1,
2807 UpgradeableLoaderState::size_of_buffer(
2808 elf_orig.len().max(elf_new.len()).saturating_add(1),
2809 ),
2810 &bpf_loader_upgradeable::id(),
2811 );
2812 transaction_accounts
2813 .get_mut(2)
2814 .unwrap()
2815 .1
2816 .set_state(&UpgradeableLoaderState::Buffer {
2817 authority_address: Some(upgrade_authority_address),
2818 })
2819 .unwrap();
2820 process_instruction(
2821 transaction_accounts,
2822 instruction_accounts,
2823 Err(InstructionError::AccountDataTooSmall),
2824 );
2825
2826 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2828 &buffer_address,
2829 &upgrade_authority_address,
2830 &upgrade_authority_address,
2831 &elf_orig,
2832 &elf_new,
2833 );
2834 transaction_accounts
2835 .get_mut(2)
2836 .unwrap()
2837 .1
2838 .set_state(&UpgradeableLoaderState::Buffer {
2839 authority_address: Some(upgrade_authority_address),
2840 })
2841 .unwrap();
2842 truncate_data(&mut transaction_accounts.get_mut(2).unwrap().1, 5);
2843 process_instruction(
2844 transaction_accounts,
2845 instruction_accounts,
2846 Err(InstructionError::InvalidAccountData),
2847 );
2848
2849 let (transaction_accounts, instruction_accounts) = get_accounts(
2851 &buffer_address,
2852 &buffer_address,
2853 &upgrade_authority_address,
2854 &elf_orig,
2855 &elf_new,
2856 );
2857 process_instruction(
2858 transaction_accounts,
2859 instruction_accounts,
2860 Err(InstructionError::IncorrectAuthority),
2861 );
2862
2863 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2865 &buffer_address,
2866 &buffer_address,
2867 &upgrade_authority_address,
2868 &elf_orig,
2869 &elf_new,
2870 );
2871 transaction_accounts
2872 .get_mut(2)
2873 .unwrap()
2874 .1
2875 .set_state(&UpgradeableLoaderState::Buffer {
2876 authority_address: None,
2877 })
2878 .unwrap();
2879 process_instruction(
2880 transaction_accounts,
2881 instruction_accounts,
2882 Err(InstructionError::IncorrectAuthority),
2883 );
2884
2885 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2887 &buffer_address,
2888 &buffer_address,
2889 &upgrade_authority_address,
2890 &elf_orig,
2891 &elf_new,
2892 );
2893 transaction_accounts
2894 .get_mut(0)
2895 .unwrap()
2896 .1
2897 .set_state(&UpgradeableLoaderState::ProgramData {
2898 slot: SLOT,
2899 upgrade_authority_address: None,
2900 })
2901 .unwrap();
2902 transaction_accounts
2903 .get_mut(2)
2904 .unwrap()
2905 .1
2906 .set_state(&UpgradeableLoaderState::Buffer {
2907 authority_address: None,
2908 })
2909 .unwrap();
2910 process_instruction(
2911 transaction_accounts,
2912 instruction_accounts,
2913 Err(InstructionError::IncorrectAuthority),
2914 );
2915 }
2916
2917 #[test]
2918 fn test_bpf_loader_upgradeable_set_upgrade_authority() {
2919 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap();
2920 let loader_id = bpf_loader_upgradeable::id();
2921 let slot = 0;
2922 let upgrade_authority_address = Pubkey::new_unique();
2923 let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
2924 let new_upgrade_authority_address = Pubkey::new_unique();
2925 let new_upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
2926 let program_address = Pubkey::new_unique();
2927 let (programdata_address, _) = Pubkey::find_program_address(
2928 &[program_address.as_ref()],
2929 &bpf_loader_upgradeable::id(),
2930 );
2931 let mut programdata_account = AccountSharedData::new(
2932 1,
2933 UpgradeableLoaderState::size_of_programdata(0),
2934 &bpf_loader_upgradeable::id(),
2935 );
2936 programdata_account
2937 .set_state(&UpgradeableLoaderState::ProgramData {
2938 slot,
2939 upgrade_authority_address: Some(upgrade_authority_address),
2940 })
2941 .unwrap();
2942 let programdata_meta = AccountMeta {
2943 pubkey: programdata_address,
2944 is_signer: false,
2945 is_writable: true,
2946 };
2947 let upgrade_authority_meta = AccountMeta {
2948 pubkey: upgrade_authority_address,
2949 is_signer: true,
2950 is_writable: false,
2951 };
2952 let new_upgrade_authority_meta = AccountMeta {
2953 pubkey: new_upgrade_authority_address,
2954 is_signer: false,
2955 is_writable: false,
2956 };
2957
2958 let accounts = process_instruction(
2960 &loader_id,
2961 &[],
2962 &instruction,
2963 vec![
2964 (programdata_address, programdata_account.clone()),
2965 (upgrade_authority_address, upgrade_authority_account.clone()),
2966 (
2967 new_upgrade_authority_address,
2968 new_upgrade_authority_account.clone(),
2969 ),
2970 ],
2971 vec![
2972 programdata_meta.clone(),
2973 upgrade_authority_meta.clone(),
2974 new_upgrade_authority_meta.clone(),
2975 ],
2976 Ok(()),
2977 );
2978 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
2979 assert_eq!(
2980 state,
2981 UpgradeableLoaderState::ProgramData {
2982 slot,
2983 upgrade_authority_address: Some(new_upgrade_authority_address),
2984 }
2985 );
2986
2987 let accounts = process_instruction(
2989 &loader_id,
2990 &[],
2991 &instruction,
2992 vec![
2993 (programdata_address, programdata_account.clone()),
2994 (upgrade_authority_address, upgrade_authority_account.clone()),
2995 ],
2996 vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
2997 Ok(()),
2998 );
2999 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3000 assert_eq!(
3001 state,
3002 UpgradeableLoaderState::ProgramData {
3003 slot,
3004 upgrade_authority_address: None,
3005 }
3006 );
3007
3008 process_instruction(
3010 &loader_id,
3011 &[],
3012 &instruction,
3013 vec![
3014 (programdata_address, programdata_account.clone()),
3015 (upgrade_authority_address, upgrade_authority_account.clone()),
3016 ],
3017 vec![
3018 programdata_meta.clone(),
3019 AccountMeta {
3020 pubkey: upgrade_authority_address,
3021 is_signer: false,
3022 is_writable: false,
3023 },
3024 ],
3025 Err(InstructionError::MissingRequiredSignature),
3026 );
3027
3028 let invalid_upgrade_authority_address = Pubkey::new_unique();
3030 process_instruction(
3031 &loader_id,
3032 &[],
3033 &instruction,
3034 vec![
3035 (programdata_address, programdata_account.clone()),
3036 (
3037 invalid_upgrade_authority_address,
3038 upgrade_authority_account.clone(),
3039 ),
3040 (new_upgrade_authority_address, new_upgrade_authority_account),
3041 ],
3042 vec![
3043 programdata_meta.clone(),
3044 AccountMeta {
3045 pubkey: invalid_upgrade_authority_address,
3046 is_signer: true,
3047 is_writable: false,
3048 },
3049 new_upgrade_authority_meta,
3050 ],
3051 Err(InstructionError::IncorrectAuthority),
3052 );
3053
3054 programdata_account
3056 .set_state(&UpgradeableLoaderState::ProgramData {
3057 slot,
3058 upgrade_authority_address: None,
3059 })
3060 .unwrap();
3061 process_instruction(
3062 &loader_id,
3063 &[],
3064 &instruction,
3065 vec![
3066 (programdata_address, programdata_account.clone()),
3067 (upgrade_authority_address, upgrade_authority_account.clone()),
3068 ],
3069 vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
3070 Err(InstructionError::Immutable),
3071 );
3072
3073 programdata_account
3075 .set_state(&UpgradeableLoaderState::Program {
3076 programdata_address: Pubkey::new_unique(),
3077 })
3078 .unwrap();
3079 process_instruction(
3080 &loader_id,
3081 &[],
3082 &instruction,
3083 vec![
3084 (programdata_address, programdata_account.clone()),
3085 (upgrade_authority_address, upgrade_authority_account),
3086 ],
3087 vec![programdata_meta, upgrade_authority_meta],
3088 Err(InstructionError::InvalidArgument),
3089 );
3090 }
3091
3092 #[test]
3093 fn test_bpf_loader_upgradeable_set_upgrade_authority_checked() {
3094 let instruction =
3095 bincode::serialize(&UpgradeableLoaderInstruction::SetAuthorityChecked).unwrap();
3096 let loader_id = bpf_loader_upgradeable::id();
3097 let slot = 0;
3098 let upgrade_authority_address = Pubkey::new_unique();
3099 let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3100 let new_upgrade_authority_address = Pubkey::new_unique();
3101 let new_upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3102 let program_address = Pubkey::new_unique();
3103 let (programdata_address, _) = Pubkey::find_program_address(
3104 &[program_address.as_ref()],
3105 &bpf_loader_upgradeable::id(),
3106 );
3107 let mut programdata_account = AccountSharedData::new(
3108 1,
3109 UpgradeableLoaderState::size_of_programdata(0),
3110 &bpf_loader_upgradeable::id(),
3111 );
3112 programdata_account
3113 .set_state(&UpgradeableLoaderState::ProgramData {
3114 slot,
3115 upgrade_authority_address: Some(upgrade_authority_address),
3116 })
3117 .unwrap();
3118 let programdata_meta = AccountMeta {
3119 pubkey: programdata_address,
3120 is_signer: false,
3121 is_writable: true,
3122 };
3123 let upgrade_authority_meta = AccountMeta {
3124 pubkey: upgrade_authority_address,
3125 is_signer: true,
3126 is_writable: false,
3127 };
3128 let new_upgrade_authority_meta = AccountMeta {
3129 pubkey: new_upgrade_authority_address,
3130 is_signer: true,
3131 is_writable: false,
3132 };
3133
3134 let accounts = process_instruction(
3136 &loader_id,
3137 &[],
3138 &instruction,
3139 vec![
3140 (programdata_address, programdata_account.clone()),
3141 (upgrade_authority_address, upgrade_authority_account.clone()),
3142 (
3143 new_upgrade_authority_address,
3144 new_upgrade_authority_account.clone(),
3145 ),
3146 ],
3147 vec![
3148 programdata_meta.clone(),
3149 upgrade_authority_meta.clone(),
3150 new_upgrade_authority_meta.clone(),
3151 ],
3152 Ok(()),
3153 );
3154
3155 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3156 assert_eq!(
3157 state,
3158 UpgradeableLoaderState::ProgramData {
3159 slot,
3160 upgrade_authority_address: Some(new_upgrade_authority_address),
3161 }
3162 );
3163
3164 process_instruction(
3166 &loader_id,
3167 &[],
3168 &instruction,
3169 vec![
3170 (programdata_address, programdata_account.clone()),
3171 (upgrade_authority_address, upgrade_authority_account.clone()),
3172 ],
3173 vec![
3174 programdata_meta.clone(),
3175 upgrade_authority_meta.clone(),
3176 upgrade_authority_meta.clone(),
3177 ],
3178 Ok(()),
3179 );
3180
3181 process_instruction(
3183 &loader_id,
3184 &[],
3185 &instruction,
3186 vec![
3187 (programdata_address, programdata_account.clone()),
3188 (upgrade_authority_address, upgrade_authority_account.clone()),
3189 (
3190 new_upgrade_authority_address,
3191 new_upgrade_authority_account.clone(),
3192 ),
3193 ],
3194 vec![programdata_meta.clone(), new_upgrade_authority_meta.clone()],
3195 Err(InstructionError::NotEnoughAccountKeys),
3196 );
3197
3198 process_instruction(
3200 &loader_id,
3201 &[],
3202 &instruction,
3203 vec![
3204 (programdata_address, programdata_account.clone()),
3205 (upgrade_authority_address, upgrade_authority_account.clone()),
3206 (
3207 new_upgrade_authority_address,
3208 new_upgrade_authority_account.clone(),
3209 ),
3210 ],
3211 vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
3212 Err(InstructionError::NotEnoughAccountKeys),
3213 );
3214
3215 process_instruction(
3217 &loader_id,
3218 &[],
3219 &instruction,
3220 vec![
3221 (programdata_address, programdata_account.clone()),
3222 (upgrade_authority_address, upgrade_authority_account.clone()),
3223 (
3224 new_upgrade_authority_address,
3225 new_upgrade_authority_account.clone(),
3226 ),
3227 ],
3228 vec![
3229 programdata_meta.clone(),
3230 AccountMeta {
3231 pubkey: upgrade_authority_address,
3232 is_signer: false,
3233 is_writable: false,
3234 },
3235 new_upgrade_authority_meta.clone(),
3236 ],
3237 Err(InstructionError::MissingRequiredSignature),
3238 );
3239
3240 process_instruction(
3242 &loader_id,
3243 &[],
3244 &instruction,
3245 vec![
3246 (programdata_address, programdata_account.clone()),
3247 (upgrade_authority_address, upgrade_authority_account.clone()),
3248 (
3249 new_upgrade_authority_address,
3250 new_upgrade_authority_account.clone(),
3251 ),
3252 ],
3253 vec![
3254 programdata_meta.clone(),
3255 upgrade_authority_meta.clone(),
3256 AccountMeta {
3257 pubkey: new_upgrade_authority_address,
3258 is_signer: false,
3259 is_writable: false,
3260 },
3261 ],
3262 Err(InstructionError::MissingRequiredSignature),
3263 );
3264
3265 let invalid_upgrade_authority_address = Pubkey::new_unique();
3267 process_instruction(
3268 &loader_id,
3269 &[],
3270 &instruction,
3271 vec![
3272 (programdata_address, programdata_account.clone()),
3273 (
3274 invalid_upgrade_authority_address,
3275 upgrade_authority_account.clone(),
3276 ),
3277 (new_upgrade_authority_address, new_upgrade_authority_account),
3278 ],
3279 vec![
3280 programdata_meta.clone(),
3281 AccountMeta {
3282 pubkey: invalid_upgrade_authority_address,
3283 is_signer: true,
3284 is_writable: false,
3285 },
3286 new_upgrade_authority_meta.clone(),
3287 ],
3288 Err(InstructionError::IncorrectAuthority),
3289 );
3290
3291 programdata_account
3293 .set_state(&UpgradeableLoaderState::ProgramData {
3294 slot,
3295 upgrade_authority_address: None,
3296 })
3297 .unwrap();
3298 process_instruction(
3299 &loader_id,
3300 &[],
3301 &instruction,
3302 vec![
3303 (programdata_address, programdata_account.clone()),
3304 (upgrade_authority_address, upgrade_authority_account.clone()),
3305 ],
3306 vec![
3307 programdata_meta.clone(),
3308 upgrade_authority_meta.clone(),
3309 new_upgrade_authority_meta.clone(),
3310 ],
3311 Err(InstructionError::Immutable),
3312 );
3313
3314 programdata_account
3316 .set_state(&UpgradeableLoaderState::Program {
3317 programdata_address: Pubkey::new_unique(),
3318 })
3319 .unwrap();
3320 process_instruction(
3321 &loader_id,
3322 &[],
3323 &instruction,
3324 vec![
3325 (programdata_address, programdata_account.clone()),
3326 (upgrade_authority_address, upgrade_authority_account),
3327 ],
3328 vec![
3329 programdata_meta,
3330 upgrade_authority_meta,
3331 new_upgrade_authority_meta,
3332 ],
3333 Err(InstructionError::InvalidArgument),
3334 );
3335 }
3336
3337 #[test]
3338 fn test_bpf_loader_upgradeable_set_buffer_authority() {
3339 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap();
3340 let loader_id = bpf_loader_upgradeable::id();
3341 let invalid_authority_address = Pubkey::new_unique();
3342 let authority_address = Pubkey::new_unique();
3343 let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3344 let new_authority_address = Pubkey::new_unique();
3345 let new_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3346 let buffer_address = Pubkey::new_unique();
3347 let mut buffer_account =
3348 AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(0), &loader_id);
3349 buffer_account
3350 .set_state(&UpgradeableLoaderState::Buffer {
3351 authority_address: Some(authority_address),
3352 })
3353 .unwrap();
3354 let mut transaction_accounts = vec![
3355 (buffer_address, buffer_account.clone()),
3356 (authority_address, authority_account.clone()),
3357 (new_authority_address, new_authority_account.clone()),
3358 ];
3359 let buffer_meta = AccountMeta {
3360 pubkey: buffer_address,
3361 is_signer: false,
3362 is_writable: true,
3363 };
3364 let authority_meta = AccountMeta {
3365 pubkey: authority_address,
3366 is_signer: true,
3367 is_writable: false,
3368 };
3369 let new_authority_meta = AccountMeta {
3370 pubkey: new_authority_address,
3371 is_signer: false,
3372 is_writable: false,
3373 };
3374
3375 let accounts = process_instruction(
3377 &loader_id,
3378 &[],
3379 &instruction,
3380 transaction_accounts.clone(),
3381 vec![buffer_meta.clone(), authority_meta.clone()],
3382 Err(InstructionError::IncorrectAuthority),
3383 );
3384 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3385 assert_eq!(
3386 state,
3387 UpgradeableLoaderState::Buffer {
3388 authority_address: Some(authority_address),
3389 }
3390 );
3391
3392 buffer_account
3394 .set_state(&UpgradeableLoaderState::Buffer {
3395 authority_address: Some(authority_address),
3396 })
3397 .unwrap();
3398 let accounts = process_instruction(
3399 &loader_id,
3400 &[],
3401 &instruction,
3402 transaction_accounts.clone(),
3403 vec![
3404 buffer_meta.clone(),
3405 authority_meta.clone(),
3406 new_authority_meta.clone(),
3407 ],
3408 Ok(()),
3409 );
3410 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3411 assert_eq!(
3412 state,
3413 UpgradeableLoaderState::Buffer {
3414 authority_address: Some(new_authority_address),
3415 }
3416 );
3417
3418 process_instruction(
3420 &loader_id,
3421 &[],
3422 &instruction,
3423 transaction_accounts.clone(),
3424 vec![
3425 buffer_meta.clone(),
3426 AccountMeta {
3427 pubkey: authority_address,
3428 is_signer: false,
3429 is_writable: false,
3430 },
3431 new_authority_meta.clone(),
3432 ],
3433 Err(InstructionError::MissingRequiredSignature),
3434 );
3435
3436 process_instruction(
3438 &loader_id,
3439 &[],
3440 &instruction,
3441 vec![
3442 (buffer_address, buffer_account.clone()),
3443 (invalid_authority_address, authority_account),
3444 (new_authority_address, new_authority_account),
3445 ],
3446 vec![
3447 buffer_meta.clone(),
3448 AccountMeta {
3449 pubkey: invalid_authority_address,
3450 is_signer: true,
3451 is_writable: false,
3452 },
3453 new_authority_meta.clone(),
3454 ],
3455 Err(InstructionError::IncorrectAuthority),
3456 );
3457
3458 process_instruction(
3460 &loader_id,
3461 &[],
3462 &instruction,
3463 transaction_accounts.clone(),
3464 vec![buffer_meta.clone(), authority_meta.clone()],
3465 Err(InstructionError::IncorrectAuthority),
3466 );
3467
3468 transaction_accounts
3470 .get_mut(0)
3471 .unwrap()
3472 .1
3473 .set_state(&UpgradeableLoaderState::Buffer {
3474 authority_address: None,
3475 })
3476 .unwrap();
3477 process_instruction(
3478 &loader_id,
3479 &[],
3480 &instruction,
3481 transaction_accounts.clone(),
3482 vec![
3483 buffer_meta.clone(),
3484 authority_meta.clone(),
3485 new_authority_meta.clone(),
3486 ],
3487 Err(InstructionError::Immutable),
3488 );
3489
3490 transaction_accounts
3492 .get_mut(0)
3493 .unwrap()
3494 .1
3495 .set_state(&UpgradeableLoaderState::Program {
3496 programdata_address: Pubkey::new_unique(),
3497 })
3498 .unwrap();
3499 process_instruction(
3500 &loader_id,
3501 &[],
3502 &instruction,
3503 transaction_accounts.clone(),
3504 vec![buffer_meta, authority_meta, new_authority_meta],
3505 Err(InstructionError::InvalidArgument),
3506 );
3507 }
3508
3509 #[test]
3510 fn test_bpf_loader_upgradeable_set_buffer_authority_checked() {
3511 let instruction =
3512 bincode::serialize(&UpgradeableLoaderInstruction::SetAuthorityChecked).unwrap();
3513 let loader_id = bpf_loader_upgradeable::id();
3514 let invalid_authority_address = Pubkey::new_unique();
3515 let authority_address = Pubkey::new_unique();
3516 let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3517 let new_authority_address = Pubkey::new_unique();
3518 let new_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3519 let buffer_address = Pubkey::new_unique();
3520 let mut buffer_account =
3521 AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(0), &loader_id);
3522 buffer_account
3523 .set_state(&UpgradeableLoaderState::Buffer {
3524 authority_address: Some(authority_address),
3525 })
3526 .unwrap();
3527 let mut transaction_accounts = vec![
3528 (buffer_address, buffer_account.clone()),
3529 (authority_address, authority_account.clone()),
3530 (new_authority_address, new_authority_account.clone()),
3531 ];
3532 let buffer_meta = AccountMeta {
3533 pubkey: buffer_address,
3534 is_signer: false,
3535 is_writable: true,
3536 };
3537 let authority_meta = AccountMeta {
3538 pubkey: authority_address,
3539 is_signer: true,
3540 is_writable: false,
3541 };
3542 let new_authority_meta = AccountMeta {
3543 pubkey: new_authority_address,
3544 is_signer: true,
3545 is_writable: false,
3546 };
3547
3548 buffer_account
3550 .set_state(&UpgradeableLoaderState::Buffer {
3551 authority_address: Some(authority_address),
3552 })
3553 .unwrap();
3554 let accounts = process_instruction(
3555 &loader_id,
3556 &[],
3557 &instruction,
3558 transaction_accounts.clone(),
3559 vec![
3560 buffer_meta.clone(),
3561 authority_meta.clone(),
3562 new_authority_meta.clone(),
3563 ],
3564 Ok(()),
3565 );
3566 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3567 assert_eq!(
3568 state,
3569 UpgradeableLoaderState::Buffer {
3570 authority_address: Some(new_authority_address),
3571 }
3572 );
3573
3574 process_instruction(
3576 &loader_id,
3577 &[],
3578 &instruction,
3579 transaction_accounts.clone(),
3580 vec![
3581 buffer_meta.clone(),
3582 authority_meta.clone(),
3583 authority_meta.clone(),
3584 ],
3585 Ok(()),
3586 );
3587
3588 process_instruction(
3590 &loader_id,
3591 &[],
3592 &instruction,
3593 transaction_accounts.clone(),
3594 vec![buffer_meta.clone(), new_authority_meta.clone()],
3595 Err(InstructionError::NotEnoughAccountKeys),
3596 );
3597
3598 process_instruction(
3600 &loader_id,
3601 &[],
3602 &instruction,
3603 transaction_accounts.clone(),
3604 vec![buffer_meta.clone(), authority_meta.clone()],
3605 Err(InstructionError::NotEnoughAccountKeys),
3606 );
3607
3608 process_instruction(
3610 &loader_id,
3611 &[],
3612 &instruction,
3613 vec![
3614 (buffer_address, buffer_account.clone()),
3615 (invalid_authority_address, authority_account),
3616 (new_authority_address, new_authority_account),
3617 ],
3618 vec![
3619 buffer_meta.clone(),
3620 AccountMeta {
3621 pubkey: invalid_authority_address,
3622 is_signer: true,
3623 is_writable: false,
3624 },
3625 new_authority_meta.clone(),
3626 ],
3627 Err(InstructionError::IncorrectAuthority),
3628 );
3629
3630 process_instruction(
3632 &loader_id,
3633 &[],
3634 &instruction,
3635 transaction_accounts.clone(),
3636 vec![
3637 buffer_meta.clone(),
3638 AccountMeta {
3639 pubkey: authority_address,
3640 is_signer: false,
3641 is_writable: false,
3642 },
3643 new_authority_meta.clone(),
3644 ],
3645 Err(InstructionError::MissingRequiredSignature),
3646 );
3647
3648 process_instruction(
3650 &loader_id,
3651 &[],
3652 &instruction,
3653 transaction_accounts.clone(),
3654 vec![
3655 buffer_meta.clone(),
3656 authority_meta.clone(),
3657 AccountMeta {
3658 pubkey: new_authority_address,
3659 is_signer: false,
3660 is_writable: false,
3661 },
3662 ],
3663 Err(InstructionError::MissingRequiredSignature),
3664 );
3665
3666 transaction_accounts
3668 .get_mut(0)
3669 .unwrap()
3670 .1
3671 .set_state(&UpgradeableLoaderState::Program {
3672 programdata_address: Pubkey::new_unique(),
3673 })
3674 .unwrap();
3675 process_instruction(
3676 &loader_id,
3677 &[],
3678 &instruction,
3679 transaction_accounts.clone(),
3680 vec![
3681 buffer_meta.clone(),
3682 authority_meta.clone(),
3683 new_authority_meta.clone(),
3684 ],
3685 Err(InstructionError::InvalidArgument),
3686 );
3687
3688 transaction_accounts
3690 .get_mut(0)
3691 .unwrap()
3692 .1
3693 .set_state(&UpgradeableLoaderState::Buffer {
3694 authority_address: None,
3695 })
3696 .unwrap();
3697 process_instruction(
3698 &loader_id,
3699 &[],
3700 &instruction,
3701 transaction_accounts.clone(),
3702 vec![buffer_meta, authority_meta, new_authority_meta],
3703 Err(InstructionError::Immutable),
3704 );
3705 }
3706
3707 #[test]
3708 fn test_bpf_loader_upgradeable_close() {
3709 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Close).unwrap();
3710 let loader_id = bpf_loader_upgradeable::id();
3711 let invalid_authority_address = Pubkey::new_unique();
3712 let authority_address = Pubkey::new_unique();
3713 let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3714 let recipient_address = Pubkey::new_unique();
3715 let recipient_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3716 let buffer_address = Pubkey::new_unique();
3717 let mut buffer_account =
3718 AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(128), &loader_id);
3719 buffer_account
3720 .set_state(&UpgradeableLoaderState::Buffer {
3721 authority_address: Some(authority_address),
3722 })
3723 .unwrap();
3724 let uninitialized_address = Pubkey::new_unique();
3725 let mut uninitialized_account = AccountSharedData::new(
3726 1,
3727 UpgradeableLoaderState::size_of_programdata(0),
3728 &loader_id,
3729 );
3730 uninitialized_account
3731 .set_state(&UpgradeableLoaderState::Uninitialized)
3732 .unwrap();
3733 let programdata_address = Pubkey::new_unique();
3734 let mut programdata_account = AccountSharedData::new(
3735 1,
3736 UpgradeableLoaderState::size_of_programdata(128),
3737 &loader_id,
3738 );
3739 programdata_account
3740 .set_state(&UpgradeableLoaderState::ProgramData {
3741 slot: 0,
3742 upgrade_authority_address: Some(authority_address),
3743 })
3744 .unwrap();
3745 let program_address = Pubkey::new_unique();
3746 let mut program_account =
3747 AccountSharedData::new(1, UpgradeableLoaderState::size_of_program(), &loader_id);
3748 program_account
3749 .set_state(&UpgradeableLoaderState::Program {
3750 programdata_address,
3751 })
3752 .unwrap();
3753 let clock_account: AccountSharedData = create_account_for_test(&Clock {
3754 slot: 1,
3755 ..Clock::default()
3756 })
3757 .into();
3758 let transaction_accounts = vec![
3759 (buffer_address, buffer_account.clone()),
3760 (recipient_address, recipient_account.clone()),
3761 (authority_address, authority_account.clone()),
3762 ];
3763 let buffer_meta = AccountMeta {
3764 pubkey: buffer_address,
3765 is_signer: false,
3766 is_writable: true,
3767 };
3768 let recipient_meta = AccountMeta {
3769 pubkey: recipient_address,
3770 is_signer: false,
3771 is_writable: true,
3772 };
3773 let authority_meta = AccountMeta {
3774 pubkey: authority_address,
3775 is_signer: true,
3776 is_writable: false,
3777 };
3778
3779 let accounts = process_instruction(
3781 &loader_id,
3782 &[],
3783 &instruction,
3784 transaction_accounts,
3785 vec![
3786 buffer_meta.clone(),
3787 recipient_meta.clone(),
3788 authority_meta.clone(),
3789 ],
3790 Ok(()),
3791 );
3792 assert_eq!(0, accounts.first().unwrap().kelvins());
3793 assert_eq!(2, accounts.get(1).unwrap().kelvins());
3794 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3795 assert_eq!(state, UpgradeableLoaderState::Uninitialized);
3796 assert_eq!(
3797 UpgradeableLoaderState::size_of_uninitialized(),
3798 accounts.first().unwrap().data().len()
3799 );
3800
3801 process_instruction(
3803 &loader_id,
3804 &[],
3805 &instruction,
3806 vec![
3807 (buffer_address, buffer_account.clone()),
3808 (recipient_address, recipient_account.clone()),
3809 (invalid_authority_address, authority_account.clone()),
3810 ],
3811 vec![
3812 buffer_meta,
3813 recipient_meta.clone(),
3814 AccountMeta {
3815 pubkey: invalid_authority_address,
3816 is_signer: true,
3817 is_writable: false,
3818 },
3819 ],
3820 Err(InstructionError::IncorrectAuthority),
3821 );
3822
3823 let accounts = process_instruction(
3825 &loader_id,
3826 &[],
3827 &instruction,
3828 vec![
3829 (uninitialized_address, uninitialized_account.clone()),
3830 (recipient_address, recipient_account.clone()),
3831 (invalid_authority_address, authority_account.clone()),
3832 ],
3833 vec![
3834 AccountMeta {
3835 pubkey: uninitialized_address,
3836 is_signer: false,
3837 is_writable: true,
3838 },
3839 recipient_meta.clone(),
3840 authority_meta.clone(),
3841 ],
3842 Ok(()),
3843 );
3844 assert_eq!(0, accounts.first().unwrap().kelvins());
3845 assert_eq!(2, accounts.get(1).unwrap().kelvins());
3846 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3847 assert_eq!(state, UpgradeableLoaderState::Uninitialized);
3848 assert_eq!(
3849 UpgradeableLoaderState::size_of_uninitialized(),
3850 accounts.first().unwrap().data().len()
3851 );
3852
3853 let accounts = process_instruction(
3855 &loader_id,
3856 &[],
3857 &instruction,
3858 vec![
3859 (programdata_address, programdata_account.clone()),
3860 (recipient_address, recipient_account.clone()),
3861 (authority_address, authority_account.clone()),
3862 (program_address, program_account.clone()),
3863 (sysvar::clock::id(), clock_account.clone()),
3864 ],
3865 vec![
3866 AccountMeta {
3867 pubkey: programdata_address,
3868 is_signer: false,
3869 is_writable: true,
3870 },
3871 recipient_meta,
3872 authority_meta,
3873 AccountMeta {
3874 pubkey: program_address,
3875 is_signer: false,
3876 is_writable: true,
3877 },
3878 ],
3879 Ok(()),
3880 );
3881 assert_eq!(0, accounts.first().unwrap().kelvins());
3882 assert_eq!(2, accounts.get(1).unwrap().kelvins());
3883 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3884 assert_eq!(state, UpgradeableLoaderState::Uninitialized);
3885 assert_eq!(
3886 UpgradeableLoaderState::size_of_uninitialized(),
3887 accounts.first().unwrap().data().len()
3888 );
3889
3890 programdata_account = accounts.first().unwrap().clone().into();
3892 program_account = accounts.get(3).unwrap().clone().into();
3893 process_instruction(
3894 &loader_id,
3895 &[1],
3896 &[],
3897 vec![
3898 (programdata_address, programdata_account.clone()),
3899 (program_address, program_account.clone()),
3900 ],
3901 Vec::new(),
3902 Err(InstructionError::UnsupportedProgramId),
3903 );
3904
3905 process_instruction(
3907 &loader_id,
3908 &[],
3909 &bincode::serialize(&UpgradeableLoaderInstruction::DeployWithMaxDataLen {
3910 max_data_len: 0,
3911 })
3912 .unwrap(),
3913 vec![
3914 (recipient_address, recipient_account),
3915 (programdata_address, programdata_account),
3916 (program_address, program_account),
3917 (buffer_address, buffer_account),
3918 (
3919 sysvar::rent::id(),
3920 create_account_for_test(&Rent::default()).into(),
3921 ),
3922 (sysvar::clock::id(), clock_account),
3923 (
3924 system_program::id(),
3925 AccountSharedData::new(0, 0, &system_program::id()),
3926 ),
3927 (authority_address, authority_account),
3928 ],
3929 vec![
3930 AccountMeta {
3931 pubkey: recipient_address,
3932 is_signer: true,
3933 is_writable: true,
3934 },
3935 AccountMeta {
3936 pubkey: programdata_address,
3937 is_signer: false,
3938 is_writable: true,
3939 },
3940 AccountMeta {
3941 pubkey: program_address,
3942 is_signer: false,
3943 is_writable: true,
3944 },
3945 AccountMeta {
3946 pubkey: buffer_address,
3947 is_signer: false,
3948 is_writable: false,
3949 },
3950 AccountMeta {
3951 pubkey: sysvar::rent::id(),
3952 is_signer: false,
3953 is_writable: false,
3954 },
3955 AccountMeta {
3956 pubkey: sysvar::clock::id(),
3957 is_signer: false,
3958 is_writable: false,
3959 },
3960 AccountMeta {
3961 pubkey: system_program::id(),
3962 is_signer: false,
3963 is_writable: false,
3964 },
3965 AccountMeta {
3966 pubkey: authority_address,
3967 is_signer: false,
3968 is_writable: false,
3969 },
3970 ],
3971 Err(InstructionError::AccountAlreadyInitialized),
3972 );
3973 }
3974
3975 fn fuzz<F>(
3977 bytes: &[u8],
3978 outer_iters: usize,
3979 inner_iters: usize,
3980 offset: Range<usize>,
3981 value: Range<u8>,
3982 work: F,
3983 ) where
3984 F: Fn(&mut [u8]),
3985 {
3986 let mut rng = rand::thread_rng();
3987 for _ in 0..outer_iters {
3988 let mut mangled_bytes = bytes.to_vec();
3989 for _ in 0..inner_iters {
3990 let offset = rng.gen_range(offset.start..offset.end);
3991 let value = rng.gen_range(value.start..value.end);
3992 *mangled_bytes.get_mut(offset).unwrap() = value;
3993 work(&mut mangled_bytes);
3994 }
3995 }
3996 }
3997
3998 #[test]
3999 #[ignore]
4000 fn test_fuzz() {
4001 let loader_id = bpf_loader::id();
4002 let program_id = Pubkey::new_unique();
4003
4004 let mut file = File::open("test_elfs/out/sbpfv3_return_ok.so").expect("file open failed");
4006 let mut elf = Vec::new();
4007 file.read_to_end(&mut elf).unwrap();
4008
4009 fuzz(
4011 &elf,
4012 1_000_000_000,
4013 100,
4014 0..elf.len(),
4015 0..255,
4016 |bytes: &mut [u8]| {
4017 let mut program_account = AccountSharedData::new(1, 0, &loader_id);
4018 program_account.set_data(bytes.to_vec());
4019 process_instruction(
4020 &loader_id,
4021 &[],
4022 &[],
4023 vec![(program_id, program_account)],
4024 Vec::new(),
4025 Ok(()),
4026 );
4027 },
4028 );
4029 }
4030
4031 #[test]
4032 fn test_calculate_heap_cost() {
4033 let heap_cost = 8_u64;
4034
4035 assert_eq!(0, calculate_heap_cost(31 * 1024, heap_cost));
4039
4040 assert_eq!(0, calculate_heap_cost(32 * 1024, heap_cost));
4042
4043 assert_eq!(heap_cost, calculate_heap_cost(33 * 1024, heap_cost));
4045
4046 assert_eq!(heap_cost, calculate_heap_cost(64 * 1024, heap_cost));
4048 }
4049
4050 fn deploy_test_program(
4051 invoke_context: &mut InvokeContext<'_>,
4052 program_id: Pubkey,
4053 ) -> Result<(), InstructionError> {
4054 let mut file = File::open("test_elfs/out/sbpfv3_return_ok.so").expect("file open failed");
4055 let mut elf = Vec::new();
4056 file.read_to_end(&mut elf).unwrap();
4057 deploy_program!(
4058 invoke_context,
4059 &program_id,
4060 &bpf_loader_upgradeable::id(),
4061 elf.len(),
4062 &elf,
4063 2_u64,
4064 );
4065 Ok(())
4066 }
4067
4068 #[test]
4069 fn test_program_usage_count_on_upgrade() {
4070 let transaction_accounts = vec![(
4071 sysvar::epoch_schedule::id(),
4072 create_account_for_test(&EpochSchedule::default()),
4073 )];
4074 with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
4075 let program_id = Pubkey::new_unique();
4076 let env = Arc::new(BuiltinProgram::new_mock());
4077 let program = ProgramCacheEntry {
4078 program: ProgramCacheEntryType::Unloaded(env),
4079 account_owner: ProgramCacheEntryOwner::LoaderV2,
4080 account_size: 0,
4081 deployment_slot: 0,
4082 effective_slot: 0,
4083 tx_usage_counter: AtomicU64::new(100),
4084 ix_usage_counter: AtomicU64::new(100),
4085 latest_access_slot: AtomicU64::new(0),
4086 };
4087 invoke_context
4088 .program_cache_for_tx_batch
4089 .replenish(program_id, Arc::new(program));
4090
4091 assert_matches!(
4092 deploy_test_program(&mut invoke_context, program_id,),
4093 Ok(())
4094 );
4095
4096 let updated_program = invoke_context
4097 .program_cache_for_tx_batch
4098 .find(&program_id)
4099 .expect("Didn't find upgraded program in the cache");
4100
4101 assert_eq!(updated_program.deployment_slot, 2);
4102 assert_eq!(
4103 updated_program.tx_usage_counter.load(Ordering::Relaxed),
4104 100
4105 );
4106 assert_eq!(
4107 updated_program.ix_usage_counter.load(Ordering::Relaxed),
4108 100
4109 );
4110 }
4111
4112 #[test]
4113 fn test_program_usage_count_on_non_upgrade() {
4114 let transaction_accounts = vec![(
4115 sysvar::epoch_schedule::id(),
4116 create_account_for_test(&EpochSchedule::default()),
4117 )];
4118 with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
4119 let program_id = Pubkey::new_unique();
4120 let env = Arc::new(BuiltinProgram::new_mock());
4121 let program = ProgramCacheEntry {
4122 program: ProgramCacheEntryType::Unloaded(env),
4123 account_owner: ProgramCacheEntryOwner::LoaderV2,
4124 account_size: 0,
4125 deployment_slot: 0,
4126 effective_slot: 0,
4127 tx_usage_counter: AtomicU64::new(100),
4128 ix_usage_counter: AtomicU64::new(100),
4129 latest_access_slot: AtomicU64::new(0),
4130 };
4131 invoke_context
4132 .program_cache_for_tx_batch
4133 .replenish(program_id, Arc::new(program));
4134
4135 let program_id2 = Pubkey::new_unique();
4136 assert_matches!(
4137 deploy_test_program(&mut invoke_context, program_id2),
4138 Ok(())
4139 );
4140
4141 let program2 = invoke_context
4142 .program_cache_for_tx_batch
4143 .find(&program_id2)
4144 .expect("Didn't find upgraded program in the cache");
4145
4146 assert_eq!(program2.deployment_slot, 2);
4147 assert_eq!(program2.tx_usage_counter.load(Ordering::Relaxed), 0);
4148 assert_eq!(program2.ix_usage_counter.load(Ordering::Relaxed), 0);
4149 }
4150}