solana_bpf_loader_program/
lib.rs

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