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