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