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