From 8df2a4bac0954b004556c2fc2e5c6bb7b86d1028 Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Wed, 25 Nov 2020 16:18:00 -0700 Subject: [PATCH] runtime: Factor out `DurableNoncePartial` finishing logic and add tests --- runtime/src/accounts.rs | 39 ++------------- runtime/src/bank.rs | 103 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 106 insertions(+), 36 deletions(-) diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index 1d364f723c..74378eba43 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -359,40 +359,9 @@ impl Accounts { // Update hash_age_kind with fee-subtracted accounts let hash_age_kind = if let Some(hash_age_kind) = hash_age_kind { - match hash_age_kind { - HashAgeKind::Extant => Some(HashAgeKind::Extant), - HashAgeKind::DurableNoncePartial(pubkey, account) => { - let fee_payer = tx - .message() - .account_keys - .iter() - .enumerate() - .find(|(i, k)| Self::is_non_loader_key(tx.message(), k, *i)) - .map(|(i, k)| (*k, accounts[i].clone())); - if let Some((fee_pubkey, fee_account)) = fee_payer { - if fee_pubkey == pubkey { - Some(HashAgeKind::DurableNonceFull( - pubkey, - fee_account, - None, - )) - } else { - Some(HashAgeKind::DurableNonceFull( - pubkey, - account, - Some(fee_account), - )) - } - } else { - return ( - Err(TransactionError::AccountNotFound), - Some(HashAgeKind::DurableNoncePartial(pubkey, account)), - ); - } - } - HashAgeKind::DurableNonceFull(_, _, _) => { - panic!("update: unexpected HashAgeKind variant") - } + match hash_age_kind.finish_partial(tx.message(), &accounts) { + Ok(hash_age_kind) => Some(hash_age_kind), + Err(e) => return (Err(e), Some(hash_age_kind)), } } else { None @@ -815,7 +784,7 @@ impl Accounts { self.accounts_db.add_root(slot) } - fn is_non_loader_key(message: &Message, key: &Pubkey, key_index: usize) -> bool { + pub fn is_non_loader_key(message: &Message, key: &Pubkey, key_index: usize) -> bool { !message.program_ids().contains(&key) || message.is_key_passed_to_program(key_index) } diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 89898431e8..b83526d72b 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -471,6 +471,36 @@ impl HashAgeKind { } } } + + pub fn finish_partial(&self, message: &Message, accounts: &[Account]) -> Result { + match self { + HashAgeKind::Extant => Ok(HashAgeKind::Extant), + HashAgeKind::DurableNoncePartial(pubkey, account) => { + let fee_payer = message + .account_keys + .iter() + .enumerate() + .find(|(i, k)| Accounts::is_non_loader_key(message, k, *i)) + .and_then(|(i, k)| accounts.get(i).cloned().map(|a| (*k, a))); + if let Some((fee_pubkey, fee_account)) = fee_payer { + if fee_pubkey == *pubkey { + Ok(HashAgeKind::DurableNonceFull(*pubkey, fee_account, None)) + } else { + Ok(HashAgeKind::DurableNonceFull( + *pubkey, + account.clone(), + Some(fee_account), + )) + } + } else { + Err(TransactionError::AccountNotFound) + } + } + HashAgeKind::DurableNonceFull(_, _, _) => { + panic!("update: unexpected HashAgeKind variant") + } + } + } } // Bank's common fields shared by all supported snapshot versions for deserialization. @@ -4548,7 +4578,7 @@ pub(crate) mod tests { poh_config::PohConfig, process_instruction::InvokeContext, rent::Rent, - signature::{Keypair, Signer}, + signature::{keypair_from_seed, Keypair, Signer}, system_instruction::{self, SystemError}, system_program, sysvar::{fees::Fees, rewards::Rewards}, @@ -4620,6 +4650,77 @@ pub(crate) mod tests { ); } + #[test] + #[should_panic(expected = "update: unexpected HashAgeKind variant")] + fn test_hash_age_kind_finish_partial_full_panics() { + drop( + HashAgeKind::DurableNonceFull(Pubkey::default(), Account::default(), None) + .finish_partial(&Message::default(), &[]), + ); + } + + #[test] + fn test_hash_age_kind_finish_partial() { + let nonce_authority = keypair_from_seed(&[0; 32]).unwrap(); + let nonce_address = nonce_authority.pubkey(); + let from = keypair_from_seed(&[1; 32]).unwrap(); + let from_address = from.pubkey(); + let to_address = Pubkey::new_unique(); + let instructions = vec![ + system_instruction::advance_nonce_account(&nonce_address, &nonce_authority.pubkey()), + system_instruction::transfer(&from_address, &to_address, 42), + ]; + let message = Message::new(&instructions, Some(&from_address)); + + let from_account = Account::new(1, 0, &Pubkey::default()); + let nonce_account = Account::new(2, 0, &Pubkey::default()); + let to_account = Account::new(3, 0, &Pubkey::default()); + let recent_blockhashes_sysvar_account = Account::new(4, 0, &Pubkey::default()); + let accounts = [ + from_account.clone(), + nonce_account.clone(), + to_account.clone(), + recent_blockhashes_sysvar_account.clone(), + ]; + + assert_eq!( + HashAgeKind::Extant.finish_partial(&message, &accounts), + Ok(HashAgeKind::Extant) + ); + + let hash_age_kind = HashAgeKind::DurableNoncePartial(nonce_address, nonce_account.clone()); + assert_eq!( + hash_age_kind.finish_partial(&message, &accounts), + Ok(HashAgeKind::DurableNonceFull( + nonce_address, + nonce_account.clone(), + Some(from_account.clone()) + )), + ); + + assert_eq!( + hash_age_kind.finish_partial(&message, &[]), + Err(TransactionError::AccountNotFound), + ); + + let message = Message::new(&instructions, Some(&nonce_address)); + let accounts = [ + nonce_account.clone(), + from_account, + to_account, + recent_blockhashes_sysvar_account, + ]; + + assert_eq!( + hash_age_kind.finish_partial(&message, &accounts), + Ok(HashAgeKind::DurableNonceFull( + nonce_address, + nonce_account, + None + )), + ); + } + #[test] fn test_bank_unix_timestamp_from_genesis() { let (genesis_config, _mint_keypair) = create_genesis_config(1);