2021-12-03 09:00:31 -08:00
|
|
|
use {
|
2023-01-14 04:02:10 -08:00
|
|
|
crate::{bank::Bank, bank_client::BankClient},
|
2021-12-03 09:00:31 -08:00
|
|
|
serde::Serialize,
|
|
|
|
solana_sdk::{
|
2023-01-14 04:02:10 -08:00
|
|
|
account::{AccountSharedData, WritableAccount},
|
2021-12-03 09:00:31 -08:00
|
|
|
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
|
2023-01-13 11:38:36 -08:00
|
|
|
client::{Client, SyncClient},
|
|
|
|
clock::Clock,
|
2021-12-03 09:00:31 -08:00
|
|
|
instruction::{AccountMeta, Instruction},
|
|
|
|
loader_instruction,
|
|
|
|
message::Message,
|
|
|
|
pubkey::Pubkey,
|
|
|
|
signature::{Keypair, Signer},
|
|
|
|
system_instruction,
|
|
|
|
},
|
2023-01-13 11:38:36 -08:00
|
|
|
std::{env, fs::File, io::Read, path::PathBuf},
|
2020-01-28 17:03:20 -08:00
|
|
|
};
|
2019-03-02 20:03:36 -08:00
|
|
|
|
2022-03-14 18:41:03 -07:00
|
|
|
const CHUNK_SIZE: usize = 512; // Size of chunk just needs to fit into tx
|
|
|
|
|
2023-01-13 11:38:36 -08:00
|
|
|
pub fn load_program_from_file(name: &str) -> Vec<u8> {
|
|
|
|
let mut pathbuf = {
|
|
|
|
let current_exe = env::current_exe().unwrap();
|
|
|
|
PathBuf::from(current_exe.parent().unwrap().parent().unwrap())
|
|
|
|
};
|
|
|
|
pathbuf.push("sbf/");
|
|
|
|
pathbuf.push(name);
|
|
|
|
pathbuf.set_extension("so");
|
|
|
|
let mut file = File::open(&pathbuf).unwrap_or_else(|err| {
|
|
|
|
panic!("Failed to open {}: {}", pathbuf.display(), err);
|
|
|
|
});
|
|
|
|
let mut program = Vec::new();
|
|
|
|
file.read_to_end(&mut program).unwrap();
|
|
|
|
program
|
|
|
|
}
|
2019-03-02 20:03:36 -08:00
|
|
|
|
2023-01-14 04:02:10 -08:00
|
|
|
// Creates an unverified program by bypassing the loader built-in program
|
|
|
|
pub fn create_program(bank: &Bank, loader_id: &Pubkey, name: &str) -> Pubkey {
|
|
|
|
let program_id = Pubkey::new_unique();
|
|
|
|
let elf = load_program_from_file(name);
|
|
|
|
let mut program_account = AccountSharedData::new(1, elf.len(), loader_id);
|
|
|
|
program_account
|
|
|
|
.data_as_mut_slice()
|
|
|
|
.get_mut(..)
|
|
|
|
.unwrap()
|
|
|
|
.copy_from_slice(&elf);
|
|
|
|
program_account.set_executable(true);
|
|
|
|
bank.store_account(&program_id, &program_account);
|
|
|
|
program_id
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn load_and_finalize_program<T: Client>(
|
2023-01-13 11:38:36 -08:00
|
|
|
bank_client: &T,
|
|
|
|
loader_id: &Pubkey,
|
|
|
|
program_keypair: Option<Keypair>,
|
|
|
|
payer_keypair: &Keypair,
|
|
|
|
name: &str,
|
|
|
|
) -> (Keypair, Instruction) {
|
|
|
|
let program = load_program_from_file(name);
|
|
|
|
let program_keypair = program_keypair.unwrap_or_else(|| {
|
|
|
|
let program_keypair = Keypair::new();
|
|
|
|
let instruction = system_instruction::create_account(
|
|
|
|
&payer_keypair.pubkey(),
|
|
|
|
&program_keypair.pubkey(),
|
|
|
|
1.max(
|
|
|
|
bank_client
|
|
|
|
.get_minimum_balance_for_rent_exemption(program.len())
|
|
|
|
.unwrap(),
|
|
|
|
),
|
|
|
|
program.len() as u64,
|
|
|
|
loader_id,
|
|
|
|
);
|
|
|
|
let message = Message::new(&[instruction], Some(&payer_keypair.pubkey()));
|
|
|
|
bank_client
|
|
|
|
.send_and_confirm_message(&[payer_keypair, &program_keypair], message)
|
|
|
|
.unwrap();
|
|
|
|
program_keypair
|
|
|
|
});
|
2022-03-14 18:41:03 -07:00
|
|
|
let chunk_size = CHUNK_SIZE;
|
2019-03-02 20:03:36 -08:00
|
|
|
let mut offset = 0;
|
|
|
|
for chunk in program.chunks(chunk_size) {
|
2019-03-21 07:14:14 -07:00
|
|
|
let instruction =
|
2023-01-13 11:38:36 -08:00
|
|
|
loader_instruction::write(&program_keypair.pubkey(), loader_id, offset, chunk.to_vec());
|
|
|
|
let message = Message::new(&[instruction], Some(&payer_keypair.pubkey()));
|
2019-03-27 06:34:01 -07:00
|
|
|
bank_client
|
2023-01-13 11:38:36 -08:00
|
|
|
.send_and_confirm_message(&[payer_keypair, &program_keypair], message)
|
2019-03-27 06:34:01 -07:00
|
|
|
.unwrap();
|
2019-03-02 20:03:36 -08:00
|
|
|
offset += chunk_size as u32;
|
|
|
|
}
|
2023-01-13 11:38:36 -08:00
|
|
|
let instruction = loader_instruction::finalize(&program_keypair.pubkey(), loader_id);
|
|
|
|
(program_keypair, instruction)
|
|
|
|
}
|
2019-03-02 20:03:36 -08:00
|
|
|
|
2023-01-14 04:02:10 -08:00
|
|
|
pub fn load_program<T: Client>(
|
2023-01-13 11:38:36 -08:00
|
|
|
bank_client: &T,
|
|
|
|
loader_id: &Pubkey,
|
|
|
|
payer_keypair: &Keypair,
|
|
|
|
name: &str,
|
|
|
|
) -> Pubkey {
|
|
|
|
let (program_keypair, instruction) =
|
2023-01-14 04:02:10 -08:00
|
|
|
load_and_finalize_program(bank_client, loader_id, None, payer_keypair, name);
|
2023-01-13 11:38:36 -08:00
|
|
|
let message = Message::new(&[instruction], Some(&payer_keypair.pubkey()));
|
2019-03-27 06:34:01 -07:00
|
|
|
bank_client
|
2023-01-13 11:38:36 -08:00
|
|
|
.send_and_confirm_message(&[payer_keypair, &program_keypair], message)
|
2019-03-27 06:34:01 -07:00
|
|
|
.unwrap();
|
2023-01-13 11:38:36 -08:00
|
|
|
program_keypair.pubkey()
|
2019-03-21 07:14:14 -07:00
|
|
|
}
|
2019-03-02 20:03:36 -08:00
|
|
|
|
2023-01-13 11:38:36 -08:00
|
|
|
pub fn load_upgradeable_buffer<T: Client>(
|
2020-12-14 15:35:10 -08:00
|
|
|
bank_client: &T,
|
|
|
|
from_keypair: &Keypair,
|
2021-01-19 16:24:44 -08:00
|
|
|
buffer_keypair: &Keypair,
|
2021-01-29 12:43:42 -08:00
|
|
|
buffer_authority_keypair: &Keypair,
|
2023-01-13 11:38:36 -08:00
|
|
|
name: &str,
|
|
|
|
) -> Vec<u8> {
|
|
|
|
let program = load_program_from_file(name);
|
2020-12-14 15:35:10 -08:00
|
|
|
let buffer_pubkey = buffer_keypair.pubkey();
|
2021-01-29 12:43:42 -08:00
|
|
|
let buffer_authority_pubkey = buffer_authority_keypair.pubkey();
|
2020-12-14 15:35:10 -08:00
|
|
|
|
|
|
|
bank_client
|
|
|
|
.send_and_confirm_message(
|
2021-06-18 06:34:46 -07:00
|
|
|
&[from_keypair, buffer_keypair],
|
2020-12-14 15:35:10 -08:00
|
|
|
Message::new(
|
|
|
|
&bpf_loader_upgradeable::create_buffer(
|
|
|
|
&from_keypair.pubkey(),
|
|
|
|
&buffer_pubkey,
|
2021-01-29 12:43:42 -08:00
|
|
|
&buffer_authority_pubkey,
|
2020-12-14 15:35:10 -08:00
|
|
|
1.max(
|
|
|
|
bank_client
|
|
|
|
.get_minimum_balance_for_rent_exemption(program.len())
|
|
|
|
.unwrap(),
|
|
|
|
),
|
|
|
|
program.len(),
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
Some(&from_keypair.pubkey()),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2022-03-14 18:41:03 -07:00
|
|
|
let chunk_size = CHUNK_SIZE;
|
2020-12-14 15:35:10 -08:00
|
|
|
let mut offset = 0;
|
|
|
|
for chunk in program.chunks(chunk_size) {
|
|
|
|
let message = Message::new(
|
|
|
|
&[bpf_loader_upgradeable::write(
|
|
|
|
&buffer_pubkey,
|
2021-01-29 12:43:42 -08:00
|
|
|
&buffer_authority_pubkey,
|
2020-12-14 15:35:10 -08:00
|
|
|
offset,
|
|
|
|
chunk.to_vec(),
|
|
|
|
)],
|
|
|
|
Some(&from_keypair.pubkey()),
|
|
|
|
);
|
|
|
|
bank_client
|
2021-06-18 06:34:46 -07:00
|
|
|
.send_and_confirm_message(&[from_keypair, buffer_authority_keypair], message)
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap();
|
|
|
|
offset += chunk_size as u32;
|
|
|
|
}
|
2023-01-13 11:38:36 -08:00
|
|
|
|
|
|
|
program
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
|
|
|
|
2023-01-13 11:38:36 -08:00
|
|
|
pub fn load_upgradeable_program(
|
|
|
|
bank_client: &BankClient,
|
2020-12-14 15:35:10 -08:00
|
|
|
from_keypair: &Keypair,
|
2021-01-19 16:24:44 -08:00
|
|
|
buffer_keypair: &Keypair,
|
|
|
|
executable_keypair: &Keypair,
|
|
|
|
authority_keypair: &Keypair,
|
2023-01-13 11:38:36 -08:00
|
|
|
name: &str,
|
2021-01-19 16:24:44 -08:00
|
|
|
) {
|
2023-01-13 11:38:36 -08:00
|
|
|
let program = load_upgradeable_buffer(
|
2021-01-29 12:43:42 -08:00
|
|
|
bank_client,
|
2021-06-18 06:34:46 -07:00
|
|
|
from_keypair,
|
2021-01-29 12:43:42 -08:00
|
|
|
buffer_keypair,
|
|
|
|
authority_keypair,
|
2023-01-13 11:38:36 -08:00
|
|
|
name,
|
2021-01-29 12:43:42 -08:00
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
|
|
|
|
let message = Message::new(
|
|
|
|
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
|
|
|
&from_keypair.pubkey(),
|
2023-01-17 00:44:27 -08:00
|
|
|
&executable_keypair.pubkey(),
|
2021-01-19 16:24:44 -08:00
|
|
|
&buffer_keypair.pubkey(),
|
2023-01-17 00:44:27 -08:00
|
|
|
&authority_keypair.pubkey(),
|
2020-12-14 15:35:10 -08:00
|
|
|
1.max(
|
|
|
|
bank_client
|
|
|
|
.get_minimum_balance_for_rent_exemption(
|
2022-05-11 07:22:59 -07:00
|
|
|
UpgradeableLoaderState::size_of_program(),
|
2020-12-14 15:35:10 -08:00
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
),
|
|
|
|
program.len() * 2,
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
Some(&from_keypair.pubkey()),
|
|
|
|
);
|
|
|
|
bank_client
|
2021-01-29 12:43:42 -08:00
|
|
|
.send_and_confirm_message(
|
2021-06-18 06:34:46 -07:00
|
|
|
&[from_keypair, executable_keypair, authority_keypair],
|
2021-01-29 12:43:42 -08:00
|
|
|
message,
|
|
|
|
)
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap();
|
2023-01-13 11:38:36 -08:00
|
|
|
bank_client.set_sysvar_for_tests(&Clock {
|
|
|
|
slot: 1,
|
|
|
|
..Clock::default()
|
|
|
|
});
|
2020-12-14 15:35:10 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn upgrade_program<T: Client>(
|
|
|
|
bank_client: &T,
|
2023-01-13 11:38:36 -08:00
|
|
|
payer_keypair: &Keypair,
|
|
|
|
buffer_keypair: &Keypair,
|
|
|
|
executable_pubkey: &Pubkey,
|
2020-12-14 15:35:10 -08:00
|
|
|
authority_keypair: &Keypair,
|
2023-01-13 11:38:36 -08:00
|
|
|
name: &str,
|
2020-12-14 15:35:10 -08:00
|
|
|
) {
|
2023-01-13 11:38:36 -08:00
|
|
|
load_upgradeable_buffer(
|
|
|
|
bank_client,
|
|
|
|
payer_keypair,
|
|
|
|
buffer_keypair,
|
|
|
|
authority_keypair,
|
|
|
|
name,
|
|
|
|
);
|
2020-12-14 15:35:10 -08:00
|
|
|
let message = Message::new(
|
|
|
|
&[bpf_loader_upgradeable::upgrade(
|
2023-01-13 11:38:36 -08:00
|
|
|
executable_pubkey,
|
|
|
|
&buffer_keypair.pubkey(),
|
2020-12-14 15:35:10 -08:00
|
|
|
&authority_keypair.pubkey(),
|
2023-01-13 11:38:36 -08:00
|
|
|
&payer_keypair.pubkey(),
|
2020-12-14 15:35:10 -08:00
|
|
|
)],
|
2023-01-13 11:38:36 -08:00
|
|
|
Some(&payer_keypair.pubkey()),
|
2020-12-14 15:35:10 -08:00
|
|
|
);
|
|
|
|
bank_client
|
2023-01-13 11:38:36 -08:00
|
|
|
.send_and_confirm_message(&[payer_keypair, authority_keypair], message)
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_upgrade_authority<T: Client>(
|
|
|
|
bank_client: &T,
|
|
|
|
from_keypair: &Keypair,
|
|
|
|
program_pubkey: &Pubkey,
|
|
|
|
current_authority_keypair: &Keypair,
|
|
|
|
new_authority_pubkey: Option<&Pubkey>,
|
|
|
|
) {
|
|
|
|
let message = Message::new(
|
2021-01-08 09:37:57 -08:00
|
|
|
&[bpf_loader_upgradeable::set_upgrade_authority(
|
2020-12-14 15:35:10 -08:00
|
|
|
program_pubkey,
|
|
|
|
¤t_authority_keypair.pubkey(),
|
|
|
|
new_authority_pubkey,
|
|
|
|
)],
|
|
|
|
Some(&from_keypair.pubkey()),
|
|
|
|
);
|
|
|
|
bank_client
|
2021-06-18 06:34:46 -07:00
|
|
|
.send_and_confirm_message(&[from_keypair, current_authority_keypair], message)
|
2020-12-14 15:35:10 -08:00
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
2019-10-25 16:22:41 -07:00
|
|
|
// Return an Instruction that invokes `program_id` with `data` and required
|
|
|
|
// a signature from `from_pubkey`.
|
|
|
|
pub fn create_invoke_instruction<T: Serialize>(
|
|
|
|
from_pubkey: Pubkey,
|
|
|
|
program_id: Pubkey,
|
|
|
|
data: &T,
|
|
|
|
) -> Instruction {
|
|
|
|
let account_metas = vec![AccountMeta::new(from_pubkey, true)];
|
2021-03-03 21:46:48 -08:00
|
|
|
Instruction::new_with_bincode(program_id, data, account_metas)
|
2019-03-02 20:03:36 -08:00
|
|
|
}
|