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