Refactor: Add AccountKeys struct for static and dynamic message keys (#22960)

This commit is contained in:
Justin Starry 2022-02-05 20:00:31 +08:00 committed by GitHub
parent e05cf4bf97
commit ba215e94f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 917 additions and 442 deletions

View File

@ -6262,7 +6262,7 @@ pub mod tests {
.map(|transaction| {
let mut pre_balances: Vec<u64> = vec![];
let mut post_balances: Vec<u64> = vec![];
for i in 0..transaction.message.total_account_keys_len() {
for i in 0..transaction.message.static_account_keys().len() {
pre_balances.push(i as u64 * 10);
post_balances.push(i as u64 * 11);
}
@ -7129,7 +7129,7 @@ pub mod tests {
.map(|transaction| {
let mut pre_balances: Vec<u64> = vec![];
let mut post_balances: Vec<u64> = vec![];
for i in 0..transaction.message.total_account_keys_len() {
for i in 0..transaction.message.static_account_keys().len() {
pre_balances.push(i as u64 * 10);
post_balances.push(i as u64 * 11);
}
@ -7231,7 +7231,7 @@ pub mod tests {
.map(|transaction| {
let mut pre_balances: Vec<u64> = vec![];
let mut post_balances: Vec<u64> = vec![];
for i in 0..transaction.message.total_account_keys_len() {
for i in 0..transaction.message.static_account_keys().len() {
pre_balances.push(i as u64 * 10);
post_balances.push(i as u64 * 11);
}
@ -7590,7 +7590,7 @@ pub mod tests {
.write_transaction_status(
slot,
transaction.signatures[0],
transaction.message.static_account_keys_iter().collect(),
transaction.message.static_account_keys().iter().collect(),
vec![],
TransactionStatusMeta::default(),
)
@ -7614,7 +7614,7 @@ pub mod tests {
.write_transaction_status(
slot,
transaction.signatures[0],
transaction.message.static_account_keys_iter().collect(),
transaction.message.static_account_keys().iter().collect(),
vec![],
TransactionStatusMeta::default(),
)

View File

@ -1,4 +1,4 @@
use {super::*, std::time::Instant};
use {super::*, solana_sdk::message::AccountKeys, std::time::Instant};
#[derive(Default)]
pub struct PurgeStats {
@ -334,16 +334,17 @@ impl Blockstore {
if let Some(&signature) = transaction.signatures.get(0) {
batch.delete::<cf::TransactionStatus>((0, signature, slot))?;
batch.delete::<cf::TransactionStatus>((1, signature, slot))?;
for pubkey in transaction.message.into_static_account_keys() {
batch.delete::<cf::AddressSignatures>((0, pubkey, slot, signature))?;
batch.delete::<cf::AddressSignatures>((1, pubkey, slot, signature))?;
}
let meta = self.read_transaction_status((signature, slot))?;
let loaded_addresses =
meta.map(|meta| meta.loaded_addresses).unwrap_or_default();
for address in loaded_addresses.into_ordered_iter() {
batch.delete::<cf::AddressSignatures>((0, address, slot, signature))?;
batch.delete::<cf::AddressSignatures>((1, address, slot, signature))?;
let loaded_addresses = meta.map(|meta| meta.loaded_addresses);
let account_keys = AccountKeys::new(
transaction.message.static_account_keys(),
loaded_addresses.as_ref(),
);
for pubkey in account_keys.iter() {
batch.delete::<cf::AddressSignatures>((0, *pubkey, slot, signature))?;
batch.delete::<cf::AddressSignatures>((1, *pubkey, slot, signature))?;
}
}
}

View File

@ -3591,7 +3591,7 @@ pub mod rpc_full {
if config.sig_verify {
verify_transaction(&transaction, &bank.feature_set)?;
}
let number_of_accounts = transaction.message().account_keys_len();
let number_of_accounts = transaction.message().account_keys().len();
let TransactionSimulationResult {
result,

View File

@ -250,10 +250,11 @@ impl Accounts {
// If a fee can pay for execution then the program will be scheduled
let mut payer_index = None;
let mut tx_rent: TransactionRent = 0;
let mut accounts = Vec::with_capacity(message.account_keys_len());
let mut account_deps = Vec::with_capacity(message.account_keys_len());
let account_keys = message.account_keys();
let mut accounts = Vec::with_capacity(account_keys.len());
let mut account_deps = Vec::with_capacity(account_keys.len());
let mut rent_debits = RentDebits::default();
for (i, key) in message.account_keys_iter().enumerate() {
for (i, key) in account_keys.iter().enumerate() {
let account = if !message.is_non_loader_key(i) {
// Fill in an empty account for the program slots.
AccountSharedData::default()
@ -328,7 +329,7 @@ impl Accounts {
};
accounts.push((*key, account));
}
debug_assert_eq!(accounts.len(), message.account_keys_len());
debug_assert_eq!(accounts.len(), account_keys.len());
// Appends the account_deps at the end of the accounts,
// this way they can be accessed in a uniform way.
// At places where only the accounts are needed,
@ -1176,7 +1177,7 @@ impl Accounts {
let message = tx.message();
let loaded_transaction = tx_load_result.as_mut().unwrap();
let mut fee_payer_index = None;
for (i, (address, account)) in (0..message.account_keys_len())
for (i, (address, account)) in (0..message.account_keys().len())
.zip(loaded_transaction.accounts.iter_mut())
.filter(|(i, _)| message.is_non_loader_key(*i))
{

View File

@ -838,7 +838,7 @@ impl NonceFull {
accounts: &[TransactionAccount],
rent_debits: &RentDebits,
) -> Result<Self> {
let fee_payer = (0..message.account_keys_len()).find_map(|i| {
let fee_payer = (0..message.account_keys().len()).find_map(|i| {
if let Some((k, a)) = &accounts.get(i) {
if message.is_non_loader_key(i) {
return Some((k, a));
@ -3464,7 +3464,7 @@ impl Bank {
&self,
transaction: SanitizedTransaction,
) -> TransactionSimulationResult {
let number_of_accounts = transaction.message().account_keys_len();
let number_of_accounts = transaction.message().account_keys().len();
let batch = self.prepare_simulation_batch(transaction);
let mut timings = ExecuteTimings::default();
@ -3648,7 +3648,7 @@ impl Bank {
let mut balances: TransactionBalances = vec![];
for transaction in batch.sanitized_transactions() {
let mut transaction_balances: Vec<u64> = vec![];
for account_key in transaction.message().account_keys_iter() {
for account_key in transaction.message().account_keys().iter() {
transaction_balances.push(self.get_balance(account_key));
}
balances.push(transaction_balances);
@ -4045,7 +4045,7 @@ impl Bank {
for (execution_result, tx) in execution_results.iter().zip(sanitized_txs) {
if let Some(debug_keys) = &self.transaction_debug_keys {
for key in tx.message().account_keys_iter() {
for key in tx.message().account_keys().iter() {
if debug_keys.contains(key) {
let result = execution_result.flattened_result();
info!("slot: {} result: {:?} tx: {:?}", self.slot, result, tx);
@ -4062,7 +4062,7 @@ impl Bank {
.mentioned_addresses
.is_empty()
{
for key in tx.message().account_keys_iter() {
for key in tx.message().account_keys().iter() {
if transaction_log_collector_config
.mentioned_addresses
.contains(key)
@ -5971,7 +5971,7 @@ impl Bank {
) {
let message = tx.message();
for (_i, (pubkey, account)) in
(0..message.account_keys_len()).zip(loaded_transaction.accounts.iter())
(0..message.account_keys().len()).zip(loaded_transaction.accounts.iter())
{
self.stakes_cache.check_and_store(pubkey, account);
}
@ -6764,16 +6764,16 @@ pub(crate) mod tests {
let message = new_sanitized_message(&instructions, Some(&from_address));
let accounts = [
(
*message.get_account_key(0).unwrap(),
*message.account_keys().get(0).unwrap(),
rent_collected_from_account.clone(),
),
(
*message.get_account_key(1).unwrap(),
*message.account_keys().get(1).unwrap(),
rent_collected_nonce_account.clone(),
),
(*message.get_account_key(2).unwrap(), to_account.clone()),
(*message.account_keys().get(2).unwrap(), to_account.clone()),
(
*message.get_account_key(3).unwrap(),
*message.account_keys().get(3).unwrap(),
recent_blockhashes_sysvar_account.clone(),
),
];
@ -6795,16 +6795,16 @@ pub(crate) mod tests {
let message = new_sanitized_message(&instructions, Some(&nonce_address));
let accounts = [
(
*message.get_account_key(0).unwrap(),
*message.account_keys().get(0).unwrap(),
rent_collected_nonce_account,
),
(
*message.get_account_key(1).unwrap(),
*message.account_keys().get(1).unwrap(),
rent_collected_from_account,
),
(*message.get_account_key(2).unwrap(), to_account),
(*message.account_keys().get(2).unwrap(), to_account),
(
*message.get_account_key(3).unwrap(),
*message.account_keys().get(3).unwrap(),
recent_blockhashes_sysvar_account,
),
];

View File

@ -19,7 +19,7 @@ impl Bank {
transaction_context: &TransactionContext,
message: &SanitizedMessage,
) -> Vec<TransactionAccountStateInfo> {
(0..message.account_keys_len())
(0..message.account_keys().len())
.map(|i| {
let rent_state = if message.is_writable(i) {
let state = if let Ok(account) = transaction_context.get_account_at_index(i) {

View File

@ -157,14 +157,18 @@ impl CostModel {
transaction: &SanitizedTransaction,
) {
let message = transaction.message();
message.account_keys_iter().enumerate().for_each(|(i, k)| {
let is_writable = message.is_writable(i);
message
.account_keys()
.iter()
.enumerate()
.for_each(|(i, k)| {
let is_writable = message.is_writable(i);
if is_writable {
tx_cost.writable_accounts.push(*k);
tx_cost.write_lock_cost += WRITE_LOCK_UNITS;
}
});
if is_writable {
tx_cost.writable_accounts.push(*k);
tx_cost.write_lock_cost += WRITE_LOCK_UNITS;
}
});
}
fn get_data_bytes_cost(&self, transaction: &SanitizedTransaction) -> u64 {

View File

@ -44,7 +44,7 @@ pub fn parse_sanitized_vote_transaction(tx: &SanitizedTransaction) -> Option<Par
return None;
}
let first_account = usize::from(*first_instruction.accounts.first()?);
let key = message.get_account_key(first_account)?;
let key = message.account_keys().get(first_account)?;
let (vote, switch_proof_hash) = parse_vote_instruction_data(&first_instruction.data)?;
Some((*key, vote, switch_proof_hash))
}

View File

@ -0,0 +1,199 @@
use {
crate::{message::v0::LoadedAddresses, pubkey::Pubkey},
std::ops::Index,
};
/// Collection of static and dynamically loaded keys used to load accounts
/// during transaction processing.
pub struct AccountKeys<'a> {
static_keys: &'a [Pubkey],
dynamic_keys: Option<&'a LoadedAddresses>,
}
impl Index<usize> for AccountKeys<'_> {
type Output = Pubkey;
fn index(&self, index: usize) -> &Self::Output {
self.get(index).expect("index is invalid")
}
}
impl<'a> AccountKeys<'a> {
pub fn new(static_keys: &'a [Pubkey], dynamic_keys: Option<&'a LoadedAddresses>) -> Self {
Self {
static_keys,
dynamic_keys,
}
}
/// Returns an iterator of account key segments. The ordering of segments
/// affects how account indexes from compiled instructions are resolved and
/// so should not be changed.
fn key_segment_iter(&self) -> impl Iterator<Item = &'a [Pubkey]> {
if let Some(dynamic_keys) = self.dynamic_keys {
[
self.static_keys,
&dynamic_keys.writable,
&dynamic_keys.readonly,
]
.into_iter()
} else {
// empty segments added for branch type compatibility
[self.static_keys, &[], &[]].into_iter()
}
}
/// Returns the address of the account at the specified index of the list of
/// message account keys constructed from static keys, followed by dynamically
/// loaded writable addresses, and lastly the list of dynamically loaded
/// readonly addresses.
pub fn get(&self, mut index: usize) -> Option<&'a Pubkey> {
for key_segment in self.key_segment_iter() {
if index < key_segment.len() {
return Some(&key_segment[index]);
}
index = index.saturating_sub(key_segment.len());
}
None
}
/// Returns the total length of loaded accounts for a message
pub fn len(&self) -> usize {
let mut len = 0usize;
for key_segment in self.key_segment_iter() {
len = len.saturating_add(key_segment.len());
}
len
}
/// Returns true if this collection of account keys is empty
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Iterator for the addresses of the loaded accounts for a message
pub fn iter(&self) -> impl Iterator<Item = &'a Pubkey> {
self.key_segment_iter().flatten()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_account_keys() -> [Pubkey; 6] {
let key0 = Pubkey::new_unique();
let key1 = Pubkey::new_unique();
let key2 = Pubkey::new_unique();
let key3 = Pubkey::new_unique();
let key4 = Pubkey::new_unique();
let key5 = Pubkey::new_unique();
[key0, key1, key2, key3, key4, key5]
}
#[test]
fn test_key_segment_iter() {
let keys = test_account_keys();
let static_keys = vec![keys[0], keys[1], keys[2]];
let dynamic_keys = LoadedAddresses {
writable: vec![keys[3], keys[4]],
readonly: vec![keys[5]],
};
let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
let expected_segments = vec![
vec![keys[0], keys[1], keys[2]],
vec![keys[3], keys[4]],
vec![keys[5]],
];
assert!(account_keys
.key_segment_iter()
.into_iter()
.eq(expected_segments.iter()));
}
#[test]
fn test_len() {
let keys = test_account_keys();
let static_keys = vec![keys[0], keys[1], keys[2], keys[3], keys[4], keys[5]];
let account_keys = AccountKeys::new(&static_keys, None);
assert_eq!(account_keys.len(), keys.len());
}
#[test]
fn test_len_with_dynamic_keys() {
let keys = test_account_keys();
let static_keys = vec![keys[0], keys[1], keys[2]];
let dynamic_keys = LoadedAddresses {
writable: vec![keys[3], keys[4]],
readonly: vec![keys[5]],
};
let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
assert_eq!(account_keys.len(), keys.len());
}
#[test]
fn test_iter() {
let keys = test_account_keys();
let static_keys = vec![keys[0], keys[1], keys[2], keys[3], keys[4], keys[5]];
let account_keys = AccountKeys::new(&static_keys, None);
assert!(account_keys.iter().eq(keys.iter()));
}
#[test]
fn test_iter_with_dynamic_keys() {
let keys = test_account_keys();
let static_keys = vec![keys[0], keys[1], keys[2]];
let dynamic_keys = LoadedAddresses {
writable: vec![keys[3], keys[4]],
readonly: vec![keys[5]],
};
let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
assert!(account_keys.iter().eq(keys.iter()));
}
#[test]
fn test_get() {
let keys = test_account_keys();
let static_keys = vec![keys[0], keys[1], keys[2], keys[3]];
let account_keys = AccountKeys::new(&static_keys, None);
assert_eq!(account_keys.get(0), Some(&keys[0]));
assert_eq!(account_keys.get(1), Some(&keys[1]));
assert_eq!(account_keys.get(2), Some(&keys[2]));
assert_eq!(account_keys.get(3), Some(&keys[3]));
assert_eq!(account_keys.get(4), None);
assert_eq!(account_keys.get(5), None);
}
#[test]
fn test_get_with_dynamic_keys() {
let keys = test_account_keys();
let static_keys = vec![keys[0], keys[1], keys[2]];
let dynamic_keys = LoadedAddresses {
writable: vec![keys[3], keys[4]],
readonly: vec![keys[5]],
};
let account_keys = AccountKeys::new(&static_keys, Some(&dynamic_keys));
assert_eq!(account_keys.get(0), Some(&keys[0]));
assert_eq!(account_keys.get(1), Some(&keys[1]));
assert_eq!(account_keys.get(2), Some(&keys[2]));
assert_eq!(account_keys.get(3), Some(&keys[3]));
assert_eq!(account_keys.get(4), Some(&keys[4]));
assert_eq!(account_keys.get(5), Some(&keys[5]));
}
}

View File

@ -5,10 +5,11 @@ pub mod legacy;
#[cfg(not(target_arch = "bpf"))]
#[path = ""]
mod non_bpf_modules {
mod account_keys;
mod sanitized;
mod versions;
pub use {sanitized::*, versions::*};
pub use {account_keys::*, sanitized::*, versions::*};
}
pub use legacy::Message;

View File

@ -5,7 +5,7 @@ use {
message::{
legacy::Message as LegacyMessage,
v0::{self, LoadedAddresses},
MessageHeader,
AccountKeys, MessageHeader,
},
nonce::NONCED_TX_MARKER_IX_INDEX,
program_utils::limited_deserialize,
@ -85,7 +85,8 @@ impl SanitizedMessage {
/// Returns the fee payer for the transaction
pub fn fee_payer(&self) -> &Pubkey {
self.get_account_key(0)
self.account_keys()
.get(0)
.expect("sanitized message always has non-program fee payer at index 0")
}
@ -117,34 +118,19 @@ impl SanitizedMessage {
}
.map(move |ix| {
(
self.get_account_key(usize::from(ix.program_id_index))
self.account_keys()
.get(usize::from(ix.program_id_index))
.expect("program id index is sanitized"),
ix,
)
})
}
/// Iterator of all account keys referenced in this message, including dynamically loaded keys.
pub fn account_keys_iter(&self) -> Box<dyn Iterator<Item = &Pubkey> + '_> {
/// Returns the list of account keys that are loaded for this message.
pub fn account_keys(&self) -> AccountKeys {
match self {
Self::Legacy(message) => Box::new(message.account_keys.iter()),
Self::V0(message) => Box::new(message.account_keys_iter()),
}
}
/// Length of all account keys referenced in this message, including dynamically loaded keys.
pub fn account_keys_len(&self) -> usize {
match self {
Self::Legacy(message) => message.account_keys.len(),
Self::V0(message) => message.account_keys_len(),
}
}
/// Returns the address of the account at the specified index.
pub fn get_account_key(&self, index: usize) -> Option<&Pubkey> {
match self {
Self::Legacy(message) => message.account_keys.get(index),
Self::V0(message) => message.get_account_key(index),
Self::Legacy(message) => AccountKeys::new(&message.account_keys, None),
Self::V0(message) => message.account_keys(),
}
}
@ -210,7 +196,7 @@ impl SanitizedMessage {
}
fn try_position(&self, key: &Pubkey) -> Option<u8> {
u8::try_from(self.account_keys_iter().position(|k| k == key)?).ok()
u8::try_from(self.account_keys().iter().position(|k| k == key)?).ok()
}
/// Try to compile an instruction using the account keys in this message.
@ -230,6 +216,7 @@ impl SanitizedMessage {
/// Decompile message instructions without cloning account keys
pub fn decompile_instructions(&self) -> Vec<BorrowedInstruction> {
let account_keys = self.account_keys();
self.program_instructions_iter()
.map(|(program_id, instruction)| {
let accounts = instruction
@ -240,7 +227,7 @@ impl SanitizedMessage {
BorrowedAccountMeta {
is_signer: self.is_signer(account_index),
is_writable: self.is_writable(account_index),
pubkey: self.get_account_key(account_index).unwrap(),
pubkey: account_keys.get(account_index).unwrap(),
}
})
.collect();
@ -267,7 +254,7 @@ impl SanitizedMessage {
self.instructions()
.get(NONCED_TX_MARKER_IX_INDEX as usize)
.filter(
|ix| match self.get_account_key(ix.program_id_index as usize) {
|ix| match self.account_keys().get(ix.program_id_index as usize) {
Some(program_id) => system_program::check_id(program_id),
_ => false,
},
@ -284,7 +271,7 @@ impl SanitizedMessage {
if nonce_must_be_writable && !self.is_writable(idx) {
None
} else {
self.get_account_key(idx)
self.account_keys().get(idx)
}
})
})

View File

@ -50,45 +50,6 @@ impl VersionedMessage {
}
}
pub fn into_static_account_keys(self) -> Vec<Pubkey> {
match self {
Self::Legacy(message) => message.account_keys,
Self::V0(message) => message.account_keys,
}
}
pub fn static_account_keys_iter(&self) -> impl Iterator<Item = &Pubkey> {
match self {
Self::Legacy(message) => message.account_keys.iter(),
Self::V0(message) => message.account_keys.iter(),
}
}
pub fn static_account_keys_len(&self) -> usize {
match self {
Self::Legacy(message) => message.account_keys.len(),
Self::V0(message) => message.account_keys.len(),
}
}
pub fn total_account_keys_len(&self) -> usize {
match self {
Self::Legacy(message) => message.account_keys.len(),
Self::V0(message) => message.account_keys.len().saturating_add(
message
.address_table_lookups
.iter()
.map(|lookup| {
lookup
.writable_indexes
.len()
.saturating_add(lookup.readonly_indexes.len())
})
.sum(),
),
}
}
pub fn recent_blockhash(&self) -> &Hash {
match self {
Self::Legacy(message) => &message.recent_blockhash,

View File

@ -1,7 +1,7 @@
use {
crate::{
bpf_loader_upgradeable,
message::{legacy::BUILTIN_PROGRAMS_KEYS, v0},
message::{legacy::BUILTIN_PROGRAMS_KEYS, v0, AccountKeys},
pubkey::Pubkey,
sysvar,
},
@ -57,66 +57,18 @@ impl LoadedAddresses {
pub fn len(&self) -> usize {
self.writable.len().saturating_add(self.readonly.len())
}
/// Iterate over loaded addresses in the order that they are used
/// as account indexes
pub fn ordered_iter(&self) -> impl Iterator<Item = &Pubkey> {
self.writable.iter().chain(self.readonly.iter())
}
/// Iterate over loaded addresses in the order that they are used
/// as account indexes
pub fn into_ordered_iter(self) -> impl Iterator<Item = Pubkey> {
self.writable.into_iter().chain(self.readonly.into_iter())
}
}
impl LoadedMessage {
/// Returns an iterator of account key segments. The ordering of segments
/// affects how account indexes from compiled instructions are resolved and
/// so should not be changed.
fn account_keys_segment_iter(&self) -> impl Iterator<Item = &Vec<Pubkey>> {
vec![
&self.message.account_keys,
&self.loaded_addresses.writable,
&self.loaded_addresses.readonly,
]
.into_iter()
}
/// Returns the total length of loaded accounts for this message
pub fn account_keys_len(&self) -> usize {
let mut len = 0usize;
for key_segment in self.account_keys_segment_iter() {
len = len.saturating_add(key_segment.len());
}
len
}
/// Iterator for the addresses of the loaded accounts for this message
pub fn account_keys_iter(&self) -> impl Iterator<Item = &Pubkey> {
self.account_keys_segment_iter().flatten()
/// Returns the list of account keys that are loaded for this message.
pub fn account_keys(&self) -> AccountKeys {
AccountKeys::new(&self.account_keys, Some(&self.loaded_addresses))
}
/// Returns true if any account keys are duplicates
pub fn has_duplicates(&self) -> bool {
let mut uniq = HashSet::new();
self.account_keys_iter().any(|x| !uniq.insert(x))
}
/// Returns the address of the account at the specified index of the list of
/// message account keys constructed from static keys, followed by dynamically
/// loaded writable addresses, and lastly the list of dynamically loaded
/// readonly addresses.
pub fn get_account_key(&self, mut index: usize) -> Option<&Pubkey> {
for key_segment in self.account_keys_segment_iter() {
if index < key_segment.len() {
return Some(&key_segment[index]);
}
index = index.saturating_sub(key_segment.len());
}
None
self.account_keys().iter().any(|x| !uniq.insert(x))
}
/// Returns true if the account at the specified index was requested to be
@ -144,7 +96,7 @@ impl LoadedMessage {
/// Returns true if the account at the specified index was loaded as writable
pub fn is_writable(&self, key_index: usize) -> bool {
if self.is_writable_index(key_index) {
if let Some(key) = self.get_account_key(key_index) {
if let Some(key) = self.account_keys().get(key_index) {
let demote_program_id = self.is_key_called_as_program(key_index)
&& !self.is_upgradeable_loader_present();
return !(sysvar::is_sysvar_id(key)
@ -169,7 +121,8 @@ impl LoadedMessage {
/// Returns true if any account is the bpf upgradeable loader
pub fn is_upgradeable_loader_present(&self) -> bool {
self.account_keys_iter()
self.account_keys()
.iter()
.any(|&key| key == bpf_loader_upgradeable::id())
}
}
@ -209,39 +162,6 @@ mod tests {
(message, [key0, key1, key2, key3, key4, key5])
}
#[test]
fn test_account_keys_segment_iter() {
let (message, keys) = check_test_loaded_message();
let expected_segments = vec![
vec![keys[0], keys[1], keys[2], keys[3]],
vec![keys[4]],
vec![keys[5]],
];
let mut iter = message.account_keys_segment_iter();
for expected_segment in expected_segments {
assert_eq!(iter.next(), Some(&expected_segment));
}
}
#[test]
fn test_account_keys_len() {
let (message, keys) = check_test_loaded_message();
assert_eq!(message.account_keys_len(), keys.len());
}
#[test]
fn test_account_keys_iter() {
let (message, keys) = check_test_loaded_message();
let mut iter = message.account_keys_iter();
for expected_key in keys {
assert_eq!(iter.next(), Some(&expected_key));
}
}
#[test]
fn test_has_duplicates() {
let message = check_test_loaded_message().0;
@ -276,18 +196,6 @@ mod tests {
}
}
#[test]
fn test_get_account_key() {
let (message, keys) = check_test_loaded_message();
assert_eq!(message.get_account_key(0), Some(&keys[0]));
assert_eq!(message.get_account_key(1), Some(&keys[1]));
assert_eq!(message.get_account_key(2), Some(&keys[2]));
assert_eq!(message.get_account_key(3), Some(&keys[3]));
assert_eq!(message.get_account_key(4), Some(&keys[4]));
assert_eq!(message.get_account_key(5), Some(&keys[5]));
}
#[test]
fn test_is_writable_index() {
let message = check_test_loaded_message().0;

View File

@ -156,7 +156,7 @@ impl SanitizedTransaction {
if self.message.has_duplicates() {
Err(TransactionError::AccountLoadedTwice)
} else if feature_set.is_active(&feature_set::max_tx_account_locks::id())
&& self.message.account_keys_len() > MAX_TX_ACCOUNT_LOCKS
&& self.message.account_keys().len() > MAX_TX_ACCOUNT_LOCKS
{
Err(TransactionError::TooManyAccountLocks)
} else {
@ -167,17 +167,16 @@ impl SanitizedTransaction {
/// Return the list of accounts that must be locked during processing this transaction.
pub fn get_account_locks_unchecked(&self) -> TransactionAccountLocks {
let message = &self.message;
let account_keys = message.account_keys();
let num_readonly_accounts = message.num_readonly_accounts();
let num_writable_accounts = message
.account_keys_len()
.saturating_sub(num_readonly_accounts);
let num_writable_accounts = account_keys.len().saturating_sub(num_readonly_accounts);
let mut account_locks = TransactionAccountLocks {
writable: Vec::with_capacity(num_writable_accounts),
readonly: Vec::with_capacity(num_readonly_accounts),
};
for (i, key) in message.account_keys_iter().enumerate() {
for (i, key) in account_keys.iter().enumerate() {
if message.is_writable(i) {
account_locks.writable.push(key);
} else {
@ -215,7 +214,7 @@ impl SanitizedTransaction {
if self
.signatures
.iter()
.zip(self.message.account_keys_iter())
.zip(self.message.account_keys().iter())
.map(|(signature, pubkey)| signature.verify(pubkey.as_ref(), &message_bytes))
.any(|verified| !verified)
{

View File

@ -41,7 +41,7 @@ impl Sanitize for VersionedTransaction {
// Signatures are verified before message keys are loaded so all signers
// must correspond to static account keys.
if self.signatures.len() > self.message.static_account_keys_len() {
if self.signatures.len() > self.message.static_account_keys().len() {
return Err(SanitizeError::IndexOutOfBounds);
}
@ -127,7 +127,7 @@ impl VersionedTransaction {
fn _verify_with_results(&self, message_bytes: &[u8]) -> Vec<bool> {
self.signatures
.iter()
.zip(self.message.static_account_keys_iter())
.zip(self.message.static_account_keys().iter())
.map(|(signature, pubkey)| signature.verify(pubkey.as_ref(), message_bytes))
.collect()
}

View File

@ -643,7 +643,7 @@ impl LedgerStorage {
let signature = transaction.signatures[0];
let memo = extract_and_fmt_memos(transaction_with_meta);
for address in transaction_with_meta.account_keys_iter() {
for address in transaction_with_meta.account_keys().iter() {
if !is_sysvar_id(address) {
by_addr
.entry(address)
@ -730,7 +730,7 @@ impl LedgerStorage {
let index = index as u32;
let err = meta.as_ref().and_then(|meta| meta.status.clone().err());
for address in transaction_with_meta.account_keys_iter() {
for address in transaction_with_meta.account_keys().iter() {
if !is_sysvar_id(address) {
addresses.insert(address);
}

View File

@ -2,7 +2,7 @@ use {
crate::{parse_instruction::parse_memo_data, VersionedTransactionWithStatusMeta},
solana_sdk::{
instruction::CompiledInstruction,
message::{Message, SanitizedMessage},
message::{AccountKeys, Message, SanitizedMessage},
pubkey::Pubkey,
},
};
@ -45,20 +45,23 @@ pub trait ExtractMemos {
impl ExtractMemos for Message {
fn extract_memos(&self) -> Vec<String> {
extract_memos_inner(self.account_keys.iter(), &self.instructions)
extract_memos_inner(
&AccountKeys::new(&self.account_keys, None),
&self.instructions,
)
}
}
impl ExtractMemos for SanitizedMessage {
fn extract_memos(&self) -> Vec<String> {
extract_memos_inner(self.account_keys_iter(), self.instructions())
extract_memos_inner(&self.account_keys(), self.instructions())
}
}
impl ExtractMemos for VersionedTransactionWithStatusMeta {
fn extract_memos(&self) -> Vec<String> {
extract_memos_inner(
self.account_keys_iter(),
&self.account_keys(),
self.transaction.message.instructions(),
)
}
@ -70,11 +73,11 @@ enum KeyType<'a> {
Unknown(&'a Pubkey),
}
fn extract_memos_inner<'a>(
account_keys: impl Iterator<Item = &'a Pubkey>,
fn extract_memos_inner(
account_keys: &AccountKeys,
instructions: &[CompiledInstruction],
) -> Vec<String> {
let mut account_keys: Vec<KeyType> = account_keys.map(KeyType::Unknown).collect();
let mut account_keys: Vec<KeyType> = account_keys.iter().map(KeyType::Unknown).collect();
instructions
.iter()
.filter_map(|ix| {
@ -129,15 +132,16 @@ mod test {
data: memo1.as_bytes().to_vec(),
},
];
let account_keys = vec![
let static_keys = vec![
fee_payer,
spl_memo_id_v1(),
another_program_id,
spl_memo_id_v3(),
];
let account_keys = AccountKeys::new(&static_keys, None);
assert_eq!(
extract_memos_inner(account_keys.iter(), &memo_instructions),
extract_memos_inner(&account_keys, &memo_instructions),
expected_memos
);
}

View File

@ -26,8 +26,7 @@ use {
clock::{Slot, UnixTimestamp},
commitment_config::CommitmentConfig,
instruction::CompiledInstruction,
message::{v0::LoadedAddresses, Message, MessageHeader},
pubkey::Pubkey,
message::{v0::LoadedAddresses, AccountKeys, Message, MessageHeader},
sanitize::Sanitize,
signature::Signature,
transaction::{Result, Transaction, TransactionError, VersionedTransaction},
@ -82,8 +81,8 @@ pub enum UiInstruction {
}
impl UiInstruction {
fn parse(instruction: &CompiledInstruction, account_keys: &[Pubkey]) -> Self {
let program_id = instruction.program_id(account_keys);
fn parse(instruction: &CompiledInstruction, account_keys: &AccountKeys) -> Self {
let program_id = &account_keys[instruction.program_id_index as usize];
if let Ok(parsed_instruction) = parse(program_id, instruction, account_keys) {
UiInstruction::Parsed(UiParsedInstruction::Parsed(parsed_instruction))
} else {
@ -130,7 +129,7 @@ pub struct UiPartiallyDecodedInstruction {
}
impl UiPartiallyDecodedInstruction {
fn from(instruction: &CompiledInstruction, account_keys: &[Pubkey]) -> Self {
fn from(instruction: &CompiledInstruction, account_keys: &AccountKeys) -> Self {
Self {
program_id: account_keys[instruction.program_id_index as usize].to_string(),
accounts: instruction
@ -162,12 +161,13 @@ pub struct UiInnerInstructions {
impl UiInnerInstructions {
fn parse(inner_instructions: InnerInstructions, message: &Message) -> Self {
let account_keys = AccountKeys::new(&message.account_keys, None);
Self {
index: inner_instructions.index,
instructions: inner_instructions
.instructions
.iter()
.map(|ix| UiInstruction::parse(ix, &message.account_keys))
.map(|ix| UiInstruction::parse(ix, &account_keys))
.collect(),
}
}
@ -572,14 +572,11 @@ pub struct VersionedTransactionWithStatusMeta {
}
impl VersionedTransactionWithStatusMeta {
pub fn account_keys_iter(&self) -> impl Iterator<Item = &Pubkey> {
let static_keys_iter = self.transaction.message.static_account_keys().iter();
let dynamic_keys_iter = self
.meta
.iter()
.flat_map(|meta| meta.loaded_addresses.ordered_iter());
static_keys_iter.chain(dynamic_keys_iter)
pub fn account_keys(&self) -> AccountKeys {
AccountKeys::new(
self.transaction.message.static_account_keys(),
self.meta.as_ref().map(|meta| &meta.loaded_addresses),
)
}
pub fn into_legacy_transaction_with_meta(self) -> Option<TransactionWithStatusMeta> {
@ -753,13 +750,14 @@ impl Encodable for &Message {
type Encoded = UiMessage;
fn encode(self, encoding: UiTransactionEncoding) -> Self::Encoded {
if encoding == UiTransactionEncoding::JsonParsed {
let account_keys = AccountKeys::new(&self.account_keys, None);
UiMessage::Parsed(UiParsedMessage {
account_keys: parse_accounts(self),
recent_blockhash: self.recent_blockhash.to_string(),
instructions: self
.instructions
.iter()
.map(|instruction| UiInstruction::parse(instruction, &self.account_keys))
.map(|instruction| UiInstruction::parse(instruction, &account_keys))
.collect(),
})
} else {

View File

@ -3,7 +3,7 @@ use {
check_num_accounts, ParsableProgram, ParseInstructionError, ParsedInstructionEnum,
},
serde_json::json,
solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey},
solana_sdk::{instruction::CompiledInstruction, message::AccountKeys, pubkey::Pubkey},
};
// A helper function to convert spl_associated_token_account::id() as spl_sdk::pubkey::Pubkey
@ -14,7 +14,7 @@ pub fn spl_associated_token_id() -> Pubkey {
pub fn parse_associated_token(
instruction: &CompiledInstruction,
account_keys: &[Pubkey],
account_keys: &AccountKeys,
) -> Result<ParsedInstructionEnum, ParseInstructionError> {
match instruction.accounts.iter().max() {
Some(index) if (*index as usize) < account_keys.len() => {}
@ -88,8 +88,9 @@ mod test {
);
let message = Message::new(&[create_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
let account_keys = AccountKeys::new(&keys, None);
assert_eq!(
parse_associated_token(&compiled_instruction, &keys).unwrap(),
parse_associated_token(&compiled_instruction, &account_keys).unwrap(),
ParsedInstructionEnum {
instruction_type: "create".to_string(),
info: json!({

View File

@ -6,13 +6,13 @@ use {
serde_json::json,
solana_sdk::{
instruction::CompiledInstruction, loader_instruction::LoaderInstruction,
loader_upgradeable_instruction::UpgradeableLoaderInstruction, pubkey::Pubkey,
loader_upgradeable_instruction::UpgradeableLoaderInstruction, message::AccountKeys,
},
};
pub fn parse_bpf_loader(
instruction: &CompiledInstruction,
account_keys: &[Pubkey],
account_keys: &AccountKeys,
) -> Result<ParsedInstructionEnum, ParseInstructionError> {
let bpf_loader_instruction: LoaderInstruction = deserialize(&instruction.data)
.map_err(|_| ParseInstructionError::InstructionNotParsable(ParsableProgram::BpfLoader))?;
@ -41,7 +41,7 @@ pub fn parse_bpf_loader(
pub fn parse_bpf_upgradeable_loader(
instruction: &CompiledInstruction,
account_keys: &[Pubkey],
account_keys: &AccountKeys,
) -> Result<ParsedInstructionEnum, ParseInstructionError> {
let bpf_upgradeable_loader_instruction: UpgradeableLoaderInstruction =
deserialize(&instruction.data).map_err(|_| {
@ -159,7 +159,10 @@ mod test {
use {
super::*,
serde_json::Value,
solana_sdk::{message::Message, pubkey},
solana_sdk::{
message::Message,
pubkey::{self, Pubkey},
},
};
#[test]
@ -180,7 +183,11 @@ mod test {
);
let message = Message::new(&[instruction], Some(&fee_payer));
assert_eq!(
parse_bpf_loader(&message.instructions[0], &account_keys).unwrap(),
parse_bpf_loader(
&message.instructions[0],
&AccountKeys::new(&account_keys, None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "write".to_string(),
info: json!({
@ -190,12 +197,20 @@ mod test {
}),
}
);
assert!(parse_bpf_loader(&message.instructions[0], &missing_account_keys).is_err());
assert!(parse_bpf_loader(
&message.instructions[0],
&AccountKeys::new(&missing_account_keys, None)
)
.is_err());
let instruction = solana_sdk::loader_instruction::finalize(&account_pubkey, &program_id);
let message = Message::new(&[instruction], Some(&fee_payer));
assert_eq!(
parse_bpf_loader(&message.instructions[0], &account_keys).unwrap(),
parse_bpf_loader(
&message.instructions[0],
&AccountKeys::new(&account_keys, None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "finalize".to_string(),
info: json!({
@ -203,21 +218,33 @@ mod test {
}),
}
);
assert!(parse_bpf_loader(&message.instructions[0], &missing_account_keys).is_err());
assert!(parse_bpf_loader(
&message.instructions[0],
&AccountKeys::new(&missing_account_keys, None)
)
.is_err());
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
};
assert!(parse_bpf_loader(&bad_compiled_instruction, &account_keys).is_err());
assert!(parse_bpf_loader(
&bad_compiled_instruction,
&AccountKeys::new(&account_keys, None)
)
.is_err());
let bad_compiled_instruction = CompiledInstruction {
program_id_index: 3,
accounts: vec![],
data: vec![1, 0, 0, 0],
};
assert!(parse_bpf_loader(&bad_compiled_instruction, &account_keys).is_err());
assert!(parse_bpf_loader(
&bad_compiled_instruction,
&AccountKeys::new(&account_keys, None)
)
.is_err());
}
#[test]
@ -240,7 +267,11 @@ mod test {
.unwrap();
let message = Message::new(&instructions, None);
assert_eq!(
parse_bpf_upgradeable_loader(&message.instructions[1], &keys[0..3]).unwrap(),
parse_bpf_upgradeable_loader(
&message.instructions[1],
&AccountKeys::new(&keys[0..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "initializeBuffer".to_string(),
info: json!({
@ -249,13 +280,21 @@ mod test {
}),
}
);
assert!(parse_bpf_upgradeable_loader(&message.instructions[1], &keys[0..2]).is_err());
assert!(parse_bpf_upgradeable_loader(
&message.instructions[1],
&AccountKeys::new(&keys[0..2], None)
)
.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(),
parse_bpf_upgradeable_loader(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "write".to_string(),
info: json!({
@ -266,7 +305,11 @@ mod test {
}),
}
);
assert!(parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..1]).is_err());
assert!(parse_bpf_upgradeable_loader(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.is_err());
let instructions = solana_sdk::bpf_loader_upgradeable::deploy_with_max_program_len(
&keys[0],
@ -279,7 +322,11 @@ mod test {
.unwrap();
let message = Message::new(&instructions, None);
assert_eq!(
parse_bpf_upgradeable_loader(&message.instructions[1], &keys[0..8]).unwrap(),
parse_bpf_upgradeable_loader(
&message.instructions[1],
&AccountKeys::new(&keys[0..8], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "deployWithMaxDataLen".to_string(),
info: json!({
@ -295,13 +342,21 @@ mod test {
}),
}
);
assert!(parse_bpf_upgradeable_loader(&message.instructions[1], &keys[0..7]).is_err());
assert!(parse_bpf_upgradeable_loader(
&message.instructions[1],
&AccountKeys::new(&keys[0..7], None)
)
.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(),
parse_bpf_upgradeable_loader(
&message.instructions[0],
&AccountKeys::new(&keys[0..7], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "upgrade".to_string(),
info: json!({
@ -315,13 +370,21 @@ mod test {
}),
}
);
assert!(parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..6]).is_err());
assert!(parse_bpf_upgradeable_loader(
&message.instructions[0],
&AccountKeys::new(&keys[0..6], None)
)
.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(),
parse_bpf_upgradeable_loader(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "setAuthority".to_string(),
info: json!({
@ -331,7 +394,11 @@ mod test {
}),
}
);
assert!(parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..1]).is_err());
assert!(parse_bpf_upgradeable_loader(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.is_err());
let instruction = solana_sdk::bpf_loader_upgradeable::set_upgrade_authority(
&keys[1],
@ -340,7 +407,11 @@ mod test {
);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..3]).unwrap(),
parse_bpf_upgradeable_loader(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "setAuthority".to_string(),
info: json!({
@ -350,13 +421,21 @@ mod test {
}),
}
);
assert!(parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..1]).is_err());
assert!(parse_bpf_upgradeable_loader(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.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(),
parse_bpf_upgradeable_loader(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "setAuthority".to_string(),
info: json!({
@ -366,12 +445,20 @@ mod test {
}),
}
);
assert!(parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..1]).is_err());
assert!(parse_bpf_upgradeable_loader(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.is_err());
let instruction = solana_sdk::bpf_loader_upgradeable::close(&keys[0], &keys[1], &keys[2]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_bpf_upgradeable_loader(&message.instructions[0], &keys[..3]).unwrap(),
parse_bpf_upgradeable_loader(
&message.instructions[0],
&AccountKeys::new(&keys[..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "close".to_string(),
info: json!({
@ -381,6 +468,10 @@ mod test {
}),
}
);
assert!(parse_bpf_upgradeable_loader(&message.instructions[0], &keys[0..1]).is_err());
assert!(parse_bpf_upgradeable_loader(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.is_err());
}
}

View File

@ -11,7 +11,10 @@ use {
inflector::Inflector,
serde_json::Value,
solana_account_decoder::parse_token::spl_token_id,
solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey, stake, system_program},
solana_sdk::{
instruction::CompiledInstruction, message::AccountKeys, pubkey::Pubkey, stake,
system_program,
},
std::{
collections::HashMap,
str::{from_utf8, Utf8Error},
@ -98,7 +101,7 @@ pub enum ParsableProgram {
pub fn parse(
program_id: &Pubkey,
instruction: &CompiledInstruction,
account_keys: &[Pubkey],
account_keys: &AccountKeys,
) -> Result<ParsedInstruction, ParseInstructionError> {
let program_name = PARSABLE_PROGRAM_IDS
.get(program_id)
@ -156,13 +159,14 @@ mod test {
#[test]
fn test_parse() {
let no_keys = AccountKeys::new(&[], None);
let memo_instruction = CompiledInstruction {
program_id_index: 0,
accounts: vec![],
data: vec![240, 159, 166, 150],
};
assert_eq!(
parse(&MEMO_V1_PROGRAM_ID, &memo_instruction, &[]).unwrap(),
parse(&MEMO_V1_PROGRAM_ID, &memo_instruction, &no_keys).unwrap(),
ParsedInstruction {
program: "spl-memo".to_string(),
program_id: MEMO_V1_PROGRAM_ID.to_string(),
@ -170,7 +174,7 @@ mod test {
}
);
assert_eq!(
parse(&MEMO_V3_PROGRAM_ID, &memo_instruction, &[]).unwrap(),
parse(&MEMO_V3_PROGRAM_ID, &memo_instruction, &no_keys).unwrap(),
ParsedInstruction {
program: "spl-memo".to_string(),
program_id: MEMO_V3_PROGRAM_ID.to_string(),
@ -179,7 +183,7 @@ mod test {
);
let non_parsable_program_id = Pubkey::new(&[1; 32]);
assert!(parse(&non_parsable_program_id, &memo_instruction, &[]).is_err());
assert!(parse(&non_parsable_program_id, &memo_instruction, &no_keys).is_err());
}
#[test]

View File

@ -5,13 +5,14 @@ use {
bincode::deserialize,
serde_json::{json, Map},
solana_sdk::{
instruction::CompiledInstruction, pubkey::Pubkey, stake::instruction::StakeInstruction,
instruction::CompiledInstruction, message::AccountKeys,
stake::instruction::StakeInstruction,
},
};
pub fn parse_stake(
instruction: &CompiledInstruction,
account_keys: &[Pubkey],
account_keys: &AccountKeys,
) -> Result<ParsedInstructionEnum, ParseInstructionError> {
let stake_instruction: StakeInstruction = deserialize(&instruction.data)
.map_err(|_| ParseInstructionError::InstructionNotParsable(ParsableProgram::Stake))?;
@ -312,7 +313,11 @@ mod test {
instruction::create_account(&keys[0], &keys[1], &authorized, &lockup, lamports);
let message = Message::new(&instructions, None);
assert_eq!(
parse_stake(&message.instructions[1], &keys[0..3]).unwrap(),
parse_stake(
&message.instructions[1],
&AccountKeys::new(&keys[0..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "initialize".to_string(),
info: json!({
@ -330,13 +335,21 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[1], &keys[0..2]).is_err());
assert!(parse_stake(
&message.instructions[1],
&AccountKeys::new(&keys[0..2], None)
)
.is_err());
let instruction =
instruction::authorize(&keys[1], &keys[0], &keys[3], StakeAuthorize::Staker, None);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..3]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "authorize".to_string(),
info: json!({
@ -348,7 +361,11 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err());
assert!(parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.is_err());
let instruction = instruction::authorize(
&keys[2],
@ -359,7 +376,11 @@ mod test {
);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..4]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..4], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "authorize".to_string(),
info: json!({
@ -372,12 +393,20 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err());
assert!(parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.is_err());
let instruction = instruction::delegate_stake(&keys[1], &keys[0], &keys[2]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..6]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..6], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "delegate".to_string(),
info: json!({
@ -390,7 +419,11 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[0], &keys[0..5]).is_err());
assert!(parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..5], None)
)
.is_err());
// This looks wrong, but in an actual compiled instruction, the order is:
// * split account (signer, allocate + assign first)
@ -399,7 +432,11 @@ mod test {
let instructions = instruction::split(&keys[2], &keys[1], lamports, &keys[0]);
let message = Message::new(&instructions, None);
assert_eq!(
parse_stake(&message.instructions[2], &keys[0..3]).unwrap(),
parse_stake(
&message.instructions[2],
&AccountKeys::new(&keys[0..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "split".to_string(),
info: json!({
@ -410,12 +447,20 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[2], &keys[0..2]).is_err());
assert!(parse_stake(
&message.instructions[2],
&AccountKeys::new(&keys[0..2], None)
)
.is_err());
let instruction = instruction::withdraw(&keys[1], &keys[0], &keys[2], lamports, None);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..5]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..5], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "withdraw".to_string(),
info: json!({
@ -432,7 +477,11 @@ mod test {
instruction::withdraw(&keys[2], &keys[0], &keys[3], lamports, Some(&keys[1]));
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..6]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..6], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "withdraw".to_string(),
info: json!({
@ -446,12 +495,20 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[0], &keys[0..4]).is_err());
assert!(parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..4], None)
)
.is_err());
let instruction = instruction::deactivate_stake(&keys[1], &keys[0]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..3]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "deactivate".to_string(),
info: json!({
@ -461,12 +518,20 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err());
assert!(parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.is_err());
let instructions = instruction::merge(&keys[1], &keys[0], &keys[2]);
let message = Message::new(&instructions, None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..5]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..5], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "merge".to_string(),
info: json!({
@ -478,7 +543,11 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[0], &keys[0..4]).is_err());
assert!(parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..4], None)
)
.is_err());
let seed = "test_seed";
let instruction = instruction::authorize_with_seed(
@ -492,7 +561,11 @@ mod test {
);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..3]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "authorizeWithSeed".to_string(),
info: json!({
@ -506,7 +579,11 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err());
assert!(parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.is_err());
let instruction = instruction::authorize_with_seed(
&keys[2],
@ -519,7 +596,11 @@ mod test {
);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..4]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..4], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "authorizeWithSeed".to_string(),
info: json!({
@ -534,7 +615,11 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[0], &keys[0..3]).is_err());
assert!(parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.is_err());
}
#[test]
@ -556,7 +641,11 @@ mod test {
let instruction = instruction::set_lockup(&keys[1], &lockup, &keys[0]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..2]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "setLockup".to_string(),
info: json!({
@ -577,7 +666,11 @@ mod test {
let instruction = instruction::set_lockup(&keys[1], &lockup, &keys[0]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..2]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "setLockup".to_string(),
info: json!({
@ -599,7 +692,11 @@ mod test {
let instruction = instruction::set_lockup(&keys[1], &lockup, &keys[0]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..2]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "setLockup".to_string(),
info: json!({
@ -614,7 +711,11 @@ mod test {
}
);
assert!(parse_stake(&message.instructions[0], &keys[0..1]).is_err());
assert!(parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.is_err());
let lockup = LockupArgs {
unix_timestamp: Some(unix_timestamp),
@ -624,7 +725,11 @@ mod test {
let instruction = instruction::set_lockup_checked(&keys[1], &lockup, &keys[0]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..2]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "setLockupChecked".to_string(),
info: json!({
@ -645,7 +750,11 @@ mod test {
let instruction = instruction::set_lockup_checked(&keys[1], &lockup, &keys[0]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..2]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "setLockupChecked".to_string(),
info: json!({
@ -658,7 +767,11 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[0], &keys[0..1]).is_err());
assert!(parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.is_err());
let lockup = LockupArgs {
unix_timestamp: Some(unix_timestamp),
@ -668,7 +781,11 @@ mod test {
let instruction = instruction::set_lockup_checked(&keys[2], &lockup, &keys[0]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..3]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "setLockupChecked".to_string(),
info: json!({
@ -682,7 +799,11 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err());
assert!(parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.is_err());
}
#[test]
@ -703,7 +824,11 @@ mod test {
instruction::create_account_checked(&keys[0], &keys[1], &authorized, lamports);
let message = Message::new(&instructions, None);
assert_eq!(
parse_stake(&message.instructions[1], &keys[0..4]).unwrap(),
parse_stake(
&message.instructions[1],
&AccountKeys::new(&keys[0..4], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "initializeChecked".to_string(),
info: json!({
@ -714,7 +839,11 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[1], &keys[0..3]).is_err());
assert!(parse_stake(
&message.instructions[1],
&AccountKeys::new(&keys[0..3], None)
)
.is_err());
let instruction = instruction::authorize_checked(
&keys[2],
@ -725,7 +854,11 @@ mod test {
);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..4]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..4], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "authorizeChecked".to_string(),
info: json!({
@ -737,7 +870,11 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[0], &keys[0..3]).is_err());
assert!(parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.is_err());
let instruction = instruction::authorize_checked(
&keys[3],
@ -748,7 +885,11 @@ mod test {
);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..5]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..5], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "authorizeChecked".to_string(),
info: json!({
@ -761,7 +902,11 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[0], &keys[0..4]).is_err());
assert!(parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..4], None)
)
.is_err());
let seed = "test_seed";
let instruction = instruction::authorize_checked_with_seed(
@ -775,7 +920,11 @@ mod test {
);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..4]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..4], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "authorizeCheckedWithSeed".to_string(),
info: json!({
@ -789,7 +938,11 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[0], &keys[0..3]).is_err());
assert!(parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.is_err());
let instruction = instruction::authorize_checked_with_seed(
&keys[3],
@ -802,7 +955,11 @@ mod test {
);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_stake(&message.instructions[0], &keys[0..5]).unwrap(),
parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..5], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "authorizeCheckedWithSeed".to_string(),
info: json!({
@ -817,6 +974,10 @@ mod test {
}),
}
);
assert!(parse_stake(&message.instructions[0], &keys[0..4]).is_err());
assert!(parse_stake(
&message.instructions[0],
&AccountKeys::new(&keys[0..4], None)
)
.is_err());
}
}

View File

@ -5,13 +5,14 @@ use {
bincode::deserialize,
serde_json::json,
solana_sdk::{
instruction::CompiledInstruction, pubkey::Pubkey, system_instruction::SystemInstruction,
instruction::CompiledInstruction, message::AccountKeys,
system_instruction::SystemInstruction,
},
};
pub fn parse_system(
instruction: &CompiledInstruction,
account_keys: &[Pubkey],
account_keys: &AccountKeys,
) -> Result<ParsedInstructionEnum, ParseInstructionError> {
let system_instruction: SystemInstruction = deserialize(&instruction.data)
.map_err(|_| ParseInstructionError::InstructionNotParsable(ParsableProgram::System))?;
@ -219,7 +220,11 @@ mod test {
system_instruction::create_account(&keys[0], &keys[1], lamports, space, &keys[2]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_system(&message.instructions[0], &keys[0..2]).unwrap(),
parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "createAccount".to_string(),
info: json!({
@ -231,12 +236,20 @@ mod test {
}),
}
);
assert!(parse_system(&message.instructions[0], &keys[0..1]).is_err());
assert!(parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.is_err());
let instruction = system_instruction::assign(&keys[0], &keys[1]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_system(&message.instructions[0], &keys[0..1]).unwrap(),
parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "assign".to_string(),
info: json!({
@ -245,12 +258,16 @@ mod test {
}),
}
);
assert!(parse_system(&message.instructions[0], &[]).is_err());
assert!(parse_system(&message.instructions[0], &AccountKeys::new(&[], None)).is_err());
let instruction = system_instruction::transfer(&keys[0], &keys[1], lamports);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_system(&message.instructions[0], &keys[0..2]).unwrap(),
parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "transfer".to_string(),
info: json!({
@ -260,7 +277,11 @@ mod test {
}),
}
);
assert!(parse_system(&message.instructions[0], &keys[0..1]).is_err());
assert!(parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.is_err());
let seed = "test_seed";
let instruction = system_instruction::create_account_with_seed(
@ -268,7 +289,11 @@ mod test {
);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_system(&message.instructions[0], &keys[0..3]).unwrap(),
parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "createAccountWithSeed".to_string(),
info: json!({
@ -289,7 +314,11 @@ mod test {
);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_system(&message.instructions[0], &keys[0..2]).unwrap(),
parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "createAccountWithSeed".to_string(),
info: json!({
@ -303,12 +332,20 @@ mod test {
}),
}
);
assert!(parse_system(&message.instructions[0], &keys[0..1]).is_err());
assert!(parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.is_err());
let instruction = system_instruction::allocate(&keys[0], space);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_system(&message.instructions[0], &keys[0..1]).unwrap(),
parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "allocate".to_string(),
info: json!({
@ -317,13 +354,17 @@ mod test {
}),
}
);
assert!(parse_system(&message.instructions[0], &[]).is_err());
assert!(parse_system(&message.instructions[0], &AccountKeys::new(&[], None)).is_err());
let instruction =
system_instruction::allocate_with_seed(&keys[1], &keys[0], seed, space, &keys[2]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_system(&message.instructions[0], &keys[0..2]).unwrap(),
parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "allocateWithSeed".to_string(),
info: json!({
@ -335,12 +376,20 @@ mod test {
}),
}
);
assert!(parse_system(&message.instructions[0], &keys[0..1]).is_err());
assert!(parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.is_err());
let instruction = system_instruction::assign_with_seed(&keys[1], &keys[0], seed, &keys[2]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_system(&message.instructions[0], &keys[0..2]).unwrap(),
parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "assignWithSeed".to_string(),
info: json!({
@ -351,7 +400,11 @@ mod test {
}),
}
);
assert!(parse_system(&message.instructions[0], &keys[0..1]).is_err());
assert!(parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.is_err());
let instruction = system_instruction::transfer_with_seed(
&keys[1],
@ -363,7 +416,11 @@ mod test {
);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_system(&message.instructions[0], &keys[0..3]).unwrap(),
parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "transferWithSeed".to_string(),
info: json!({
@ -376,7 +433,11 @@ mod test {
}),
}
);
assert!(parse_system(&message.instructions[0], &keys[0..2]).is_err());
assert!(parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.is_err());
}
#[test]
@ -390,7 +451,11 @@ mod test {
let instruction = system_instruction::advance_nonce_account(&keys[1], &keys[0]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_system(&message.instructions[0], &keys[0..3]).unwrap(),
parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "advanceNonce".to_string(),
info: json!({
@ -400,14 +465,22 @@ mod test {
}),
}
);
assert!(parse_system(&message.instructions[0], &keys[0..2]).is_err());
assert!(parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.is_err());
let lamports = 55;
let instruction =
system_instruction::withdraw_nonce_account(&keys[1], &keys[0], &keys[2], lamports);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_system(&message.instructions[0], &keys[0..5]).unwrap(),
parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..5], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "withdrawFromNonce".to_string(),
info: json!({
@ -420,13 +493,21 @@ mod test {
}),
}
);
assert!(parse_system(&message.instructions[0], &keys[0..4]).is_err());
assert!(parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..4], None)
)
.is_err());
let instructions =
system_instruction::create_nonce_account(&keys[0], &keys[1], &keys[4], lamports);
let message = Message::new(&instructions, None);
assert_eq!(
parse_system(&message.instructions[1], &keys[0..4]).unwrap(),
parse_system(
&message.instructions[1],
&AccountKeys::new(&keys[0..4], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "initializeNonce".to_string(),
info: json!({
@ -437,12 +518,20 @@ mod test {
}),
}
);
assert!(parse_system(&message.instructions[1], &keys[0..3]).is_err());
assert!(parse_system(
&message.instructions[1],
&AccountKeys::new(&keys[0..3], None)
)
.is_err());
let instruction = system_instruction::authorize_nonce_account(&keys[1], &keys[0], &keys[2]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_system(&message.instructions[0], &keys[0..2]).unwrap(),
parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "authorizeNonce".to_string(),
info: json!({
@ -452,6 +541,10 @@ mod test {
}),
}
);
assert!(parse_system(&message.instructions[0], &keys[0..1]).is_err());
assert!(parse_system(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.is_err());
}
}

View File

@ -6,7 +6,7 @@ use {
solana_account_decoder::parse_token::{pubkey_from_spl_token, token_amount_to_ui_amount},
solana_sdk::{
instruction::{AccountMeta, CompiledInstruction, Instruction},
pubkey::Pubkey,
message::AccountKeys,
},
spl_token::{
instruction::{AuthorityType, TokenInstruction},
@ -18,7 +18,7 @@ use {
pub fn parse_token(
instruction: &CompiledInstruction,
account_keys: &[Pubkey],
account_keys: &AccountKeys,
) -> Result<ParsedInstructionEnum, ParseInstructionError> {
let token_instruction = TokenInstruction::unpack(&instruction.data)
.map_err(|_| ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken))?;
@ -411,7 +411,7 @@ impl From<AuthorityType> for UiAuthorityType {
fn parse_signers(
map: &mut Map<String, Value>,
last_nonsigner_index: usize,
account_keys: &[Pubkey],
account_keys: &AccountKeys,
accounts: &[u8],
owner_field_name: &str,
multisig_field_name: &str,
@ -458,7 +458,7 @@ pub fn spl_token_instruction(instruction: SplTokenInstruction) -> Instruction {
mod test {
use {
super::*,
solana_sdk::instruction::CompiledInstruction,
solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey},
spl_token::{
instruction::*,
solana_program::{
@ -503,7 +503,7 @@ mod test {
let message = Message::new(&[initialize_mint_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "initializeMint".to_string(),
info: json!({
@ -527,7 +527,7 @@ mod test {
let message = Message::new(&[initialize_mint_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "initializeMint".to_string(),
info: json!({
@ -550,7 +550,7 @@ mod test {
let message = Message::new(&[initialize_account_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "initializeAccount".to_string(),
info: json!({
@ -577,7 +577,7 @@ mod test {
let message = Message::new(&[initialize_multisig_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "initializeMultisig".to_string(),
info: json!({
@ -602,7 +602,7 @@ mod test {
let message = Message::new(&[transfer_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "transfer".to_string(),
info: json!({
@ -626,7 +626,7 @@ mod test {
let message = Message::new(&[transfer_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "transfer".to_string(),
info: json!({
@ -652,7 +652,7 @@ mod test {
let message = Message::new(&[approve_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "approve".to_string(),
info: json!({
@ -676,7 +676,7 @@ mod test {
let message = Message::new(&[approve_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "approve".to_string(),
info: json!({
@ -700,7 +700,7 @@ mod test {
let message = Message::new(&[revoke_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "revoke".to_string(),
info: json!({
@ -723,7 +723,7 @@ mod test {
let message = Message::new(&[set_authority_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "setAuthority".to_string(),
info: json!({
@ -748,7 +748,7 @@ mod test {
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
let new_authority: Option<String> = None;
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "setAuthority".to_string(),
info: json!({
@ -773,7 +773,7 @@ mod test {
let message = Message::new(&[mint_to_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "mintTo".to_string(),
info: json!({
@ -798,7 +798,7 @@ mod test {
let message = Message::new(&[burn_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "burn".to_string(),
info: json!({
@ -822,7 +822,7 @@ mod test {
let message = Message::new(&[close_account_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "closeAccount".to_string(),
info: json!({
@ -845,7 +845,7 @@ mod test {
let message = Message::new(&[freeze_account_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "freezeAccount".to_string(),
info: json!({
@ -868,7 +868,7 @@ mod test {
let message = Message::new(&[thaw_account_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "thawAccount".to_string(),
info: json!({
@ -894,7 +894,7 @@ mod test {
let message = Message::new(&[transfer_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "transferChecked".to_string(),
info: json!({
@ -926,7 +926,7 @@ mod test {
let message = Message::new(&[transfer_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "transferChecked".to_string(),
info: json!({
@ -960,7 +960,7 @@ mod test {
let message = Message::new(&[approve_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "approveChecked".to_string(),
info: json!({
@ -992,7 +992,7 @@ mod test {
let message = Message::new(&[approve_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "approveChecked".to_string(),
info: json!({
@ -1025,7 +1025,7 @@ mod test {
let message = Message::new(&[mint_to_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "mintToChecked".to_string(),
info: json!({
@ -1056,7 +1056,7 @@ mod test {
let message = Message::new(&[burn_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "burnChecked".to_string(),
info: json!({
@ -1078,7 +1078,7 @@ mod test {
let message = Message::new(&[sync_native_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(&compiled_instruction, &keys).unwrap(),
parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).unwrap(),
ParsedInstructionEnum {
instruction_type: "syncNative".to_string(),
info: json!({
@ -1107,10 +1107,10 @@ mod test {
.unwrap();
let message = Message::new(&[initialize_mint_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..1]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..1], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
let initialize_mint_ix = initialize_mint(
&spl_token::id(),
@ -1122,10 +1122,10 @@ mod test {
.unwrap();
let message = Message::new(&[initialize_mint_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..1]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..1], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test InitializeAccount
let initialize_account_ix = initialize_account(
@ -1137,10 +1137,10 @@ mod test {
.unwrap();
let message = Message::new(&[initialize_account_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..3]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..3], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test InitializeMultisig
let initialize_multisig_ix = initialize_multisig(
@ -1156,10 +1156,10 @@ mod test {
.unwrap();
let message = Message::new(&[initialize_multisig_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..4]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..4], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test Transfer, incl multisig
let transfer_ix = transfer(
@ -1173,10 +1173,10 @@ mod test {
.unwrap();
let message = Message::new(&[transfer_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
let transfer_ix = transfer(
&spl_token::id(),
@ -1189,10 +1189,10 @@ mod test {
.unwrap();
let message = Message::new(&[transfer_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..4]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..4], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test Approve, incl multisig
let approve_ix = approve(
@ -1206,10 +1206,10 @@ mod test {
.unwrap();
let message = Message::new(&[approve_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
let approve_ix = approve(
&spl_token::id(),
@ -1222,10 +1222,10 @@ mod test {
.unwrap();
let message = Message::new(&[approve_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..4]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..4], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test Revoke
let revoke_ix = revoke(
@ -1237,10 +1237,10 @@ mod test {
.unwrap();
let message = Message::new(&[revoke_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..1]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..1], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test SetAuthority
let set_authority_ix = set_authority(
@ -1254,10 +1254,10 @@ mod test {
.unwrap();
let message = Message::new(&[set_authority_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..1]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..1], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test MintTo
let mint_to_ix = mint_to(
@ -1271,10 +1271,10 @@ mod test {
.unwrap();
let message = Message::new(&[mint_to_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test Burn
let burn_ix = burn(
@ -1288,10 +1288,10 @@ mod test {
.unwrap();
let message = Message::new(&[burn_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test CloseAccount
let close_account_ix = close_account(
@ -1304,10 +1304,10 @@ mod test {
.unwrap();
let message = Message::new(&[close_account_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test FreezeAccount
let freeze_account_ix = freeze_account(
@ -1320,10 +1320,10 @@ mod test {
.unwrap();
let message = Message::new(&[freeze_account_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test ThawAccount
let thaw_account_ix = thaw_account(
@ -1336,10 +1336,10 @@ mod test {
.unwrap();
let message = Message::new(&[thaw_account_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test TransferChecked, incl multisig
let transfer_ix = transfer_checked(
@ -1355,10 +1355,10 @@ mod test {
.unwrap();
let message = Message::new(&[transfer_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..3]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..3], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
let transfer_ix = transfer_checked(
&spl_token::id(),
@ -1373,10 +1373,10 @@ mod test {
.unwrap();
let message = Message::new(&[transfer_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..5]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..5], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test ApproveChecked, incl multisig
let approve_ix = approve_checked(
@ -1392,10 +1392,10 @@ mod test {
.unwrap();
let message = Message::new(&[approve_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..3]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..3], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
let approve_ix = approve_checked(
&spl_token::id(),
@ -1410,10 +1410,10 @@ mod test {
.unwrap();
let message = Message::new(&[approve_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..5]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..5], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test MintToChecked
let mint_to_ix = mint_to_checked(
@ -1428,10 +1428,10 @@ mod test {
.unwrap();
let message = Message::new(&[mint_to_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test BurnChecked
let burn_ix = burn_checked(
@ -1446,18 +1446,18 @@ mod test {
.unwrap();
let message = Message::new(&[burn_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
// Test SyncNative
let sync_native_ix = sync_native(&spl_token::id(), &convert_pubkey(keys[0])).unwrap();
let message = Message::new(&[sync_native_ix], None);
let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert!(parse_token(&compiled_instruction, &[]).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&[], None)).is_err());
compiled_instruction.accounts =
compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
assert!(parse_token(&compiled_instruction, &keys).is_err());
assert!(parse_token(&compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
}
}

View File

@ -4,13 +4,13 @@ use {
},
bincode::deserialize,
serde_json::json,
solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey},
solana_sdk::{instruction::CompiledInstruction, message::AccountKeys},
solana_vote_program::vote_instruction::VoteInstruction,
};
pub fn parse_vote(
instruction: &CompiledInstruction,
account_keys: &[Pubkey],
account_keys: &AccountKeys,
) -> Result<ParsedInstructionEnum, ParseInstructionError> {
let vote_instruction: VoteInstruction = deserialize(&instruction.data)
.map_err(|_| ParseInstructionError::InstructionNotParsable(ParsableProgram::Vote))?;
@ -227,7 +227,11 @@ mod test {
);
let message = Message::new(&instructions, None);
assert_eq!(
parse_vote(&message.instructions[1], &keys[0..5]).unwrap(),
parse_vote(
&message.instructions[1],
&AccountKeys::new(&keys[0..5], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "initialize".to_string(),
info: json!({
@ -241,13 +245,21 @@ mod test {
}),
}
);
assert!(parse_vote(&message.instructions[1], &keys[0..3]).is_err());
assert!(parse_vote(
&message.instructions[1],
&AccountKeys::new(&keys[0..3], None)
)
.is_err());
let authority_type = VoteAuthorize::Voter;
let instruction = vote_instruction::authorize(&keys[1], &keys[0], &keys[3], authority_type);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_vote(&message.instructions[0], &keys[0..3]).unwrap(),
parse_vote(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "authorize".to_string(),
info: json!({
@ -259,12 +271,20 @@ mod test {
}),
}
);
assert!(parse_vote(&message.instructions[0], &keys[0..2]).is_err());
assert!(parse_vote(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.is_err());
let instruction = vote_instruction::vote(&keys[1], &keys[0], vote.clone());
let message = Message::new(&[instruction], None);
assert_eq!(
parse_vote(&message.instructions[0], &keys[0..4]).unwrap(),
parse_vote(
&message.instructions[0],
&AccountKeys::new(&keys[0..4], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "vote".to_string(),
info: json!({
@ -280,12 +300,20 @@ mod test {
}),
}
);
assert!(parse_vote(&message.instructions[0], &keys[0..3]).is_err());
assert!(parse_vote(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.is_err());
let instruction = vote_instruction::withdraw(&keys[1], &keys[0], lamports, &keys[2]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_vote(&message.instructions[0], &keys[0..3]).unwrap(),
parse_vote(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "withdraw".to_string(),
info: json!({
@ -296,12 +324,20 @@ mod test {
}),
}
);
assert!(parse_vote(&message.instructions[0], &keys[0..2]).is_err());
assert!(parse_vote(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.is_err());
let instruction = vote_instruction::update_validator_identity(&keys[2], &keys[1], &keys[0]);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_vote(&message.instructions[0], &keys[0..3]).unwrap(),
parse_vote(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "updateValidatorIdentity".to_string(),
info: json!({
@ -311,12 +347,20 @@ mod test {
}),
}
);
assert!(parse_vote(&message.instructions[0], &keys[0..2]).is_err());
assert!(parse_vote(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.is_err());
let instruction = vote_instruction::update_commission(&keys[1], &keys[0], commission);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_vote(&message.instructions[0], &keys[0..2]).unwrap(),
parse_vote(
&message.instructions[0],
&AccountKeys::new(&keys[0..2], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "updateCommission".to_string(),
info: json!({
@ -326,13 +370,21 @@ mod test {
}),
}
);
assert!(parse_vote(&message.instructions[0], &keys[0..1]).is_err());
assert!(parse_vote(
&message.instructions[0],
&AccountKeys::new(&keys[0..1], None)
)
.is_err());
let proof_hash = Hash::new_from_array([2; 32]);
let instruction = vote_instruction::vote_switch(&keys[1], &keys[0], vote, proof_hash);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_vote(&message.instructions[0], &keys[0..4]).unwrap(),
parse_vote(
&message.instructions[0],
&AccountKeys::new(&keys[0..4], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "voteSwitch".to_string(),
info: json!({
@ -349,14 +401,22 @@ mod test {
}),
}
);
assert!(parse_vote(&message.instructions[0], &keys[0..3]).is_err());
assert!(parse_vote(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.is_err());
let authority_type = VoteAuthorize::Voter;
let instruction =
vote_instruction::authorize_checked(&keys[1], &keys[0], &keys[3], authority_type);
let message = Message::new(&[instruction], None);
assert_eq!(
parse_vote(&message.instructions[0], &keys[0..4]).unwrap(),
parse_vote(
&message.instructions[0],
&AccountKeys::new(&keys[0..4], None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "authorizeChecked".to_string(),
info: json!({
@ -368,6 +428,10 @@ mod test {
}),
}
);
assert!(parse_vote(&message.instructions[0], &keys[0..3]).is_err());
assert!(parse_vote(
&message.instructions[0],
&AccountKeys::new(&keys[0..3], None)
)
.is_err());
}
}

View File

@ -62,14 +62,12 @@ pub fn collect_token_balances(
let mut collect_time = Measure::start("collect_token_balances");
for transaction in batch.sanitized_transactions() {
let has_token_program = transaction
.message()
.account_keys_iter()
.any(is_token_program);
let account_keys = transaction.message().account_keys();
let has_token_program = account_keys.iter().any(is_token_program);
let mut transaction_balances: Vec<TransactionTokenBalance> = vec![];
if has_token_program {
for (index, account_id) in transaction.message().account_keys_iter().enumerate() {
for (index, account_id) in account_keys.iter().enumerate() {
if transaction.message().is_invoked(index) || is_token_program(account_id) {
continue;
}