From c02d320fbcc899d9edc0b47225f6a4cfc6fb1503 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Wed, 5 Jan 2022 19:47:27 -0700 Subject: [PATCH] Only check rent-state of writable tx accounts --- runtime/src/account_rent_state.rs | 22 ++++++++++ runtime/src/bank.rs | 21 ++++----- .../bank/transaction_account_state_info.rs | 44 +++++++++---------- 3 files changed, 54 insertions(+), 33 deletions(-) diff --git a/runtime/src/account_rent_state.rs b/runtime/src/account_rent_state.rs index 46d22c0ce69baa..66e9abd6973e46 100644 --- a/runtime/src/account_rent_state.rs +++ b/runtime/src/account_rent_state.rs @@ -6,6 +6,8 @@ use { native_loader, rent::Rent, sysvar, + transaction::{Result, TransactionError}, + transaction_context::TransactionContext, }, }; @@ -52,6 +54,26 @@ pub(crate) fn submit_rent_state_metrics(pre_rent_state: &RentState, post_rent_st } } +pub(crate) fn check_rent_state( + pre_rent_state: Option<&RentState>, + post_rent_state: Option<&RentState>, + transaction_context: &TransactionContext, + index: usize, +) -> Result<()> { + if let Some((pre_rent_state, post_rent_state)) = pre_rent_state.zip(post_rent_state) { + if !post_rent_state.transition_allowed_from(pre_rent_state) { + debug!( + "Account {:?} not rent exempt, state {:?}", + transaction_context.get_key_of_account_at_index(index), + transaction_context.get_account_at_index(index).borrow(), + ); + submit_rent_state_metrics(pre_rent_state, post_rent_state); + return Err(TransactionError::InvalidRentPayingAccount); + } + } + Ok(()) +} + #[cfg(test)] mod tests { use {super::*, solana_sdk::pubkey::Pubkey}; diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 98ceec075352fc..5911a2f86d677d 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -3589,7 +3589,8 @@ impl Bank { compute_budget.max_invoke_depth.saturating_add(1), ); - let pre_account_state_info = self.get_transaction_account_state_info(&transaction_context); + let pre_account_state_info = + self.get_transaction_account_state_info(&transaction_context, tx.message()); let instruction_recorder = if enable_cpi_recording { Some(InstructionRecorder::new_ref( @@ -3635,7 +3636,8 @@ impl Bank { .and_then(|instruction_recorder| Rc::try_unwrap(instruction_recorder).ok()) .map(|instruction_recorder| instruction_recorder.into_inner().deconstruct()); - let post_account_state_info = self.get_transaction_account_state_info(&transaction_context); + let post_account_state_info = + self.get_transaction_account_state_info(&transaction_context, tx.message()); if self .feature_set @@ -15345,21 +15347,20 @@ pub(crate) mod tests { } fn mock_transfer_process_instruction( - first_instruction_account: usize, + _first_instruction_account: usize, data: &[u8], invoke_context: &mut InvokeContext, ) -> result::Result<(), InstructionError> { - let keyed_accounts = invoke_context.get_keyed_accounts()?; + let transaction_context = &invoke_context.transaction_context; + let instruction_context = transaction_context.get_current_instruction_context()?; if let Ok(instruction) = bincode::deserialize(data) { match instruction { MockTransferInstruction::Transfer(amount) => { - keyed_account_at_index(keyed_accounts, first_instruction_account + 1)? - .account - .borrow_mut() + instruction_context + .try_borrow_instruction_account(transaction_context, 1)? .checked_sub_lamports(amount)?; - keyed_account_at_index(keyed_accounts, first_instruction_account + 2)? - .account - .borrow_mut() + instruction_context + .try_borrow_instruction_account(transaction_context, 2)? .checked_add_lamports(amount)?; Ok(()) } diff --git a/runtime/src/bank/transaction_account_state_info.rs b/runtime/src/bank/transaction_account_state_info.rs index aa921a2f78c277..ee479c4a99bd83 100644 --- a/runtime/src/bank/transaction_account_state_info.rs +++ b/runtime/src/bank/transaction_account_state_info.rs @@ -1,31 +1,36 @@ use { crate::{ - account_rent_state::{submit_rent_state_metrics, RentState}, + account_rent_state::{check_rent_state, RentState}, bank::Bank, message_processor::ProcessedMessageInfo, }, - log::debug, solana_sdk::{ - transaction::{Result, TransactionError}, - transaction_context::TransactionContext, + message::SanitizedMessage, transaction::Result, transaction_context::TransactionContext, }, }; pub(crate) struct TransactionAccountStateInfo { - rent_state: RentState, + rent_state: Option, // None: readonly account } impl Bank { pub(crate) fn get_transaction_account_state_info( &self, transaction_context: &TransactionContext, + message: &SanitizedMessage, ) -> Vec { (0..transaction_context.get_number_of_accounts()) .map(|i| { - let account = transaction_context.get_account_at_index(i).borrow(); - TransactionAccountStateInfo { - rent_state: RentState::from_account(&account, &self.rent_collector().rent), - } + let rent_state = if message.is_writable(i) { + let account = transaction_context.get_account_at_index(i).borrow(); + Some(RentState::from_account( + &account, + &self.rent_collector().rent, + )) + } else { + None + }; + TransactionAccountStateInfo { rent_state } }) .collect() } @@ -40,20 +45,13 @@ impl Bank { for (i, (pre_state_info, post_state_info)) in pre_state_infos.iter().zip(post_state_infos).enumerate() { - if !post_state_info - .rent_state - .transition_allowed_from(&pre_state_info.rent_state) - { - debug!( - "Account {:?} not rent exempt, state {:?}", - transaction_context.get_key_of_account_at_index(i), - transaction_context.get_account_at_index(i).borrow(), - ); - submit_rent_state_metrics( - &pre_state_info.rent_state, - &post_state_info.rent_state, - ); - *process_result = Err(TransactionError::InvalidRentPayingAccount) + if let Err(err) = check_rent_state( + pre_state_info.rent_state.as_ref(), + post_state_info.rent_state.as_ref(), + transaction_context, + i, + ) { + *process_result = Err(err) } } }