Parse upgradeable loader instructions and accounts (#15195)
* Parse upgradeable-loader instructions * Parse upgradeable-loader accounts
This commit is contained in:
parent
c51e49a746
commit
c0a6272afd
|
@ -4,6 +4,7 @@ extern crate lazy_static;
|
|||
extern crate serde_derive;
|
||||
|
||||
pub mod parse_account_data;
|
||||
pub mod parse_bpf_loader;
|
||||
pub mod parse_config;
|
||||
pub mod parse_nonce;
|
||||
pub mod parse_stake;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::{
|
||||
parse_bpf_loader::parse_bpf_upgradeable_loader,
|
||||
parse_config::parse_config,
|
||||
parse_nonce::parse_nonce,
|
||||
parse_stake::parse_stake,
|
||||
|
@ -13,6 +14,7 @@ use std::collections::HashMap;
|
|||
use thiserror::Error;
|
||||
|
||||
lazy_static! {
|
||||
static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id();
|
||||
static ref CONFIG_PROGRAM_ID: Pubkey = solana_config_program::id();
|
||||
static ref STAKE_PROGRAM_ID: Pubkey = solana_stake_program::id();
|
||||
static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id();
|
||||
|
@ -21,6 +23,10 @@ lazy_static! {
|
|||
static ref VOTE_PROGRAM_ID: Pubkey = solana_vote_program::id();
|
||||
pub static ref PARSABLE_PROGRAM_IDS: HashMap<Pubkey, ParsableAccount> = {
|
||||
let mut m = HashMap::new();
|
||||
m.insert(
|
||||
*BPF_UPGRADEABLE_LOADER_PROGRAM_ID,
|
||||
ParsableAccount::BpfUpgradeableLoader,
|
||||
);
|
||||
m.insert(*CONFIG_PROGRAM_ID, ParsableAccount::Config);
|
||||
m.insert(*SYSTEM_PROGRAM_ID, ParsableAccount::Nonce);
|
||||
m.insert(*TOKEN_PROGRAM_ID, ParsableAccount::SplToken);
|
||||
|
@ -60,6 +66,7 @@ pub struct ParsedAccount {
|
|||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum ParsableAccount {
|
||||
BpfUpgradeableLoader,
|
||||
Config,
|
||||
Nonce,
|
||||
SplToken,
|
||||
|
@ -84,6 +91,9 @@ pub fn parse_account_data(
|
|||
.ok_or(ParseAccountError::ProgramNotParsable)?;
|
||||
let additional_data = additional_data.unwrap_or_default();
|
||||
let parsed_json = match program_name {
|
||||
ParsableAccount::BpfUpgradeableLoader => {
|
||||
serde_json::to_value(parse_bpf_upgradeable_loader(data)?)?
|
||||
}
|
||||
ParsableAccount::Config => serde_json::to_value(parse_config(data, pubkey)?)?,
|
||||
ParsableAccount::Nonce => serde_json::to_value(parse_nonce(data)?)?,
|
||||
ParsableAccount::SplToken => {
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
use crate::{
|
||||
parse_account_data::{ParsableAccount, ParseAccountError},
|
||||
UiAccountData, UiAccountEncoding,
|
||||
};
|
||||
use bincode::{deserialize, serialized_size};
|
||||
use solana_sdk::{bpf_loader_upgradeable::UpgradeableLoaderState, pubkey::Pubkey};
|
||||
|
||||
pub fn parse_bpf_upgradeable_loader(
|
||||
data: &[u8],
|
||||
) -> Result<BpfUpgradeableLoaderAccountType, ParseAccountError> {
|
||||
let account_state: UpgradeableLoaderState = deserialize(data).map_err(|_| {
|
||||
ParseAccountError::AccountNotParsable(ParsableAccount::BpfUpgradeableLoader)
|
||||
})?;
|
||||
let parsed_account = match account_state {
|
||||
UpgradeableLoaderState::Uninitialized => BpfUpgradeableLoaderAccountType::Uninitialized,
|
||||
UpgradeableLoaderState::Buffer { authority_address } => {
|
||||
let offset = if authority_address.is_some() {
|
||||
UpgradeableLoaderState::buffer_data_offset().unwrap()
|
||||
} else {
|
||||
// This case included for code completeness; in practice, a Buffer account will
|
||||
// always have authority_address.is_some()
|
||||
UpgradeableLoaderState::buffer_data_offset().unwrap()
|
||||
- serialized_size(&Pubkey::default()).unwrap() as usize
|
||||
};
|
||||
BpfUpgradeableLoaderAccountType::Buffer(UiBuffer {
|
||||
authority: authority_address.map(|pubkey| pubkey.to_string()),
|
||||
data: UiAccountData::Binary(
|
||||
base64::encode(&data[offset as usize..]),
|
||||
UiAccountEncoding::Base64,
|
||||
),
|
||||
})
|
||||
}
|
||||
UpgradeableLoaderState::Program {
|
||||
programdata_address,
|
||||
} => BpfUpgradeableLoaderAccountType::Program(UiProgram {
|
||||
program_data: programdata_address.to_string(),
|
||||
}),
|
||||
UpgradeableLoaderState::ProgramData {
|
||||
slot,
|
||||
upgrade_authority_address,
|
||||
} => {
|
||||
let offset = if upgrade_authority_address.is_some() {
|
||||
UpgradeableLoaderState::programdata_data_offset().unwrap()
|
||||
} else {
|
||||
UpgradeableLoaderState::programdata_data_offset().unwrap()
|
||||
- serialized_size(&Pubkey::default()).unwrap() as usize
|
||||
};
|
||||
BpfUpgradeableLoaderAccountType::ProgramData(UiProgramData {
|
||||
slot,
|
||||
authority: upgrade_authority_address.map(|pubkey| pubkey.to_string()),
|
||||
data: UiAccountData::Binary(
|
||||
base64::encode(&data[offset as usize..]),
|
||||
UiAccountEncoding::Base64,
|
||||
),
|
||||
})
|
||||
}
|
||||
};
|
||||
Ok(parsed_account)
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase", tag = "type", content = "info")]
|
||||
pub enum BpfUpgradeableLoaderAccountType {
|
||||
Uninitialized,
|
||||
Buffer(UiBuffer),
|
||||
Program(UiProgram),
|
||||
ProgramData(UiProgramData),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UiBuffer {
|
||||
pub authority: Option<String>,
|
||||
pub data: UiAccountData,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UiProgram {
|
||||
pub program_data: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UiProgramData {
|
||||
pub slot: u64,
|
||||
pub authority: Option<String>,
|
||||
pub data: UiAccountData,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use bincode::serialize;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
|
||||
#[test]
|
||||
fn test_parse_bpf_upgradeable_loader_accounts() {
|
||||
let bpf_loader_state = UpgradeableLoaderState::Uninitialized;
|
||||
let account_data = serialize(&bpf_loader_state).unwrap();
|
||||
assert_eq!(
|
||||
parse_bpf_upgradeable_loader(&account_data).unwrap(),
|
||||
BpfUpgradeableLoaderAccountType::Uninitialized
|
||||
);
|
||||
|
||||
let program = vec![7u8; 64]; // Arbitrary program data
|
||||
|
||||
let authority = Pubkey::new_unique();
|
||||
let bpf_loader_state = UpgradeableLoaderState::Buffer {
|
||||
authority_address: Some(authority),
|
||||
};
|
||||
let mut account_data = serialize(&bpf_loader_state).unwrap();
|
||||
account_data.extend_from_slice(&program);
|
||||
assert_eq!(
|
||||
parse_bpf_upgradeable_loader(&account_data).unwrap(),
|
||||
BpfUpgradeableLoaderAccountType::Buffer(UiBuffer {
|
||||
authority: Some(authority.to_string()),
|
||||
data: UiAccountData::Binary(base64::encode(&program), UiAccountEncoding::Base64),
|
||||
})
|
||||
);
|
||||
|
||||
// This case included for code completeness; in practice, a Buffer account will always have
|
||||
// authority_address.is_some()
|
||||
let bpf_loader_state = UpgradeableLoaderState::Buffer {
|
||||
authority_address: None,
|
||||
};
|
||||
let mut account_data = serialize(&bpf_loader_state).unwrap();
|
||||
account_data.extend_from_slice(&program);
|
||||
assert_eq!(
|
||||
parse_bpf_upgradeable_loader(&account_data).unwrap(),
|
||||
BpfUpgradeableLoaderAccountType::Buffer(UiBuffer {
|
||||
authority: None,
|
||||
data: UiAccountData::Binary(base64::encode(&program), UiAccountEncoding::Base64),
|
||||
})
|
||||
);
|
||||
|
||||
let programdata_address = Pubkey::new_unique();
|
||||
let bpf_loader_state = UpgradeableLoaderState::Program {
|
||||
programdata_address,
|
||||
};
|
||||
let account_data = serialize(&bpf_loader_state).unwrap();
|
||||
assert_eq!(
|
||||
parse_bpf_upgradeable_loader(&account_data).unwrap(),
|
||||
BpfUpgradeableLoaderAccountType::Program(UiProgram {
|
||||
program_data: programdata_address.to_string(),
|
||||
})
|
||||
);
|
||||
|
||||
let authority = Pubkey::new_unique();
|
||||
let slot = 42;
|
||||
let bpf_loader_state = UpgradeableLoaderState::ProgramData {
|
||||
slot,
|
||||
upgrade_authority_address: Some(authority),
|
||||
};
|
||||
let mut account_data = serialize(&bpf_loader_state).unwrap();
|
||||
account_data.extend_from_slice(&program);
|
||||
assert_eq!(
|
||||
parse_bpf_upgradeable_loader(&account_data).unwrap(),
|
||||
BpfUpgradeableLoaderAccountType::ProgramData(UiProgramData {
|
||||
slot,
|
||||
authority: Some(authority.to_string()),
|
||||
data: UiAccountData::Binary(base64::encode(&program), UiAccountEncoding::Base64),
|
||||
})
|
||||
);
|
||||
|
||||
let bpf_loader_state = UpgradeableLoaderState::ProgramData {
|
||||
slot,
|
||||
upgrade_authority_address: None,
|
||||
};
|
||||
let mut account_data = serialize(&bpf_loader_state).unwrap();
|
||||
account_data.extend_from_slice(&program);
|
||||
assert_eq!(
|
||||
parse_bpf_upgradeable_loader(&account_data).unwrap(),
|
||||
BpfUpgradeableLoaderAccountType::ProgramData(UiProgramData {
|
||||
slot,
|
||||
authority: None,
|
||||
data: UiAccountData::Binary(base64::encode(&program), UiAccountEncoding::Base64),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
use crate::parse_instruction::{ParsableProgram, ParseInstructionError, ParsedInstructionEnum};
|
||||
use crate::parse_instruction::{
|
||||
check_num_accounts, ParsableProgram, ParseInstructionError, ParsedInstructionEnum,
|
||||
};
|
||||
use bincode::deserialize;
|
||||
use serde_json::json;
|
||||
use solana_sdk::{
|
||||
instruction::CompiledInstruction, loader_instruction::LoaderInstruction, pubkey::Pubkey,
|
||||
instruction::CompiledInstruction, loader_instruction::LoaderInstruction,
|
||||
loader_upgradeable_instruction::UpgradeableLoaderInstruction, pubkey::Pubkey,
|
||||
};
|
||||
|
||||
pub fn parse_bpf_loader(
|
||||
|
@ -34,9 +37,114 @@ pub fn parse_bpf_loader(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_bpf_upgradeable_loader(
|
||||
instruction: &CompiledInstruction,
|
||||
account_keys: &[Pubkey],
|
||||
) -> 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
|
||||
},
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_num_bpf_upgradeable_loader_accounts(
|
||||
accounts: &[u8],
|
||||
num: usize,
|
||||
) -> Result<(), ParseInstructionError> {
|
||||
check_num_accounts(accounts, num, ParsableProgram::BpfUpgradeableLoader)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use serde_json::Value;
|
||||
use solana_sdk::{message::Message, pubkey};
|
||||
|
||||
#[test]
|
||||
|
@ -96,4 +204,153 @@ mod test {
|
|||
};
|
||||
assert!(parse_bpf_loader(&bad_compiled_instruction, &account_keys).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_bpf_upgradeable_loader_instructions() {
|
||||
let mut keys: Vec<Pubkey> = vec![];
|
||||
for _ in 0..8 {
|
||||
keys.push(Pubkey::new_unique());
|
||||
}
|
||||
let offset = 4242;
|
||||
let bytes = vec![8; 99];
|
||||
let max_data_len = 54321;
|
||||
|
||||
let instructions = solana_sdk::bpf_loader_upgradeable::create_buffer(
|
||||
&keys[0],
|
||||
&keys[1],
|
||||
&keys[2],
|
||||
55,
|
||||
max_data_len,
|
||||
)
|
||||
.unwrap();
|
||||
let message = Message::new(&instructions, None);
|
||||
assert_eq!(
|
||||
parse_bpf_upgradeable_loader(&message.instructions[1], &keys[0..3]).unwrap(),
|
||||
ParsedInstructionEnum {
|
||||
instruction_type: "initializeBuffer".to_string(),
|
||||
info: json!({
|
||||
"account": keys[1].to_string(),
|
||||
"authority": keys[2].to_string(),
|
||||
}),
|
||||
}
|
||||
);
|
||||
assert!(parse_bpf_upgradeable_loader(&message.instructions[1], &keys[0..2]).is_err());
|
||||
|
||||
let instruction =
|
||||
solana_sdk::bpf_loader_upgradeable::write(&keys[1], &keys[0], offset, bytes.clone());
|
||||
let message = Message::new(&[instruction], None);
|
||||
assert_eq!(
|
||||
parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..2]).unwrap(),
|
||||
ParsedInstructionEnum {
|
||||
instruction_type: "write".to_string(),
|
||||
info: json!({
|
||||
"offset": offset,
|
||||
"bytes": base64::encode(&bytes),
|
||||
"account": keys[1].to_string(),
|
||||
"authority": keys[0].to_string(),
|
||||
}),
|
||||
}
|
||||
);
|
||||
assert!(parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..1]).is_err());
|
||||
|
||||
let instructions = solana_sdk::bpf_loader_upgradeable::deploy_with_max_program_len(
|
||||
&keys[0],
|
||||
&keys[1],
|
||||
&keys[4],
|
||||
&keys[2],
|
||||
55,
|
||||
max_data_len,
|
||||
)
|
||||
.unwrap();
|
||||
let message = Message::new(&instructions, None);
|
||||
assert_eq!(
|
||||
parse_bpf_upgradeable_loader(&message.instructions[1], &keys[0..8]).unwrap(),
|
||||
ParsedInstructionEnum {
|
||||
instruction_type: "deployWithMaxDataLen".to_string(),
|
||||
info: json!({
|
||||
"maxDataLen": max_data_len,
|
||||
"payerAccount": keys[0].to_string(),
|
||||
"programAccount": keys[1].to_string(),
|
||||
"authority": keys[2].to_string(),
|
||||
"programDataAccount": keys[3].to_string(),
|
||||
"bufferAccount": keys[4].to_string(),
|
||||
"rentSysvar": keys[5].to_string(),
|
||||
"clockSysvar": keys[6].to_string(),
|
||||
"systemProgram": keys[7].to_string(),
|
||||
}),
|
||||
}
|
||||
);
|
||||
assert!(parse_bpf_upgradeable_loader(&message.instructions[1], &keys[0..7]).is_err());
|
||||
|
||||
let instruction =
|
||||
solana_sdk::bpf_loader_upgradeable::upgrade(&keys[2], &keys[3], &keys[0], &keys[4]);
|
||||
let message = Message::new(&[instruction], None);
|
||||
assert_eq!(
|
||||
parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..7]).unwrap(),
|
||||
ParsedInstructionEnum {
|
||||
instruction_type: "upgrade".to_string(),
|
||||
info: json!({
|
||||
"authority": keys[0].to_string(),
|
||||
"programDataAccount": keys[1].to_string(),
|
||||
"programAccount": keys[2].to_string(),
|
||||
"bufferAccount": keys[3].to_string(),
|
||||
"spillAccount": keys[4].to_string(),
|
||||
"rentSysvar": keys[5].to_string(),
|
||||
"clockSysvar": keys[6].to_string(),
|
||||
}),
|
||||
}
|
||||
);
|
||||
assert!(parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..6]).is_err());
|
||||
|
||||
let instruction =
|
||||
solana_sdk::bpf_loader_upgradeable::set_buffer_authority(&keys[1], &keys[0], &keys[2]);
|
||||
let message = Message::new(&[instruction], None);
|
||||
assert_eq!(
|
||||
parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..3]).unwrap(),
|
||||
ParsedInstructionEnum {
|
||||
instruction_type: "setAuthority".to_string(),
|
||||
info: json!({
|
||||
"account": keys[1].to_string(),
|
||||
"authority": keys[0].to_string(),
|
||||
"newAuthority": keys[2].to_string(),
|
||||
}),
|
||||
}
|
||||
);
|
||||
assert!(parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..1]).is_err());
|
||||
|
||||
let instruction = solana_sdk::bpf_loader_upgradeable::set_upgrade_authority(
|
||||
&keys[1],
|
||||
&keys[0],
|
||||
Some(&keys[2]),
|
||||
);
|
||||
let message = Message::new(&[instruction], None);
|
||||
assert_eq!(
|
||||
parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..3]).unwrap(),
|
||||
ParsedInstructionEnum {
|
||||
instruction_type: "setAuthority".to_string(),
|
||||
info: json!({
|
||||
"account": keys[1].to_string(),
|
||||
"authority": keys[0].to_string(),
|
||||
"newAuthority": keys[2].to_string(),
|
||||
}),
|
||||
}
|
||||
);
|
||||
assert!(parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..1]).is_err());
|
||||
|
||||
let instruction =
|
||||
solana_sdk::bpf_loader_upgradeable::set_upgrade_authority(&keys[1], &keys[0], None);
|
||||
let message = Message::new(&[instruction], None);
|
||||
assert_eq!(
|
||||
parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..2]).unwrap(),
|
||||
ParsedInstructionEnum {
|
||||
instruction_type: "setAuthority".to_string(),
|
||||
info: json!({
|
||||
"account": keys[1].to_string(),
|
||||
"authority": keys[0].to_string(),
|
||||
"newAuthority": Value::Null,
|
||||
}),
|
||||
}
|
||||
);
|
||||
assert!(parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..1]).is_err());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use crate::{
|
||||
parse_bpf_loader::parse_bpf_loader, parse_stake::parse_stake, parse_system::parse_system,
|
||||
parse_token::parse_token, parse_vote::parse_vote,
|
||||
parse_bpf_loader::{parse_bpf_loader, parse_bpf_upgradeable_loader},
|
||||
parse_stake::parse_stake,
|
||||
parse_system::parse_system,
|
||||
parse_token::parse_token,
|
||||
parse_vote::parse_vote,
|
||||
};
|
||||
use inflector::Inflector;
|
||||
use serde_json::Value;
|
||||
|
@ -14,6 +17,7 @@ use thiserror::Error;
|
|||
|
||||
lazy_static! {
|
||||
static ref BPF_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader::id();
|
||||
static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id();
|
||||
static ref MEMO_V1_PROGRAM_ID: Pubkey =
|
||||
Pubkey::from_str(&spl_memo_v1_0::id().to_string()).unwrap();
|
||||
static ref MEMO_V3_PROGRAM_ID: Pubkey =
|
||||
|
@ -28,6 +32,10 @@ lazy_static! {
|
|||
m.insert(*MEMO_V3_PROGRAM_ID, ParsableProgram::SplMemo);
|
||||
m.insert(*TOKEN_PROGRAM_ID, ParsableProgram::SplToken);
|
||||
m.insert(*BPF_LOADER_PROGRAM_ID, ParsableProgram::BpfLoader);
|
||||
m.insert(
|
||||
*BPF_UPGRADEABLE_LOADER_PROGRAM_ID,
|
||||
ParsableProgram::BpfUpgradeableLoader,
|
||||
);
|
||||
m.insert(*STAKE_PROGRAM_ID, ParsableProgram::Stake);
|
||||
m.insert(*SYSTEM_PROGRAM_ID, ParsableProgram::System);
|
||||
m.insert(*VOTE_PROGRAM_ID, ParsableProgram::Vote);
|
||||
|
@ -73,6 +81,7 @@ pub enum ParsableProgram {
|
|||
SplMemo,
|
||||
SplToken,
|
||||
BpfLoader,
|
||||
BpfUpgradeableLoader,
|
||||
Stake,
|
||||
System,
|
||||
Vote,
|
||||
|
@ -92,6 +101,9 @@ pub fn parse(
|
|||
ParsableProgram::BpfLoader => {
|
||||
serde_json::to_value(parse_bpf_loader(instruction, account_keys)?)?
|
||||
}
|
||||
ParsableProgram::BpfUpgradeableLoader => {
|
||||
serde_json::to_value(parse_bpf_upgradeable_loader(instruction, account_keys)?)?
|
||||
}
|
||||
ParsableProgram::Stake => serde_json::to_value(parse_stake(instruction, account_keys)?)?,
|
||||
ParsableProgram::System => serde_json::to_value(parse_system(instruction, account_keys)?)?,
|
||||
ParsableProgram::Vote => serde_json::to_value(parse_vote(instruction, account_keys)?)?,
|
||||
|
|
Loading…
Reference in New Issue