solana_bpf_loader_program/
lib.rs

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