Skip to main content

solana_bpf_loader_program/
lib.rs

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