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