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                            0,
2487                            solana_system_program::system_processor::Entrypoint::register,
2488                        )),
2489                    );
2490                },
2491            )
2492        }
2493
2494        // Case: Success
2495        let (transaction_accounts, instruction_accounts) = get_accounts(
2496            &payer_address,
2497            &buffer_address,
2498            &upgrade_authority_address,
2499            &upgrade_authority_address,
2500            &elf,
2501        );
2502        let programdata_address = instruction_accounts.get(1).unwrap().pubkey;
2503        let accounts = process_instruction(
2504            elf.len(),
2505            transaction_accounts,
2506            instruction_accounts,
2507            Ok(()),
2508        );
2509        let min_programdata_balance =
2510            Rent::default().minimum_balance(UpgradeableLoaderState::size_of_programdata(elf.len()));
2511        assert_eq!(min_programdata_balance, accounts.get(1).unwrap().lamports());
2512        assert_eq!(2, accounts.first().unwrap().lamports());
2513        assert_eq!(0, accounts.get(3).unwrap().lamports());
2514        assert_eq!(
2515            UpgradeableLoaderState::size_of_buffer(0),
2516            accounts.get(3).unwrap().data().len()
2517        );
2518        let state: UpgradeableLoaderState = accounts.get(1).unwrap().state().unwrap();
2519        assert_eq!(
2520            state,
2521            UpgradeableLoaderState::ProgramData {
2522                slot: SLOT,
2523                upgrade_authority_address: Some(upgrade_authority_address),
2524            }
2525        );
2526        for (i, byte) in accounts
2527            .get(1)
2528            .unwrap()
2529            .data()
2530            .get(
2531                UpgradeableLoaderState::size_of_programdata_metadata()
2532                    ..UpgradeableLoaderState::size_of_programdata(elf.len()),
2533            )
2534            .unwrap()
2535            .iter()
2536            .enumerate()
2537        {
2538            assert_eq!(*elf.get(i).unwrap(), *byte);
2539        }
2540        let state: UpgradeableLoaderState = accounts.get(2).unwrap().state().unwrap();
2541        assert_eq!(
2542            state,
2543            UpgradeableLoaderState::Program {
2544                programdata_address,
2545            }
2546        );
2547        assert!(accounts.get(2).unwrap().executable());
2548
2549        // Case: wrong authority
2550        let (mut transaction_accounts, mut instruction_accounts) = get_accounts(
2551            &payer_address,
2552            &buffer_address,
2553            &upgrade_authority_address,
2554            &upgrade_authority_address,
2555            &elf,
2556        );
2557        let invalid_upgrade_authority_address = Pubkey::new_unique();
2558        transaction_accounts.get_mut(7).unwrap().0 = invalid_upgrade_authority_address;
2559        instruction_accounts.get_mut(7).unwrap().pubkey = invalid_upgrade_authority_address;
2560        process_instruction(
2561            elf.len(),
2562            transaction_accounts,
2563            instruction_accounts,
2564            Err(InstructionError::IncorrectAuthority),
2565        );
2566
2567        // Case: authority did not sign
2568        let (transaction_accounts, mut instruction_accounts) = get_accounts(
2569            &payer_address,
2570            &buffer_address,
2571            &upgrade_authority_address,
2572            &upgrade_authority_address,
2573            &elf,
2574        );
2575        instruction_accounts.get_mut(7).unwrap().is_signer = false;
2576        process_instruction(
2577            elf.len(),
2578            transaction_accounts,
2579            instruction_accounts,
2580            Err(InstructionError::MissingRequiredSignature),
2581        );
2582
2583        // Case: Buffer account and payer account alias
2584        let (transaction_accounts, mut instruction_accounts) = get_accounts(
2585            &payer_address,
2586            &buffer_address,
2587            &upgrade_authority_address,
2588            &upgrade_authority_address,
2589            &elf,
2590        );
2591        *instruction_accounts.get_mut(0).unwrap() = instruction_accounts.get(3).unwrap().clone();
2592        process_instruction(
2593            elf.len(),
2594            transaction_accounts,
2595            instruction_accounts,
2596            Err(InstructionError::AccountBorrowFailed),
2597        );
2598
2599        // Case: Program account not owned by loader
2600        //
2601        // Unlike `Upgrade`, `DeployWithMaxDataLen` has no explicit owner
2602        // check on the program account. Validation passes, and the failure
2603        // only surfaces at the end when the handler tries to mutate the
2604        // program's state — `set_state` requires the account to be owned by
2605        // the currently-executing program, so it trips
2606        // `ExternalAccountDataModified`.
2607        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2608            &payer_address,
2609            &buffer_address,
2610            &upgrade_authority_address,
2611            &upgrade_authority_address,
2612            &elf,
2613        );
2614        transaction_accounts
2615            .get_mut(2)
2616            .unwrap()
2617            .1
2618            .set_owner(Pubkey::new_unique());
2619        process_instruction(
2620            elf.len(),
2621            transaction_accounts,
2622            instruction_accounts,
2623            Err(InstructionError::ExternalAccountDataModified),
2624        );
2625
2626        // Case: Program account not writable
2627        //
2628        // `DeployWithMaxDataLen` also lacks an explicit writability check on
2629        // the program account, so the failure again surfaces at
2630        // `set_state`, this time via the writability guard: a non-writable
2631        // account yields `ReadonlyDataModified`.
2632        let (transaction_accounts, mut instruction_accounts) = get_accounts(
2633            &payer_address,
2634            &buffer_address,
2635            &upgrade_authority_address,
2636            &upgrade_authority_address,
2637            &elf,
2638        );
2639        instruction_accounts.get_mut(2).unwrap().is_writable = false;
2640        process_instruction(
2641            elf.len(),
2642            transaction_accounts,
2643            instruction_accounts,
2644            Err(InstructionError::ReadonlyDataModified),
2645        );
2646
2647        // Case: Program account already initialized
2648        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2649            &payer_address,
2650            &buffer_address,
2651            &upgrade_authority_address,
2652            &upgrade_authority_address,
2653            &elf,
2654        );
2655        transaction_accounts
2656            .get_mut(2)
2657            .unwrap()
2658            .1
2659            .set_state(&UpgradeableLoaderState::Program {
2660                programdata_address: Pubkey::new_unique(),
2661            })
2662            .unwrap();
2663        process_instruction(
2664            elf.len(),
2665            transaction_accounts,
2666            instruction_accounts,
2667            Err(InstructionError::AccountAlreadyInitialized),
2668        );
2669
2670        // Case: Program account too small
2671        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2672            &payer_address,
2673            &buffer_address,
2674            &upgrade_authority_address,
2675            &upgrade_authority_address,
2676            &elf,
2677        );
2678        truncate_data(&mut transaction_accounts.get_mut(2).unwrap().1, 5);
2679        process_instruction(
2680            elf.len(),
2681            transaction_accounts,
2682            instruction_accounts,
2683            Err(InstructionError::AccountDataTooSmall),
2684        );
2685
2686        // Case: Program account not rent-exempt
2687        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2688            &payer_address,
2689            &buffer_address,
2690            &upgrade_authority_address,
2691            &upgrade_authority_address,
2692            &elf,
2693        );
2694        transaction_accounts.get_mut(2).unwrap().1.set_lamports(1);
2695        process_instruction(
2696            elf.len(),
2697            transaction_accounts,
2698            instruction_accounts,
2699            Err(InstructionError::ExecutableAccountNotRentExempt),
2700        );
2701
2702        // Case: ProgramData address not derived
2703        let (mut transaction_accounts, mut instruction_accounts) = get_accounts(
2704            &payer_address,
2705            &buffer_address,
2706            &upgrade_authority_address,
2707            &upgrade_authority_address,
2708            &elf,
2709        );
2710        let invalid_programdata_address = Pubkey::new_unique();
2711        transaction_accounts.get_mut(1).unwrap().0 = invalid_programdata_address;
2712        instruction_accounts.get_mut(1).unwrap().pubkey = invalid_programdata_address;
2713        process_instruction(
2714            elf.len(),
2715            transaction_accounts,
2716            instruction_accounts,
2717            Err(InstructionError::InvalidArgument),
2718        );
2719
2720        // Case: Buffer account not initialized
2721        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2722            &payer_address,
2723            &buffer_address,
2724            &upgrade_authority_address,
2725            &upgrade_authority_address,
2726            &elf,
2727        );
2728        transaction_accounts
2729            .get_mut(3)
2730            .unwrap()
2731            .1
2732            .set_state(&UpgradeableLoaderState::Uninitialized)
2733            .unwrap();
2734        process_instruction(
2735            elf.len(),
2736            transaction_accounts,
2737            instruction_accounts,
2738            Err(InstructionError::InvalidArgument),
2739        );
2740
2741        // Case: Buffer account not writable
2742        for buffer_balance in [0, 1_000_000, 15 * 1_000_000_000] {
2743            let (mut transaction_accounts, mut instruction_accounts) = get_accounts(
2744                &payer_address,
2745                &buffer_address,
2746                &upgrade_authority_address,
2747                &upgrade_authority_address,
2748                &elf,
2749            );
2750            transaction_accounts
2751                .get_mut(3)
2752                .unwrap()
2753                .1
2754                .set_lamports(buffer_balance);
2755            instruction_accounts.get_mut(3).unwrap().is_writable = false;
2756            process_instruction(
2757                elf.len(),
2758                transaction_accounts,
2759                instruction_accounts,
2760                Err(InstructionError::InvalidArgument),
2761            );
2762        }
2763
2764        // Case: Buffer account not owned by loader: lamports scenario
2765        //
2766        // In `DeployWithMaxDataLen`, the buffer's lamports are drained to the
2767        // payer before the payer is debited for the programdata's rent. Then,
2768        // the buffer's data is set to `size_of_buffer(0)`.
2769        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2770            &payer_address,
2771            &buffer_address,
2772            &upgrade_authority_address,
2773            &upgrade_authority_address,
2774            &elf,
2775        );
2776        {
2777            // Let's make sure the programdata requires a top-up.
2778            let required_rent = Rent::default()
2779                .minimum_balance(UpgradeableLoaderState::size_of_programdata(elf.len()));
2780            let programdata = &transaction_accounts.get(1).unwrap().1;
2781            assert!(programdata.lamports() < required_rent);
2782            let buffer = &mut transaction_accounts.get_mut(3).unwrap().1;
2783            buffer.set_owner(Pubkey::new_unique());
2784            buffer.set_lamports(required_rent);
2785        }
2786        process_instruction(
2787            elf.len(),
2788            transaction_accounts,
2789            instruction_accounts,
2790            Err(InstructionError::IncorrectProgramId),
2791        );
2792
2793        // Case: Buffer account not owned by loader: shrink scenario
2794        //
2795        // Same as the above case, but give the buffer a lamports balance of
2796        // `0`, rendering its balance "unchanged" by the drain operation.
2797        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2798            &payer_address,
2799            &buffer_address,
2800            &upgrade_authority_address,
2801            &upgrade_authority_address,
2802            &elf,
2803        );
2804        {
2805            // Set the buffer's lamports to zero.
2806            let buffer = &mut transaction_accounts.get_mut(3).unwrap().1;
2807            buffer.set_owner(Pubkey::new_unique());
2808            buffer.set_lamports(0);
2809        }
2810        process_instruction(
2811            elf.len(),
2812            transaction_accounts,
2813            instruction_accounts,
2814            Err(InstructionError::IncorrectProgramId),
2815        );
2816
2817        // Case: Buffer account not owned by loader: no-op scenario
2818        //
2819        // Same as the above case, but also truncate the buffer's data to
2820        // `size_of_buffer(0)` - just the buffer metadata, no ELF - rendering
2821        // the closing resize "unchanged" as well.
2822        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2823            &payer_address,
2824            &buffer_address,
2825            &upgrade_authority_address,
2826            &upgrade_authority_address,
2827            &elf,
2828        );
2829        {
2830            // Empty the buffer (metadata only) and zero its lamports.
2831            let buffer = &mut transaction_accounts.get_mut(3).unwrap().1;
2832            buffer.set_owner(Pubkey::new_unique());
2833            buffer.set_lamports(0);
2834            truncate_data(buffer, UpgradeableLoaderState::size_of_buffer(0));
2835        }
2836        process_instruction(
2837            elf.len(),
2838            transaction_accounts,
2839            instruction_accounts,
2840            Err(InstructionError::IncorrectProgramId),
2841        );
2842
2843        // Case: Max data length too small for Buffer data
2844        let (transaction_accounts, instruction_accounts) = get_accounts(
2845            &payer_address,
2846            &buffer_address,
2847            &upgrade_authority_address,
2848            &upgrade_authority_address,
2849            &elf,
2850        );
2851        process_instruction(
2852            elf.len().saturating_sub(1),
2853            transaction_accounts,
2854            instruction_accounts,
2855            Err(InstructionError::AccountDataTooSmall),
2856        );
2857
2858        // Case: Max data length too large
2859        let (transaction_accounts, instruction_accounts) = get_accounts(
2860            &payer_address,
2861            &buffer_address,
2862            &upgrade_authority_address,
2863            &upgrade_authority_address,
2864            &elf,
2865        );
2866        process_instruction(
2867            MAX_PERMITTED_DATA_LENGTH as usize,
2868            transaction_accounts,
2869            instruction_accounts,
2870            Err(InstructionError::InvalidArgument),
2871        );
2872
2873        // Case: Mismatched buffer authority
2874        let (transaction_accounts, instruction_accounts) = get_accounts(
2875            &payer_address,
2876            &buffer_address,
2877            &buffer_address,
2878            &upgrade_authority_address,
2879            &elf,
2880        );
2881        process_instruction(
2882            elf.len(),
2883            transaction_accounts,
2884            instruction_accounts,
2885            Err(InstructionError::IncorrectAuthority),
2886        );
2887
2888        // Case: No buffer authority
2889        let (mut transaction_accounts, instruction_accounts) = get_accounts(
2890            &payer_address,
2891            &buffer_address,
2892            &buffer_address,
2893            &upgrade_authority_address,
2894            &elf,
2895        );
2896        transaction_accounts
2897            .get_mut(3)
2898            .unwrap()
2899            .1
2900            .set_state(&UpgradeableLoaderState::Buffer {
2901                authority_address: None,
2902            })
2903            .unwrap();
2904        process_instruction(
2905            elf.len(),
2906            transaction_accounts,
2907            instruction_accounts,
2908            Err(InstructionError::IncorrectAuthority),
2909        );
2910
2911        // Case: Deploy SBPFv0
2912        let mut file =
2913            File::open("test_elfs/out/sbpfv0_verifier_err.so").expect("file open failed");
2914        let mut elf = Vec::new();
2915        file.read_to_end(&mut elf).unwrap();
2916        let (transaction_accounts, instruction_accounts) = get_accounts(
2917            &payer_address,
2918            &buffer_address,
2919            &upgrade_authority_address,
2920            &upgrade_authority_address,
2921            &elf,
2922        );
2923        process_instruction(
2924            elf.len(),
2925            transaction_accounts,
2926            instruction_accounts,
2927            Err(InstructionError::InvalidAccountData),
2928        );
2929    }
2930
2931    #[test]
2932    fn test_bpf_loader_upgradeable_set_upgrade_authority() {
2933        let instruction = bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap();
2934        let loader_id = bpf_loader_upgradeable::id();
2935        let slot = 0;
2936        let upgrade_authority_address = Pubkey::new_unique();
2937        let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
2938        let new_upgrade_authority_address = Pubkey::new_unique();
2939        let new_upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
2940        let program_address = Pubkey::new_unique();
2941        let (programdata_address, _) = Pubkey::find_program_address(
2942            &[program_address.as_ref()],
2943            &bpf_loader_upgradeable::id(),
2944        );
2945        let mut programdata_account = AccountSharedData::new(
2946            1,
2947            UpgradeableLoaderState::size_of_programdata(0),
2948            &bpf_loader_upgradeable::id(),
2949        );
2950        programdata_account
2951            .set_state(&UpgradeableLoaderState::ProgramData {
2952                slot,
2953                upgrade_authority_address: Some(upgrade_authority_address),
2954            })
2955            .unwrap();
2956        let programdata_meta = AccountMeta {
2957            pubkey: programdata_address,
2958            is_signer: false,
2959            is_writable: true,
2960        };
2961        let upgrade_authority_meta = AccountMeta {
2962            pubkey: upgrade_authority_address,
2963            is_signer: true,
2964            is_writable: false,
2965        };
2966        let new_upgrade_authority_meta = AccountMeta {
2967            pubkey: new_upgrade_authority_address,
2968            is_signer: false,
2969            is_writable: false,
2970        };
2971
2972        // Case: Set to new authority
2973        let accounts = process_instruction(
2974            &loader_id,
2975            &instruction,
2976            vec![
2977                (programdata_address, programdata_account.clone()),
2978                (upgrade_authority_address, upgrade_authority_account.clone()),
2979                (
2980                    new_upgrade_authority_address,
2981                    new_upgrade_authority_account.clone(),
2982                ),
2983            ],
2984            vec![
2985                programdata_meta.clone(),
2986                upgrade_authority_meta.clone(),
2987                new_upgrade_authority_meta.clone(),
2988            ],
2989            Ok(()),
2990        );
2991        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
2992        assert_eq!(
2993            state,
2994            UpgradeableLoaderState::ProgramData {
2995                slot,
2996                upgrade_authority_address: Some(new_upgrade_authority_address),
2997            }
2998        );
2999
3000        // Case: Finalize
3001        let accounts = process_instruction(
3002            &loader_id,
3003            &instruction,
3004            vec![
3005                (programdata_address, programdata_account.clone()),
3006                (upgrade_authority_address, upgrade_authority_account.clone()),
3007            ],
3008            vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
3009            Ok(()),
3010        );
3011        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3012        assert_eq!(
3013            state,
3014            UpgradeableLoaderState::ProgramData {
3015                slot,
3016                upgrade_authority_address: None,
3017            }
3018        );
3019
3020        // Case: Finalize a SBPFv0 program
3021        let mut file =
3022            File::open("test_elfs/out/sbpfv0_verifier_err.so").expect("file open failed");
3023        let mut elf = Vec::new();
3024        file.read_to_end(&mut elf).unwrap();
3025        programdata_account.resize(UpgradeableLoaderState::size_of_programdata(elf.len()), 0);
3026        programdata_account
3027            .data_as_mut_slice()
3028            .get_mut(UpgradeableLoaderState::size_of_programdata_metadata()..)
3029            .unwrap()
3030            .copy_from_slice(&elf);
3031        process_instruction(
3032            &loader_id,
3033            &instruction,
3034            vec![
3035                (programdata_address, programdata_account.clone()),
3036                (upgrade_authority_address, upgrade_authority_account.clone()),
3037            ],
3038            vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
3039            Err(InstructionError::InvalidAccountData),
3040        );
3041
3042        // Case: Authority did not sign
3043        process_instruction(
3044            &loader_id,
3045            &instruction,
3046            vec![
3047                (programdata_address, programdata_account.clone()),
3048                (upgrade_authority_address, upgrade_authority_account.clone()),
3049            ],
3050            vec![
3051                programdata_meta.clone(),
3052                AccountMeta {
3053                    pubkey: upgrade_authority_address,
3054                    is_signer: false,
3055                    is_writable: false,
3056                },
3057            ],
3058            Err(InstructionError::MissingRequiredSignature),
3059        );
3060
3061        // Case: wrong authority
3062        let invalid_upgrade_authority_address = Pubkey::new_unique();
3063        process_instruction(
3064            &loader_id,
3065            &instruction,
3066            vec![
3067                (programdata_address, programdata_account.clone()),
3068                (
3069                    invalid_upgrade_authority_address,
3070                    upgrade_authority_account.clone(),
3071                ),
3072                (new_upgrade_authority_address, new_upgrade_authority_account),
3073            ],
3074            vec![
3075                programdata_meta.clone(),
3076                AccountMeta {
3077                    pubkey: invalid_upgrade_authority_address,
3078                    is_signer: true,
3079                    is_writable: false,
3080                },
3081                new_upgrade_authority_meta,
3082            ],
3083            Err(InstructionError::IncorrectAuthority),
3084        );
3085
3086        // Case: No authority
3087        programdata_account
3088            .set_state(&UpgradeableLoaderState::ProgramData {
3089                slot,
3090                upgrade_authority_address: None,
3091            })
3092            .unwrap();
3093        process_instruction(
3094            &loader_id,
3095            &instruction,
3096            vec![
3097                (programdata_address, programdata_account.clone()),
3098                (upgrade_authority_address, upgrade_authority_account.clone()),
3099            ],
3100            vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
3101            Err(InstructionError::Immutable),
3102        );
3103
3104        // Case: Not a ProgramData account
3105        programdata_account
3106            .set_state(&UpgradeableLoaderState::Program {
3107                programdata_address: Pubkey::new_unique(),
3108            })
3109            .unwrap();
3110        process_instruction(
3111            &loader_id,
3112            &instruction,
3113            vec![
3114                (programdata_address, programdata_account.clone()),
3115                (upgrade_authority_address, upgrade_authority_account),
3116            ],
3117            vec![programdata_meta, upgrade_authority_meta],
3118            Err(InstructionError::InvalidArgument),
3119        );
3120    }
3121
3122    #[test]
3123    fn test_bpf_loader_upgradeable_set_upgrade_authority_checked() {
3124        let instruction =
3125            bincode::serialize(&UpgradeableLoaderInstruction::SetAuthorityChecked).unwrap();
3126        let loader_id = bpf_loader_upgradeable::id();
3127        let slot = 0;
3128        let upgrade_authority_address = Pubkey::new_unique();
3129        let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3130        let new_upgrade_authority_address = Pubkey::new_unique();
3131        let new_upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3132        let program_address = Pubkey::new_unique();
3133        let (programdata_address, _) = Pubkey::find_program_address(
3134            &[program_address.as_ref()],
3135            &bpf_loader_upgradeable::id(),
3136        );
3137        let mut programdata_account = AccountSharedData::new(
3138            1,
3139            UpgradeableLoaderState::size_of_programdata(0),
3140            &bpf_loader_upgradeable::id(),
3141        );
3142        programdata_account
3143            .set_state(&UpgradeableLoaderState::ProgramData {
3144                slot,
3145                upgrade_authority_address: Some(upgrade_authority_address),
3146            })
3147            .unwrap();
3148        let programdata_meta = AccountMeta {
3149            pubkey: programdata_address,
3150            is_signer: false,
3151            is_writable: true,
3152        };
3153        let upgrade_authority_meta = AccountMeta {
3154            pubkey: upgrade_authority_address,
3155            is_signer: true,
3156            is_writable: false,
3157        };
3158        let new_upgrade_authority_meta = AccountMeta {
3159            pubkey: new_upgrade_authority_address,
3160            is_signer: true,
3161            is_writable: false,
3162        };
3163
3164        // Case: Set to new authority
3165        let accounts = process_instruction(
3166            &loader_id,
3167            &instruction,
3168            vec![
3169                (programdata_address, programdata_account.clone()),
3170                (upgrade_authority_address, upgrade_authority_account.clone()),
3171                (
3172                    new_upgrade_authority_address,
3173                    new_upgrade_authority_account.clone(),
3174                ),
3175            ],
3176            vec![
3177                programdata_meta.clone(),
3178                upgrade_authority_meta.clone(),
3179                new_upgrade_authority_meta.clone(),
3180            ],
3181            Ok(()),
3182        );
3183
3184        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3185        assert_eq!(
3186            state,
3187            UpgradeableLoaderState::ProgramData {
3188                slot,
3189                upgrade_authority_address: Some(new_upgrade_authority_address),
3190            }
3191        );
3192
3193        // Case: set to same authority
3194        process_instruction(
3195            &loader_id,
3196            &instruction,
3197            vec![
3198                (programdata_address, programdata_account.clone()),
3199                (upgrade_authority_address, upgrade_authority_account.clone()),
3200            ],
3201            vec![
3202                programdata_meta.clone(),
3203                upgrade_authority_meta.clone(),
3204                upgrade_authority_meta.clone(),
3205            ],
3206            Ok(()),
3207        );
3208
3209        // Case: present authority not in instruction
3210        process_instruction(
3211            &loader_id,
3212            &instruction,
3213            vec![
3214                (programdata_address, programdata_account.clone()),
3215                (upgrade_authority_address, upgrade_authority_account.clone()),
3216                (
3217                    new_upgrade_authority_address,
3218                    new_upgrade_authority_account.clone(),
3219                ),
3220            ],
3221            vec![programdata_meta.clone(), new_upgrade_authority_meta.clone()],
3222            Err(InstructionError::MissingAccount),
3223        );
3224
3225        // Case: new authority not in instruction
3226        process_instruction(
3227            &loader_id,
3228            &instruction,
3229            vec![
3230                (programdata_address, programdata_account.clone()),
3231                (upgrade_authority_address, upgrade_authority_account.clone()),
3232                (
3233                    new_upgrade_authority_address,
3234                    new_upgrade_authority_account.clone(),
3235                ),
3236            ],
3237            vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
3238            Err(InstructionError::MissingAccount),
3239        );
3240
3241        // Case: present authority did not sign
3242        process_instruction(
3243            &loader_id,
3244            &instruction,
3245            vec![
3246                (programdata_address, programdata_account.clone()),
3247                (upgrade_authority_address, upgrade_authority_account.clone()),
3248                (
3249                    new_upgrade_authority_address,
3250                    new_upgrade_authority_account.clone(),
3251                ),
3252            ],
3253            vec![
3254                programdata_meta.clone(),
3255                AccountMeta {
3256                    pubkey: upgrade_authority_address,
3257                    is_signer: false,
3258                    is_writable: false,
3259                },
3260                new_upgrade_authority_meta.clone(),
3261            ],
3262            Err(InstructionError::MissingRequiredSignature),
3263        );
3264
3265        // Case: New authority did not sign
3266        process_instruction(
3267            &loader_id,
3268            &instruction,
3269            vec![
3270                (programdata_address, programdata_account.clone()),
3271                (upgrade_authority_address, upgrade_authority_account.clone()),
3272                (
3273                    new_upgrade_authority_address,
3274                    new_upgrade_authority_account.clone(),
3275                ),
3276            ],
3277            vec![
3278                programdata_meta.clone(),
3279                upgrade_authority_meta.clone(),
3280                AccountMeta {
3281                    pubkey: new_upgrade_authority_address,
3282                    is_signer: false,
3283                    is_writable: false,
3284                },
3285            ],
3286            Err(InstructionError::MissingRequiredSignature),
3287        );
3288
3289        // Case: wrong present authority
3290        let invalid_upgrade_authority_address = Pubkey::new_unique();
3291        process_instruction(
3292            &loader_id,
3293            &instruction,
3294            vec![
3295                (programdata_address, programdata_account.clone()),
3296                (
3297                    invalid_upgrade_authority_address,
3298                    upgrade_authority_account.clone(),
3299                ),
3300                (new_upgrade_authority_address, new_upgrade_authority_account),
3301            ],
3302            vec![
3303                programdata_meta.clone(),
3304                AccountMeta {
3305                    pubkey: invalid_upgrade_authority_address,
3306                    is_signer: true,
3307                    is_writable: false,
3308                },
3309                new_upgrade_authority_meta.clone(),
3310            ],
3311            Err(InstructionError::IncorrectAuthority),
3312        );
3313
3314        // Case: programdata is immutable
3315        programdata_account
3316            .set_state(&UpgradeableLoaderState::ProgramData {
3317                slot,
3318                upgrade_authority_address: None,
3319            })
3320            .unwrap();
3321        process_instruction(
3322            &loader_id,
3323            &instruction,
3324            vec![
3325                (programdata_address, programdata_account.clone()),
3326                (upgrade_authority_address, upgrade_authority_account.clone()),
3327            ],
3328            vec![
3329                programdata_meta.clone(),
3330                upgrade_authority_meta.clone(),
3331                new_upgrade_authority_meta.clone(),
3332            ],
3333            Err(InstructionError::Immutable),
3334        );
3335
3336        // Case: Not a ProgramData account
3337        programdata_account
3338            .set_state(&UpgradeableLoaderState::Program {
3339                programdata_address: Pubkey::new_unique(),
3340            })
3341            .unwrap();
3342        process_instruction(
3343            &loader_id,
3344            &instruction,
3345            vec![
3346                (programdata_address, programdata_account.clone()),
3347                (upgrade_authority_address, upgrade_authority_account),
3348            ],
3349            vec![
3350                programdata_meta,
3351                upgrade_authority_meta,
3352                new_upgrade_authority_meta,
3353            ],
3354            Err(InstructionError::InvalidArgument),
3355        );
3356    }
3357
3358    #[test]
3359    fn test_bpf_loader_upgradeable_set_buffer_authority() {
3360        let instruction = bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap();
3361        let loader_id = bpf_loader_upgradeable::id();
3362        let invalid_authority_address = Pubkey::new_unique();
3363        let authority_address = Pubkey::new_unique();
3364        let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3365        let new_authority_address = Pubkey::new_unique();
3366        let new_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3367        let buffer_address = Pubkey::new_unique();
3368        let mut buffer_account =
3369            AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(0), &loader_id);
3370        buffer_account
3371            .set_state(&UpgradeableLoaderState::Buffer {
3372                authority_address: Some(authority_address),
3373            })
3374            .unwrap();
3375        let mut transaction_accounts = vec![
3376            (buffer_address, buffer_account.clone()),
3377            (authority_address, authority_account.clone()),
3378            (new_authority_address, new_authority_account.clone()),
3379        ];
3380        let buffer_meta = AccountMeta {
3381            pubkey: buffer_address,
3382            is_signer: false,
3383            is_writable: true,
3384        };
3385        let authority_meta = AccountMeta {
3386            pubkey: authority_address,
3387            is_signer: true,
3388            is_writable: false,
3389        };
3390        let new_authority_meta = AccountMeta {
3391            pubkey: new_authority_address,
3392            is_signer: false,
3393            is_writable: false,
3394        };
3395
3396        // Case: New authority required
3397        let accounts = process_instruction(
3398            &loader_id,
3399            &instruction,
3400            transaction_accounts.clone(),
3401            vec![buffer_meta.clone(), authority_meta.clone()],
3402            Err(InstructionError::IncorrectAuthority),
3403        );
3404        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3405        assert_eq!(
3406            state,
3407            UpgradeableLoaderState::Buffer {
3408                authority_address: Some(authority_address),
3409            }
3410        );
3411
3412        // Case: Set to new authority
3413        buffer_account
3414            .set_state(&UpgradeableLoaderState::Buffer {
3415                authority_address: Some(authority_address),
3416            })
3417            .unwrap();
3418        let accounts = process_instruction(
3419            &loader_id,
3420            &instruction,
3421            transaction_accounts.clone(),
3422            vec![
3423                buffer_meta.clone(),
3424                authority_meta.clone(),
3425                new_authority_meta.clone(),
3426            ],
3427            Ok(()),
3428        );
3429        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3430        assert_eq!(
3431            state,
3432            UpgradeableLoaderState::Buffer {
3433                authority_address: Some(new_authority_address),
3434            }
3435        );
3436
3437        // Case: Authority did not sign
3438        process_instruction(
3439            &loader_id,
3440            &instruction,
3441            transaction_accounts.clone(),
3442            vec![
3443                buffer_meta.clone(),
3444                AccountMeta {
3445                    pubkey: authority_address,
3446                    is_signer: false,
3447                    is_writable: false,
3448                },
3449                new_authority_meta.clone(),
3450            ],
3451            Err(InstructionError::MissingRequiredSignature),
3452        );
3453
3454        // Case: wrong authority
3455        process_instruction(
3456            &loader_id,
3457            &instruction,
3458            vec![
3459                (buffer_address, buffer_account.clone()),
3460                (invalid_authority_address, authority_account),
3461                (new_authority_address, new_authority_account),
3462            ],
3463            vec![
3464                buffer_meta.clone(),
3465                AccountMeta {
3466                    pubkey: invalid_authority_address,
3467                    is_signer: true,
3468                    is_writable: false,
3469                },
3470                new_authority_meta.clone(),
3471            ],
3472            Err(InstructionError::IncorrectAuthority),
3473        );
3474
3475        // Case: No authority
3476        process_instruction(
3477            &loader_id,
3478            &instruction,
3479            transaction_accounts.clone(),
3480            vec![buffer_meta.clone(), authority_meta.clone()],
3481            Err(InstructionError::IncorrectAuthority),
3482        );
3483
3484        // Case: Set to no authority
3485        transaction_accounts
3486            .get_mut(0)
3487            .unwrap()
3488            .1
3489            .set_state(&UpgradeableLoaderState::Buffer {
3490                authority_address: None,
3491            })
3492            .unwrap();
3493        process_instruction(
3494            &loader_id,
3495            &instruction,
3496            transaction_accounts.clone(),
3497            vec![
3498                buffer_meta.clone(),
3499                authority_meta.clone(),
3500                new_authority_meta.clone(),
3501            ],
3502            Err(InstructionError::Immutable),
3503        );
3504
3505        // Case: Not a Buffer account
3506        transaction_accounts
3507            .get_mut(0)
3508            .unwrap()
3509            .1
3510            .set_state(&UpgradeableLoaderState::Program {
3511                programdata_address: Pubkey::new_unique(),
3512            })
3513            .unwrap();
3514        process_instruction(
3515            &loader_id,
3516            &instruction,
3517            transaction_accounts.clone(),
3518            vec![buffer_meta, authority_meta, new_authority_meta],
3519            Err(InstructionError::InvalidArgument),
3520        );
3521    }
3522
3523    #[test]
3524    fn test_bpf_loader_upgradeable_set_buffer_authority_checked() {
3525        let instruction =
3526            bincode::serialize(&UpgradeableLoaderInstruction::SetAuthorityChecked).unwrap();
3527        let loader_id = bpf_loader_upgradeable::id();
3528        let invalid_authority_address = Pubkey::new_unique();
3529        let authority_address = Pubkey::new_unique();
3530        let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3531        let new_authority_address = Pubkey::new_unique();
3532        let new_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3533        let buffer_address = Pubkey::new_unique();
3534        let mut buffer_account =
3535            AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(0), &loader_id);
3536        buffer_account
3537            .set_state(&UpgradeableLoaderState::Buffer {
3538                authority_address: Some(authority_address),
3539            })
3540            .unwrap();
3541        let mut transaction_accounts = vec![
3542            (buffer_address, buffer_account.clone()),
3543            (authority_address, authority_account.clone()),
3544            (new_authority_address, new_authority_account.clone()),
3545        ];
3546        let buffer_meta = AccountMeta {
3547            pubkey: buffer_address,
3548            is_signer: false,
3549            is_writable: true,
3550        };
3551        let authority_meta = AccountMeta {
3552            pubkey: authority_address,
3553            is_signer: true,
3554            is_writable: false,
3555        };
3556        let new_authority_meta = AccountMeta {
3557            pubkey: new_authority_address,
3558            is_signer: true,
3559            is_writable: false,
3560        };
3561
3562        // Case: Set to new authority
3563        buffer_account
3564            .set_state(&UpgradeableLoaderState::Buffer {
3565                authority_address: Some(authority_address),
3566            })
3567            .unwrap();
3568        let accounts = process_instruction(
3569            &loader_id,
3570            &instruction,
3571            transaction_accounts.clone(),
3572            vec![
3573                buffer_meta.clone(),
3574                authority_meta.clone(),
3575                new_authority_meta.clone(),
3576            ],
3577            Ok(()),
3578        );
3579        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3580        assert_eq!(
3581            state,
3582            UpgradeableLoaderState::Buffer {
3583                authority_address: Some(new_authority_address),
3584            }
3585        );
3586
3587        // Case: set to same authority
3588        process_instruction(
3589            &loader_id,
3590            &instruction,
3591            transaction_accounts.clone(),
3592            vec![
3593                buffer_meta.clone(),
3594                authority_meta.clone(),
3595                authority_meta.clone(),
3596            ],
3597            Ok(()),
3598        );
3599
3600        // Case: Missing current authority
3601        process_instruction(
3602            &loader_id,
3603            &instruction,
3604            transaction_accounts.clone(),
3605            vec![buffer_meta.clone(), new_authority_meta.clone()],
3606            Err(InstructionError::MissingAccount),
3607        );
3608
3609        // Case: Missing new authority
3610        process_instruction(
3611            &loader_id,
3612            &instruction,
3613            transaction_accounts.clone(),
3614            vec![buffer_meta.clone(), authority_meta.clone()],
3615            Err(InstructionError::MissingAccount),
3616        );
3617
3618        // Case: wrong present authority
3619        process_instruction(
3620            &loader_id,
3621            &instruction,
3622            vec![
3623                (buffer_address, buffer_account.clone()),
3624                (invalid_authority_address, authority_account),
3625                (new_authority_address, new_authority_account),
3626            ],
3627            vec![
3628                buffer_meta.clone(),
3629                AccountMeta {
3630                    pubkey: invalid_authority_address,
3631                    is_signer: true,
3632                    is_writable: false,
3633                },
3634                new_authority_meta.clone(),
3635            ],
3636            Err(InstructionError::IncorrectAuthority),
3637        );
3638
3639        // Case: present authority did not sign
3640        process_instruction(
3641            &loader_id,
3642            &instruction,
3643            transaction_accounts.clone(),
3644            vec![
3645                buffer_meta.clone(),
3646                AccountMeta {
3647                    pubkey: authority_address,
3648                    is_signer: false,
3649                    is_writable: false,
3650                },
3651                new_authority_meta.clone(),
3652            ],
3653            Err(InstructionError::MissingRequiredSignature),
3654        );
3655
3656        // Case: new authority did not sign
3657        process_instruction(
3658            &loader_id,
3659            &instruction,
3660            transaction_accounts.clone(),
3661            vec![
3662                buffer_meta.clone(),
3663                authority_meta.clone(),
3664                AccountMeta {
3665                    pubkey: new_authority_address,
3666                    is_signer: false,
3667                    is_writable: false,
3668                },
3669            ],
3670            Err(InstructionError::MissingRequiredSignature),
3671        );
3672
3673        // Case: Not a Buffer account
3674        transaction_accounts
3675            .get_mut(0)
3676            .unwrap()
3677            .1
3678            .set_state(&UpgradeableLoaderState::Program {
3679                programdata_address: Pubkey::new_unique(),
3680            })
3681            .unwrap();
3682        process_instruction(
3683            &loader_id,
3684            &instruction,
3685            transaction_accounts.clone(),
3686            vec![
3687                buffer_meta.clone(),
3688                authority_meta.clone(),
3689                new_authority_meta.clone(),
3690            ],
3691            Err(InstructionError::InvalidArgument),
3692        );
3693
3694        // Case: Buffer is immutable
3695        transaction_accounts
3696            .get_mut(0)
3697            .unwrap()
3698            .1
3699            .set_state(&UpgradeableLoaderState::Buffer {
3700                authority_address: None,
3701            })
3702            .unwrap();
3703        process_instruction(
3704            &loader_id,
3705            &instruction,
3706            transaction_accounts.clone(),
3707            vec![buffer_meta, authority_meta, new_authority_meta],
3708            Err(InstructionError::Immutable),
3709        );
3710    }
3711
3712    #[test]
3713    fn test_bpf_loader_upgradeable_close() {
3714        let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Close).unwrap();
3715        let loader_id = bpf_loader_upgradeable::id();
3716        let invalid_authority_address = Pubkey::new_unique();
3717        let authority_address = Pubkey::new_unique();
3718        let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3719        let recipient_address = Pubkey::new_unique();
3720        let recipient_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3721        let buffer_address = Pubkey::new_unique();
3722        let mut buffer_account =
3723            AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(128), &loader_id);
3724        buffer_account
3725            .set_state(&UpgradeableLoaderState::Buffer {
3726                authority_address: Some(authority_address),
3727            })
3728            .unwrap();
3729        let uninitialized_address = Pubkey::new_unique();
3730        let mut uninitialized_account = AccountSharedData::new(
3731            1,
3732            UpgradeableLoaderState::size_of_programdata(0),
3733            &loader_id,
3734        );
3735        uninitialized_account
3736            .set_state(&UpgradeableLoaderState::Uninitialized)
3737            .unwrap();
3738        let programdata_address = Pubkey::new_unique();
3739        let mut programdata_account = AccountSharedData::new(
3740            1,
3741            UpgradeableLoaderState::size_of_programdata(128),
3742            &loader_id,
3743        );
3744        programdata_account
3745            .set_state(&UpgradeableLoaderState::ProgramData {
3746                slot: 0,
3747                upgrade_authority_address: Some(authority_address),
3748            })
3749            .unwrap();
3750        let program_address = Pubkey::new_unique();
3751        let mut program_account =
3752            AccountSharedData::new(1, UpgradeableLoaderState::size_of_program(), &loader_id);
3753        program_account.set_executable(true);
3754        program_account
3755            .set_state(&UpgradeableLoaderState::Program {
3756                programdata_address,
3757            })
3758            .unwrap();
3759        let clock_account = create_sysvar_account(&Clock {
3760            slot: 1,
3761            ..Clock::default()
3762        });
3763        let transaction_accounts = vec![
3764            (buffer_address, buffer_account.clone()),
3765            (recipient_address, recipient_account.clone()),
3766            (authority_address, authority_account.clone()),
3767        ];
3768        let buffer_meta = AccountMeta {
3769            pubkey: buffer_address,
3770            is_signer: false,
3771            is_writable: true,
3772        };
3773        let recipient_meta = AccountMeta {
3774            pubkey: recipient_address,
3775            is_signer: false,
3776            is_writable: true,
3777        };
3778        let authority_meta = AccountMeta {
3779            pubkey: authority_address,
3780            is_signer: true,
3781            is_writable: false,
3782        };
3783
3784        // Case: close a buffer account
3785        let accounts = process_instruction(
3786            &loader_id,
3787            &instruction,
3788            transaction_accounts,
3789            vec![
3790                buffer_meta.clone(),
3791                recipient_meta.clone(),
3792                authority_meta.clone(),
3793            ],
3794            Ok(()),
3795        );
3796        assert_eq!(0, accounts.first().unwrap().lamports());
3797        assert_eq!(2, accounts.get(1).unwrap().lamports());
3798        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3799        assert_eq!(state, UpgradeableLoaderState::Uninitialized);
3800        assert_eq!(
3801            UpgradeableLoaderState::size_of_uninitialized(),
3802            accounts.first().unwrap().data().len()
3803        );
3804
3805        // Case: close with wrong authority
3806        process_instruction(
3807            &loader_id,
3808            &instruction,
3809            vec![
3810                (buffer_address, buffer_account.clone()),
3811                (recipient_address, recipient_account.clone()),
3812                (invalid_authority_address, authority_account.clone()),
3813            ],
3814            vec![
3815                buffer_meta,
3816                recipient_meta.clone(),
3817                AccountMeta {
3818                    pubkey: invalid_authority_address,
3819                    is_signer: true,
3820                    is_writable: false,
3821                },
3822            ],
3823            Err(InstructionError::IncorrectAuthority),
3824        );
3825
3826        // Case: close an uninitialized account
3827        let accounts = process_instruction(
3828            &loader_id,
3829            &instruction,
3830            vec![
3831                (uninitialized_address, uninitialized_account.clone()),
3832                (recipient_address, recipient_account.clone()),
3833                (invalid_authority_address, authority_account.clone()),
3834            ],
3835            vec![
3836                AccountMeta {
3837                    pubkey: uninitialized_address,
3838                    is_signer: false,
3839                    is_writable: true,
3840                },
3841                recipient_meta.clone(),
3842                authority_meta.clone(),
3843            ],
3844            Ok(()),
3845        );
3846        assert_eq!(0, accounts.first().unwrap().lamports());
3847        assert_eq!(2, accounts.get(1).unwrap().lamports());
3848        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3849        assert_eq!(state, UpgradeableLoaderState::Uninitialized);
3850        assert_eq!(
3851            UpgradeableLoaderState::size_of_uninitialized(),
3852            accounts.first().unwrap().data().len()
3853        );
3854
3855        // Case: close a program account with a non-writable program account
3856        process_instruction(
3857            &loader_id,
3858            &instruction,
3859            vec![
3860                (programdata_address, programdata_account.clone()),
3861                (recipient_address, recipient_account.clone()),
3862                (authority_address, authority_account.clone()),
3863                (program_address, program_account.clone()),
3864                (sysvar::clock::id(), clock_account.clone()),
3865            ],
3866            vec![
3867                AccountMeta {
3868                    pubkey: programdata_address,
3869                    is_signer: false,
3870                    is_writable: true,
3871                },
3872                recipient_meta.clone(),
3873                authority_meta.clone(),
3874                AccountMeta {
3875                    pubkey: program_address,
3876                    is_signer: false,
3877                    is_writable: false,
3878                },
3879            ],
3880            Err(InstructionError::InvalidArgument),
3881        );
3882
3883        // Case: close a program account
3884        let accounts = process_instruction(
3885            &loader_id,
3886            &instruction,
3887            vec![
3888                (programdata_address, programdata_account.clone()),
3889                (recipient_address, recipient_account.clone()),
3890                (authority_address, authority_account.clone()),
3891                (program_address, program_account.clone()),
3892                (sysvar::clock::id(), clock_account.clone()),
3893            ],
3894            vec![
3895                AccountMeta {
3896                    pubkey: programdata_address,
3897                    is_signer: false,
3898                    is_writable: true,
3899                },
3900                recipient_meta,
3901                authority_meta,
3902                AccountMeta {
3903                    pubkey: program_address,
3904                    is_signer: false,
3905                    is_writable: true,
3906                },
3907            ],
3908            Ok(()),
3909        );
3910        assert_eq!(0, accounts.first().unwrap().lamports());
3911        assert_eq!(2, accounts.get(1).unwrap().lamports());
3912        let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3913        assert_eq!(state, UpgradeableLoaderState::Uninitialized);
3914        assert_eq!(
3915            UpgradeableLoaderState::size_of_uninitialized(),
3916            accounts.first().unwrap().data().len()
3917        );
3918
3919        // Try to invoke closed account
3920        programdata_account = accounts.first().unwrap().clone();
3921        program_account = accounts.get(3).unwrap().clone();
3922        process_instruction(
3923            &program_address,
3924            &[],
3925            vec![
3926                (programdata_address, programdata_account.clone()),
3927                (program_address, program_account.clone()),
3928            ],
3929            Vec::new(),
3930            Err(InstructionError::UnsupportedProgramId),
3931        );
3932
3933        // Case: Reopen should fail
3934        process_instruction(
3935            &loader_id,
3936            &bincode::serialize(&UpgradeableLoaderInstruction::DeployWithMaxDataLen {
3937                max_data_len: 0,
3938            })
3939            .unwrap(),
3940            vec![
3941                (recipient_address, recipient_account),
3942                (programdata_address, programdata_account),
3943                (program_address, program_account),
3944                (buffer_address, buffer_account),
3945                (sysvar::rent::id(), create_sysvar_account(&Rent::default())),
3946                (sysvar::clock::id(), clock_account),
3947                (
3948                    system_program::id(),
3949                    AccountSharedData::new(0, 0, &system_program::id()),
3950                ),
3951                (authority_address, authority_account),
3952            ],
3953            vec![
3954                AccountMeta {
3955                    pubkey: recipient_address,
3956                    is_signer: true,
3957                    is_writable: true,
3958                },
3959                AccountMeta {
3960                    pubkey: programdata_address,
3961                    is_signer: false,
3962                    is_writable: true,
3963                },
3964                AccountMeta {
3965                    pubkey: program_address,
3966                    is_signer: false,
3967                    is_writable: true,
3968                },
3969                AccountMeta {
3970                    pubkey: buffer_address,
3971                    is_signer: false,
3972                    is_writable: false,
3973                },
3974                AccountMeta {
3975                    pubkey: sysvar::rent::id(),
3976                    is_signer: false,
3977                    is_writable: false,
3978                },
3979                AccountMeta {
3980                    pubkey: sysvar::clock::id(),
3981                    is_signer: false,
3982                    is_writable: false,
3983                },
3984                AccountMeta {
3985                    pubkey: system_program::id(),
3986                    is_signer: false,
3987                    is_writable: false,
3988                },
3989                AccountMeta {
3990                    pubkey: authority_address,
3991                    is_signer: false,
3992                    is_writable: false,
3993                },
3994            ],
3995            Err(InstructionError::AccountAlreadyInitialized),
3996        );
3997    }
3998
3999    /// fuzzing utility function
4000    fn fuzz<F>(
4001        bytes: &[u8],
4002        outer_iters: usize,
4003        inner_iters: usize,
4004        offset: Range<usize>,
4005        value: Range<u8>,
4006        work: F,
4007    ) where
4008        F: Fn(&mut [u8]),
4009    {
4010        let mut rng = rand::rng();
4011        for _ in 0..outer_iters {
4012            let mut mangled_bytes = bytes.to_vec();
4013            for _ in 0..inner_iters {
4014                let offset = rng.random_range(offset.start..offset.end);
4015                let value = rng.random_range(value.start..value.end);
4016                *mangled_bytes.get_mut(offset).unwrap() = value;
4017                work(&mut mangled_bytes);
4018            }
4019        }
4020    }
4021
4022    #[test]
4023    #[ignore]
4024    fn test_fuzz() {
4025        let loader_id = bpf_loader::id();
4026        let program_id = Pubkey::new_unique();
4027
4028        // Create program account
4029        let mut file = File::open("test_elfs/out/sbpfv3_return_ok.so").expect("file open failed");
4030        let mut elf = Vec::new();
4031        file.read_to_end(&mut elf).unwrap();
4032
4033        // Mangle the whole file
4034        fuzz(
4035            &elf,
4036            1_000_000_000,
4037            100,
4038            0..elf.len(),
4039            0..255,
4040            |bytes: &mut [u8]| {
4041                let mut program_account = AccountSharedData::new(1, 0, &loader_id);
4042                program_account.set_data_from_slice(bytes);
4043                program_account.set_executable(true);
4044                process_instruction(
4045                    &program_id,
4046                    &[],
4047                    vec![(program_id, program_account)],
4048                    Vec::new(),
4049                    Ok(()),
4050                );
4051            },
4052        );
4053    }
4054
4055    #[test]
4056    fn test_calculate_heap_cost() {
4057        let heap_cost = 8_u64;
4058
4059        // heap allocations are in 32K block, `heap_cost` of CU is consumed per additional 32k
4060
4061        // assert less than 32K heap should cost zero unit
4062        assert_eq!(0, calculate_heap_cost(31 * 1024, heap_cost));
4063
4064        // assert exact 32K heap should be cost zero unit
4065        assert_eq!(0, calculate_heap_cost(32 * 1024, heap_cost));
4066
4067        // assert slightly more than 32K heap should cost 1 * heap_cost
4068        assert_eq!(heap_cost, calculate_heap_cost(33 * 1024, heap_cost));
4069
4070        // assert exact 64K heap should cost 1 * heap_cost
4071        assert_eq!(heap_cost, calculate_heap_cost(64 * 1024, heap_cost));
4072    }
4073
4074    fn deploy_test_program(
4075        invoke_context: &mut InvokeContext,
4076        program_id: Pubkey,
4077    ) -> Result<(), InstructionError> {
4078        let mut file = File::open("test_elfs/out/sbpfv3_return_ok.so").expect("file open failed");
4079        let mut elf = Vec::new();
4080        file.read_to_end(&mut elf).unwrap();
4081        deploy_program!(
4082            invoke_context,
4083            &program_id,
4084            &bpf_loader_upgradeable::id(),
4085            &elf,
4086            2_u64,
4087            true, // disable_sbpf_v0_v1_v2_deployment
4088        );
4089        Ok(())
4090    }
4091
4092    // Concurrency rationale: these tests construct `ProgramCacheEntry` instances
4093    // directly. The struct's `latest_access_slot: AtomicU64` field is defined in
4094    // `solana-program-runtime`; under the `shuttle-test` feature
4095    // `solana-svm-type-overrides` swaps `std::sync::atomic::AtomicU64` for
4096    // `shuttle::sync::atomic::AtomicU64`, whose Shuttle-backed operations
4097    // (load, fetch_max, and similar) must run inside an active Shuttle
4098    // scheduler. We therefore extract the test bodies into `do_test_*` helpers
4099    // and drive them via `shuttle::check_random` stubs when the feature is on.
4100    // We use `check_random` only (no `check_dfs` companion) because the test
4101    // bodies spawn no Shuttle threads, so DFS gives no meaningful interleaving
4102    // coverage; `check_random` is enough to provide the scheduler context.
4103    // This matches the single-scheduler pattern used in
4104    // `net-utils/src/token_bucket.rs` and `poh/src/record_channels.rs`.
4105    //
4106    // 100 iterations is intentionally low: the test bodies are single-threaded
4107    // (no `shuttle::thread::spawn`), so additional iterations validate only
4108    // the harness wiring, not concurrent interleavings. Bump this if a future
4109    // refactor introduces real concurrency in the test bodies.
4110    #[cfg(feature = "shuttle-test")]
4111    const PROGRAM_USAGE_COUNT_RANDOM_ITERATIONS: usize = 100;
4112
4113    #[test]
4114    fn test_program_usage_count_on_upgrade() {
4115        #[cfg(feature = "shuttle-test")]
4116        shuttle::check_random(
4117            do_test_program_usage_count_on_upgrade,
4118            PROGRAM_USAGE_COUNT_RANDOM_ITERATIONS,
4119        );
4120        #[cfg(not(feature = "shuttle-test"))]
4121        do_test_program_usage_count_on_upgrade();
4122    }
4123
4124    fn do_test_program_usage_count_on_upgrade() {
4125        let transaction_accounts = vec![(
4126            sysvar::epoch_schedule::id(),
4127            create_sysvar_account(&EpochSchedule::default()),
4128        )];
4129        with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
4130        let program_id = Pubkey::new_unique();
4131        let env = ProgramRuntimeEnvironment::from(BuiltinProgram::new_mock());
4132        let stats = ProgramStatistics {
4133            uses: 100.into(),
4134            ..Default::default()
4135        };
4136        let program = ProgramCacheEntry {
4137            program: ProgramCacheEntryType::Unloaded(env),
4138            account_owner: ProgramCacheEntryOwner::LoaderV2,
4139            deployment_slot: 0,
4140            stats: stats.into(),
4141            latest_access_slot: AtomicU64::new(0),
4142        };
4143        invoke_context
4144            .program_cache_for_tx_batch
4145            .replenish(program_id, Arc::new(program));
4146        invoke_context
4147            .program_cache_for_tx_batch
4148            .set_slot_for_tests(2);
4149
4150        assert_matches!(
4151            deploy_test_program(&mut invoke_context, program_id,),
4152            Ok(())
4153        );
4154
4155        let updated_program = invoke_context
4156            .program_cache_for_tx_batch
4157            .find(&program_id)
4158            .expect("Didn't find upgraded program in the cache");
4159
4160        assert_eq!(updated_program.deployment_slot, 2);
4161        assert_eq!(updated_program.stats.uses.load(Ordering::Relaxed), 100);
4162    }
4163
4164    #[test]
4165    fn test_program_usage_count_on_non_upgrade() {
4166        #[cfg(feature = "shuttle-test")]
4167        shuttle::check_random(
4168            do_test_program_usage_count_on_non_upgrade,
4169            PROGRAM_USAGE_COUNT_RANDOM_ITERATIONS,
4170        );
4171        #[cfg(not(feature = "shuttle-test"))]
4172        do_test_program_usage_count_on_non_upgrade();
4173    }
4174
4175    fn do_test_program_usage_count_on_non_upgrade() {
4176        let transaction_accounts = vec![(
4177            sysvar::epoch_schedule::id(),
4178            create_sysvar_account(&EpochSchedule::default()),
4179        )];
4180        with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
4181        let program_id = Pubkey::new_unique();
4182        let env = ProgramRuntimeEnvironment::from(BuiltinProgram::new_mock());
4183        let stats = ProgramStatistics {
4184            uses: 100.into(),
4185            ..Default::default()
4186        };
4187        let program = ProgramCacheEntry {
4188            program: ProgramCacheEntryType::Unloaded(env),
4189            account_owner: ProgramCacheEntryOwner::LoaderV2,
4190            deployment_slot: 0,
4191            stats: stats.into(),
4192            latest_access_slot: AtomicU64::new(0),
4193        };
4194        invoke_context
4195            .program_cache_for_tx_batch
4196            .replenish(program_id, Arc::new(program));
4197        invoke_context
4198            .program_cache_for_tx_batch
4199            .set_slot_for_tests(2);
4200
4201        let program_id2 = Pubkey::new_unique();
4202        assert_matches!(
4203            deploy_test_program(&mut invoke_context, program_id2),
4204            Ok(())
4205        );
4206
4207        let program2 = invoke_context
4208            .program_cache_for_tx_batch
4209            .find(&program_id2)
4210            .expect("Didn't find upgraded program in the cache");
4211
4212        assert_eq!(program2.deployment_slot, 2);
4213        assert_eq!(program2.stats.uses.load(Ordering::Relaxed), 0);
4214    }
4215}