2021-10-13 20:46:52 -07:00
|
|
|
use {
|
|
|
|
crate::parse_instruction::{
|
|
|
|
check_num_accounts, ParsableProgram, ParseInstructionError, ParsedInstructionEnum,
|
|
|
|
},
|
|
|
|
bincode::deserialize,
|
|
|
|
serde_json::json,
|
|
|
|
solana_sdk::{
|
|
|
|
instruction::CompiledInstruction, loader_instruction::LoaderInstruction,
|
2022-02-05 04:00:31 -08:00
|
|
|
loader_upgradeable_instruction::UpgradeableLoaderInstruction, message::AccountKeys,
|
2021-10-13 20:46:52 -07:00
|
|
|
},
|
2020-10-19 22:13:02 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
pub fn parse_bpf_loader(
|
|
|
|
instruction: &CompiledInstruction,
|
2022-02-05 04:00:31 -08:00
|
|
|
account_keys: &AccountKeys,
|
2020-10-19 22:13:02 -07:00
|
|
|
) -> Result<ParsedInstructionEnum, ParseInstructionError> {
|
2020-10-20 07:56:36 -07:00
|
|
|
let bpf_loader_instruction: LoaderInstruction = deserialize(&instruction.data)
|
2020-10-20 08:00:41 -07:00
|
|
|
.map_err(|_| ParseInstructionError::InstructionNotParsable(ParsableProgram::BpfLoader))?;
|
2020-10-19 22:13:02 -07:00
|
|
|
if instruction.accounts.is_empty() || instruction.accounts[0] as usize >= account_keys.len() {
|
|
|
|
return Err(ParseInstructionError::InstructionKeyMismatch(
|
|
|
|
ParsableProgram::BpfLoader,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
match bpf_loader_instruction {
|
2022-06-13 17:32:40 -07:00
|
|
|
LoaderInstruction::Write { offset, bytes } => {
|
|
|
|
check_num_bpf_loader_accounts(&instruction.accounts, 1)?;
|
|
|
|
Ok(ParsedInstructionEnum {
|
|
|
|
instruction_type: "write".to_string(),
|
|
|
|
info: json!({
|
|
|
|
"offset": offset,
|
|
|
|
"bytes": base64::encode(bytes),
|
|
|
|
"account": account_keys[instruction.accounts[0] as usize].to_string(),
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
LoaderInstruction::Finalize => {
|
|
|
|
check_num_bpf_loader_accounts(&instruction.accounts, 2)?;
|
|
|
|
Ok(ParsedInstructionEnum {
|
|
|
|
instruction_type: "finalize".to_string(),
|
|
|
|
info: json!({
|
|
|
|
"account": account_keys[instruction.accounts[0] as usize].to_string(),
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
}
|
2020-10-19 22:13:02 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-08 16:18:10 -08:00
|
|
|
pub fn parse_bpf_upgradeable_loader(
|
|
|
|
instruction: &CompiledInstruction,
|
2022-02-05 04:00:31 -08:00
|
|
|
account_keys: &AccountKeys,
|
2021-02-08 16:18:10 -08:00
|
|
|
) -> Result<ParsedInstructionEnum, ParseInstructionError> {
|
|
|
|
let bpf_upgradeable_loader_instruction: UpgradeableLoaderInstruction =
|
|
|
|
deserialize(&instruction.data).map_err(|_| {
|
|
|
|
ParseInstructionError::InstructionNotParsable(ParsableProgram::BpfUpgradeableLoader)
|
|
|
|
})?;
|
|
|
|
match instruction.accounts.iter().max() {
|
|
|
|
Some(index) if (*index as usize) < account_keys.len() => {}
|
|
|
|
_ => {
|
|
|
|
// Runtime should prevent this from ever happening
|
|
|
|
return Err(ParseInstructionError::InstructionKeyMismatch(
|
|
|
|
ParsableProgram::BpfUpgradeableLoader,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
match bpf_upgradeable_loader_instruction {
|
|
|
|
UpgradeableLoaderInstruction::InitializeBuffer => {
|
|
|
|
check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 1)?;
|
|
|
|
let mut value = json!({
|
|
|
|
"account": account_keys[instruction.accounts[0] as usize].to_string(),
|
|
|
|
});
|
|
|
|
let map = value.as_object_mut().unwrap();
|
|
|
|
if instruction.accounts.len() > 1 {
|
|
|
|
map.insert(
|
|
|
|
"authority".to_string(),
|
|
|
|
json!(account_keys[instruction.accounts[1] as usize].to_string()),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
Ok(ParsedInstructionEnum {
|
|
|
|
instruction_type: "initializeBuffer".to_string(),
|
|
|
|
info: value,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
UpgradeableLoaderInstruction::Write { offset, bytes } => {
|
|
|
|
check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 2)?;
|
|
|
|
Ok(ParsedInstructionEnum {
|
|
|
|
instruction_type: "write".to_string(),
|
|
|
|
info: json!({
|
|
|
|
"offset": offset,
|
|
|
|
"bytes": base64::encode(bytes),
|
|
|
|
"account": account_keys[instruction.accounts[0] as usize].to_string(),
|
|
|
|
"authority": account_keys[instruction.accounts[1] as usize].to_string(),
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len } => {
|
|
|
|
check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 8)?;
|
|
|
|
Ok(ParsedInstructionEnum {
|
|
|
|
instruction_type: "deployWithMaxDataLen".to_string(),
|
|
|
|
info: json!({
|
|
|
|
"maxDataLen": max_data_len,
|
|
|
|
"payerAccount": account_keys[instruction.accounts[0] as usize].to_string(),
|
|
|
|
"programDataAccount": account_keys[instruction.accounts[1] as usize].to_string(),
|
|
|
|
"programAccount": account_keys[instruction.accounts[2] as usize].to_string(),
|
|
|
|
"bufferAccount": account_keys[instruction.accounts[3] as usize].to_string(),
|
|
|
|
"rentSysvar": account_keys[instruction.accounts[4] as usize].to_string(),
|
|
|
|
"clockSysvar": account_keys[instruction.accounts[5] as usize].to_string(),
|
|
|
|
"systemProgram": account_keys[instruction.accounts[6] as usize].to_string(),
|
|
|
|
"authority": account_keys[instruction.accounts[7] as usize].to_string(),
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
UpgradeableLoaderInstruction::Upgrade => {
|
|
|
|
check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 7)?;
|
|
|
|
Ok(ParsedInstructionEnum {
|
|
|
|
instruction_type: "upgrade".to_string(),
|
|
|
|
info: json!({
|
|
|
|
"programDataAccount": account_keys[instruction.accounts[0] as usize].to_string(),
|
|
|
|
"programAccount": account_keys[instruction.accounts[1] as usize].to_string(),
|
|
|
|
"bufferAccount": account_keys[instruction.accounts[2] as usize].to_string(),
|
|
|
|
"spillAccount": account_keys[instruction.accounts[3] as usize].to_string(),
|
|
|
|
"rentSysvar": account_keys[instruction.accounts[4] as usize].to_string(),
|
|
|
|
"clockSysvar": account_keys[instruction.accounts[5] as usize].to_string(),
|
|
|
|
"authority": account_keys[instruction.accounts[6] as usize].to_string(),
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
UpgradeableLoaderInstruction::SetAuthority => {
|
|
|
|
check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 2)?;
|
|
|
|
Ok(ParsedInstructionEnum {
|
|
|
|
instruction_type: "setAuthority".to_string(),
|
|
|
|
info: json!({
|
|
|
|
"account": account_keys[instruction.accounts[0] as usize].to_string(),
|
|
|
|
"authority": account_keys[instruction.accounts[1] as usize].to_string(),
|
|
|
|
"newAuthority": if instruction.accounts.len() > 2 {
|
|
|
|
Some(account_keys[instruction.accounts[2] as usize].to_string())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
}
|
2021-03-17 21:39:29 -07:00
|
|
|
UpgradeableLoaderInstruction::Close => {
|
|
|
|
check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 3)?;
|
|
|
|
Ok(ParsedInstructionEnum {
|
|
|
|
instruction_type: "close".to_string(),
|
|
|
|
info: json!({
|
|
|
|
"account": account_keys[instruction.accounts[0] as usize].to_string(),
|
|
|
|
"recipient": account_keys[instruction.accounts[1] as usize].to_string(),
|
2022-08-05 10:37:42 -07:00
|
|
|
"authority": account_keys[instruction.accounts[2] as usize].to_string(),
|
|
|
|
"programAccount": if instruction.accounts.len() > 3 {
|
|
|
|
Some(account_keys[instruction.accounts[3] as usize].to_string())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2021-03-17 21:39:29 -07:00
|
|
|
}),
|
|
|
|
})
|
|
|
|
}
|
2022-09-21 21:03:06 -07:00
|
|
|
UpgradeableLoaderInstruction::ExtendProgram { additional_bytes } => {
|
2022-07-11 14:46:32 -07:00
|
|
|
check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 2)?;
|
|
|
|
Ok(ParsedInstructionEnum {
|
2022-09-21 21:03:06 -07:00
|
|
|
instruction_type: "extendProgram".to_string(),
|
2022-07-11 14:46:32 -07:00
|
|
|
info: json!({
|
|
|
|
"additionalBytes": additional_bytes,
|
|
|
|
"programDataAccount": account_keys[instruction.accounts[0] as usize].to_string(),
|
2022-09-21 21:03:06 -07:00
|
|
|
"programAccount": account_keys[instruction.accounts[1] as usize].to_string(),
|
|
|
|
"systemProgram": if instruction.accounts.len() > 3 {
|
2022-07-11 14:46:32 -07:00
|
|
|
Some(account_keys[instruction.accounts[2] as usize].to_string())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
},
|
2022-09-21 21:03:06 -07:00
|
|
|
"payerAccount": if instruction.accounts.len() > 4 {
|
|
|
|
Some(account_keys[instruction.accounts[3] as usize].to_string())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
},
|
2022-07-11 14:46:32 -07:00
|
|
|
}),
|
|
|
|
})
|
|
|
|
}
|
2021-02-08 16:18:10 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-13 17:32:40 -07:00
|
|
|
fn check_num_bpf_loader_accounts(accounts: &[u8], num: usize) -> Result<(), ParseInstructionError> {
|
|
|
|
check_num_accounts(accounts, num, ParsableProgram::BpfLoader)
|
|
|
|
}
|
|
|
|
|
2021-02-08 16:18:10 -08:00
|
|
|
fn check_num_bpf_upgradeable_loader_accounts(
|
|
|
|
accounts: &[u8],
|
|
|
|
num: usize,
|
|
|
|
) -> Result<(), ParseInstructionError> {
|
|
|
|
check_num_accounts(accounts, num, ParsableProgram::BpfUpgradeableLoader)
|
|
|
|
}
|
|
|
|
|
2020-10-19 22:13:02 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2021-10-13 20:46:52 -07:00
|
|
|
use {
|
|
|
|
super::*,
|
|
|
|
serde_json::Value,
|
2022-02-05 04:00:31 -08:00
|
|
|
solana_sdk::{
|
2022-03-21 05:53:32 -07:00
|
|
|
bpf_loader_upgradeable,
|
2022-02-05 04:00:31 -08:00
|
|
|
message::Message,
|
|
|
|
pubkey::{self, Pubkey},
|
2022-03-21 05:53:32 -07:00
|
|
|
system_program, sysvar,
|
2022-02-05 04:00:31 -08:00
|
|
|
},
|
2021-10-13 20:46:52 -07:00
|
|
|
};
|
2020-10-19 22:13:02 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_parse_bpf_loader_instructions() {
|
2020-10-19 12:23:14 -07:00
|
|
|
let account_pubkey = pubkey::new_rand();
|
|
|
|
let program_id = pubkey::new_rand();
|
2020-10-19 22:13:02 -07:00
|
|
|
let offset = 4242;
|
|
|
|
let bytes = vec![8; 99];
|
2020-10-19 12:23:14 -07:00
|
|
|
let fee_payer = pubkey::new_rand();
|
2020-10-19 22:13:02 -07:00
|
|
|
let account_keys = vec![fee_payer, account_pubkey];
|
|
|
|
let missing_account_keys = vec![account_pubkey];
|
|
|
|
|
|
|
|
let instruction = solana_sdk::loader_instruction::write(
|
|
|
|
&account_pubkey,
|
|
|
|
&program_id,
|
|
|
|
offset,
|
|
|
|
bytes.clone(),
|
|
|
|
);
|
2022-06-13 17:32:40 -07:00
|
|
|
let mut message = Message::new(&[instruction], Some(&fee_payer));
|
2020-10-19 22:13:02 -07:00
|
|
|
assert_eq!(
|
2022-02-05 04:00:31 -08:00
|
|
|
parse_bpf_loader(
|
|
|
|
&message.instructions[0],
|
|
|
|
&AccountKeys::new(&account_keys, None)
|
|
|
|
)
|
|
|
|
.unwrap(),
|
2020-10-19 22:13:02 -07:00
|
|
|
ParsedInstructionEnum {
|
|
|
|
instruction_type: "write".to_string(),
|
|
|
|
info: json!({
|
|
|
|
"offset": offset,
|
|
|
|
"bytes": base64::encode(&bytes),
|
|
|
|
"account": account_pubkey.to_string(),
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
);
|
2022-02-05 04:00:31 -08:00
|
|
|
assert!(parse_bpf_loader(
|
|
|
|
&message.instructions[0],
|
|
|
|
&AccountKeys::new(&missing_account_keys, None)
|
|
|
|
)
|
|
|
|
.is_err());
|
2022-06-13 17:32:40 -07:00
|
|
|
message.instructions[0].accounts.pop();
|
|
|
|
assert!(parse_bpf_loader(
|
|
|
|
&message.instructions[0],
|
|
|
|
&AccountKeys::new(&account_keys, None)
|
|
|
|
)
|
|
|
|
.is_err());
|
2020-10-19 22:13:02 -07:00
|
|
|
|
|
|
|
let instruction = solana_sdk::loader_instruction::finalize(&account_pubkey, &program_id);
|
2022-06-13 17:32:40 -07:00
|
|
|
let mut message = Message::new(&[instruction], Some(&fee_payer));
|
2020-10-19 22:13:02 -07:00
|
|
|
assert_eq!(
|
2022-02-05 04:00:31 -08:00
|
|
|
parse_bpf_loader(
|
|
|
|
&message.instructions[0],
|
|
|
|
&AccountKeys::new(&account_keys, None)
|
|
|
|
)
|
|
|
|
.unwrap(),
|
2020-10-19 22:13:02 -07:00
|
|
|
ParsedInstructionEnum {
|
|
|
|
instruction_type: "finalize".to_string(),
|
|
|
|
info: json!({
|
|
|
|
"account": account_pubkey.to_string(),
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
);
|
2022-02-05 04:00:31 -08:00
|
|
|
assert!(parse_bpf_loader(
|
|
|
|
&message.instructions[0],
|
|
|
|
&AccountKeys::new(&missing_account_keys, None)
|
|
|
|
)
|
|
|
|
.is_err());
|
2022-06-13 17:32:40 -07:00
|
|
|
message.instructions[0].accounts.pop();
|
|
|
|
assert!(parse_bpf_loader(
|
|
|
|
&message.instructions[0],
|
|
|
|
&AccountKeys::new(&account_keys, None)
|
|
|
|
)
|
|
|
|
.is_err());
|
2020-10-19 22:13:02 -07:00
|
|
|
|
|
|
|
let bad_compiled_instruction = CompiledInstruction {
|
|
|
|
program_id_index: 3,
|
|
|
|
accounts: vec![1, 2],
|
|
|
|
data: vec![2, 0, 0, 0], // LoaderInstruction enum only has 2 variants
|
|
|
|
};
|
2022-02-05 04:00:31 -08:00
|
|
|
assert!(parse_bpf_loader(
|
|
|
|
&bad_compiled_instruction,
|
|
|
|
&AccountKeys::new(&account_keys, None)
|
|
|
|
)
|
|
|
|
.is_err());
|
2020-10-19 22:13:02 -07:00
|
|
|
|
|
|
|
let bad_compiled_instruction = CompiledInstruction {
|
|
|
|
program_id_index: 3,
|
|
|
|
accounts: vec![],
|
|
|
|
data: vec![1, 0, 0, 0],
|
|
|
|
};
|
2022-02-05 04:00:31 -08:00
|
|
|
assert!(parse_bpf_loader(
|
|
|
|
&bad_compiled_instruction,
|
|
|
|
&AccountKeys::new(&account_keys, None)
|
|
|
|
)
|
|
|
|
.is_err());
|
2020-10-19 22:13:02 -07:00
|
|
|
}
|
2021-02-08 16:18:10 -08:00
|
|
|
|
|
|
|
#[test]
|
2022-03-21 05:53:32 -07:00
|
|
|
fn test_parse_bpf_upgradeable_loader_create_buffer_ix() {
|
2021-02-08 16:18:10 -08:00
|
|
|
let max_data_len = 54321;
|
|
|
|
|
2022-03-21 05:53:32 -07:00
|
|
|
let payer_address = Pubkey::new_unique();
|
|
|
|
let buffer_address = Pubkey::new_unique();
|
|
|
|
let authority_address = Pubkey::new_unique();
|
|
|
|
let instructions = bpf_loader_upgradeable::create_buffer(
|
|
|
|
&payer_address,
|
|
|
|
&buffer_address,
|
|
|
|
&authority_address,
|
2021-02-08 16:18:10 -08:00
|
|
|
55,
|
|
|
|
max_data_len,
|
|
|
|
)
|
|
|
|
.unwrap();
|
2022-06-13 17:32:40 -07:00
|
|
|
let mut message = Message::new(&instructions, None);
|
2021-02-08 16:18:10 -08:00
|
|
|
assert_eq!(
|
2022-02-05 04:00:31 -08:00
|
|
|
parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[1],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys, None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.unwrap(),
|
2021-02-08 16:18:10 -08:00
|
|
|
ParsedInstructionEnum {
|
|
|
|
instruction_type: "initializeBuffer".to_string(),
|
|
|
|
info: json!({
|
2022-03-21 05:53:32 -07:00
|
|
|
"account": buffer_address.to_string(),
|
|
|
|
"authority": authority_address.to_string(),
|
2021-02-08 16:18:10 -08:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
);
|
2022-02-05 04:00:31 -08:00
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[1],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys[0..2], None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.is_err());
|
2022-06-13 17:32:40 -07:00
|
|
|
let keys = message.account_keys.clone();
|
|
|
|
message.instructions[1].accounts.pop();
|
|
|
|
message.instructions[1].accounts.pop();
|
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[1],
|
|
|
|
&AccountKeys::new(&keys, None)
|
|
|
|
)
|
|
|
|
.is_err());
|
2022-03-21 05:53:32 -07:00
|
|
|
}
|
2021-02-08 16:18:10 -08:00
|
|
|
|
2022-03-21 05:53:32 -07:00
|
|
|
#[test]
|
|
|
|
fn test_parse_bpf_upgradeable_loader_write_ix() {
|
|
|
|
let offset = 4242;
|
|
|
|
let bytes = vec![8; 99];
|
|
|
|
|
|
|
|
let buffer_address = Pubkey::new_unique();
|
|
|
|
let authority_address = Pubkey::new_unique();
|
|
|
|
let instruction = bpf_loader_upgradeable::write(
|
|
|
|
&buffer_address,
|
|
|
|
&authority_address,
|
|
|
|
offset,
|
|
|
|
bytes.clone(),
|
|
|
|
);
|
2022-06-13 17:32:40 -07:00
|
|
|
let mut message = Message::new(&[instruction], None);
|
2021-02-08 16:18:10 -08:00
|
|
|
assert_eq!(
|
2022-02-05 04:00:31 -08:00
|
|
|
parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys, None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.unwrap(),
|
2021-02-08 16:18:10 -08:00
|
|
|
ParsedInstructionEnum {
|
|
|
|
instruction_type: "write".to_string(),
|
|
|
|
info: json!({
|
|
|
|
"offset": offset,
|
|
|
|
"bytes": base64::encode(&bytes),
|
2022-03-21 05:53:32 -07:00
|
|
|
"account": buffer_address.to_string(),
|
|
|
|
"authority": authority_address.to_string(),
|
2021-02-08 16:18:10 -08:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
);
|
2022-02-05 04:00:31 -08:00
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys[0..1], None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.is_err());
|
2022-06-13 17:32:40 -07:00
|
|
|
let keys = message.account_keys.clone();
|
|
|
|
message.instructions[0].accounts.pop();
|
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
|
|
|
&AccountKeys::new(&keys, None)
|
|
|
|
)
|
|
|
|
.is_err());
|
2022-03-21 05:53:32 -07:00
|
|
|
}
|
2021-02-08 16:18:10 -08:00
|
|
|
|
2022-03-21 05:53:32 -07:00
|
|
|
#[test]
|
|
|
|
fn test_parse_bpf_upgradeable_loader_deploy_ix() {
|
|
|
|
let max_data_len = 54321;
|
|
|
|
|
|
|
|
let payer_address = Pubkey::new_unique();
|
|
|
|
let program_address = Pubkey::new_unique();
|
|
|
|
let buffer_address = Pubkey::new_unique();
|
|
|
|
let upgrade_authority_address = Pubkey::new_unique();
|
|
|
|
let programdata_address = Pubkey::find_program_address(
|
|
|
|
&[program_address.as_ref()],
|
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
)
|
|
|
|
.0;
|
|
|
|
let instructions = bpf_loader_upgradeable::deploy_with_max_program_len(
|
|
|
|
&payer_address,
|
|
|
|
&program_address,
|
|
|
|
&buffer_address,
|
|
|
|
&upgrade_authority_address,
|
2021-02-08 16:18:10 -08:00
|
|
|
55,
|
|
|
|
max_data_len,
|
|
|
|
)
|
|
|
|
.unwrap();
|
2022-06-13 17:32:40 -07:00
|
|
|
let mut message = Message::new(&instructions, None);
|
2021-02-08 16:18:10 -08:00
|
|
|
assert_eq!(
|
2022-02-05 04:00:31 -08:00
|
|
|
parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[1],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys, None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.unwrap(),
|
2021-02-08 16:18:10 -08:00
|
|
|
ParsedInstructionEnum {
|
|
|
|
instruction_type: "deployWithMaxDataLen".to_string(),
|
|
|
|
info: json!({
|
|
|
|
"maxDataLen": max_data_len,
|
2022-03-21 05:53:32 -07:00
|
|
|
"payerAccount": payer_address.to_string(),
|
|
|
|
"programAccount": program_address.to_string(),
|
|
|
|
"authority": upgrade_authority_address.to_string(),
|
|
|
|
"programDataAccount": programdata_address.to_string(),
|
|
|
|
"bufferAccount": buffer_address.to_string(),
|
|
|
|
"rentSysvar": sysvar::rent::ID.to_string(),
|
|
|
|
"clockSysvar": sysvar::clock::ID.to_string(),
|
|
|
|
"systemProgram": system_program::ID.to_string(),
|
2021-02-08 16:18:10 -08:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
);
|
2022-02-05 04:00:31 -08:00
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[1],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys[0..7], None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.is_err());
|
2022-06-13 17:32:40 -07:00
|
|
|
let keys = message.account_keys.clone();
|
|
|
|
message.instructions[1].accounts.pop();
|
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[1],
|
|
|
|
&AccountKeys::new(&keys, None)
|
|
|
|
)
|
|
|
|
.is_err());
|
2022-03-21 05:53:32 -07:00
|
|
|
}
|
2021-02-08 16:18:10 -08:00
|
|
|
|
2022-03-21 05:53:32 -07:00
|
|
|
#[test]
|
|
|
|
fn test_parse_bpf_upgradeable_loader_upgrade_ix() {
|
|
|
|
let program_address = Pubkey::new_unique();
|
|
|
|
let buffer_address = Pubkey::new_unique();
|
|
|
|
let authority_address = Pubkey::new_unique();
|
|
|
|
let spill_address = Pubkey::new_unique();
|
|
|
|
let programdata_address = Pubkey::find_program_address(
|
|
|
|
&[program_address.as_ref()],
|
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
)
|
|
|
|
.0;
|
|
|
|
let instruction = bpf_loader_upgradeable::upgrade(
|
|
|
|
&program_address,
|
|
|
|
&buffer_address,
|
|
|
|
&authority_address,
|
|
|
|
&spill_address,
|
|
|
|
);
|
2022-06-13 17:32:40 -07:00
|
|
|
let mut message = Message::new(&[instruction], None);
|
2021-02-08 16:18:10 -08:00
|
|
|
assert_eq!(
|
2022-02-05 04:00:31 -08:00
|
|
|
parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys, None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.unwrap(),
|
2021-02-08 16:18:10 -08:00
|
|
|
ParsedInstructionEnum {
|
|
|
|
instruction_type: "upgrade".to_string(),
|
|
|
|
info: json!({
|
2022-03-21 05:53:32 -07:00
|
|
|
"authority": authority_address.to_string(),
|
|
|
|
"programDataAccount": programdata_address.to_string(),
|
|
|
|
"programAccount": program_address.to_string(),
|
|
|
|
"bufferAccount": buffer_address.to_string(),
|
|
|
|
"spillAccount": spill_address.to_string(),
|
|
|
|
"rentSysvar": sysvar::rent::ID.to_string(),
|
|
|
|
"clockSysvar": sysvar::clock::ID.to_string(),
|
2021-02-08 16:18:10 -08:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
);
|
2022-02-05 04:00:31 -08:00
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys[0..6], None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.is_err());
|
2022-06-13 17:32:40 -07:00
|
|
|
let keys = message.account_keys.clone();
|
|
|
|
message.instructions[0].accounts.pop();
|
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
|
|
|
&AccountKeys::new(&keys, None)
|
|
|
|
)
|
|
|
|
.is_err());
|
2022-03-21 05:53:32 -07:00
|
|
|
}
|
2021-02-08 16:18:10 -08:00
|
|
|
|
2022-03-21 05:53:32 -07:00
|
|
|
#[test]
|
|
|
|
fn test_parse_bpf_upgradeable_loader_set_buffer_authority_ix() {
|
|
|
|
let buffer_address = Pubkey::new_unique();
|
|
|
|
let current_authority_address = Pubkey::new_unique();
|
|
|
|
let new_authority_address = Pubkey::new_unique();
|
|
|
|
let instruction = bpf_loader_upgradeable::set_buffer_authority(
|
|
|
|
&buffer_address,
|
|
|
|
¤t_authority_address,
|
|
|
|
&new_authority_address,
|
|
|
|
);
|
2022-06-13 17:32:40 -07:00
|
|
|
let mut message = Message::new(&[instruction], None);
|
2021-02-08 16:18:10 -08:00
|
|
|
assert_eq!(
|
2022-02-05 04:00:31 -08:00
|
|
|
parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys, None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.unwrap(),
|
2021-02-08 16:18:10 -08:00
|
|
|
ParsedInstructionEnum {
|
|
|
|
instruction_type: "setAuthority".to_string(),
|
|
|
|
info: json!({
|
2022-03-21 05:53:32 -07:00
|
|
|
"account": buffer_address.to_string(),
|
|
|
|
"authority": current_authority_address.to_string(),
|
|
|
|
"newAuthority": new_authority_address.to_string(),
|
2021-02-08 16:18:10 -08:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
);
|
2022-02-05 04:00:31 -08:00
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys[0..1], None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.is_err());
|
2022-06-13 17:32:40 -07:00
|
|
|
let keys = message.account_keys.clone();
|
|
|
|
message.instructions[0].accounts.pop();
|
|
|
|
message.instructions[0].accounts.pop();
|
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
|
|
|
&AccountKeys::new(&keys, None)
|
|
|
|
)
|
|
|
|
.is_err());
|
2022-03-21 05:53:32 -07:00
|
|
|
}
|
2021-02-08 16:18:10 -08:00
|
|
|
|
2022-03-21 05:53:32 -07:00
|
|
|
#[test]
|
|
|
|
fn test_parse_bpf_upgradeable_loader_set_upgrade_authority_ix() {
|
|
|
|
let program_address = Pubkey::new_unique();
|
|
|
|
let current_authority_address = Pubkey::new_unique();
|
|
|
|
let new_authority_address = Pubkey::new_unique();
|
|
|
|
let (programdata_address, _) = Pubkey::find_program_address(
|
|
|
|
&[program_address.as_ref()],
|
|
|
|
&bpf_loader_upgradeable::id(),
|
|
|
|
);
|
|
|
|
let instruction = bpf_loader_upgradeable::set_upgrade_authority(
|
|
|
|
&program_address,
|
|
|
|
¤t_authority_address,
|
|
|
|
Some(&new_authority_address),
|
2021-02-08 16:18:10 -08:00
|
|
|
);
|
2022-06-13 17:32:40 -07:00
|
|
|
let mut message = Message::new(&[instruction], None);
|
2021-02-08 16:18:10 -08:00
|
|
|
assert_eq!(
|
2022-02-05 04:00:31 -08:00
|
|
|
parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys, None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.unwrap(),
|
2021-02-08 16:18:10 -08:00
|
|
|
ParsedInstructionEnum {
|
|
|
|
instruction_type: "setAuthority".to_string(),
|
|
|
|
info: json!({
|
2022-03-21 05:53:32 -07:00
|
|
|
"account": programdata_address.to_string(),
|
|
|
|
"authority": current_authority_address.to_string(),
|
|
|
|
"newAuthority": new_authority_address.to_string(),
|
2021-02-08 16:18:10 -08:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
);
|
2022-02-05 04:00:31 -08:00
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys[0..1], None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.is_err());
|
2022-06-13 17:32:40 -07:00
|
|
|
let keys = message.account_keys.clone();
|
|
|
|
message.instructions[0].accounts.pop();
|
|
|
|
message.instructions[0].accounts.pop();
|
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
|
|
|
&AccountKeys::new(&keys, None)
|
|
|
|
)
|
|
|
|
.is_err());
|
2021-02-08 16:18:10 -08:00
|
|
|
|
2022-03-21 05:53:32 -07:00
|
|
|
let instruction = bpf_loader_upgradeable::set_upgrade_authority(
|
|
|
|
&program_address,
|
|
|
|
¤t_authority_address,
|
|
|
|
None,
|
|
|
|
);
|
2022-06-13 17:32:40 -07:00
|
|
|
let mut message = Message::new(&[instruction], None);
|
2021-02-08 16:18:10 -08:00
|
|
|
assert_eq!(
|
2022-02-05 04:00:31 -08:00
|
|
|
parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys, None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.unwrap(),
|
2021-02-08 16:18:10 -08:00
|
|
|
ParsedInstructionEnum {
|
|
|
|
instruction_type: "setAuthority".to_string(),
|
|
|
|
info: json!({
|
2022-03-21 05:53:32 -07:00
|
|
|
"account": programdata_address.to_string(),
|
|
|
|
"authority": current_authority_address.to_string(),
|
2021-02-08 16:18:10 -08:00
|
|
|
"newAuthority": Value::Null,
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
);
|
2022-02-05 04:00:31 -08:00
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys[0..1], None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.is_err());
|
2022-06-13 17:32:40 -07:00
|
|
|
let keys = message.account_keys.clone();
|
|
|
|
message.instructions[0].accounts.pop();
|
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
|
|
|
&AccountKeys::new(&keys, None)
|
|
|
|
)
|
|
|
|
.is_err());
|
2022-03-21 05:53:32 -07:00
|
|
|
}
|
2021-03-17 21:39:29 -07:00
|
|
|
|
2022-03-21 05:53:32 -07:00
|
|
|
#[test]
|
2022-08-05 10:37:42 -07:00
|
|
|
fn test_parse_bpf_upgradeable_loader_close_buffer_ix() {
|
2022-03-21 05:53:32 -07:00
|
|
|
let close_address = Pubkey::new_unique();
|
|
|
|
let recipient_address = Pubkey::new_unique();
|
|
|
|
let authority_address = Pubkey::new_unique();
|
|
|
|
let instruction =
|
|
|
|
bpf_loader_upgradeable::close(&close_address, &recipient_address, &authority_address);
|
2022-06-13 17:32:40 -07:00
|
|
|
let mut message = Message::new(&[instruction], None);
|
2021-03-17 21:39:29 -07:00
|
|
|
assert_eq!(
|
2022-02-05 04:00:31 -08:00
|
|
|
parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys, None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.unwrap(),
|
2021-03-17 21:39:29 -07:00
|
|
|
ParsedInstructionEnum {
|
|
|
|
instruction_type: "close".to_string(),
|
|
|
|
info: json!({
|
2022-03-21 05:53:32 -07:00
|
|
|
"account": close_address.to_string(),
|
|
|
|
"recipient": recipient_address.to_string(),
|
|
|
|
"authority": authority_address.to_string(),
|
2022-08-05 10:37:42 -07:00
|
|
|
"programAccount": Value::Null
|
2021-03-17 21:39:29 -07:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
);
|
2022-02-05 04:00:31 -08:00
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
2022-03-21 05:53:32 -07:00
|
|
|
&AccountKeys::new(&message.account_keys[0..1], None)
|
2022-02-05 04:00:31 -08:00
|
|
|
)
|
|
|
|
.is_err());
|
2022-06-13 17:32:40 -07:00
|
|
|
let keys = message.account_keys.clone();
|
|
|
|
message.instructions[0].accounts.pop();
|
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
|
|
|
&AccountKeys::new(&keys, None)
|
|
|
|
)
|
|
|
|
.is_err());
|
2021-02-08 16:18:10 -08:00
|
|
|
}
|
2022-08-05 10:37:42 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_parse_bpf_upgradeable_loader_close_program_ix() {
|
|
|
|
let close_address = Pubkey::new_unique();
|
|
|
|
let recipient_address = Pubkey::new_unique();
|
|
|
|
let authority_address = Pubkey::new_unique();
|
|
|
|
let program_address = Pubkey::new_unique();
|
|
|
|
let instruction = bpf_loader_upgradeable::close_any(
|
|
|
|
&close_address,
|
|
|
|
&recipient_address,
|
|
|
|
Some(&authority_address),
|
|
|
|
Some(&program_address),
|
|
|
|
);
|
|
|
|
let mut message = Message::new(&[instruction], None);
|
|
|
|
assert_eq!(
|
|
|
|
parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
|
|
|
&AccountKeys::new(&message.account_keys, None)
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
ParsedInstructionEnum {
|
|
|
|
instruction_type: "close".to_string(),
|
|
|
|
info: json!({
|
|
|
|
"account": close_address.to_string(),
|
|
|
|
"recipient": recipient_address.to_string(),
|
|
|
|
"authority": authority_address.to_string(),
|
|
|
|
"programAccount": program_address.to_string()
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
);
|
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
|
|
|
&AccountKeys::new(&message.account_keys[0..1], None)
|
|
|
|
)
|
|
|
|
.is_err());
|
|
|
|
let keys = message.account_keys.clone();
|
|
|
|
message.instructions[0].accounts.pop();
|
|
|
|
message.instructions[0].accounts.pop();
|
|
|
|
assert!(parse_bpf_upgradeable_loader(
|
|
|
|
&message.instructions[0],
|
|
|
|
&AccountKeys::new(&keys, None)
|
|
|
|
)
|
|
|
|
.is_err());
|
|
|
|
}
|
2020-10-19 22:13:02 -07:00
|
|
|
}
|