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, state_traits::StateMut,
1104        },
1105        solana_clock::Clock,
1106        solana_epoch_schedule::EpochSchedule,
1107        solana_instruction::{AccountMeta, error::InstructionError},
1108        solana_program_runtime::{
1109            invoke_context::mock_process_instruction, loaded_programs::ProgramRuntimeEnvironment,
1110            program_metrics::ProgramStatistics, vm::calculate_heap_cost, with_mock_invoke_context,
1111        },
1112        solana_pubkey::Pubkey,
1113        solana_rent::Rent,
1114        solana_sbpf::program::{BuiltinFunctionDefinition, BuiltinProgram},
1115        solana_sdk_ids::{system_program, sysvar},
1116        solana_svm_type_overrides::sync::atomic::{AtomicU64, Ordering},
1117        solana_sysvar_id::SysvarId,
1118        std::{fs::File, io::Read, ops::Range},
1119    };
1120
1121    fn create_sysvar_account<T>(value: &T) -> AccountSharedData
1122    where
1123        T: wincode::Serialize<Src = T> + SysvarId,
1124    {
1125        let serialized_len = wincode::serialized_size(value).unwrap() as usize;
1126        let canonical_data_len = match T::id() {
1127            sysvar::clock::ID => solana_clock::SIZE,
1128            sysvar::epoch_schedule::ID => solana_epoch_schedule::SIZE,
1129            sysvar::rent::ID => solana_rent::SIZE,
1130            id => panic!("unsupported sysvar: {id}"),
1131        };
1132        let required_data_len = canonical_data_len.max(serialized_len);
1133        let mut account = AccountSharedData::new(1, required_data_len, &sysvar::id());
1134        wincode::serialize_into(account.data_as_mut_slice(), value).unwrap();
1135        account
1136    }
1137
1138    // 10 iterations is intentionally low: `mock_process_instruction` runs on a
1139    // single thread, so additional `shuttle::check_random` iterations validate
1140    // only the harness wiring, not concurrent interleavings. Bump this if a
1141    // future refactor introduces `shuttle::thread::spawn` inside
1142    // `mock_process_instruction`.
1143    #[cfg(feature = "shuttle-test")]
1144    const MOCK_PROCESS_RANDOM_ITERATIONS: usize = 10;
1145
1146    /// Wrapper around `mock_process_instruction` that runs under
1147    /// `shuttle::check_random` when the `shuttle-test` feature is enabled,
1148    /// providing the Shuttle scheduler context required by
1149    /// `solana-svm-type-overrides`'s shuttle-aware atomic types. With default
1150    /// features, this is a thin pass-through to `mock_process_instruction`
1151    /// with `Entrypoint::register` and an empty post-adjustment closure.
1152    ///
1153    /// `mock_process_instruction` itself is single-threaded: the only
1154    /// Shuttle-backed atomic in the access path is
1155    /// `ProgramCacheEntry::latest_access_slot` (routed to
1156    /// `shuttle::sync::atomic::AtomicU64` by `solana_svm_type_overrides`), and
1157    /// it is touched from one Shuttle thread. Iteration-to-iteration variance
1158    /// under `shuttle::check_random` is solely scheduler bookkeeping noise, so
1159    /// any iteration's captured result is equivalent. If
1160    /// `mock_process_instruction` ever spawns Shuttle threads internally,
1161    /// this last-write-wins capture must be re-evaluated.
1162    ///
1163    /// `setup` is typed as `fn(&mut InvokeContext)` (function pointer, not
1164    /// `impl Fn`) so it satisfies Shuttle's `Fn + Send + Sync + 'static` bound
1165    /// when captured by value into the inner closure. Callers must pass
1166    /// non-capturing closures or `fn` items; capturing closures will produce a
1167    /// fn-pointer coercion error at the call site.
1168    fn process_instruction_with_setup(
1169        program_id: &Pubkey,
1170        instruction_data: &[u8],
1171        transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
1172        instruction_accounts: Vec<AccountMeta>,
1173        expected_result: Result<(), InstructionError>,
1174        setup: fn(&mut InvokeContext),
1175    ) -> Vec<AccountSharedData> {
1176        #[cfg(feature = "shuttle-test")]
1177        {
1178            let program_id = *program_id;
1179            let instruction_data = instruction_data.to_vec();
1180            let result = shuttle::sync::Arc::new(shuttle::sync::Mutex::new(None));
1181            let result_for_test = shuttle::sync::Arc::clone(&result);
1182            shuttle::check_random(
1183                move || {
1184                    let accounts = mock_process_instruction(
1185                        &program_id,
1186                        &instruction_data,
1187                        transaction_accounts.clone(),
1188                        instruction_accounts.clone(),
1189                        expected_result.clone(),
1190                        Entrypoint::register,
1191                        setup,
1192                        |_invoke_context| {},
1193                    );
1194                    *result_for_test.lock().unwrap() = Some(accounts);
1195                },
1196                MOCK_PROCESS_RANDOM_ITERATIONS,
1197            );
1198
1199            // Consume the harness cell after Shuttle exits so extraction does
1200            // not call `shuttle::sync::Mutex::lock` outside the scheduler.
1201            let Ok(mut result) = shuttle::sync::Arc::try_unwrap(result) else {
1202                panic!("shuttle test result still has outstanding references")
1203            };
1204            result
1205                .get_mut()
1206                .unwrap()
1207                .take()
1208                .expect("shuttle test did not produce a result")
1209        }
1210
1211        #[cfg(not(feature = "shuttle-test"))]
1212        mock_process_instruction(
1213            program_id,
1214            instruction_data,
1215            transaction_accounts,
1216            instruction_accounts,
1217            expected_result,
1218            Entrypoint::register,
1219            setup,
1220            |_invoke_context| {},
1221        )
1222    }
1223
1224    fn process_instruction(
1225        program_id: &Pubkey,
1226        instruction_data: &[u8],
1227        transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
1228        instruction_accounts: Vec<AccountMeta>,
1229        expected_result: Result<(), InstructionError>,
1230    ) -> Vec<AccountSharedData> {
1231        process_instruction_with_setup(
1232            program_id,
1233            instruction_data,
1234            transaction_accounts,
1235            instruction_accounts,
1236            expected_result,
1237            |invoke_context| {
1238                test_utils::load_all_invoked_programs(invoke_context);
1239            },
1240        )
1241    }
1242
1243    fn load_program_account_from_elf(loader_id: &Pubkey, path: &str) -> AccountSharedData {
1244        let mut file = File::open(path).expect("file open failed");
1245        let mut elf = Vec::new();
1246        file.read_to_end(&mut elf).unwrap();
1247        let rent = Rent::default();
1248        let mut program_account =
1249            AccountSharedData::new(rent.minimum_balance(elf.len()), 0, loader_id);
1250        program_account.set_data_from_slice(&elf);
1251        program_account.set_executable(true);
1252        program_account
1253    }
1254
1255    #[test]
1256    fn test_bpf_loader_invoke_main() {
1257        let loader_id = bpf_loader::id();
1258        let program_id = Pubkey::new_unique();
1259        let program_account =
1260            load_program_account_from_elf(&loader_id, "test_elfs/out/sbpfv3_return_ok.so");
1261        let parameter_id = Pubkey::new_unique();
1262        let parameter_account = AccountSharedData::new(1, 0, &loader_id);
1263        let parameter_meta = AccountMeta {
1264            pubkey: parameter_id,
1265            is_signer: false,
1266            is_writable: false,
1267        };
1268
1269        // Case: No program account
1270        process_instruction(
1271            &loader_id,
1272            &[],
1273            Vec::new(),
1274            Vec::new(),
1275            Err(InstructionError::UnsupportedProgramId),
1276        );
1277
1278        // Case: Only a program account
1279        process_instruction(
1280            &program_id,
1281            &[],
1282            vec![(program_id, program_account.clone())],
1283            Vec::new(),
1284            Ok(()),
1285        );
1286
1287        // Case: With program and parameter account
1288        process_instruction(
1289            &program_id,
1290            &[],
1291            vec![
1292                (program_id, program_account.clone()),
1293                (parameter_id, parameter_account.clone()),
1294            ],
1295            vec![parameter_meta.clone()],
1296            Ok(()),
1297        );
1298
1299        // Case: With duplicate accounts
1300        process_instruction(
1301            &program_id,
1302            &[],
1303            vec![
1304                (program_id, program_account.clone()),
1305                (parameter_id, parameter_account.clone()),
1306            ],
1307            vec![parameter_meta.clone(), parameter_meta],
1308            Ok(()),
1309        );
1310
1311        // Case: limited budget
1312        process_instruction_with_setup(
1313            &program_id,
1314            &[],
1315            vec![(program_id, program_account)],
1316            Vec::new(),
1317            Err(InstructionError::ProgramFailedToComplete),
1318            |invoke_context| {
1319                invoke_context.compute_meter.mock_set_remaining(0);
1320                test_utils::load_all_invoked_programs(invoke_context);
1321            },
1322        );
1323
1324        // Case: Account not a program
1325        process_instruction_with_setup(
1326            &program_id,
1327            &[],
1328            vec![(program_id, parameter_account.clone())],
1329            Vec::new(),
1330            Err(InstructionError::UnsupportedProgramId),
1331            |invoke_context| {
1332                test_utils::load_all_invoked_programs(invoke_context);
1333            },
1334        );
1335        process_instruction(
1336            &program_id,
1337            &[],
1338            vec![(program_id, parameter_account)],
1339            Vec::new(),
1340            Err(InstructionError::UnsupportedProgramId),
1341        );
1342    }
1343
1344    #[test]
1345    fn test_bpf_loader_serialize_unaligned() {
1346        let loader_id = bpf_loader_deprecated::id();
1347        let program_id = Pubkey::new_unique();
1348        let program_account =
1349            load_program_account_from_elf(&loader_id, "test_elfs/out/noop_unaligned.so");
1350        let parameter_id = Pubkey::new_unique();
1351        let parameter_account = AccountSharedData::new(1, 0, &loader_id);
1352        let parameter_meta = AccountMeta {
1353            pubkey: parameter_id,
1354            is_signer: false,
1355            is_writable: false,
1356        };
1357
1358        // Case: With program and parameter account
1359        process_instruction(
1360            &program_id,
1361            &[],
1362            vec![
1363                (program_id, program_account.clone()),
1364                (parameter_id, parameter_account.clone()),
1365            ],
1366            vec![parameter_meta.clone()],
1367            Ok(()),
1368        );
1369
1370        // Case: With duplicate accounts
1371        process_instruction(
1372            &program_id,
1373            &[],
1374            vec![
1375                (program_id, program_account),
1376                (parameter_id, parameter_account),
1377            ],
1378            vec![parameter_meta.clone(), parameter_meta],
1379            Ok(()),
1380        );
1381    }
1382
1383    #[test]
1384    fn test_bpf_loader_serialize_aligned() {
1385        let loader_id = bpf_loader::id();
1386        let program_id = Pubkey::new_unique();
1387        let program_account =
1388            load_program_account_from_elf(&loader_id, "test_elfs/out/noop_aligned.so");
1389        let parameter_id = Pubkey::new_unique();
1390        let parameter_account = AccountSharedData::new(1, 0, &loader_id);
1391        let parameter_meta = AccountMeta {
1392            pubkey: parameter_id,
1393            is_signer: false,
1394            is_writable: false,
1395        };
1396
1397        // Case: With program and parameter account
1398        process_instruction(
1399            &program_id,
1400            &[],
1401            vec![
1402                (program_id, program_account.clone()),
1403                (parameter_id, parameter_account.clone()),
1404            ],
1405            vec![parameter_meta.clone()],
1406            Ok(()),
1407        );
1408
1409        // Case: With duplicate accounts
1410        process_instruction(
1411            &program_id,
1412            &[],
1413            vec![
1414                (program_id, program_account),
1415                (parameter_id, parameter_account),
1416            ],
1417            vec![parameter_meta.clone(), parameter_meta],
1418            Ok(()),
1419        );
1420    }
1421
1422    #[test]
1423    fn test_bpf_loader_upgradeable_initialize_buffer() {
1424        let loader_id = bpf_loader_upgradeable::id();
1425        let buffer_address = Pubkey::new_unique();
1426        let buffer_account =
1427            AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
1428        let authority_address = Pubkey::new_unique();
1429        let authority_account =
1430            AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
1431        let instruction_data =
1432            bincode::serialize(&UpgradeableLoaderInstruction::InitializeBuffer).unwrap();
1433        let instruction_accounts = vec![
1434            AccountMeta {
1435                pubkey: buffer_address,
1436                is_signer: false,
1437                is_writable: true,
1438            },
1439            AccountMeta {
1440                pubkey: authority_address,
1441                is_signer: false,
1442                is_writable: false,
1443            },
1444        ];
1445
1446        // Case: Success
1447        let accounts = process_instruction(
1448            &loader_id,
1449            &instruction_data,
1450            vec![
1451                (buffer_address, buffer_account),
1452                (authority_address, authority_account),
1453            ],
1454            instruction_accounts.clone(),
1455            Ok(()),
1456        );
1457        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
1458        assert_eq!(
1459            state,
1460            UpgradeableLoaderState::Buffer {
1461                authority_address: Some(authority_address)
1462            }
1463        );
1464
1465        // Case: Already initialized
1466        let accounts = process_instruction(
1467            &loader_id,
1468            &instruction_data,
1469            vec![
1470                (buffer_address, accounts.first().unwrap().clone()),
1471                (authority_address, accounts.get(1).unwrap().clone()),
1472            ],
1473            instruction_accounts,
1474            Err(InstructionError::AccountAlreadyInitialized),
1475        );
1476        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
1477        assert_eq!(
1478            state,
1479            UpgradeableLoaderState::Buffer {
1480                authority_address: Some(authority_address)
1481            }
1482        );
1483    }
1484
1485    #[test]
1486    fn test_bpf_loader_upgradeable_write() {
1487        let loader_id = bpf_loader_upgradeable::id();
1488        let buffer_address = Pubkey::new_unique();
1489        let mut buffer_account =
1490            AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
1491        let instruction_accounts = vec![
1492            AccountMeta {
1493                pubkey: buffer_address,
1494                is_signer: false,
1495                is_writable: true,
1496            },
1497            AccountMeta {
1498                pubkey: buffer_address,
1499                is_signer: true,
1500                is_writable: false,
1501            },
1502        ];
1503
1504        // Case: Not initialized
1505        let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
1506            offset: 0,
1507            bytes: vec![42; 9],
1508        })
1509        .unwrap();
1510        process_instruction(
1511            &loader_id,
1512            &instruction,
1513            vec![(buffer_address, buffer_account.clone())],
1514            instruction_accounts.clone(),
1515            Err(InstructionError::InvalidAccountData),
1516        );
1517
1518        // Case: Write entire buffer
1519        let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
1520            offset: 0,
1521            bytes: vec![42; 9],
1522        })
1523        .unwrap();
1524        buffer_account
1525            .set_state(&UpgradeableLoaderState::Buffer {
1526                authority_address: Some(buffer_address),
1527            })
1528            .unwrap();
1529        let accounts = process_instruction(
1530            &loader_id,
1531            &instruction,
1532            vec![(buffer_address, buffer_account.clone())],
1533            instruction_accounts.clone(),
1534            Ok(()),
1535        );
1536        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
1537        assert_eq!(
1538            state,
1539            UpgradeableLoaderState::Buffer {
1540                authority_address: Some(buffer_address)
1541            }
1542        );
1543        assert_eq!(
1544            &accounts
1545                .first()
1546                .unwrap()
1547                .data()
1548                .get(UpgradeableLoaderState::size_of_buffer_metadata()..)
1549                .unwrap(),
1550            &[42; 9]
1551        );
1552
1553        // Case: Write portion of the buffer
1554        let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
1555            offset: 3,
1556            bytes: vec![42; 6],
1557        })
1558        .unwrap();
1559        let mut buffer_account =
1560            AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
1561        buffer_account
1562            .set_state(&UpgradeableLoaderState::Buffer {
1563                authority_address: Some(buffer_address),
1564            })
1565            .unwrap();
1566        let accounts = process_instruction(
1567            &loader_id,
1568            &instruction,
1569            vec![(buffer_address, buffer_account.clone())],
1570            instruction_accounts.clone(),
1571            Ok(()),
1572        );
1573        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
1574        assert_eq!(
1575            state,
1576            UpgradeableLoaderState::Buffer {
1577                authority_address: Some(buffer_address)
1578            }
1579        );
1580        assert_eq!(
1581            &accounts
1582                .first()
1583                .unwrap()
1584                .data()
1585                .get(UpgradeableLoaderState::size_of_buffer_metadata()..)
1586                .unwrap(),
1587            &[0, 0, 0, 42, 42, 42, 42, 42, 42]
1588        );
1589
1590        // Case: overflow size
1591        let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
1592            offset: 0,
1593            bytes: vec![42; 10],
1594        })
1595        .unwrap();
1596        buffer_account
1597            .set_state(&UpgradeableLoaderState::Buffer {
1598                authority_address: Some(buffer_address),
1599            })
1600            .unwrap();
1601        process_instruction(
1602            &loader_id,
1603            &instruction,
1604            vec![(buffer_address, buffer_account.clone())],
1605            instruction_accounts.clone(),
1606            Err(InstructionError::AccountDataTooSmall),
1607        );
1608
1609        // Case: overflow offset
1610        let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
1611            offset: 1,
1612            bytes: vec![42; 9],
1613        })
1614        .unwrap();
1615        buffer_account
1616            .set_state(&UpgradeableLoaderState::Buffer {
1617                authority_address: Some(buffer_address),
1618            })
1619            .unwrap();
1620        process_instruction(
1621            &loader_id,
1622            &instruction,
1623            vec![(buffer_address, buffer_account.clone())],
1624            instruction_accounts.clone(),
1625            Err(InstructionError::AccountDataTooSmall),
1626        );
1627
1628        // Case: Not signed
1629        let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
1630            offset: 0,
1631            bytes: vec![42; 9],
1632        })
1633        .unwrap();
1634        buffer_account
1635            .set_state(&UpgradeableLoaderState::Buffer {
1636                authority_address: Some(buffer_address),
1637            })
1638            .unwrap();
1639        process_instruction(
1640            &loader_id,
1641            &instruction,
1642            vec![(buffer_address, buffer_account.clone())],
1643            vec![
1644                AccountMeta {
1645                    pubkey: buffer_address,
1646                    is_signer: false,
1647                    is_writable: false,
1648                },
1649                AccountMeta {
1650                    pubkey: buffer_address,
1651                    is_signer: false,
1652                    is_writable: false,
1653                },
1654            ],
1655            Err(InstructionError::MissingRequiredSignature),
1656        );
1657
1658        // Case: wrong authority
1659        let authority_address = Pubkey::new_unique();
1660        let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
1661            offset: 1,
1662            bytes: vec![42; 9],
1663        })
1664        .unwrap();
1665        buffer_account
1666            .set_state(&UpgradeableLoaderState::Buffer {
1667                authority_address: Some(buffer_address),
1668            })
1669            .unwrap();
1670        process_instruction(
1671            &loader_id,
1672            &instruction,
1673            vec![
1674                (buffer_address, buffer_account.clone()),
1675                (authority_address, buffer_account.clone()),
1676            ],
1677            vec![
1678                AccountMeta {
1679                    pubkey: buffer_address,
1680                    is_signer: false,
1681                    is_writable: false,
1682                },
1683                AccountMeta {
1684                    pubkey: authority_address,
1685                    is_signer: false,
1686                    is_writable: false,
1687                },
1688            ],
1689            Err(InstructionError::IncorrectAuthority),
1690        );
1691
1692        // Case: None authority
1693        let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
1694            offset: 1,
1695            bytes: vec![42; 9],
1696        })
1697        .unwrap();
1698        buffer_account
1699            .set_state(&UpgradeableLoaderState::Buffer {
1700                authority_address: None,
1701            })
1702            .unwrap();
1703        process_instruction(
1704            &loader_id,
1705            &instruction,
1706            vec![(buffer_address, buffer_account.clone())],
1707            instruction_accounts,
1708            Err(InstructionError::Immutable),
1709        );
1710    }
1711
1712    fn truncate_data(account: &mut AccountSharedData, len: usize) {
1713        let mut data = account.data().to_vec();
1714        data.truncate(len);
1715        account.set_data_from_slice(&data);
1716    }
1717
1718    #[test]
1719    fn test_bpf_loader_upgradeable_upgrade() {
1720        let mut file = File::open("test_elfs/out/sbpfv3_return_ok.so").expect("file open failed");
1721        let mut elf_orig = Vec::new();
1722        file.read_to_end(&mut elf_orig).unwrap();
1723        let mut file = File::open("test_elfs/out/sbpfv3_return_err.so").expect("file open failed");
1724        let mut elf_new = Vec::new();
1725        file.read_to_end(&mut elf_new).unwrap();
1726        assert_ne!(elf_orig.len(), elf_new.len());
1727        const SLOT: u64 = 42;
1728        let buffer_address = Pubkey::new_unique();
1729        let upgrade_authority_address = Pubkey::new_unique();
1730
1731        fn get_accounts(
1732            buffer_address: &Pubkey,
1733            buffer_authority: &Pubkey,
1734            upgrade_authority_address: &Pubkey,
1735            elf_orig: &[u8],
1736            elf_new: &[u8],
1737        ) -> (Vec<(Pubkey, AccountSharedData)>, Vec<AccountMeta>) {
1738            let loader_id = bpf_loader_upgradeable::id();
1739            let program_address = Pubkey::new_unique();
1740            let spill_address = Pubkey::new_unique();
1741            let rent = Rent::default();
1742            let min_program_balance =
1743                1.max(rent.minimum_balance(UpgradeableLoaderState::size_of_program()));
1744            let min_programdata_balance = 1.max(rent.minimum_balance(
1745                UpgradeableLoaderState::size_of_programdata(elf_orig.len().max(elf_new.len())),
1746            ));
1747            let (programdata_address, _) =
1748                Pubkey::find_program_address(&[program_address.as_ref()], &loader_id);
1749            let mut buffer_account = AccountSharedData::new(
1750                1,
1751                UpgradeableLoaderState::size_of_buffer(elf_new.len()),
1752                &bpf_loader_upgradeable::id(),
1753            );
1754            buffer_account
1755                .set_state(&UpgradeableLoaderState::Buffer {
1756                    authority_address: Some(*buffer_authority),
1757                })
1758                .unwrap();
1759            buffer_account
1760                .data_as_mut_slice()
1761                .get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..)
1762                .unwrap()
1763                .copy_from_slice(elf_new);
1764            let mut programdata_account = AccountSharedData::new(
1765                min_programdata_balance,
1766                UpgradeableLoaderState::size_of_programdata(elf_orig.len().max(elf_new.len())),
1767                &bpf_loader_upgradeable::id(),
1768            );
1769            programdata_account
1770                .set_state(&UpgradeableLoaderState::ProgramData {
1771                    slot: SLOT,
1772                    upgrade_authority_address: Some(*upgrade_authority_address),
1773                })
1774                .unwrap();
1775            let mut program_account = AccountSharedData::new(
1776                min_program_balance,
1777                UpgradeableLoaderState::size_of_program(),
1778                &bpf_loader_upgradeable::id(),
1779            );
1780            program_account.set_executable(true);
1781            program_account
1782                .set_state(&UpgradeableLoaderState::Program {
1783                    programdata_address,
1784                })
1785                .unwrap();
1786            let spill_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
1787            let rent_account = create_sysvar_account(&rent);
1788            let clock_account = create_sysvar_account(&Clock {
1789                slot: SLOT.saturating_add(1),
1790                ..Clock::default()
1791            });
1792            let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
1793            let transaction_accounts = vec![
1794                (programdata_address, programdata_account),
1795                (program_address, program_account),
1796                (*buffer_address, buffer_account),
1797                (spill_address, spill_account),
1798                (sysvar::rent::id(), rent_account),
1799                (sysvar::clock::id(), clock_account),
1800                (*upgrade_authority_address, upgrade_authority_account),
1801            ];
1802            let instruction_accounts = vec![
1803                AccountMeta {
1804                    pubkey: programdata_address,
1805                    is_signer: false,
1806                    is_writable: true,
1807                },
1808                AccountMeta {
1809                    pubkey: program_address,
1810                    is_signer: false,
1811                    is_writable: true,
1812                },
1813                AccountMeta {
1814                    pubkey: *buffer_address,
1815                    is_signer: false,
1816                    is_writable: true,
1817                },
1818                AccountMeta {
1819                    pubkey: spill_address,
1820                    is_signer: false,
1821                    is_writable: true,
1822                },
1823                AccountMeta {
1824                    pubkey: sysvar::rent::id(),
1825                    is_signer: false,
1826                    is_writable: false,
1827                },
1828                AccountMeta {
1829                    pubkey: sysvar::clock::id(),
1830                    is_signer: false,
1831                    is_writable: false,
1832                },
1833                AccountMeta {
1834                    pubkey: *upgrade_authority_address,
1835                    is_signer: true,
1836                    is_writable: false,
1837                },
1838            ];
1839            (transaction_accounts, instruction_accounts)
1840        }
1841
1842        fn process_instruction(
1843            transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
1844            instruction_accounts: Vec<AccountMeta>,
1845            expected_result: Result<(), InstructionError>,
1846        ) -> Vec<AccountSharedData> {
1847            let instruction_data =
1848                bincode::serialize(&UpgradeableLoaderInstruction::Upgrade).unwrap();
1849            process_instruction_with_setup(
1850                &bpf_loader_upgradeable::id(),
1851                &instruction_data,
1852                transaction_accounts,
1853                instruction_accounts,
1854                expected_result,
1855                |_invoke_context| {},
1856            )
1857        }
1858
1859        // Case: Success
1860        let (transaction_accounts, instruction_accounts) = get_accounts(
1861            &buffer_address,
1862            &upgrade_authority_address,
1863            &upgrade_authority_address,
1864            &elf_orig,
1865            &elf_new,
1866        );
1867        let accounts = process_instruction(transaction_accounts, instruction_accounts, Ok(()));
1868        let min_programdata_balance = Rent::default().minimum_balance(
1869            UpgradeableLoaderState::size_of_programdata(elf_orig.len().max(elf_new.len())),
1870        );
1871        assert_eq!(
1872            min_programdata_balance,
1873            accounts.first().unwrap().lamports()
1874        );
1875        assert_eq!(0, accounts.get(2).unwrap().lamports());
1876        assert_eq!(1, accounts.get(3).unwrap().lamports());
1877        assert_eq!(
1878            UpgradeableLoaderState::size_of_buffer(0),
1879            accounts.get(2).unwrap().data().len()
1880        );
1881        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
1882        assert_eq!(
1883            state,
1884            UpgradeableLoaderState::ProgramData {
1885                slot: SLOT.saturating_add(1),
1886                upgrade_authority_address: Some(upgrade_authority_address)
1887            }
1888        );
1889        for (i, byte) in accounts
1890            .first()
1891            .unwrap()
1892            .data()
1893            .get(
1894                UpgradeableLoaderState::size_of_programdata_metadata()
1895                    ..UpgradeableLoaderState::size_of_programdata(elf_new.len()),
1896            )
1897            .unwrap()
1898            .iter()
1899            .enumerate()
1900        {
1901            assert_eq!(*elf_new.get(i).unwrap(), *byte);
1902        }
1903
1904        // Case: not upgradable
1905        let (mut transaction_accounts, instruction_accounts) = get_accounts(
1906            &buffer_address,
1907            &upgrade_authority_address,
1908            &upgrade_authority_address,
1909            &elf_orig,
1910            &elf_new,
1911        );
1912        transaction_accounts
1913            .get_mut(0)
1914            .unwrap()
1915            .1
1916            .set_state(&UpgradeableLoaderState::ProgramData {
1917                slot: SLOT,
1918                upgrade_authority_address: None,
1919            })
1920            .unwrap();
1921        process_instruction(
1922            transaction_accounts,
1923            instruction_accounts,
1924            Err(InstructionError::Immutable),
1925        );
1926
1927        // Case: wrong authority
1928        let (mut transaction_accounts, mut instruction_accounts) = get_accounts(
1929            &buffer_address,
1930            &upgrade_authority_address,
1931            &upgrade_authority_address,
1932            &elf_orig,
1933            &elf_new,
1934        );
1935        let invalid_upgrade_authority_address = Pubkey::new_unique();
1936        transaction_accounts.get_mut(6).unwrap().0 = invalid_upgrade_authority_address;
1937        instruction_accounts.get_mut(6).unwrap().pubkey = invalid_upgrade_authority_address;
1938        process_instruction(
1939            transaction_accounts,
1940            instruction_accounts,
1941            Err(InstructionError::IncorrectAuthority),
1942        );
1943
1944        // Case: authority did not sign
1945        let (transaction_accounts, mut instruction_accounts) = get_accounts(
1946            &buffer_address,
1947            &upgrade_authority_address,
1948            &upgrade_authority_address,
1949            &elf_orig,
1950            &elf_new,
1951        );
1952        instruction_accounts.get_mut(6).unwrap().is_signer = false;
1953        process_instruction(
1954            transaction_accounts,
1955            instruction_accounts,
1956            Err(InstructionError::MissingRequiredSignature),
1957        );
1958
1959        // Case: Buffer account and spill account alias
1960        let (transaction_accounts, mut instruction_accounts) = get_accounts(
1961            &buffer_address,
1962            &upgrade_authority_address,
1963            &upgrade_authority_address,
1964            &elf_orig,
1965            &elf_new,
1966        );
1967        *instruction_accounts.get_mut(3).unwrap() = instruction_accounts.get(2).unwrap().clone();
1968        process_instruction(
1969            transaction_accounts,
1970            instruction_accounts,
1971            Err(InstructionError::AccountBorrowFailed),
1972        );
1973
1974        // Case: Programdata account and spill account alias
1975        let (transaction_accounts, mut instruction_accounts) = get_accounts(
1976            &buffer_address,
1977            &upgrade_authority_address,
1978            &upgrade_authority_address,
1979            &elf_orig,
1980            &elf_new,
1981        );
1982        *instruction_accounts.get_mut(3).unwrap() = instruction_accounts.first().unwrap().clone();
1983        process_instruction(
1984            transaction_accounts,
1985            instruction_accounts,
1986            Err(InstructionError::AccountBorrowFailed),
1987        );
1988
1989        // Case: Program account not a program
1990        let (transaction_accounts, mut instruction_accounts) = get_accounts(
1991            &buffer_address,
1992            &upgrade_authority_address,
1993            &upgrade_authority_address,
1994            &elf_orig,
1995            &elf_new,
1996        );
1997        *instruction_accounts.get_mut(1).unwrap() = instruction_accounts.get(2).unwrap().clone();
1998        let instruction_data = bincode::serialize(&UpgradeableLoaderInstruction::Upgrade).unwrap();
1999
2000        process_instruction_with_setup(
2001            &bpf_loader_upgradeable::id(),
2002            &instruction_data,
2003            transaction_accounts.clone(),
2004            instruction_accounts.clone(),
2005            Err(InstructionError::InvalidAccountData),
2006            |invoke_context| {
2007                test_utils::load_all_invoked_programs(invoke_context);
2008            },
2009        );
2010        process_instruction(
2011            transaction_accounts.clone(),
2012            instruction_accounts.clone(),
2013            Err(InstructionError::InvalidAccountData),
2014        );
2015
2016        // Case: Program account now owned by loader
2017        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2018            &buffer_address,
2019            &upgrade_authority_address,
2020            &upgrade_authority_address,
2021            &elf_orig,
2022            &elf_new,
2023        );
2024        transaction_accounts
2025            .get_mut(1)
2026            .unwrap()
2027            .1
2028            .set_owner(Pubkey::new_unique());
2029        process_instruction(
2030            transaction_accounts,
2031            instruction_accounts,
2032            Err(InstructionError::IncorrectProgramId),
2033        );
2034
2035        // Case: Program account not writable
2036        let (transaction_accounts, mut instruction_accounts) = get_accounts(
2037            &buffer_address,
2038            &upgrade_authority_address,
2039            &upgrade_authority_address,
2040            &elf_orig,
2041            &elf_new,
2042        );
2043        instruction_accounts.get_mut(1).unwrap().is_writable = false;
2044        process_instruction(
2045            transaction_accounts,
2046            instruction_accounts,
2047            Err(InstructionError::InvalidArgument),
2048        );
2049
2050        // Case: Program account not initialized
2051        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2052            &buffer_address,
2053            &upgrade_authority_address,
2054            &upgrade_authority_address,
2055            &elf_orig,
2056            &elf_new,
2057        );
2058        transaction_accounts
2059            .get_mut(1)
2060            .unwrap()
2061            .1
2062            .set_state(&UpgradeableLoaderState::Uninitialized)
2063            .unwrap();
2064        process_instruction(
2065            transaction_accounts,
2066            instruction_accounts,
2067            Err(InstructionError::InvalidAccountData),
2068        );
2069
2070        // Case: Program ProgramData account mismatch
2071        let (mut transaction_accounts, mut instruction_accounts) = get_accounts(
2072            &buffer_address,
2073            &upgrade_authority_address,
2074            &upgrade_authority_address,
2075            &elf_orig,
2076            &elf_new,
2077        );
2078        let invalid_programdata_address = Pubkey::new_unique();
2079        transaction_accounts.get_mut(0).unwrap().0 = invalid_programdata_address;
2080        instruction_accounts.get_mut(0).unwrap().pubkey = invalid_programdata_address;
2081        process_instruction(
2082            transaction_accounts,
2083            instruction_accounts,
2084            Err(InstructionError::InvalidArgument),
2085        );
2086
2087        // Case: Buffer account not initialized
2088        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2089            &buffer_address,
2090            &upgrade_authority_address,
2091            &upgrade_authority_address,
2092            &elf_orig,
2093            &elf_new,
2094        );
2095        transaction_accounts
2096            .get_mut(2)
2097            .unwrap()
2098            .1
2099            .set_state(&UpgradeableLoaderState::Uninitialized)
2100            .unwrap();
2101        process_instruction(
2102            transaction_accounts,
2103            instruction_accounts,
2104            Err(InstructionError::InvalidArgument),
2105        );
2106
2107        // Case: Buffer account not writable
2108        for buffer_balance in [0, 1_000_000, 15 * 1_000_000_000] {
2109            let (mut transaction_accounts, mut instruction_accounts) = get_accounts(
2110                &buffer_address,
2111                &upgrade_authority_address,
2112                &upgrade_authority_address,
2113                &elf_orig,
2114                &elf_new,
2115            );
2116            transaction_accounts
2117                .get_mut(2)
2118                .unwrap()
2119                .1
2120                .set_lamports(buffer_balance);
2121            instruction_accounts.get_mut(2).unwrap().is_writable = false;
2122            process_instruction(
2123                transaction_accounts,
2124                instruction_accounts,
2125                Err(InstructionError::InvalidArgument),
2126            );
2127        }
2128
2129        // Case: Buffer account not owned by loader: lamports scenario
2130        //
2131        // In `Upgrade`, the buffer's lamports are used to fund the additional
2132        // programdata rent directly, with the rest spilled to the spill
2133        // account. Then, the buffer's data is set to `size_of_buffer(0)`.
2134        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2135            &buffer_address,
2136            &upgrade_authority_address,
2137            &upgrade_authority_address,
2138            &elf_orig,
2139            &elf_new,
2140        );
2141        {
2142            // Let's make sure the programdata requires a top-up.
2143            let required_rent = |elf_len| {
2144                Rent::default()
2145                    .minimum_balance(UpgradeableLoaderState::size_of_programdata(elf_len))
2146            };
2147            let rent_orig = required_rent(elf_orig.len());
2148            let rent_new = required_rent(elf_new.len());
2149            let programdata = &mut transaction_accounts.first_mut().unwrap().1;
2150            programdata.set_lamports(rent_orig);
2151            let buffer = &mut transaction_accounts.get_mut(2).unwrap().1;
2152            buffer.set_owner(Pubkey::new_unique());
2153            buffer.set_lamports(rent_new);
2154        }
2155        process_instruction(
2156            transaction_accounts,
2157            instruction_accounts,
2158            Err(InstructionError::IncorrectProgramId),
2159        );
2160
2161        // Case: Buffer account not owned by loader: shrink scenario
2162        //
2163        // Same as the above case, but give the buffer a lamports balance of
2164        // `0`, rendering its balance "unchanged" by the spill operation.
2165        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2166            &buffer_address,
2167            &upgrade_authority_address,
2168            &upgrade_authority_address,
2169            &elf_orig,
2170            &elf_new,
2171        );
2172        {
2173            // Set the buffer's lamports to zero.
2174            let buffer = &mut transaction_accounts.get_mut(2).unwrap().1;
2175            buffer.set_owner(Pubkey::new_unique());
2176            buffer.set_lamports(0);
2177        }
2178        process_instruction(
2179            transaction_accounts,
2180            instruction_accounts,
2181            Err(InstructionError::IncorrectProgramId),
2182        );
2183
2184        // Case: Buffer account not owned by loader: no-op scenario
2185        //
2186        // Same as the above case, but also truncate the buffer's data to
2187        // `size_of_buffer(0)` - just the buffer metadata, no ELF - rendering
2188        // the closing resize "unchanged" as well.
2189        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2190            &buffer_address,
2191            &upgrade_authority_address,
2192            &upgrade_authority_address,
2193            &elf_orig,
2194            &elf_new,
2195        );
2196        {
2197            // Empty the buffer (metadata only) and zero its lamports.
2198            let buffer = &mut transaction_accounts.get_mut(2).unwrap().1;
2199            buffer.set_owner(Pubkey::new_unique());
2200            buffer.set_lamports(0);
2201            truncate_data(buffer, UpgradeableLoaderState::size_of_buffer(0));
2202        }
2203        process_instruction(
2204            transaction_accounts,
2205            instruction_accounts,
2206            Err(InstructionError::IncorrectProgramId),
2207        );
2208
2209        // Case: Buffer account too big
2210        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2211            &buffer_address,
2212            &upgrade_authority_address,
2213            &upgrade_authority_address,
2214            &elf_orig,
2215            &elf_new,
2216        );
2217        transaction_accounts.get_mut(2).unwrap().1 = AccountSharedData::new(
2218            1,
2219            UpgradeableLoaderState::size_of_buffer(
2220                elf_orig.len().max(elf_new.len()).saturating_add(1),
2221            ),
2222            &bpf_loader_upgradeable::id(),
2223        );
2224        transaction_accounts
2225            .get_mut(2)
2226            .unwrap()
2227            .1
2228            .set_state(&UpgradeableLoaderState::Buffer {
2229                authority_address: Some(upgrade_authority_address),
2230            })
2231            .unwrap();
2232        process_instruction(
2233            transaction_accounts,
2234            instruction_accounts,
2235            Err(InstructionError::AccountDataTooSmall),
2236        );
2237
2238        // Case: Buffer account too small
2239        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2240            &buffer_address,
2241            &upgrade_authority_address,
2242            &upgrade_authority_address,
2243            &elf_orig,
2244            &elf_new,
2245        );
2246        transaction_accounts
2247            .get_mut(2)
2248            .unwrap()
2249            .1
2250            .set_state(&UpgradeableLoaderState::Buffer {
2251                authority_address: Some(upgrade_authority_address),
2252            })
2253            .unwrap();
2254        truncate_data(&mut transaction_accounts.get_mut(2).unwrap().1, 5);
2255        process_instruction(
2256            transaction_accounts,
2257            instruction_accounts,
2258            Err(InstructionError::InvalidAccountData),
2259        );
2260
2261        // Case: Mismatched buffer and program authority
2262        let (transaction_accounts, instruction_accounts) = get_accounts(
2263            &buffer_address,
2264            &buffer_address,
2265            &upgrade_authority_address,
2266            &elf_orig,
2267            &elf_new,
2268        );
2269        process_instruction(
2270            transaction_accounts,
2271            instruction_accounts,
2272            Err(InstructionError::IncorrectAuthority),
2273        );
2274
2275        // Case: No buffer authority
2276        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2277            &buffer_address,
2278            &buffer_address,
2279            &upgrade_authority_address,
2280            &elf_orig,
2281            &elf_new,
2282        );
2283        transaction_accounts
2284            .get_mut(2)
2285            .unwrap()
2286            .1
2287            .set_state(&UpgradeableLoaderState::Buffer {
2288                authority_address: None,
2289            })
2290            .unwrap();
2291        process_instruction(
2292            transaction_accounts,
2293            instruction_accounts,
2294            Err(InstructionError::IncorrectAuthority),
2295        );
2296
2297        // Case: No buffer and program authority
2298        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2299            &buffer_address,
2300            &buffer_address,
2301            &upgrade_authority_address,
2302            &elf_orig,
2303            &elf_new,
2304        );
2305        transaction_accounts
2306            .get_mut(0)
2307            .unwrap()
2308            .1
2309            .set_state(&UpgradeableLoaderState::ProgramData {
2310                slot: SLOT,
2311                upgrade_authority_address: None,
2312            })
2313            .unwrap();
2314        transaction_accounts
2315            .get_mut(2)
2316            .unwrap()
2317            .1
2318            .set_state(&UpgradeableLoaderState::Buffer {
2319                authority_address: None,
2320            })
2321            .unwrap();
2322        process_instruction(
2323            transaction_accounts,
2324            instruction_accounts,
2325            Err(InstructionError::IncorrectAuthority),
2326        );
2327
2328        // Case: Upgrade to SBPFv0
2329        let mut file =
2330            File::open("test_elfs/out/sbpfv0_verifier_err.so").expect("file open failed");
2331        let mut elf_new = Vec::new();
2332        file.read_to_end(&mut elf_new).unwrap();
2333        let (transaction_accounts, instruction_accounts) = get_accounts(
2334            &buffer_address,
2335            &upgrade_authority_address,
2336            &upgrade_authority_address,
2337            &elf_orig,
2338            &elf_new,
2339        );
2340        process_instruction(
2341            transaction_accounts,
2342            instruction_accounts,
2343            Err(InstructionError::InvalidAccountData),
2344        );
2345    }
2346
2347    #[test]
2348    fn test_bpf_loader_upgradeable_deploy_with_max_data_len() {
2349        let mut file = File::open("test_elfs/out/sbpfv3_return_ok.so").expect("file open failed");
2350        let mut elf = Vec::new();
2351        file.read_to_end(&mut elf).unwrap();
2352        const SLOT: u64 = 42;
2353        let payer_address = Pubkey::new_unique();
2354        let buffer_address = Pubkey::new_unique();
2355        let upgrade_authority_address = Pubkey::new_unique();
2356
2357        fn get_accounts(
2358            payer_address: &Pubkey,
2359            buffer_address: &Pubkey,
2360            buffer_authority: &Pubkey,
2361            upgrade_authority_address: &Pubkey,
2362            elf: &[u8],
2363        ) -> (Vec<(Pubkey, AccountSharedData)>, Vec<AccountMeta>) {
2364            let loader_id = bpf_loader_upgradeable::id();
2365            let program_address = Pubkey::new_unique();
2366            let rent = Rent::default();
2367            let min_program_balance =
2368                1.max(rent.minimum_balance(UpgradeableLoaderState::size_of_program()));
2369            let min_programdata_balance =
2370                1.max(rent.minimum_balance(UpgradeableLoaderState::size_of_programdata(elf.len())));
2371            let (programdata_address, _) =
2372                Pubkey::find_program_address(&[program_address.as_ref()], &loader_id);
2373            let mut buffer_account = AccountSharedData::new(
2374                1,
2375                UpgradeableLoaderState::size_of_buffer(elf.len()),
2376                &bpf_loader_upgradeable::id(),
2377            );
2378            buffer_account
2379                .set_state(&UpgradeableLoaderState::Buffer {
2380                    authority_address: Some(*buffer_authority),
2381                })
2382                .unwrap();
2383            buffer_account
2384                .data_as_mut_slice()
2385                .get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..)
2386                .unwrap()
2387                .copy_from_slice(elf);
2388            let programdata_account = AccountSharedData::new(0, 0, &system_program::id());
2389            let mut program_account = AccountSharedData::new(
2390                min_program_balance,
2391                UpgradeableLoaderState::size_of_program(),
2392                &bpf_loader_upgradeable::id(),
2393            );
2394            program_account
2395                .set_state(&UpgradeableLoaderState::Uninitialized)
2396                .unwrap();
2397            let payer_account = AccountSharedData::new(
2398                min_programdata_balance.saturating_add(1),
2399                0,
2400                &system_program::id(),
2401            );
2402            let rent_account = create_sysvar_account(&rent);
2403            let clock_account = create_sysvar_account(&Clock {
2404                slot: SLOT,
2405                ..Clock::default()
2406            });
2407            let system_program_account = AccountSharedData::new(0, 0, &native_loader::id());
2408            let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
2409            let transaction_accounts = vec![
2410                (*payer_address, payer_account),
2411                (programdata_address, programdata_account),
2412                (program_address, program_account),
2413                (*buffer_address, buffer_account),
2414                (sysvar::rent::id(), rent_account),
2415                (sysvar::clock::id(), clock_account),
2416                (system_program::id(), system_program_account),
2417                (*upgrade_authority_address, upgrade_authority_account),
2418            ];
2419            let instruction_accounts = vec![
2420                AccountMeta {
2421                    pubkey: *payer_address,
2422                    is_signer: true,
2423                    is_writable: true,
2424                },
2425                AccountMeta {
2426                    pubkey: programdata_address,
2427                    is_signer: false,
2428                    is_writable: true,
2429                },
2430                AccountMeta {
2431                    pubkey: program_address,
2432                    is_signer: false,
2433                    is_writable: true,
2434                },
2435                AccountMeta {
2436                    pubkey: *buffer_address,
2437                    is_signer: false,
2438                    is_writable: true,
2439                },
2440                AccountMeta {
2441                    pubkey: sysvar::rent::id(),
2442                    is_signer: false,
2443                    is_writable: false,
2444                },
2445                AccountMeta {
2446                    pubkey: sysvar::clock::id(),
2447                    is_signer: false,
2448                    is_writable: false,
2449                },
2450                AccountMeta {
2451                    pubkey: system_program::id(),
2452                    is_signer: false,
2453                    is_writable: false,
2454                },
2455                AccountMeta {
2456                    pubkey: *upgrade_authority_address,
2457                    is_signer: true,
2458                    is_writable: false,
2459                },
2460            ];
2461            (transaction_accounts, instruction_accounts)
2462        }
2463
2464        fn process_instruction(
2465            max_data_len: usize,
2466            transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
2467            instruction_accounts: Vec<AccountMeta>,
2468            expected_result: Result<(), InstructionError>,
2469        ) -> Vec<AccountSharedData> {
2470            let instruction_data =
2471                bincode::serialize(&UpgradeableLoaderInstruction::DeployWithMaxDataLen {
2472                    max_data_len,
2473                })
2474                .unwrap();
2475            process_instruction_with_setup(
2476                &bpf_loader_upgradeable::id(),
2477                &instruction_data,
2478                transaction_accounts,
2479                instruction_accounts,
2480                expected_result,
2481                |invoke_context| {
2482                    // Register the system program for CPI support.
2483                    invoke_context.program_cache_for_tx_batch.replenish(
2484                        system_program::id(),
2485                        Arc::new(ProgramCacheEntry::new_builtin(
2486                            solana_system_program::system_processor::Entrypoint::register,
2487                        )),
2488                    );
2489                },
2490            )
2491        }
2492
2493        // Case: Success
2494        let (transaction_accounts, instruction_accounts) = get_accounts(
2495            &payer_address,
2496            &buffer_address,
2497            &upgrade_authority_address,
2498            &upgrade_authority_address,
2499            &elf,
2500        );
2501        let programdata_address = instruction_accounts.get(1).unwrap().pubkey;
2502        let accounts = process_instruction(
2503            elf.len(),
2504            transaction_accounts,
2505            instruction_accounts,
2506            Ok(()),
2507        );
2508        let min_programdata_balance =
2509            Rent::default().minimum_balance(UpgradeableLoaderState::size_of_programdata(elf.len()));
2510        assert_eq!(min_programdata_balance, accounts.get(1).unwrap().lamports());
2511        assert_eq!(2, accounts.first().unwrap().lamports());
2512        assert_eq!(0, accounts.get(3).unwrap().lamports());
2513        assert_eq!(
2514            UpgradeableLoaderState::size_of_buffer(0),
2515            accounts.get(3).unwrap().data().len()
2516        );
2517        let state: UpgradeableLoaderState = accounts.get(1).unwrap().state().unwrap();
2518        assert_eq!(
2519            state,
2520            UpgradeableLoaderState::ProgramData {
2521                slot: SLOT,
2522                upgrade_authority_address: Some(upgrade_authority_address),
2523            }
2524        );
2525        for (i, byte) in accounts
2526            .get(1)
2527            .unwrap()
2528            .data()
2529            .get(
2530                UpgradeableLoaderState::size_of_programdata_metadata()
2531                    ..UpgradeableLoaderState::size_of_programdata(elf.len()),
2532            )
2533            .unwrap()
2534            .iter()
2535            .enumerate()
2536        {
2537            assert_eq!(*elf.get(i).unwrap(), *byte);
2538        }
2539        let state: UpgradeableLoaderState = accounts.get(2).unwrap().state().unwrap();
2540        assert_eq!(
2541            state,
2542            UpgradeableLoaderState::Program {
2543                programdata_address,
2544            }
2545        );
2546        assert!(accounts.get(2).unwrap().executable());
2547
2548        // Case: wrong authority
2549        let (mut transaction_accounts, mut instruction_accounts) = get_accounts(
2550            &payer_address,
2551            &buffer_address,
2552            &upgrade_authority_address,
2553            &upgrade_authority_address,
2554            &elf,
2555        );
2556        let invalid_upgrade_authority_address = Pubkey::new_unique();
2557        transaction_accounts.get_mut(7).unwrap().0 = invalid_upgrade_authority_address;
2558        instruction_accounts.get_mut(7).unwrap().pubkey = invalid_upgrade_authority_address;
2559        process_instruction(
2560            elf.len(),
2561            transaction_accounts,
2562            instruction_accounts,
2563            Err(InstructionError::IncorrectAuthority),
2564        );
2565
2566        // Case: authority did not sign
2567        let (transaction_accounts, mut instruction_accounts) = get_accounts(
2568            &payer_address,
2569            &buffer_address,
2570            &upgrade_authority_address,
2571            &upgrade_authority_address,
2572            &elf,
2573        );
2574        instruction_accounts.get_mut(7).unwrap().is_signer = false;
2575        process_instruction(
2576            elf.len(),
2577            transaction_accounts,
2578            instruction_accounts,
2579            Err(InstructionError::MissingRequiredSignature),
2580        );
2581
2582        // Case: Buffer account and payer account alias
2583        let (transaction_accounts, mut instruction_accounts) = get_accounts(
2584            &payer_address,
2585            &buffer_address,
2586            &upgrade_authority_address,
2587            &upgrade_authority_address,
2588            &elf,
2589        );
2590        *instruction_accounts.get_mut(0).unwrap() = instruction_accounts.get(3).unwrap().clone();
2591        process_instruction(
2592            elf.len(),
2593            transaction_accounts,
2594            instruction_accounts,
2595            Err(InstructionError::AccountBorrowFailed),
2596        );
2597
2598        // Case: Program account not owned by loader
2599        //
2600        // Unlike `Upgrade`, `DeployWithMaxDataLen` has no explicit owner
2601        // check on the program account. Validation passes, and the failure
2602        // only surfaces at the end when the handler tries to mutate the
2603        // program's state — `set_state` requires the account to be owned by
2604        // the currently-executing program, so it trips
2605        // `ExternalAccountDataModified`.
2606        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2607            &payer_address,
2608            &buffer_address,
2609            &upgrade_authority_address,
2610            &upgrade_authority_address,
2611            &elf,
2612        );
2613        transaction_accounts
2614            .get_mut(2)
2615            .unwrap()
2616            .1
2617            .set_owner(Pubkey::new_unique());
2618        process_instruction(
2619            elf.len(),
2620            transaction_accounts,
2621            instruction_accounts,
2622            Err(InstructionError::ExternalAccountDataModified),
2623        );
2624
2625        // Case: Program account not writable
2626        //
2627        // `DeployWithMaxDataLen` also lacks an explicit writability check on
2628        // the program account, so the failure again surfaces at
2629        // `set_state`, this time via the writability guard: a non-writable
2630        // account yields `ReadonlyDataModified`.
2631        let (transaction_accounts, mut instruction_accounts) = get_accounts(
2632            &payer_address,
2633            &buffer_address,
2634            &upgrade_authority_address,
2635            &upgrade_authority_address,
2636            &elf,
2637        );
2638        instruction_accounts.get_mut(2).unwrap().is_writable = false;
2639        process_instruction(
2640            elf.len(),
2641            transaction_accounts,
2642            instruction_accounts,
2643            Err(InstructionError::ReadonlyDataModified),
2644        );
2645
2646        // Case: Program account already initialized
2647        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2648            &payer_address,
2649            &buffer_address,
2650            &upgrade_authority_address,
2651            &upgrade_authority_address,
2652            &elf,
2653        );
2654        transaction_accounts
2655            .get_mut(2)
2656            .unwrap()
2657            .1
2658            .set_state(&UpgradeableLoaderState::Program {
2659                programdata_address: Pubkey::new_unique(),
2660            })
2661            .unwrap();
2662        process_instruction(
2663            elf.len(),
2664            transaction_accounts,
2665            instruction_accounts,
2666            Err(InstructionError::AccountAlreadyInitialized),
2667        );
2668
2669        // Case: Program account too small
2670        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2671            &payer_address,
2672            &buffer_address,
2673            &upgrade_authority_address,
2674            &upgrade_authority_address,
2675            &elf,
2676        );
2677        truncate_data(&mut transaction_accounts.get_mut(2).unwrap().1, 5);
2678        process_instruction(
2679            elf.len(),
2680            transaction_accounts,
2681            instruction_accounts,
2682            Err(InstructionError::AccountDataTooSmall),
2683        );
2684
2685        // Case: Program account not rent-exempt
2686        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2687            &payer_address,
2688            &buffer_address,
2689            &upgrade_authority_address,
2690            &upgrade_authority_address,
2691            &elf,
2692        );
2693        transaction_accounts.get_mut(2).unwrap().1.set_lamports(1);
2694        process_instruction(
2695            elf.len(),
2696            transaction_accounts,
2697            instruction_accounts,
2698            Err(InstructionError::ExecutableAccountNotRentExempt),
2699        );
2700
2701        // Case: ProgramData address not derived
2702        let (mut transaction_accounts, mut instruction_accounts) = get_accounts(
2703            &payer_address,
2704            &buffer_address,
2705            &upgrade_authority_address,
2706            &upgrade_authority_address,
2707            &elf,
2708        );
2709        let invalid_programdata_address = Pubkey::new_unique();
2710        transaction_accounts.get_mut(1).unwrap().0 = invalid_programdata_address;
2711        instruction_accounts.get_mut(1).unwrap().pubkey = invalid_programdata_address;
2712        process_instruction(
2713            elf.len(),
2714            transaction_accounts,
2715            instruction_accounts,
2716            Err(InstructionError::InvalidArgument),
2717        );
2718
2719        // Case: Buffer account not initialized
2720        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2721            &payer_address,
2722            &buffer_address,
2723            &upgrade_authority_address,
2724            &upgrade_authority_address,
2725            &elf,
2726        );
2727        transaction_accounts
2728            .get_mut(3)
2729            .unwrap()
2730            .1
2731            .set_state(&UpgradeableLoaderState::Uninitialized)
2732            .unwrap();
2733        process_instruction(
2734            elf.len(),
2735            transaction_accounts,
2736            instruction_accounts,
2737            Err(InstructionError::InvalidArgument),
2738        );
2739
2740        // Case: Buffer account not writable
2741        for buffer_balance in [0, 1_000_000, 15 * 1_000_000_000] {
2742            let (mut transaction_accounts, mut instruction_accounts) = get_accounts(
2743                &payer_address,
2744                &buffer_address,
2745                &upgrade_authority_address,
2746                &upgrade_authority_address,
2747                &elf,
2748            );
2749            transaction_accounts
2750                .get_mut(3)
2751                .unwrap()
2752                .1
2753                .set_lamports(buffer_balance);
2754            instruction_accounts.get_mut(3).unwrap().is_writable = false;
2755            process_instruction(
2756                elf.len(),
2757                transaction_accounts,
2758                instruction_accounts,
2759                Err(InstructionError::InvalidArgument),
2760            );
2761        }
2762
2763        // Case: Buffer account not owned by loader: lamports scenario
2764        //
2765        // In `DeployWithMaxDataLen`, the buffer's lamports are drained to the
2766        // payer before the payer is debited for the programdata's rent. Then,
2767        // the buffer's data is set to `size_of_buffer(0)`.
2768        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2769            &payer_address,
2770            &buffer_address,
2771            &upgrade_authority_address,
2772            &upgrade_authority_address,
2773            &elf,
2774        );
2775        {
2776            // Let's make sure the programdata requires a top-up.
2777            let required_rent = Rent::default()
2778                .minimum_balance(UpgradeableLoaderState::size_of_programdata(elf.len()));
2779            let programdata = &transaction_accounts.get(1).unwrap().1;
2780            assert!(programdata.lamports() < required_rent);
2781            let buffer = &mut transaction_accounts.get_mut(3).unwrap().1;
2782            buffer.set_owner(Pubkey::new_unique());
2783            buffer.set_lamports(required_rent);
2784        }
2785        process_instruction(
2786            elf.len(),
2787            transaction_accounts,
2788            instruction_accounts,
2789            Err(InstructionError::IncorrectProgramId),
2790        );
2791
2792        // Case: Buffer account not owned by loader: shrink scenario
2793        //
2794        // Same as the above case, but give the buffer a lamports balance of
2795        // `0`, rendering its balance "unchanged" by the drain operation.
2796        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2797            &payer_address,
2798            &buffer_address,
2799            &upgrade_authority_address,
2800            &upgrade_authority_address,
2801            &elf,
2802        );
2803        {
2804            // Set the buffer's lamports to zero.
2805            let buffer = &mut transaction_accounts.get_mut(3).unwrap().1;
2806            buffer.set_owner(Pubkey::new_unique());
2807            buffer.set_lamports(0);
2808        }
2809        process_instruction(
2810            elf.len(),
2811            transaction_accounts,
2812            instruction_accounts,
2813            Err(InstructionError::IncorrectProgramId),
2814        );
2815
2816        // Case: Buffer account not owned by loader: no-op scenario
2817        //
2818        // Same as the above case, but also truncate the buffer's data to
2819        // `size_of_buffer(0)` - just the buffer metadata, no ELF - rendering
2820        // the closing resize "unchanged" as well.
2821        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2822            &payer_address,
2823            &buffer_address,
2824            &upgrade_authority_address,
2825            &upgrade_authority_address,
2826            &elf,
2827        );
2828        {
2829            // Empty the buffer (metadata only) and zero its lamports.
2830            let buffer = &mut transaction_accounts.get_mut(3).unwrap().1;
2831            buffer.set_owner(Pubkey::new_unique());
2832            buffer.set_lamports(0);
2833            truncate_data(buffer, UpgradeableLoaderState::size_of_buffer(0));
2834        }
2835        process_instruction(
2836            elf.len(),
2837            transaction_accounts,
2838            instruction_accounts,
2839            Err(InstructionError::IncorrectProgramId),
2840        );
2841
2842        // Case: Max data length too small for Buffer data
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            elf.len().saturating_sub(1),
2852            transaction_accounts,
2853            instruction_accounts,
2854            Err(InstructionError::AccountDataTooSmall),
2855        );
2856
2857        // Case: Max data length too large
2858        let (transaction_accounts, instruction_accounts) = get_accounts(
2859            &payer_address,
2860            &buffer_address,
2861            &upgrade_authority_address,
2862            &upgrade_authority_address,
2863            &elf,
2864        );
2865        process_instruction(
2866            MAX_PERMITTED_DATA_LENGTH as usize,
2867            transaction_accounts,
2868            instruction_accounts,
2869            Err(InstructionError::InvalidArgument),
2870        );
2871
2872        // Case: Mismatched buffer authority
2873        let (transaction_accounts, instruction_accounts) = get_accounts(
2874            &payer_address,
2875            &buffer_address,
2876            &buffer_address,
2877            &upgrade_authority_address,
2878            &elf,
2879        );
2880        process_instruction(
2881            elf.len(),
2882            transaction_accounts,
2883            instruction_accounts,
2884            Err(InstructionError::IncorrectAuthority),
2885        );
2886
2887        // Case: No buffer authority
2888        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2889            &payer_address,
2890            &buffer_address,
2891            &buffer_address,
2892            &upgrade_authority_address,
2893            &elf,
2894        );
2895        transaction_accounts
2896            .get_mut(3)
2897            .unwrap()
2898            .1
2899            .set_state(&UpgradeableLoaderState::Buffer {
2900                authority_address: None,
2901            })
2902            .unwrap();
2903        process_instruction(
2904            elf.len(),
2905            transaction_accounts,
2906            instruction_accounts,
2907            Err(InstructionError::IncorrectAuthority),
2908        );
2909
2910        // Case: Deploy SBPFv0
2911        let mut file =
2912            File::open("test_elfs/out/sbpfv0_verifier_err.so").expect("file open failed");
2913        let mut elf = Vec::new();
2914        file.read_to_end(&mut elf).unwrap();
2915        let (transaction_accounts, instruction_accounts) = get_accounts(
2916            &payer_address,
2917            &buffer_address,
2918            &upgrade_authority_address,
2919            &upgrade_authority_address,
2920            &elf,
2921        );
2922        process_instruction(
2923            elf.len(),
2924            transaction_accounts,
2925            instruction_accounts,
2926            Err(InstructionError::InvalidAccountData),
2927        );
2928    }
2929
2930    #[test]
2931    fn test_bpf_loader_upgradeable_set_upgrade_authority() {
2932        let instruction = bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap();
2933        let loader_id = bpf_loader_upgradeable::id();
2934        let slot = 0;
2935        let upgrade_authority_address = Pubkey::new_unique();
2936        let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
2937        let new_upgrade_authority_address = Pubkey::new_unique();
2938        let new_upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
2939        let program_address = Pubkey::new_unique();
2940        let (programdata_address, _) = Pubkey::find_program_address(
2941            &[program_address.as_ref()],
2942            &bpf_loader_upgradeable::id(),
2943        );
2944        let mut programdata_account = AccountSharedData::new(
2945            1,
2946            UpgradeableLoaderState::size_of_programdata(0),
2947            &bpf_loader_upgradeable::id(),
2948        );
2949        programdata_account
2950            .set_state(&UpgradeableLoaderState::ProgramData {
2951                slot,
2952                upgrade_authority_address: Some(upgrade_authority_address),
2953            })
2954            .unwrap();
2955        let programdata_meta = AccountMeta {
2956            pubkey: programdata_address,
2957            is_signer: false,
2958            is_writable: true,
2959        };
2960        let upgrade_authority_meta = AccountMeta {
2961            pubkey: upgrade_authority_address,
2962            is_signer: true,
2963            is_writable: false,
2964        };
2965        let new_upgrade_authority_meta = AccountMeta {
2966            pubkey: new_upgrade_authority_address,
2967            is_signer: false,
2968            is_writable: false,
2969        };
2970
2971        // Case: Set to new authority
2972        let accounts = process_instruction(
2973            &loader_id,
2974            &instruction,
2975            vec![
2976                (programdata_address, programdata_account.clone()),
2977                (upgrade_authority_address, upgrade_authority_account.clone()),
2978                (
2979                    new_upgrade_authority_address,
2980                    new_upgrade_authority_account.clone(),
2981                ),
2982            ],
2983            vec![
2984                programdata_meta.clone(),
2985                upgrade_authority_meta.clone(),
2986                new_upgrade_authority_meta.clone(),
2987            ],
2988            Ok(()),
2989        );
2990        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
2991        assert_eq!(
2992            state,
2993            UpgradeableLoaderState::ProgramData {
2994                slot,
2995                upgrade_authority_address: Some(new_upgrade_authority_address),
2996            }
2997        );
2998
2999        // Case: Finalize
3000        let accounts = process_instruction(
3001            &loader_id,
3002            &instruction,
3003            vec![
3004                (programdata_address, programdata_account.clone()),
3005                (upgrade_authority_address, upgrade_authority_account.clone()),
3006            ],
3007            vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
3008            Ok(()),
3009        );
3010        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3011        assert_eq!(
3012            state,
3013            UpgradeableLoaderState::ProgramData {
3014                slot,
3015                upgrade_authority_address: None,
3016            }
3017        );
3018
3019        // Case: Finalize a SBPFv0 program
3020        let mut file =
3021            File::open("test_elfs/out/sbpfv0_verifier_err.so").expect("file open failed");
3022        let mut elf = Vec::new();
3023        file.read_to_end(&mut elf).unwrap();
3024        programdata_account.resize(UpgradeableLoaderState::size_of_programdata(elf.len()), 0);
3025        programdata_account
3026            .data_as_mut_slice()
3027            .get_mut(UpgradeableLoaderState::size_of_programdata_metadata()..)
3028            .unwrap()
3029            .copy_from_slice(&elf);
3030        process_instruction(
3031            &loader_id,
3032            &instruction,
3033            vec![
3034                (programdata_address, programdata_account.clone()),
3035                (upgrade_authority_address, upgrade_authority_account.clone()),
3036            ],
3037            vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
3038            Err(InstructionError::InvalidAccountData),
3039        );
3040
3041        // Case: Authority did not sign
3042        process_instruction(
3043            &loader_id,
3044            &instruction,
3045            vec![
3046                (programdata_address, programdata_account.clone()),
3047                (upgrade_authority_address, upgrade_authority_account.clone()),
3048            ],
3049            vec![
3050                programdata_meta.clone(),
3051                AccountMeta {
3052                    pubkey: upgrade_authority_address,
3053                    is_signer: false,
3054                    is_writable: false,
3055                },
3056            ],
3057            Err(InstructionError::MissingRequiredSignature),
3058        );
3059
3060        // Case: wrong authority
3061        let invalid_upgrade_authority_address = Pubkey::new_unique();
3062        process_instruction(
3063            &loader_id,
3064            &instruction,
3065            vec![
3066                (programdata_address, programdata_account.clone()),
3067                (
3068                    invalid_upgrade_authority_address,
3069                    upgrade_authority_account.clone(),
3070                ),
3071                (new_upgrade_authority_address, new_upgrade_authority_account),
3072            ],
3073            vec![
3074                programdata_meta.clone(),
3075                AccountMeta {
3076                    pubkey: invalid_upgrade_authority_address,
3077                    is_signer: true,
3078                    is_writable: false,
3079                },
3080                new_upgrade_authority_meta,
3081            ],
3082            Err(InstructionError::IncorrectAuthority),
3083        );
3084
3085        // Case: No authority
3086        programdata_account
3087            .set_state(&UpgradeableLoaderState::ProgramData {
3088                slot,
3089                upgrade_authority_address: None,
3090            })
3091            .unwrap();
3092        process_instruction(
3093            &loader_id,
3094            &instruction,
3095            vec![
3096                (programdata_address, programdata_account.clone()),
3097                (upgrade_authority_address, upgrade_authority_account.clone()),
3098            ],
3099            vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
3100            Err(InstructionError::Immutable),
3101        );
3102
3103        // Case: Not a ProgramData account
3104        programdata_account
3105            .set_state(&UpgradeableLoaderState::Program {
3106                programdata_address: Pubkey::new_unique(),
3107            })
3108            .unwrap();
3109        process_instruction(
3110            &loader_id,
3111            &instruction,
3112            vec![
3113                (programdata_address, programdata_account.clone()),
3114                (upgrade_authority_address, upgrade_authority_account),
3115            ],
3116            vec![programdata_meta, upgrade_authority_meta],
3117            Err(InstructionError::InvalidArgument),
3118        );
3119    }
3120
3121    #[test]
3122    fn test_bpf_loader_upgradeable_set_upgrade_authority_checked() {
3123        let instruction =
3124            bincode::serialize(&UpgradeableLoaderInstruction::SetAuthorityChecked).unwrap();
3125        let loader_id = bpf_loader_upgradeable::id();
3126        let slot = 0;
3127        let upgrade_authority_address = Pubkey::new_unique();
3128        let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3129        let new_upgrade_authority_address = Pubkey::new_unique();
3130        let new_upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3131        let program_address = Pubkey::new_unique();
3132        let (programdata_address, _) = Pubkey::find_program_address(
3133            &[program_address.as_ref()],
3134            &bpf_loader_upgradeable::id(),
3135        );
3136        let mut programdata_account = AccountSharedData::new(
3137            1,
3138            UpgradeableLoaderState::size_of_programdata(0),
3139            &bpf_loader_upgradeable::id(),
3140        );
3141        programdata_account
3142            .set_state(&UpgradeableLoaderState::ProgramData {
3143                slot,
3144                upgrade_authority_address: Some(upgrade_authority_address),
3145            })
3146            .unwrap();
3147        let programdata_meta = AccountMeta {
3148            pubkey: programdata_address,
3149            is_signer: false,
3150            is_writable: true,
3151        };
3152        let upgrade_authority_meta = AccountMeta {
3153            pubkey: upgrade_authority_address,
3154            is_signer: true,
3155            is_writable: false,
3156        };
3157        let new_upgrade_authority_meta = AccountMeta {
3158            pubkey: new_upgrade_authority_address,
3159            is_signer: true,
3160            is_writable: false,
3161        };
3162
3163        // Case: Set to new authority
3164        let accounts = process_instruction(
3165            &loader_id,
3166            &instruction,
3167            vec![
3168                (programdata_address, programdata_account.clone()),
3169                (upgrade_authority_address, upgrade_authority_account.clone()),
3170                (
3171                    new_upgrade_authority_address,
3172                    new_upgrade_authority_account.clone(),
3173                ),
3174            ],
3175            vec![
3176                programdata_meta.clone(),
3177                upgrade_authority_meta.clone(),
3178                new_upgrade_authority_meta.clone(),
3179            ],
3180            Ok(()),
3181        );
3182
3183        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3184        assert_eq!(
3185            state,
3186            UpgradeableLoaderState::ProgramData {
3187                slot,
3188                upgrade_authority_address: Some(new_upgrade_authority_address),
3189            }
3190        );
3191
3192        // Case: set to same authority
3193        process_instruction(
3194            &loader_id,
3195            &instruction,
3196            vec![
3197                (programdata_address, programdata_account.clone()),
3198                (upgrade_authority_address, upgrade_authority_account.clone()),
3199            ],
3200            vec![
3201                programdata_meta.clone(),
3202                upgrade_authority_meta.clone(),
3203                upgrade_authority_meta.clone(),
3204            ],
3205            Ok(()),
3206        );
3207
3208        // Case: present authority not in instruction
3209        process_instruction(
3210            &loader_id,
3211            &instruction,
3212            vec![
3213                (programdata_address, programdata_account.clone()),
3214                (upgrade_authority_address, upgrade_authority_account.clone()),
3215                (
3216                    new_upgrade_authority_address,
3217                    new_upgrade_authority_account.clone(),
3218                ),
3219            ],
3220            vec![programdata_meta.clone(), new_upgrade_authority_meta.clone()],
3221            Err(InstructionError::MissingAccount),
3222        );
3223
3224        // Case: new authority not in instruction
3225        process_instruction(
3226            &loader_id,
3227            &instruction,
3228            vec![
3229                (programdata_address, programdata_account.clone()),
3230                (upgrade_authority_address, upgrade_authority_account.clone()),
3231                (
3232                    new_upgrade_authority_address,
3233                    new_upgrade_authority_account.clone(),
3234                ),
3235            ],
3236            vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
3237            Err(InstructionError::MissingAccount),
3238        );
3239
3240        // Case: present authority did not sign
3241        process_instruction(
3242            &loader_id,
3243            &instruction,
3244            vec![
3245                (programdata_address, programdata_account.clone()),
3246                (upgrade_authority_address, upgrade_authority_account.clone()),
3247                (
3248                    new_upgrade_authority_address,
3249                    new_upgrade_authority_account.clone(),
3250                ),
3251            ],
3252            vec![
3253                programdata_meta.clone(),
3254                AccountMeta {
3255                    pubkey: upgrade_authority_address,
3256                    is_signer: false,
3257                    is_writable: false,
3258                },
3259                new_upgrade_authority_meta.clone(),
3260            ],
3261            Err(InstructionError::MissingRequiredSignature),
3262        );
3263
3264        // Case: New authority did not sign
3265        process_instruction(
3266            &loader_id,
3267            &instruction,
3268            vec![
3269                (programdata_address, programdata_account.clone()),
3270                (upgrade_authority_address, upgrade_authority_account.clone()),
3271                (
3272                    new_upgrade_authority_address,
3273                    new_upgrade_authority_account.clone(),
3274                ),
3275            ],
3276            vec![
3277                programdata_meta.clone(),
3278                upgrade_authority_meta.clone(),
3279                AccountMeta {
3280                    pubkey: new_upgrade_authority_address,
3281                    is_signer: false,
3282                    is_writable: false,
3283                },
3284            ],
3285            Err(InstructionError::MissingRequiredSignature),
3286        );
3287
3288        // Case: wrong present authority
3289        let invalid_upgrade_authority_address = Pubkey::new_unique();
3290        process_instruction(
3291            &loader_id,
3292            &instruction,
3293            vec![
3294                (programdata_address, programdata_account.clone()),
3295                (
3296                    invalid_upgrade_authority_address,
3297                    upgrade_authority_account.clone(),
3298                ),
3299                (new_upgrade_authority_address, new_upgrade_authority_account),
3300            ],
3301            vec![
3302                programdata_meta.clone(),
3303                AccountMeta {
3304                    pubkey: invalid_upgrade_authority_address,
3305                    is_signer: true,
3306                    is_writable: false,
3307                },
3308                new_upgrade_authority_meta.clone(),
3309            ],
3310            Err(InstructionError::IncorrectAuthority),
3311        );
3312
3313        // Case: programdata is immutable
3314        programdata_account
3315            .set_state(&UpgradeableLoaderState::ProgramData {
3316                slot,
3317                upgrade_authority_address: None,
3318            })
3319            .unwrap();
3320        process_instruction(
3321            &loader_id,
3322            &instruction,
3323            vec![
3324                (programdata_address, programdata_account.clone()),
3325                (upgrade_authority_address, upgrade_authority_account.clone()),
3326            ],
3327            vec![
3328                programdata_meta.clone(),
3329                upgrade_authority_meta.clone(),
3330                new_upgrade_authority_meta.clone(),
3331            ],
3332            Err(InstructionError::Immutable),
3333        );
3334
3335        // Case: Not a ProgramData account
3336        programdata_account
3337            .set_state(&UpgradeableLoaderState::Program {
3338                programdata_address: Pubkey::new_unique(),
3339            })
3340            .unwrap();
3341        process_instruction(
3342            &loader_id,
3343            &instruction,
3344            vec![
3345                (programdata_address, programdata_account.clone()),
3346                (upgrade_authority_address, upgrade_authority_account),
3347            ],
3348            vec![
3349                programdata_meta,
3350                upgrade_authority_meta,
3351                new_upgrade_authority_meta,
3352            ],
3353            Err(InstructionError::InvalidArgument),
3354        );
3355    }
3356
3357    #[test]
3358    fn test_bpf_loader_upgradeable_set_buffer_authority() {
3359        let instruction = bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap();
3360        let loader_id = bpf_loader_upgradeable::id();
3361        let invalid_authority_address = Pubkey::new_unique();
3362        let authority_address = Pubkey::new_unique();
3363        let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3364        let new_authority_address = Pubkey::new_unique();
3365        let new_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3366        let buffer_address = Pubkey::new_unique();
3367        let mut buffer_account =
3368            AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(0), &loader_id);
3369        buffer_account
3370            .set_state(&UpgradeableLoaderState::Buffer {
3371                authority_address: Some(authority_address),
3372            })
3373            .unwrap();
3374        let mut transaction_accounts = vec![
3375            (buffer_address, buffer_account.clone()),
3376            (authority_address, authority_account.clone()),
3377            (new_authority_address, new_authority_account.clone()),
3378        ];
3379        let buffer_meta = AccountMeta {
3380            pubkey: buffer_address,
3381            is_signer: false,
3382            is_writable: true,
3383        };
3384        let authority_meta = AccountMeta {
3385            pubkey: authority_address,
3386            is_signer: true,
3387            is_writable: false,
3388        };
3389        let new_authority_meta = AccountMeta {
3390            pubkey: new_authority_address,
3391            is_signer: false,
3392            is_writable: false,
3393        };
3394
3395        // Case: New authority required
3396        let accounts = process_instruction(
3397            &loader_id,
3398            &instruction,
3399            transaction_accounts.clone(),
3400            vec![buffer_meta.clone(), authority_meta.clone()],
3401            Err(InstructionError::IncorrectAuthority),
3402        );
3403        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3404        assert_eq!(
3405            state,
3406            UpgradeableLoaderState::Buffer {
3407                authority_address: Some(authority_address),
3408            }
3409        );
3410
3411        // Case: Set to new authority
3412        buffer_account
3413            .set_state(&UpgradeableLoaderState::Buffer {
3414                authority_address: Some(authority_address),
3415            })
3416            .unwrap();
3417        let accounts = process_instruction(
3418            &loader_id,
3419            &instruction,
3420            transaction_accounts.clone(),
3421            vec![
3422                buffer_meta.clone(),
3423                authority_meta.clone(),
3424                new_authority_meta.clone(),
3425            ],
3426            Ok(()),
3427        );
3428        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3429        assert_eq!(
3430            state,
3431            UpgradeableLoaderState::Buffer {
3432                authority_address: Some(new_authority_address),
3433            }
3434        );
3435
3436        // Case: Authority did not sign
3437        process_instruction(
3438            &loader_id,
3439            &instruction,
3440            transaction_accounts.clone(),
3441            vec![
3442                buffer_meta.clone(),
3443                AccountMeta {
3444                    pubkey: authority_address,
3445                    is_signer: false,
3446                    is_writable: false,
3447                },
3448                new_authority_meta.clone(),
3449            ],
3450            Err(InstructionError::MissingRequiredSignature),
3451        );
3452
3453        // Case: wrong authority
3454        process_instruction(
3455            &loader_id,
3456            &instruction,
3457            vec![
3458                (buffer_address, buffer_account.clone()),
3459                (invalid_authority_address, authority_account),
3460                (new_authority_address, new_authority_account),
3461            ],
3462            vec![
3463                buffer_meta.clone(),
3464                AccountMeta {
3465                    pubkey: invalid_authority_address,
3466                    is_signer: true,
3467                    is_writable: false,
3468                },
3469                new_authority_meta.clone(),
3470            ],
3471            Err(InstructionError::IncorrectAuthority),
3472        );
3473
3474        // Case: No authority
3475        process_instruction(
3476            &loader_id,
3477            &instruction,
3478            transaction_accounts.clone(),
3479            vec![buffer_meta.clone(), authority_meta.clone()],
3480            Err(InstructionError::IncorrectAuthority),
3481        );
3482
3483        // Case: Set to no authority
3484        transaction_accounts
3485            .get_mut(0)
3486            .unwrap()
3487            .1
3488            .set_state(&UpgradeableLoaderState::Buffer {
3489                authority_address: None,
3490            })
3491            .unwrap();
3492        process_instruction(
3493            &loader_id,
3494            &instruction,
3495            transaction_accounts.clone(),
3496            vec![
3497                buffer_meta.clone(),
3498                authority_meta.clone(),
3499                new_authority_meta.clone(),
3500            ],
3501            Err(InstructionError::Immutable),
3502        );
3503
3504        // Case: Not a Buffer account
3505        transaction_accounts
3506            .get_mut(0)
3507            .unwrap()
3508            .1
3509            .set_state(&UpgradeableLoaderState::Program {
3510                programdata_address: Pubkey::new_unique(),
3511            })
3512            .unwrap();
3513        process_instruction(
3514            &loader_id,
3515            &instruction,
3516            transaction_accounts.clone(),
3517            vec![buffer_meta, authority_meta, new_authority_meta],
3518            Err(InstructionError::InvalidArgument),
3519        );
3520    }
3521
3522    #[test]
3523    fn test_bpf_loader_upgradeable_set_buffer_authority_checked() {
3524        let instruction =
3525            bincode::serialize(&UpgradeableLoaderInstruction::SetAuthorityChecked).unwrap();
3526        let loader_id = bpf_loader_upgradeable::id();
3527        let invalid_authority_address = Pubkey::new_unique();
3528        let authority_address = Pubkey::new_unique();
3529        let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3530        let new_authority_address = Pubkey::new_unique();
3531        let new_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3532        let buffer_address = Pubkey::new_unique();
3533        let mut buffer_account =
3534            AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(0), &loader_id);
3535        buffer_account
3536            .set_state(&UpgradeableLoaderState::Buffer {
3537                authority_address: Some(authority_address),
3538            })
3539            .unwrap();
3540        let mut transaction_accounts = vec![
3541            (buffer_address, buffer_account.clone()),
3542            (authority_address, authority_account.clone()),
3543            (new_authority_address, new_authority_account.clone()),
3544        ];
3545        let buffer_meta = AccountMeta {
3546            pubkey: buffer_address,
3547            is_signer: false,
3548            is_writable: true,
3549        };
3550        let authority_meta = AccountMeta {
3551            pubkey: authority_address,
3552            is_signer: true,
3553            is_writable: false,
3554        };
3555        let new_authority_meta = AccountMeta {
3556            pubkey: new_authority_address,
3557            is_signer: true,
3558            is_writable: false,
3559        };
3560
3561        // Case: Set to new authority
3562        buffer_account
3563            .set_state(&UpgradeableLoaderState::Buffer {
3564                authority_address: Some(authority_address),
3565            })
3566            .unwrap();
3567        let accounts = process_instruction(
3568            &loader_id,
3569            &instruction,
3570            transaction_accounts.clone(),
3571            vec![
3572                buffer_meta.clone(),
3573                authority_meta.clone(),
3574                new_authority_meta.clone(),
3575            ],
3576            Ok(()),
3577        );
3578        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3579        assert_eq!(
3580            state,
3581            UpgradeableLoaderState::Buffer {
3582                authority_address: Some(new_authority_address),
3583            }
3584        );
3585
3586        // Case: set to same authority
3587        process_instruction(
3588            &loader_id,
3589            &instruction,
3590            transaction_accounts.clone(),
3591            vec![
3592                buffer_meta.clone(),
3593                authority_meta.clone(),
3594                authority_meta.clone(),
3595            ],
3596            Ok(()),
3597        );
3598
3599        // Case: Missing current authority
3600        process_instruction(
3601            &loader_id,
3602            &instruction,
3603            transaction_accounts.clone(),
3604            vec![buffer_meta.clone(), new_authority_meta.clone()],
3605            Err(InstructionError::MissingAccount),
3606        );
3607
3608        // Case: Missing new authority
3609        process_instruction(
3610            &loader_id,
3611            &instruction,
3612            transaction_accounts.clone(),
3613            vec![buffer_meta.clone(), authority_meta.clone()],
3614            Err(InstructionError::MissingAccount),
3615        );
3616
3617        // Case: wrong present authority
3618        process_instruction(
3619            &loader_id,
3620            &instruction,
3621            vec![
3622                (buffer_address, buffer_account.clone()),
3623                (invalid_authority_address, authority_account),
3624                (new_authority_address, new_authority_account),
3625            ],
3626            vec![
3627                buffer_meta.clone(),
3628                AccountMeta {
3629                    pubkey: invalid_authority_address,
3630                    is_signer: true,
3631                    is_writable: false,
3632                },
3633                new_authority_meta.clone(),
3634            ],
3635            Err(InstructionError::IncorrectAuthority),
3636        );
3637
3638        // Case: present authority did not sign
3639        process_instruction(
3640            &loader_id,
3641            &instruction,
3642            transaction_accounts.clone(),
3643            vec![
3644                buffer_meta.clone(),
3645                AccountMeta {
3646                    pubkey: authority_address,
3647                    is_signer: false,
3648                    is_writable: false,
3649                },
3650                new_authority_meta.clone(),
3651            ],
3652            Err(InstructionError::MissingRequiredSignature),
3653        );
3654
3655        // Case: new authority did not sign
3656        process_instruction(
3657            &loader_id,
3658            &instruction,
3659            transaction_accounts.clone(),
3660            vec![
3661                buffer_meta.clone(),
3662                authority_meta.clone(),
3663                AccountMeta {
3664                    pubkey: new_authority_address,
3665                    is_signer: false,
3666                    is_writable: false,
3667                },
3668            ],
3669            Err(InstructionError::MissingRequiredSignature),
3670        );
3671
3672        // Case: Not a Buffer account
3673        transaction_accounts
3674            .get_mut(0)
3675            .unwrap()
3676            .1
3677            .set_state(&UpgradeableLoaderState::Program {
3678                programdata_address: Pubkey::new_unique(),
3679            })
3680            .unwrap();
3681        process_instruction(
3682            &loader_id,
3683            &instruction,
3684            transaction_accounts.clone(),
3685            vec![
3686                buffer_meta.clone(),
3687                authority_meta.clone(),
3688                new_authority_meta.clone(),
3689            ],
3690            Err(InstructionError::InvalidArgument),
3691        );
3692
3693        // Case: Buffer is immutable
3694        transaction_accounts
3695            .get_mut(0)
3696            .unwrap()
3697            .1
3698            .set_state(&UpgradeableLoaderState::Buffer {
3699                authority_address: None,
3700            })
3701            .unwrap();
3702        process_instruction(
3703            &loader_id,
3704            &instruction,
3705            transaction_accounts.clone(),
3706            vec![buffer_meta, authority_meta, new_authority_meta],
3707            Err(InstructionError::Immutable),
3708        );
3709    }
3710
3711    #[test]
3712    fn test_bpf_loader_upgradeable_close() {
3713        let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Close).unwrap();
3714        let loader_id = bpf_loader_upgradeable::id();
3715        let invalid_authority_address = Pubkey::new_unique();
3716        let authority_address = Pubkey::new_unique();
3717        let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3718        let recipient_address = Pubkey::new_unique();
3719        let recipient_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3720        let buffer_address = Pubkey::new_unique();
3721        let mut buffer_account =
3722            AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(128), &loader_id);
3723        buffer_account
3724            .set_state(&UpgradeableLoaderState::Buffer {
3725                authority_address: Some(authority_address),
3726            })
3727            .unwrap();
3728        let uninitialized_address = Pubkey::new_unique();
3729        let mut uninitialized_account = AccountSharedData::new(
3730            1,
3731            UpgradeableLoaderState::size_of_programdata(0),
3732            &loader_id,
3733        );
3734        uninitialized_account
3735            .set_state(&UpgradeableLoaderState::Uninitialized)
3736            .unwrap();
3737        let programdata_address = Pubkey::new_unique();
3738        let mut programdata_account = AccountSharedData::new(
3739            1,
3740            UpgradeableLoaderState::size_of_programdata(128),
3741            &loader_id,
3742        );
3743        programdata_account
3744            .set_state(&UpgradeableLoaderState::ProgramData {
3745                slot: 0,
3746                upgrade_authority_address: Some(authority_address),
3747            })
3748            .unwrap();
3749        let program_address = Pubkey::new_unique();
3750        let mut program_account =
3751            AccountSharedData::new(1, UpgradeableLoaderState::size_of_program(), &loader_id);
3752        program_account.set_executable(true);
3753        program_account
3754            .set_state(&UpgradeableLoaderState::Program {
3755                programdata_address,
3756            })
3757            .unwrap();
3758        let clock_account = create_sysvar_account(&Clock {
3759            slot: 1,
3760            ..Clock::default()
3761        });
3762        let transaction_accounts = vec![
3763            (buffer_address, buffer_account.clone()),
3764            (recipient_address, recipient_account.clone()),
3765            (authority_address, authority_account.clone()),
3766        ];
3767        let buffer_meta = AccountMeta {
3768            pubkey: buffer_address,
3769            is_signer: false,
3770            is_writable: true,
3771        };
3772        let recipient_meta = AccountMeta {
3773            pubkey: recipient_address,
3774            is_signer: false,
3775            is_writable: true,
3776        };
3777        let authority_meta = AccountMeta {
3778            pubkey: authority_address,
3779            is_signer: true,
3780            is_writable: false,
3781        };
3782
3783        // Case: close a buffer account
3784        let accounts = process_instruction(
3785            &loader_id,
3786            &instruction,
3787            transaction_accounts,
3788            vec![
3789                buffer_meta.clone(),
3790                recipient_meta.clone(),
3791                authority_meta.clone(),
3792            ],
3793            Ok(()),
3794        );
3795        assert_eq!(0, accounts.first().unwrap().lamports());
3796        assert_eq!(2, accounts.get(1).unwrap().lamports());
3797        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3798        assert_eq!(state, UpgradeableLoaderState::Uninitialized);
3799        assert_eq!(
3800            UpgradeableLoaderState::size_of_uninitialized(),
3801            accounts.first().unwrap().data().len()
3802        );
3803
3804        // Case: close with wrong authority
3805        process_instruction(
3806            &loader_id,
3807            &instruction,
3808            vec![
3809                (buffer_address, buffer_account.clone()),
3810                (recipient_address, recipient_account.clone()),
3811                (invalid_authority_address, authority_account.clone()),
3812            ],
3813            vec![
3814                buffer_meta,
3815                recipient_meta.clone(),
3816                AccountMeta {
3817                    pubkey: invalid_authority_address,
3818                    is_signer: true,
3819                    is_writable: false,
3820                },
3821            ],
3822            Err(InstructionError::IncorrectAuthority),
3823        );
3824
3825        // Case: close an uninitialized account
3826        let accounts = process_instruction(
3827            &loader_id,
3828            &instruction,
3829            vec![
3830                (uninitialized_address, uninitialized_account.clone()),
3831                (recipient_address, recipient_account.clone()),
3832                (invalid_authority_address, authority_account.clone()),
3833            ],
3834            vec![
3835                AccountMeta {
3836                    pubkey: uninitialized_address,
3837                    is_signer: false,
3838                    is_writable: true,
3839                },
3840                recipient_meta.clone(),
3841                authority_meta.clone(),
3842            ],
3843            Ok(()),
3844        );
3845        assert_eq!(0, accounts.first().unwrap().lamports());
3846        assert_eq!(2, accounts.get(1).unwrap().lamports());
3847        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3848        assert_eq!(state, UpgradeableLoaderState::Uninitialized);
3849        assert_eq!(
3850            UpgradeableLoaderState::size_of_uninitialized(),
3851            accounts.first().unwrap().data().len()
3852        );
3853
3854        // Case: close a program account with a non-writable program account
3855        process_instruction(
3856            &loader_id,
3857            &instruction,
3858            vec![
3859                (programdata_address, programdata_account.clone()),
3860                (recipient_address, recipient_account.clone()),
3861                (authority_address, authority_account.clone()),
3862                (program_address, program_account.clone()),
3863                (sysvar::clock::id(), clock_account.clone()),
3864            ],
3865            vec![
3866                AccountMeta {
3867                    pubkey: programdata_address,
3868                    is_signer: false,
3869                    is_writable: true,
3870                },
3871                recipient_meta.clone(),
3872                authority_meta.clone(),
3873                AccountMeta {
3874                    pubkey: program_address,
3875                    is_signer: false,
3876                    is_writable: false,
3877                },
3878            ],
3879            Err(InstructionError::InvalidArgument),
3880        );
3881
3882        // Case: close a program account
3883        let accounts = process_instruction(
3884            &loader_id,
3885            &instruction,
3886            vec![
3887                (programdata_address, programdata_account.clone()),
3888                (recipient_address, recipient_account.clone()),
3889                (authority_address, authority_account.clone()),
3890                (program_address, program_account.clone()),
3891                (sysvar::clock::id(), clock_account.clone()),
3892            ],
3893            vec![
3894                AccountMeta {
3895                    pubkey: programdata_address,
3896                    is_signer: false,
3897                    is_writable: true,
3898                },
3899                recipient_meta,
3900                authority_meta,
3901                AccountMeta {
3902                    pubkey: program_address,
3903                    is_signer: false,
3904                    is_writable: true,
3905                },
3906            ],
3907            Ok(()),
3908        );
3909        assert_eq!(0, accounts.first().unwrap().lamports());
3910        assert_eq!(2, accounts.get(1).unwrap().lamports());
3911        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3912        assert_eq!(state, UpgradeableLoaderState::Uninitialized);
3913        assert_eq!(
3914            UpgradeableLoaderState::size_of_uninitialized(),
3915            accounts.first().unwrap().data().len()
3916        );
3917
3918        // Try to invoke closed account
3919        programdata_account = accounts.first().unwrap().clone();
3920        program_account = accounts.get(3).unwrap().clone();
3921        process_instruction(
3922            &program_address,
3923            &[],
3924            vec![
3925                (programdata_address, programdata_account.clone()),
3926                (program_address, program_account.clone()),
3927            ],
3928            Vec::new(),
3929            Err(InstructionError::UnsupportedProgramId),
3930        );
3931
3932        // Case: Reopen should fail
3933        process_instruction(
3934            &loader_id,
3935            &bincode::serialize(&UpgradeableLoaderInstruction::DeployWithMaxDataLen {
3936                max_data_len: 0,
3937            })
3938            .unwrap(),
3939            vec![
3940                (recipient_address, recipient_account),
3941                (programdata_address, programdata_account),
3942                (program_address, program_account),
3943                (buffer_address, buffer_account),
3944                (sysvar::rent::id(), create_sysvar_account(&Rent::default())),
3945                (sysvar::clock::id(), clock_account),
3946                (
3947                    system_program::id(),
3948                    AccountSharedData::new(0, 0, &system_program::id()),
3949                ),
3950                (authority_address, authority_account),
3951            ],
3952            vec![
3953                AccountMeta {
3954                    pubkey: recipient_address,
3955                    is_signer: true,
3956                    is_writable: true,
3957                },
3958                AccountMeta {
3959                    pubkey: programdata_address,
3960                    is_signer: false,
3961                    is_writable: true,
3962                },
3963                AccountMeta {
3964                    pubkey: program_address,
3965                    is_signer: false,
3966                    is_writable: true,
3967                },
3968                AccountMeta {
3969                    pubkey: buffer_address,
3970                    is_signer: false,
3971                    is_writable: false,
3972                },
3973                AccountMeta {
3974                    pubkey: sysvar::rent::id(),
3975                    is_signer: false,
3976                    is_writable: false,
3977                },
3978                AccountMeta {
3979                    pubkey: sysvar::clock::id(),
3980                    is_signer: false,
3981                    is_writable: false,
3982                },
3983                AccountMeta {
3984                    pubkey: system_program::id(),
3985                    is_signer: false,
3986                    is_writable: false,
3987                },
3988                AccountMeta {
3989                    pubkey: authority_address,
3990                    is_signer: false,
3991                    is_writable: false,
3992                },
3993            ],
3994            Err(InstructionError::AccountAlreadyInitialized),
3995        );
3996    }
3997
3998    /// fuzzing utility function
3999    fn fuzz<F>(
4000        bytes: &[u8],
4001        outer_iters: usize,
4002        inner_iters: usize,
4003        offset: Range<usize>,
4004        value: Range<u8>,
4005        work: F,
4006    ) where
4007        F: Fn(&mut [u8]),
4008    {
4009        let mut rng = rand::rng();
4010        for _ in 0..outer_iters {
4011            let mut mangled_bytes = bytes.to_vec();
4012            for _ in 0..inner_iters {
4013                let offset = rng.random_range(offset.start..offset.end);
4014                let value = rng.random_range(value.start..value.end);
4015                *mangled_bytes.get_mut(offset).unwrap() = value;
4016                work(&mut mangled_bytes);
4017            }
4018        }
4019    }
4020
4021    #[test]
4022    #[ignore]
4023    fn test_fuzz() {
4024        let loader_id = bpf_loader::id();
4025        let program_id = Pubkey::new_unique();
4026
4027        // Create program account
4028        let mut file = File::open("test_elfs/out/sbpfv3_return_ok.so").expect("file open failed");
4029        let mut elf = Vec::new();
4030        file.read_to_end(&mut elf).unwrap();
4031
4032        // Mangle the whole file
4033        fuzz(
4034            &elf,
4035            1_000_000_000,
4036            100,
4037            0..elf.len(),
4038            0..255,
4039            |bytes: &mut [u8]| {
4040                let mut program_account = AccountSharedData::new(1, 0, &loader_id);
4041                program_account.set_data_from_slice(bytes);
4042                program_account.set_executable(true);
4043                process_instruction(
4044                    &program_id,
4045                    &[],
4046                    vec![(program_id, program_account)],
4047                    Vec::new(),
4048                    Ok(()),
4049                );
4050            },
4051        );
4052    }
4053
4054    #[test]
4055    fn test_calculate_heap_cost() {
4056        let heap_cost = 8_u64;
4057
4058        // heap allocations are in 32K block, `heap_cost` of CU is consumed per additional 32k
4059
4060        // assert less than 32K heap should cost zero unit
4061        assert_eq!(0, calculate_heap_cost(31 * 1024, heap_cost));
4062
4063        // assert exact 32K heap should be cost zero unit
4064        assert_eq!(0, calculate_heap_cost(32 * 1024, heap_cost));
4065
4066        // assert slightly more than 32K heap should cost 1 * heap_cost
4067        assert_eq!(heap_cost, calculate_heap_cost(33 * 1024, heap_cost));
4068
4069        // assert exact 64K heap should cost 1 * heap_cost
4070        assert_eq!(heap_cost, calculate_heap_cost(64 * 1024, heap_cost));
4071    }
4072
4073    fn deploy_test_program(
4074        invoke_context: &mut InvokeContext,
4075        program_id: Pubkey,
4076    ) -> Result<(), InstructionError> {
4077        let mut file = File::open("test_elfs/out/sbpfv3_return_ok.so").expect("file open failed");
4078        let mut elf = Vec::new();
4079        file.read_to_end(&mut elf).unwrap();
4080        deploy_program!(
4081            invoke_context,
4082            &program_id,
4083            &bpf_loader_upgradeable::id(),
4084            &elf,
4085            2_u64,
4086            true, // disable_sbpf_v0_v1_v2_deployment
4087        );
4088        Ok(())
4089    }
4090
4091    // Concurrency rationale: these tests construct `ProgramCacheEntry` instances
4092    // directly. The struct's `latest_access_slot: AtomicU64` field is defined in
4093    // `solana-program-runtime`; under the `shuttle-test` feature
4094    // `solana-svm-type-overrides` swaps `std::sync::atomic::AtomicU64` for
4095    // `shuttle::sync::atomic::AtomicU64`, whose Shuttle-backed operations
4096    // (load, fetch_max, and similar) must run inside an active Shuttle
4097    // scheduler. We therefore extract the test bodies into `do_test_*` helpers
4098    // and drive them via `shuttle::check_random` stubs when the feature is on.
4099    // We use `check_random` only (no `check_dfs` companion) because the test
4100    // bodies spawn no Shuttle threads, so DFS gives no meaningful interleaving
4101    // coverage; `check_random` is enough to provide the scheduler context.
4102    // This matches the single-scheduler pattern used in
4103    // `net-utils/src/token_bucket.rs` and `poh/src/record_channels.rs`.
4104    //
4105    // 100 iterations is intentionally low: the test bodies are single-threaded
4106    // (no `shuttle::thread::spawn`), so additional iterations validate only
4107    // the harness wiring, not concurrent interleavings. Bump this if a future
4108    // refactor introduces real concurrency in the test bodies.
4109    #[cfg(feature = "shuttle-test")]
4110    const PROGRAM_USAGE_COUNT_RANDOM_ITERATIONS: usize = 100;
4111
4112    #[test]
4113    fn test_program_usage_count_on_upgrade() {
4114        #[cfg(feature = "shuttle-test")]
4115        shuttle::check_random(
4116            do_test_program_usage_count_on_upgrade,
4117            PROGRAM_USAGE_COUNT_RANDOM_ITERATIONS,
4118        );
4119        #[cfg(not(feature = "shuttle-test"))]
4120        do_test_program_usage_count_on_upgrade();
4121    }
4122
4123    fn do_test_program_usage_count_on_upgrade() {
4124        let transaction_accounts = vec![(
4125            sysvar::epoch_schedule::id(),
4126            create_sysvar_account(&EpochSchedule::default()),
4127        )];
4128        with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
4129        let program_id = Pubkey::new_unique();
4130        let env = ProgramRuntimeEnvironment::from(BuiltinProgram::new_mock());
4131        let stats = ProgramStatistics {
4132            uses: 100.into(),
4133            ..Default::default()
4134        };
4135        let program = ProgramCacheEntry {
4136            program: ProgramCacheEntryType::Unloaded(env),
4137            account_owner: ProgramCacheEntryOwner::LoaderV2,
4138            deployment_slot: 0,
4139            stats: stats.into(),
4140            latest_access_slot: AtomicU64::new(0),
4141        };
4142        invoke_context
4143            .program_cache_for_tx_batch
4144            .replenish(program_id, Arc::new(program));
4145        invoke_context
4146            .program_cache_for_tx_batch
4147            .set_slot_for_tests(2);
4148
4149        assert_matches!(
4150            deploy_test_program(&mut invoke_context, program_id,),
4151            Ok(())
4152        );
4153
4154        let updated_program = invoke_context
4155            .program_cache_for_tx_batch
4156            .find(&program_id)
4157            .expect("Didn't find upgraded program in the cache");
4158
4159        assert_eq!(updated_program.deployment_slot, 2);
4160        assert_eq!(updated_program.stats.uses.load(Ordering::Relaxed), 100);
4161    }
4162
4163    #[test]
4164    fn test_program_usage_count_on_non_upgrade() {
4165        #[cfg(feature = "shuttle-test")]
4166        shuttle::check_random(
4167            do_test_program_usage_count_on_non_upgrade,
4168            PROGRAM_USAGE_COUNT_RANDOM_ITERATIONS,
4169        );
4170        #[cfg(not(feature = "shuttle-test"))]
4171        do_test_program_usage_count_on_non_upgrade();
4172    }
4173
4174    fn do_test_program_usage_count_on_non_upgrade() {
4175        let transaction_accounts = vec![(
4176            sysvar::epoch_schedule::id(),
4177            create_sysvar_account(&EpochSchedule::default()),
4178        )];
4179        with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
4180        let program_id = Pubkey::new_unique();
4181        let env = ProgramRuntimeEnvironment::from(BuiltinProgram::new_mock());
4182        let stats = ProgramStatistics {
4183            uses: 100.into(),
4184            ..Default::default()
4185        };
4186        let program = ProgramCacheEntry {
4187            program: ProgramCacheEntryType::Unloaded(env),
4188            account_owner: ProgramCacheEntryOwner::LoaderV2,
4189            deployment_slot: 0,
4190            stats: stats.into(),
4191            latest_access_slot: AtomicU64::new(0),
4192        };
4193        invoke_context
4194            .program_cache_for_tx_batch
4195            .replenish(program_id, Arc::new(program));
4196        invoke_context
4197            .program_cache_for_tx_batch
4198            .set_slot_for_tests(2);
4199
4200        let program_id2 = Pubkey::new_unique();
4201        assert_matches!(
4202            deploy_test_program(&mut invoke_context, program_id2),
4203            Ok(())
4204        );
4205
4206        let program2 = invoke_context
4207            .program_cache_for_tx_batch
4208            .find(&program_id2)
4209            .expect("Didn't find upgraded program in the cache");
4210
4211        assert_eq!(program2.deployment_slot, 2);
4212        assert_eq!(program2.stats.uses.load(Ordering::Relaxed), 0);
4213    }
4214}