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