rialo_s_bpf_loader_program/
lib.rs

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