From 771395953b499cd250bf6482e86ca9c0af4cb2e5 Mon Sep 17 00:00:00 2001 From: Justin Starry Date: Tue, 2 Apr 2024 13:46:13 +0000 Subject: [PATCH] Plumb through reserved account keys set --- banks-server/src/banks_server.rs | 6 +++- .../immutable_deserialized_packet.rs | 5 +++- .../banking_stage/latest_unprocessed_votes.rs | 1 + .../scheduler_controller.rs | 7 ++++- .../unprocessed_transaction_storage.rs | 17 ++++++++--- ledger-tool/src/main.rs | 7 ++++- rpc/src/rpc.rs | 30 ++++++++++++++----- .../src/runtime_transaction.rs | 4 +++ runtime/src/bank.rs | 18 +++++++++-- runtime/src/bank/tests.rs | 3 +- runtime/src/bank_client.rs | 18 +++++------ sdk/program/src/message/legacy.rs | 13 ++++---- sdk/program/src/message/sanitized.rs | 25 +++++++++++----- sdk/program/src/message/versions/v0/loaded.rs | 30 +++++++++++++------ sdk/src/transaction/sanitized.rs | 26 ++++++++++++---- transaction-status/src/lib.rs | 16 ++++++++-- 16 files changed, 169 insertions(+), 57 deletions(-) diff --git a/banks-server/src/banks_server.rs b/banks-server/src/banks_server.rs index b3028c0132ed48..d6eec95d104089 100644 --- a/banks-server/src/banks_server.rs +++ b/banks-server/src/banks_server.rs @@ -178,6 +178,7 @@ fn simulate_transaction( MessageHash::Compute, Some(false), // is_simple_vote_tx bank, + bank.get_reserved_account_keys(), ) { Err(err) => { return BanksTransactionResultWithSimulation { @@ -332,6 +333,7 @@ impl Banks for BanksServer { MessageHash::Compute, Some(false), // is_simple_vote_tx bank.as_ref(), + bank.get_reserved_account_keys(), ) { Ok(tx) => tx, Err(err) => return Some(Err(err)), @@ -417,7 +419,9 @@ impl Banks for BanksServer { commitment: CommitmentLevel, ) -> Option { let bank = self.bank(commitment); - let sanitized_message = SanitizedMessage::try_from_legacy_message(message).ok()?; + let sanitized_message = + SanitizedMessage::try_from_legacy_message(message, bank.get_reserved_account_keys()) + .ok()?; bank.get_fee_for_message(&sanitized_message) } } diff --git a/core/src/banking_stage/immutable_deserialized_packet.rs b/core/src/banking_stage/immutable_deserialized_packet.rs index 8e31f9cd462473..fba145f3088652 100644 --- a/core/src/banking_stage/immutable_deserialized_packet.rs +++ b/core/src/banking_stage/immutable_deserialized_packet.rs @@ -6,6 +6,7 @@ use { feature_set, hash::Hash, message::Message, + pubkey::Pubkey, sanitize::SanitizeError, saturating_add_assign, short_vec::decode_shortu16_len, @@ -15,7 +16,7 @@ use { VersionedTransaction, }, }, - std::{cmp::Ordering, mem::size_of, sync::Arc}, + std::{cmp::Ordering, collections::HashSet, mem::size_of, sync::Arc}, thiserror::Error, }; @@ -123,6 +124,7 @@ impl ImmutableDeserializedPacket { feature_set: &Arc, votes_only: bool, address_loader: impl AddressLoader, + reserved_account_keys: &HashSet, ) -> Option { if votes_only && !self.is_simple_vote() { return None; @@ -132,6 +134,7 @@ impl ImmutableDeserializedPacket { *self.message_hash(), self.is_simple_vote(), address_loader, + reserved_account_keys, ) .ok()?; tx.verify_precompiles(feature_set).ok()?; diff --git a/core/src/banking_stage/latest_unprocessed_votes.rs b/core/src/banking_stage/latest_unprocessed_votes.rs index 6498f4c81ec381..44ed870e3fb86b 100644 --- a/core/src/banking_stage/latest_unprocessed_votes.rs +++ b/core/src/banking_stage/latest_unprocessed_votes.rs @@ -283,6 +283,7 @@ impl LatestUnprocessedVotes { &bank.feature_set, bank.vote_only_bank(), bank.as_ref(), + bank.get_reserved_account_keys(), ) { if forward_packet_batches_by_accounts.try_add_packet( diff --git a/core/src/banking_stage/transaction_scheduler/scheduler_controller.rs b/core/src/banking_stage/transaction_scheduler/scheduler_controller.rs index e608a3ba0699d3..8ca6594db6c971 100644 --- a/core/src/banking_stage/transaction_scheduler/scheduler_controller.rs +++ b/core/src/banking_stage/transaction_scheduler/scheduler_controller.rs @@ -381,7 +381,12 @@ impl SchedulerController { let (transactions, fee_budget_limits_vec): (Vec<_>, Vec<_>) = chunk .iter() .filter_map(|packet| { - packet.build_sanitized_transaction(feature_set, vote_only, bank.as_ref()) + packet.build_sanitized_transaction( + feature_set, + vote_only, + bank.as_ref(), + bank.get_reserved_account_keys(), + ) }) .inspect(|_| saturating_add_assign!(post_sanitization_count, 1)) .filter(|tx| { diff --git a/core/src/banking_stage/unprocessed_transaction_storage.rs b/core/src/banking_stage/unprocessed_transaction_storage.rs index 82ba08a3981532..c0c39276d63b2f 100644 --- a/core/src/banking_stage/unprocessed_transaction_storage.rs +++ b/core/src/banking_stage/unprocessed_transaction_storage.rs @@ -153,9 +153,13 @@ fn consume_scan_should_process_packet( } // Try to sanitize the packet - let (maybe_sanitized_transaction, sanitization_time_us) = measure_us!( - packet.build_sanitized_transaction(&bank.feature_set, bank.vote_only_bank(), bank) - ); + let (maybe_sanitized_transaction, sanitization_time_us) = measure_us!(packet + .build_sanitized_transaction( + &bank.feature_set, + bank.vote_only_bank(), + bank, + bank.get_reserved_account_keys(), + )); payload .slot_metrics_tracker @@ -770,7 +774,12 @@ impl ThreadLocalUnprocessedPackets { .enumerate() .filter_map(|(packet_index, deserialized_packet)| { deserialized_packet - .build_sanitized_transaction(&bank.feature_set, bank.vote_only_bank(), bank) + .build_sanitized_transaction( + &bank.feature_set, + bank.vote_only_bank(), + bank, + bank.get_reserved_account_keys(), + ) .map(|transaction| (transaction, packet_index)) }) .unzip(); diff --git a/ledger-tool/src/main.rs b/ledger-tool/src/main.rs index ab859ff0a7e689..3c1e23f6dfabe6 100644 --- a/ledger-tool/src/main.rs +++ b/ledger-tool/src/main.rs @@ -67,6 +67,7 @@ use { native_token::{lamports_to_sol, sol_to_lamports, Sol}, pubkey::Pubkey, rent::Rent, + reserved_account_keys::ReservedAccountKeys, shred_version::compute_shred_version, stake::{self, state::StakeStateV2}, system_program, @@ -461,6 +462,9 @@ fn compute_slot_cost( let mut program_ids = HashMap::new(); let mut cost_tracker = CostTracker::default(); + let feature_set = FeatureSet::all_enabled(); + let reserved_account_keys = ReservedAccountKeys::new_all_activated(); + for entry in entries { num_transactions += entry.transactions.len(); entry @@ -472,6 +476,7 @@ fn compute_slot_cost( MessageHash::Compute, None, SimpleAddressLoader::Disabled, + &reserved_account_keys.active, ) .map_err(|err| { warn!("Failed to compute cost of transaction: {:?}", err); @@ -481,7 +486,7 @@ fn compute_slot_cost( .for_each(|transaction| { num_programs += transaction.message().instructions().len(); - let tx_cost = CostModel::calculate_cost(&transaction, &FeatureSet::all_enabled()); + let tx_cost = CostModel::calculate_cost(&transaction, &feature_set); let result = cost_tracker.try_add(&tx_cost); if result.is_err() { println!( diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index c3b00fd9716410..81ffd50a56df2d 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -3657,7 +3657,11 @@ pub mod rpc_full { min_context_slot, })?; - let transaction = sanitize_transaction(unsanitized_tx, preflight_bank)?; + let transaction = sanitize_transaction( + unsanitized_tx, + preflight_bank, + preflight_bank.get_reserved_account_keys(), + )?; let signature = *transaction.signature(); let mut last_valid_block_height = preflight_bank @@ -3789,7 +3793,8 @@ pub mod rpc_full { }); } - let transaction = sanitize_transaction(unsanitized_tx, bank)?; + let transaction = + sanitize_transaction(unsanitized_tx, bank, bank.get_reserved_account_keys())?; if sig_verify { verify_transaction(&transaction, &bank.feature_set)?; } @@ -4041,10 +4046,12 @@ pub mod rpc_full { .map_err(|err| { Error::invalid_params(format!("invalid transaction message: {err}")) })?; - let sanitized_message = SanitizedMessage::try_new(sanitized_versioned_message, bank) - .map_err(|err| { - Error::invalid_params(format!("invalid transaction message: {err}")) - })?; + let sanitized_message = SanitizedMessage::try_new( + sanitized_versioned_message, + bank, + bank.get_reserved_account_keys(), + ) + .map_err(|err| Error::invalid_params(format!("invalid transaction message: {err}")))?; let fee = bank.get_fee_for_message(&sanitized_message); Ok(new_response(bank, fee)) } @@ -4623,9 +4630,16 @@ where fn sanitize_transaction( transaction: VersionedTransaction, address_loader: impl AddressLoader, + reserved_account_keys: &HashSet, ) -> Result { - SanitizedTransaction::try_create(transaction, MessageHash::Compute, None, address_loader) - .map_err(|err| Error::invalid_params(format!("invalid transaction: {err}"))) + SanitizedTransaction::try_create( + transaction, + MessageHash::Compute, + None, + address_loader, + reserved_account_keys, + ) + .map_err(|err| Error::invalid_params(format!("invalid transaction: {err}"))) } pub fn create_validator_exit(exit: Arc) -> Arc> { diff --git a/runtime-transaction/src/runtime_transaction.rs b/runtime-transaction/src/runtime_transaction.rs index 3ca7d4fb7920cd..bd4d4554f6e9b3 100644 --- a/runtime-transaction/src/runtime_transaction.rs +++ b/runtime-transaction/src/runtime_transaction.rs @@ -17,10 +17,12 @@ use { solana_sdk::{ hash::Hash, message::{AddressLoader, SanitizedMessage, SanitizedVersionedMessage}, + pubkey::Pubkey, signature::Signature, simple_vote_transaction_checker::is_simple_vote_transaction, transaction::{Result, SanitizedVersionedTransaction}, }, + std::collections::HashSet, }; #[derive(Debug, Clone, Eq, PartialEq)] @@ -101,12 +103,14 @@ impl RuntimeTransaction { pub fn try_from( statically_loaded_runtime_tx: RuntimeTransaction, address_loader: impl AddressLoader, + reserved_account_keys: &HashSet, ) -> Result { let mut tx = Self { signatures: statically_loaded_runtime_tx.signatures, message: SanitizedMessage::try_new( statically_loaded_runtime_tx.message, address_loader, + reserved_account_keys, )?, meta: statically_loaded_runtime_tx.meta, }; diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 8411d7773b71f9..48bb64ff1a3bcd 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -3470,7 +3470,15 @@ impl Bank { pub fn prepare_entry_batch(&self, txs: Vec) -> Result { let sanitized_txs = txs .into_iter() - .map(|tx| SanitizedTransaction::try_create(tx, MessageHash::Compute, None, self)) + .map(|tx| { + SanitizedTransaction::try_create( + tx, + MessageHash::Compute, + None, + self, + self.get_reserved_account_keys(), + ) + }) .collect::>>()?; let tx_account_lock_limit = self.get_transaction_account_lock_limit(); let lock_results = self @@ -5901,7 +5909,13 @@ impl Bank { tx.message.hash() }; - SanitizedTransaction::try_create(tx, message_hash, None, self) + SanitizedTransaction::try_create( + tx, + message_hash, + None, + self, + self.get_reserved_account_keys(), + ) }?; if verification_mode == TransactionVerificationMode::HashAndVerifyPrecompiles diff --git a/runtime/src/bank/tests.rs b/runtime/src/bank/tests.rs index 26e258247d818f..e60e2715126a3c 100644 --- a/runtime/src/bank/tests.rs +++ b/runtime/src/bank/tests.rs @@ -189,7 +189,8 @@ pub(in crate::bank) fn create_genesis_config(lamports: u64) -> (GenesisConfig, K } fn new_sanitized_message(message: Message) -> SanitizedMessage { - SanitizedMessage::try_from_legacy_message(message).unwrap() + SanitizedMessage::try_from_legacy_message(message, &ReservedAccountKeys::empty_key_set()) + .unwrap() } #[test] diff --git a/runtime/src/bank_client.rs b/runtime/src/bank_client.rs index 22a1631085870f..634cb0e28b09ab 100644 --- a/runtime/src/bank_client.rs +++ b/runtime/src/bank_client.rs @@ -285,15 +285,15 @@ impl SyncClient for BankClient { } fn get_fee_for_message(&self, message: &Message) -> Result { - SanitizedMessage::try_from_legacy_message(message.clone()) - .ok() - .and_then(|sanitized_message| self.bank.get_fee_for_message(&sanitized_message)) - .ok_or_else(|| { - TransportError::IoError(io::Error::new( - io::ErrorKind::Other, - "Unable calculate fee", - )) - }) + SanitizedMessage::try_from_legacy_message( + message.clone(), + self.bank.get_reserved_account_keys(), + ) + .ok() + .and_then(|sanitized_message| self.bank.get_fee_for_message(&sanitized_message)) + .ok_or_else(|| { + TransportError::IoError(io::Error::new(io::ErrorKind::Other, "Unable calculate fee")) + }) } } diff --git a/sdk/program/src/message/legacy.rs b/sdk/program/src/message/legacy.rs index 780259cd07fca4..6377552fe366f6 100644 --- a/sdk/program/src/message/legacy.rs +++ b/sdk/program/src/message/legacy.rs @@ -22,7 +22,7 @@ use { short_vec, system_instruction, system_program, sysvar, wasm_bindgen, }, lazy_static::lazy_static, - std::{convert::TryFrom, str::FromStr}, + std::{collections::HashSet, convert::TryFrom, str::FromStr}, }; lazy_static! { @@ -562,9 +562,9 @@ impl Message { /// locked when loaded for transaction processing in the runtime. This /// method differs from `is_maybe_writable` because it is aware of the /// latest reserved accounts which are not allowed to be write locked. - pub fn is_writable(&self, i: usize) -> bool { + pub fn is_writable(&self, i: usize, reserved_account_keys: &HashSet) -> bool { (self.is_writable_index(i)) - && !is_builtin_key_or_sysvar(&self.account_keys[i]) + && !reserved_account_keys.contains(&self.account_keys[i]) && !self.demote_program_id(i) } @@ -583,11 +583,14 @@ impl Message { } #[deprecated] - pub fn get_account_keys_by_lock_type(&self) -> (Vec<&Pubkey>, Vec<&Pubkey>) { + pub fn get_account_keys_by_lock_type( + &self, + reserved_account_keys: &HashSet, + ) -> (Vec<&Pubkey>, Vec<&Pubkey>) { let mut writable_keys = vec![]; let mut readonly_keys = vec![]; for (i, key) in self.account_keys.iter().enumerate() { - if self.is_writable(i) { + if self.is_writable(i, reserved_account_keys) { writable_keys.push(key); } else { readonly_keys.push(key); diff --git a/sdk/program/src/message/sanitized.rs b/sdk/program/src/message/sanitized.rs index ce276a60ef69e7..e6554ea60bbf12 100644 --- a/sdk/program/src/message/sanitized.rs +++ b/sdk/program/src/message/sanitized.rs @@ -17,7 +17,7 @@ use { solana_program::{system_instruction::SystemInstruction, system_program}, sysvar::instructions::{BorrowedAccountMeta, BorrowedInstruction}, }, - std::{borrow::Cow, convert::TryFrom}, + std::{borrow::Cow, collections::HashSet, convert::TryFrom}, thiserror::Error, }; @@ -31,12 +31,12 @@ pub struct LegacyMessage<'a> { } impl<'a> LegacyMessage<'a> { - pub fn new(message: legacy::Message) -> Self { + pub fn new(message: legacy::Message, reserved_account_keys: &HashSet) -> Self { let is_writable_account_cache = message .account_keys .iter() .enumerate() - .map(|(i, _key)| message.is_writable(i)) + .map(|(i, _key)| message.is_writable(i, reserved_account_keys)) .collect::>(); Self { message: Cow::Owned(message), @@ -105,23 +105,34 @@ impl SanitizedMessage { pub fn try_new( sanitized_msg: SanitizedVersionedMessage, address_loader: impl AddressLoader, + reserved_account_keys: &HashSet, ) -> Result { Ok(match sanitized_msg.message { VersionedMessage::Legacy(message) => { - SanitizedMessage::Legacy(LegacyMessage::new(message)) + SanitizedMessage::Legacy(LegacyMessage::new(message, reserved_account_keys)) } VersionedMessage::V0(message) => { let loaded_addresses = address_loader.load_addresses(&message.address_table_lookups)?; - SanitizedMessage::V0(v0::LoadedMessage::new(message, loaded_addresses)) + SanitizedMessage::V0(v0::LoadedMessage::new( + message, + loaded_addresses, + reserved_account_keys, + )) } }) } /// Create a sanitized legacy message - pub fn try_from_legacy_message(message: legacy::Message) -> Result { + pub fn try_from_legacy_message( + message: legacy::Message, + reserved_account_keys: &HashSet, + ) -> Result { message.sanitize()?; - Ok(Self::Legacy(LegacyMessage::new(message))) + Ok(Self::Legacy(LegacyMessage::new( + message, + reserved_account_keys, + ))) } /// Return true if this message contains duplicate account keys diff --git a/sdk/program/src/message/versions/v0/loaded.rs b/sdk/program/src/message/versions/v0/loaded.rs index c8edbff58b5522..dc9175c17978e1 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::is_builtin_key_or_sysvar, v0, AccountKeys}, + message::{v0, AccountKeys}, pubkey::Pubkey, }, std::{borrow::Cow, collections::HashSet}, @@ -55,32 +55,40 @@ impl LoadedAddresses { } impl<'a> LoadedMessage<'a> { - pub fn new(message: v0::Message, loaded_addresses: LoadedAddresses) -> Self { + pub fn new( + message: v0::Message, + loaded_addresses: LoadedAddresses, + reserved_account_keys: &HashSet, + ) -> Self { let mut loaded_message = Self { message: Cow::Owned(message), loaded_addresses: Cow::Owned(loaded_addresses), is_writable_account_cache: Vec::default(), }; - loaded_message.set_is_writable_account_cache(); + loaded_message.set_is_writable_account_cache(reserved_account_keys); loaded_message } - pub fn new_borrowed(message: &'a v0::Message, loaded_addresses: &'a LoadedAddresses) -> Self { + pub fn new_borrowed( + message: &'a v0::Message, + loaded_addresses: &'a LoadedAddresses, + reserved_account_keys: &HashSet, + ) -> Self { let mut loaded_message = Self { message: Cow::Borrowed(message), loaded_addresses: Cow::Borrowed(loaded_addresses), is_writable_account_cache: Vec::default(), }; - loaded_message.set_is_writable_account_cache(); + loaded_message.set_is_writable_account_cache(reserved_account_keys); loaded_message } - fn set_is_writable_account_cache(&mut self) { + fn set_is_writable_account_cache(&mut self, reserved_account_keys: &HashSet) { let is_writable_account_cache = self .account_keys() .iter() .enumerate() - .map(|(i, _key)| self.is_writable_internal(i)) + .map(|(i, _key)| self.is_writable_internal(i, reserved_account_keys)) .collect::>(); let _ = std::mem::replace( &mut self.is_writable_account_cache, @@ -127,10 +135,14 @@ impl<'a> LoadedMessage<'a> { } /// Returns true if the account at the specified index was loaded as writable - fn is_writable_internal(&self, key_index: usize) -> bool { + fn is_writable_internal( + &self, + key_index: usize, + reserved_account_keys: &HashSet, + ) -> bool { if self.is_writable_index(key_index) { if let Some(key) = self.account_keys().get(key_index) { - return !(is_builtin_key_or_sysvar(key) || self.demote_program_id(key_index)); + return !(reserved_account_keys.contains(key) || self.demote_program_id(key_index)); } } false diff --git a/sdk/src/transaction/sanitized.rs b/sdk/src/transaction/sanitized.rs index b7383b4a0a454c..bbaae62bfde9b9 100644 --- a/sdk/src/transaction/sanitized.rs +++ b/sdk/src/transaction/sanitized.rs @@ -12,6 +12,7 @@ use { }, precompiles::verify_if_precompile, pubkey::Pubkey, + reserved_account_keys::ReservedAccountKeys, sanitize::Sanitize, signature::Signature, simple_vote_transaction_checker::is_simple_vote_transaction, @@ -19,6 +20,7 @@ use { transaction::{Result, Transaction, TransactionError, VersionedTransaction}, }, solana_program::message::SanitizedVersionedMessage, + std::collections::HashSet, }; /// Maximum number of accounts that a transaction may lock. @@ -66,17 +68,22 @@ impl SanitizedTransaction { message_hash: Hash, is_simple_vote_tx: bool, address_loader: impl AddressLoader, + reserved_account_keys: &HashSet, ) -> Result { let signatures = tx.signatures; let SanitizedVersionedMessage { message } = tx.message; let message = match message { VersionedMessage::Legacy(message) => { - SanitizedMessage::Legacy(LegacyMessage::new(message)) + SanitizedMessage::Legacy(LegacyMessage::new(message, reserved_account_keys)) } VersionedMessage::V0(message) => { let loaded_addresses = address_loader.load_addresses(&message.address_table_lookups)?; - SanitizedMessage::V0(v0::LoadedMessage::new(message, loaded_addresses)) + SanitizedMessage::V0(v0::LoadedMessage::new( + message, + loaded_addresses, + reserved_account_keys, + )) } }; @@ -96,6 +103,7 @@ impl SanitizedTransaction { message_hash: impl Into, is_simple_vote_tx: Option, address_loader: impl AddressLoader, + reserved_account_keys: &HashSet, ) -> Result { let sanitized_versioned_tx = SanitizedVersionedTransaction::try_from(tx)?; let is_simple_vote_tx = is_simple_vote_tx @@ -109,15 +117,23 @@ impl SanitizedTransaction { message_hash, is_simple_vote_tx, address_loader, + reserved_account_keys, ) } - pub fn try_from_legacy_transaction(tx: Transaction) -> Result { + /// Create a sanitized transaction from a legacy transaction + pub fn try_from_legacy_transaction( + tx: Transaction, + reserved_account_keys: &HashSet, + ) -> Result { tx.sanitize()?; Ok(Self { message_hash: tx.message.hash(), - message: SanitizedMessage::Legacy(LegacyMessage::new(tx.message)), + message: SanitizedMessage::Legacy(LegacyMessage::new( + tx.message, + reserved_account_keys, + )), is_simple_vote_tx: false, signatures: tx.signatures, }) @@ -125,7 +141,7 @@ impl SanitizedTransaction { /// Create a sanitized transaction from a legacy transaction. Used for tests only. pub fn from_transaction_for_tests(tx: Transaction) -> Self { - Self::try_from_legacy_transaction(tx).unwrap() + Self::try_from_legacy_transaction(tx, &ReservedAccountKeys::empty_key_set()).unwrap() } /// Return the first signature for this transaction. diff --git a/transaction-status/src/lib.rs b/transaction-status/src/lib.rs index 0eb13d36819c4a..4028ff14bb62bb 100644 --- a/transaction-status/src/lib.rs +++ b/transaction-status/src/lib.rs @@ -19,6 +19,7 @@ use { AccountKeys, Message, MessageHeader, VersionedMessage, }, pubkey::Pubkey, + reserved_account_keys::ReservedAccountKeys, signature::Signature, transaction::{ Result as TransactionResult, Transaction, TransactionError, TransactionVersion, @@ -980,12 +981,16 @@ impl VersionedTransactionWithStatusMeta { show_rewards: bool, ) -> Result { let version = self.validate_version(max_supported_transaction_version)?; + let reserved_account_keys = ReservedAccountKeys::new_all_activated(); let account_keys = match &self.transaction.message { VersionedMessage::Legacy(message) => parse_legacy_message_accounts(message), VersionedMessage::V0(message) => { - let loaded_message = - LoadedMessage::new_borrowed(message, &self.meta.loaded_addresses); + let loaded_message = LoadedMessage::new_borrowed( + message, + &self.meta.loaded_addresses, + &reserved_account_keys.active, + ); parse_v0_message_accounts(&loaded_message) } }; @@ -1228,8 +1233,13 @@ impl EncodableWithMeta for v0::Message { meta: &TransactionStatusMeta, ) -> Self::Encoded { if encoding == UiTransactionEncoding::JsonParsed { + let reserved_account_keys = ReservedAccountKeys::new_all_activated(); let account_keys = AccountKeys::new(&self.account_keys, Some(&meta.loaded_addresses)); - let loaded_message = LoadedMessage::new_borrowed(self, &meta.loaded_addresses); + let loaded_message = LoadedMessage::new_borrowed( + self, + &meta.loaded_addresses, + &reserved_account_keys.active, + ); UiMessage::Parsed(UiParsedMessage { account_keys: parse_v0_message_accounts(&loaded_message), recent_blockhash: self.recent_blockhash.to_string(),