Skip to main content

solana_bpf_loader_program/
lib.rs

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