solana_bpf_loader_program/
lib.rs

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