diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 0616d55b04..4b4c002092 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -118,7 +118,7 @@ impl ExecuteTimings { } type BankStatusCache = StatusCache>; -#[frozen_abi(digest = "3TYCJ7hSJ5ig2NmnwxSn1ggkzm6JCmMHoyRMBQQsLCa3")] +#[frozen_abi(digest = "F3Ubz2Sx973pKSYNHTEmj6LY3te1DKUo3fs3cgzQ1uqJ")] pub type BankSlotDelta = SlotDelta>; type TransactionAccountRefCells = Vec>>; type TransactionAccountDepRefCells = Vec<(Pubkey, Rc>)>; @@ -2798,18 +2798,26 @@ impl Bank { loaders: &mut TransactionLoaders, mut account_refcells: TransactionAccountRefCells, loader_refcells: TransactionLoaderRefCells, - ) { - account_refcells.drain(..).for_each(|account_refcell| { - accounts.push(Rc::try_unwrap(account_refcell).unwrap().into_inner()) - }); - loaders - .iter_mut() - .zip(loader_refcells) - .for_each(|(ls, mut lrcs)| { - lrcs.drain(..).for_each(|(pubkey, lrc)| { - ls.push((pubkey, Rc::try_unwrap(lrc).unwrap().into_inner())) - }) - }); + ) -> std::result::Result<(), TransactionError> { + for account_refcell in account_refcells.drain(..) { + accounts.push( + Rc::try_unwrap(account_refcell) + .map_err(|_| TransactionError::AccountBorrowOutstanding)? + .into_inner(), + ) + } + for (ls, mut lrcs) in loaders.iter_mut().zip(loader_refcells) { + for (pubkey, lrc) in lrcs.drain(..) { + ls.push(( + pubkey, + Rc::try_unwrap(lrc) + .map_err(|_| TransactionError::AccountBorrowOutstanding)? + .into_inner(), + )) + } + } + + Ok(()) } fn compile_recorded_instructions( @@ -2974,7 +2982,7 @@ impl Bank { None }; - let process_result = self.message_processor.process_message( + let mut process_result = self.message_processor.process_message( tx.message(), &loader_refcells, &account_refcells, @@ -3005,12 +3013,15 @@ impl Bank { &tx.message, ); - Self::refcells_to_accounts( + if let Err(e) = Self::refcells_to_accounts( &mut loaded_transaction.accounts, &mut loaded_transaction.loaders, account_refcells, loader_refcells, - ); + ) { + warn!("Account lifetime mismanagement"); + process_result = Err(e); + } if process_result.is_ok() { self.update_executors(executors); diff --git a/sdk/program/src/instruction.rs b/sdk/program/src/instruction.rs index a8813e08ee..b6847c27d4 100644 --- a/sdk/program/src/instruction.rs +++ b/sdk/program/src/instruction.rs @@ -108,7 +108,7 @@ pub enum InstructionError { AccountBorrowFailed, /// Account data has an outstanding reference after a program's execution - #[error("instruction left account with an outstanding reference borrowed")] + #[error("instruction left account with an outstanding borrowed reference")] AccountBorrowOutstanding, /// The same account was multiply passed to an on-chain program's entrypoint, but the program diff --git a/sdk/src/transaction.rs b/sdk/src/transaction.rs index 781b5fb958..fd15382732 100644 --- a/sdk/src/transaction.rs +++ b/sdk/src/transaction.rs @@ -94,6 +94,10 @@ pub enum TransactionError { #[error("Transactions are currently disabled due to cluster maintenance")] ClusterMaintenance, + + /// Transaction processing left an account with an outstanding borrowed reference + #[error("Transaction processing left an account with an outstanding borrowed reference")] + AccountBorrowOutstanding, } pub type Result = result::Result; diff --git a/storage-proto/proto/solana.storage.transaction_by_addr.rs b/storage-proto/proto/solana.storage.transaction_by_addr.rs index 49aa771b64..58aae3b291 100644 --- a/storage-proto/proto/solana.storage.transaction_by_addr.rs +++ b/storage-proto/proto/solana.storage.transaction_by_addr.rs @@ -66,6 +66,7 @@ pub enum TransactionErrorType { InvalidProgramForExecution = 13, SanitizeFailure = 14, ClusterMaintenance = 15, + AccountBorrowOutstanding = 16, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] diff --git a/storage-proto/src/convert.rs b/storage-proto/src/convert.rs index 99b45c563c..5f98420087 100644 --- a/storage-proto/src/convert.rs +++ b/storage-proto/src/convert.rs @@ -529,6 +529,7 @@ impl TryFrom for TransactionError { 13 => TransactionError::InvalidProgramForExecution, 14 => TransactionError::SanitizeFailure, 15 => TransactionError::ClusterMaintenance, + 16 => TransactionError::AccountBorrowOutstanding, _ => return Err("Invalid TransactionError"), }) } @@ -584,6 +585,9 @@ impl From for tx_by_addr::TransactionError { TransactionError::InstructionError(_, _) => { tx_by_addr::TransactionErrorType::InstructionError } + TransactionError::AccountBorrowOutstanding => { + tx_by_addr::TransactionErrorType::AccountBorrowOutstanding + } } as i32, instruction_error: match transaction_error { TransactionError::InstructionError(index, ref instruction_error) => {