diff --git a/ledger/src/blockstore.rs b/ledger/src/blockstore.rs index e97f005d32..c8dc170800 100644 --- a/ledger/src/blockstore.rs +++ b/ledger/src/blockstore.rs @@ -6262,7 +6262,7 @@ pub mod tests { .map(|transaction| { let mut pre_balances: Vec = vec![]; let mut post_balances: Vec = 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 = vec![]; let mut post_balances: Vec = 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 = vec![]; let mut post_balances: Vec = 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(), ) diff --git a/ledger/src/blockstore/blockstore_purge.rs b/ledger/src/blockstore/blockstore_purge.rs index af9dffebb3..83bf6cbbab 100644 --- a/ledger/src/blockstore/blockstore_purge.rs +++ b/ledger/src/blockstore/blockstore_purge.rs @@ -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::((0, signature, slot))?; batch.delete::((1, signature, slot))?; - for pubkey in transaction.message.into_static_account_keys() { - batch.delete::((0, pubkey, slot, signature))?; - batch.delete::((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::((0, address, slot, signature))?; - batch.delete::((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::((0, *pubkey, slot, signature))?; + batch.delete::((1, *pubkey, slot, signature))?; } } } diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index af2149e3f9..b57fffc4a1 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -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, diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index 7c845d257b..483fb8eb22 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -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)) { diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 07d1892b78..bf724cb4e3 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -838,7 +838,7 @@ impl NonceFull { accounts: &[TransactionAccount], rent_debits: &RentDebits, ) -> Result { - 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 = 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, ), ]; diff --git a/runtime/src/bank/transaction_account_state_info.rs b/runtime/src/bank/transaction_account_state_info.rs index 0eb1434854..a2c2442eff 100644 --- a/runtime/src/bank/transaction_account_state_info.rs +++ b/runtime/src/bank/transaction_account_state_info.rs @@ -19,7 +19,7 @@ impl Bank { transaction_context: &TransactionContext, message: &SanitizedMessage, ) -> Vec { - (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) { diff --git a/runtime/src/cost_model.rs b/runtime/src/cost_model.rs index cd8c029d47..cd04a22732 100644 --- a/runtime/src/cost_model.rs +++ b/runtime/src/cost_model.rs @@ -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 { diff --git a/runtime/src/vote_parser.rs b/runtime/src/vote_parser.rs index fa04f216be..7e26f2bee3 100644 --- a/runtime/src/vote_parser.rs +++ b/runtime/src/vote_parser.rs @@ -44,7 +44,7 @@ pub fn parse_sanitized_vote_transaction(tx: &SanitizedTransaction) -> Option { + static_keys: &'a [Pubkey], + dynamic_keys: Option<&'a LoadedAddresses>, +} + +impl Index 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 { + 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 { + 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])); + } +} diff --git a/sdk/program/src/message/mod.rs b/sdk/program/src/message/mod.rs index b63e84a720..39921ede6b 100644 --- a/sdk/program/src/message/mod.rs +++ b/sdk/program/src/message/mod.rs @@ -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; diff --git a/sdk/program/src/message/sanitized.rs b/sdk/program/src/message/sanitized.rs index 2a0f5f9380..41e8a7d495 100644 --- a/sdk/program/src/message/sanitized.rs +++ b/sdk/program/src/message/sanitized.rs @@ -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 + '_> { + /// 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::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 { + 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) } }) }) diff --git a/sdk/program/src/message/versions/mod.rs b/sdk/program/src/message/versions/mod.rs index 1b1d21047d..e128c79487 100644 --- a/sdk/program/src/message/versions/mod.rs +++ b/sdk/program/src/message/versions/mod.rs @@ -50,45 +50,6 @@ impl VersionedMessage { } } - pub fn into_static_account_keys(self) -> Vec { - match self { - Self::Legacy(message) => message.account_keys, - Self::V0(message) => message.account_keys, - } - } - - pub fn static_account_keys_iter(&self) -> impl Iterator { - 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, diff --git a/sdk/program/src/message/versions/v0/loaded.rs b/sdk/program/src/message/versions/v0/loaded.rs index c3959427eb..4684f17eb1 100644 --- a/sdk/program/src/message/versions/v0/loaded.rs +++ b/sdk/program/src/message/versions/v0/loaded.rs @@ -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 { - 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 { - 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> { - 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 { - 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; diff --git a/sdk/src/transaction/sanitized.rs b/sdk/src/transaction/sanitized.rs index e4902d427d..8b7cb2994b 100644 --- a/sdk/src/transaction/sanitized.rs +++ b/sdk/src/transaction/sanitized.rs @@ -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) { diff --git a/sdk/src/transaction/versioned.rs b/sdk/src/transaction/versioned.rs index 222260d822..2e36f21dd1 100644 --- a/sdk/src/transaction/versioned.rs +++ b/sdk/src/transaction/versioned.rs @@ -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 { 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() } diff --git a/storage-bigtable/src/lib.rs b/storage-bigtable/src/lib.rs index 237ca758bd..c882cfd9a7 100644 --- a/storage-bigtable/src/lib.rs +++ b/storage-bigtable/src/lib.rs @@ -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); } diff --git a/transaction-status/src/extract_memos.rs b/transaction-status/src/extract_memos.rs index 1eccdc5b3b..9e8308ae67 100644 --- a/transaction-status/src/extract_memos.rs +++ b/transaction-status/src/extract_memos.rs @@ -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 { - 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 { - 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 { 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, +fn extract_memos_inner( + account_keys: &AccountKeys, instructions: &[CompiledInstruction], ) -> Vec { - let mut account_keys: Vec = account_keys.map(KeyType::Unknown).collect(); + let mut account_keys: Vec = 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 ); } diff --git a/transaction-status/src/lib.rs b/transaction-status/src/lib.rs index 25c54fb7e9..386f1e932a 100644 --- a/transaction-status/src/lib.rs +++ b/transaction-status/src/lib.rs @@ -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 { - 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 { @@ -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 { diff --git a/transaction-status/src/parse_associated_token.rs b/transaction-status/src/parse_associated_token.rs index 71f67a8ee4..e4ff83ef7b 100644 --- a/transaction-status/src/parse_associated_token.rs +++ b/transaction-status/src/parse_associated_token.rs @@ -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 { 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!({ diff --git a/transaction-status/src/parse_bpf_loader.rs b/transaction-status/src/parse_bpf_loader.rs index 4d02825834..68a01c9ab7 100644 --- a/transaction-status/src/parse_bpf_loader.rs +++ b/transaction-status/src/parse_bpf_loader.rs @@ -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 { 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 { 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()); } } diff --git a/transaction-status/src/parse_instruction.rs b/transaction-status/src/parse_instruction.rs index 47c70c13c6..563e0f0b54 100644 --- a/transaction-status/src/parse_instruction.rs +++ b/transaction-status/src/parse_instruction.rs @@ -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 { 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] diff --git a/transaction-status/src/parse_stake.rs b/transaction-status/src/parse_stake.rs index 5bcf4800ef..00022c5260 100644 --- a/transaction-status/src/parse_stake.rs +++ b/transaction-status/src/parse_stake.rs @@ -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 { 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()); } } diff --git a/transaction-status/src/parse_system.rs b/transaction-status/src/parse_system.rs index 8c4a391f52..c9da69003d 100644 --- a/transaction-status/src/parse_system.rs +++ b/transaction-status/src/parse_system.rs @@ -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 { 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()); } } diff --git a/transaction-status/src/parse_token.rs b/transaction-status/src/parse_token.rs index dec6a8ac2d..3e84fd9dee 100644 --- a/transaction-status/src/parse_token.rs +++ b/transaction-status/src/parse_token.rs @@ -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 { let token_instruction = TokenInstruction::unpack(&instruction.data) .map_err(|_| ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken))?; @@ -411,7 +411,7 @@ impl From for UiAuthorityType { fn parse_signers( map: &mut Map, 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 = 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()); } } diff --git a/transaction-status/src/parse_vote.rs b/transaction-status/src/parse_vote.rs index 7f1ea4ade2..f50336a597 100644 --- a/transaction-status/src/parse_vote.rs +++ b/transaction-status/src/parse_vote.rs @@ -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 { 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()); } } diff --git a/transaction-status/src/token_balances.rs b/transaction-status/src/token_balances.rs index a95664097b..8de5f0e030 100644 --- a/transaction-status/src/token_balances.rs +++ b/transaction-status/src/token_balances.rs @@ -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 = 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; }