Skip to main content

rialo_s_bpf_loader_program/
lib.rs

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