miraland_bpf_loader_program/
lib.rs

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