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