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