|
|
@@ -1,6 +1,7 @@
|
|
|
use solana_sdk::{
|
|
|
account::{Account, AccountSharedData},
|
|
|
- bpf_loader_upgradeable::UpgradeableLoaderState,
|
|
|
+ bpf_loader,
|
|
|
+ bpf_loader_upgradeable::{self, get_program_data_address, UpgradeableLoaderState},
|
|
|
pubkey::Pubkey,
|
|
|
rent::Rent,
|
|
|
};
|
|
|
@@ -39,48 +40,87 @@ static SPL_PROGRAMS: &[(Pubkey, Pubkey, &[u8])] = &[
|
|
|
),
|
|
|
];
|
|
|
|
|
|
+/// Returns a tuple `(Pubkey, Account)` for a BPF program, where the key is the
|
|
|
+/// provided program ID and the account is a valid BPF Loader program account
|
|
|
+/// containing the ELF.
|
|
|
+fn bpf_loader_program_account(program_id: &Pubkey, elf: &[u8], rent: &Rent) -> (Pubkey, Account) {
|
|
|
+ (
|
|
|
+ *program_id,
|
|
|
+ Account {
|
|
|
+ lamports: rent.minimum_balance(elf.len()).max(1),
|
|
|
+ data: elf.to_vec(),
|
|
|
+ owner: bpf_loader::id(),
|
|
|
+ executable: true,
|
|
|
+ rent_epoch: 0,
|
|
|
+ },
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+/// Returns two tuples `(Pubkey, Account)` for a BPF upgradeable program.
|
|
|
+/// The first tuple is the program account. It contains the provided program ID
|
|
|
+/// and an account with a pointer to its program data account.
|
|
|
+/// The second tuple is the program data account. It contains the program data
|
|
|
+/// address and an account with the program data - a valid BPF Loader Upgradeable
|
|
|
+/// program data account containing the ELF.
|
|
|
+pub(crate) fn bpf_loader_upgradeable_program_accounts(
|
|
|
+ program_id: &Pubkey,
|
|
|
+ elf: &[u8],
|
|
|
+ rent: &Rent,
|
|
|
+) -> [(Pubkey, Account); 2] {
|
|
|
+ let programdata_address = get_program_data_address(program_id);
|
|
|
+ let program_account = {
|
|
|
+ let space = UpgradeableLoaderState::size_of_program();
|
|
|
+ let lamports = rent.minimum_balance(space);
|
|
|
+ let data = bincode::serialize(&UpgradeableLoaderState::Program {
|
|
|
+ programdata_address,
|
|
|
+ })
|
|
|
+ .unwrap();
|
|
|
+ Account {
|
|
|
+ lamports,
|
|
|
+ data,
|
|
|
+ owner: bpf_loader_upgradeable::id(),
|
|
|
+ executable: true,
|
|
|
+ rent_epoch: 0,
|
|
|
+ }
|
|
|
+ };
|
|
|
+ let programdata_account = {
|
|
|
+ let space = UpgradeableLoaderState::size_of_programdata_metadata() + elf.len();
|
|
|
+ let lamports = rent.minimum_balance(space);
|
|
|
+ let mut data = bincode::serialize(&UpgradeableLoaderState::ProgramData {
|
|
|
+ slot: 0,
|
|
|
+ upgrade_authority_address: Some(Pubkey::default()),
|
|
|
+ })
|
|
|
+ .unwrap();
|
|
|
+ data.extend_from_slice(elf);
|
|
|
+ Account {
|
|
|
+ lamports,
|
|
|
+ data,
|
|
|
+ owner: bpf_loader_upgradeable::id(),
|
|
|
+ executable: false,
|
|
|
+ rent_epoch: 0,
|
|
|
+ }
|
|
|
+ };
|
|
|
+ [
|
|
|
+ (*program_id, program_account),
|
|
|
+ (programdata_address, programdata_account),
|
|
|
+ ]
|
|
|
+}
|
|
|
+
|
|
|
pub fn spl_programs(rent: &Rent) -> Vec<(Pubkey, AccountSharedData)> {
|
|
|
SPL_PROGRAMS
|
|
|
.iter()
|
|
|
.flat_map(|(program_id, loader_id, elf)| {
|
|
|
let mut accounts = vec![];
|
|
|
- let data = if *loader_id == solana_sdk::bpf_loader_upgradeable::ID {
|
|
|
- let (programdata_address, _) =
|
|
|
- Pubkey::find_program_address(&[program_id.as_ref()], loader_id);
|
|
|
- let mut program_data = bincode::serialize(&UpgradeableLoaderState::ProgramData {
|
|
|
- slot: 0,
|
|
|
- upgrade_authority_address: Some(Pubkey::default()),
|
|
|
- })
|
|
|
- .unwrap();
|
|
|
- program_data.extend_from_slice(elf);
|
|
|
- accounts.push((
|
|
|
- programdata_address,
|
|
|
- AccountSharedData::from(Account {
|
|
|
- lamports: rent.minimum_balance(program_data.len()).max(1),
|
|
|
- data: program_data,
|
|
|
- owner: *loader_id,
|
|
|
- executable: false,
|
|
|
- rent_epoch: 0,
|
|
|
- }),
|
|
|
- ));
|
|
|
- bincode::serialize(&UpgradeableLoaderState::Program {
|
|
|
- programdata_address,
|
|
|
- })
|
|
|
- .unwrap()
|
|
|
+ if loader_id.eq(&solana_sdk::bpf_loader_upgradeable::ID) {
|
|
|
+ for (key, account) in bpf_loader_upgradeable_program_accounts(program_id, elf, rent)
|
|
|
+ {
|
|
|
+ accounts.push((key, AccountSharedData::from(account)));
|
|
|
+ }
|
|
|
} else {
|
|
|
- elf.to_vec()
|
|
|
- };
|
|
|
- accounts.push((
|
|
|
- *program_id,
|
|
|
- AccountSharedData::from(Account {
|
|
|
- lamports: rent.minimum_balance(data.len()).max(1),
|
|
|
- data,
|
|
|
- owner: *loader_id,
|
|
|
- executable: true,
|
|
|
- rent_epoch: 0,
|
|
|
- }),
|
|
|
- ));
|
|
|
- accounts.into_iter()
|
|
|
+ let (key, account) = bpf_loader_program_account(program_id, elf, rent);
|
|
|
+ accounts.push((key, AccountSharedData::from(account)));
|
|
|
+ }
|
|
|
+ accounts
|
|
|
})
|
|
|
.collect()
|
|
|
}
|