Skip to main content

build_program_injection

Function build_program_injection 

Source
pub fn build_program_injection(
    programdata_address: Address,
    elf: &[u8],
    deploy_slot: u64,
    upgrade_authority: Option<Address>,
    lamports: u64,
) -> BTreeMap<Address, AccountData>
Expand description

Build a BPF Loader Upgradeable ProgramData account modification from raw ELF bytes.

Returns a map of {programdata_address: AccountData} ready to pass to Continue::builder().modify_accounts(...).

The ELF is wrapped in the standard ProgramData header format:

[0..4]    variant = 3  (u32 LE, UpgradeableLoaderState::ProgramData)
[4..12]   deploy_slot  (u64 LE)
[12]      upgrade_authority discriminant (0 = None, 1 = Some)
[13..45]  upgrade_authority pubkey bytes (32 bytes, present only when Some)
[45..]    ELF bytecode

deploy_slot should be set to start_slot.saturating_sub(1) so the program appears deployed before the first executed slot. Deploying at start_slot itself triggers the SVM’s same-slot restriction, marking the program unloaded.

lamports must be at least rent-exempt for the resulting account size. With upgrade_authority = None the data length is 13 + elf.len(); with Some(authority) it is 45 + elf.len(). Fetch the exact minimum with rpc.get_minimum_balance_for_rent_exemption(data_len).await?.

§Example

use simulator_client::build_program_injection;
use solana_address::Address;

let program_id: Address = "YourProgramId...".parse().unwrap();
// Compute the programdata PDA using solana_loader_v3_interface::get_program_data_address,
// then convert to Address.
let programdata_addr: Address = "ProgramDataAddr...".parse().unwrap();
let elf = std::fs::read("my_program.so").unwrap();
let deploy_slot = 399_834_991; // start_slot - 1

let mods = build_program_injection(programdata_addr, &elf, deploy_slot, None, 10_000_000_000);
// Pass mods to Continue::builder().modify_accounts(mods).build()