runtime: Replace `HashAgeKind` with `NonceRollbackInfo`

This commit is contained in:
Trent Nelson 2020-11-29 12:21:55 -07:00 committed by mergify[bot]
parent 274312ebb5
commit 404fc1570d
6 changed files with 304 additions and 324 deletions

View File

@ -23,7 +23,7 @@ use solana_perf::{
}; };
use solana_runtime::{ use solana_runtime::{
accounts_db::ErrorCounters, accounts_db::ErrorCounters,
bank::{Bank, TransactionBalancesSet, TransactionProcessResult}, bank::{Bank, TransactionBalancesSet, TransactionCheckResult, TransactionExecutionResult},
bank_utils, bank_utils,
transaction_batch::TransactionBatch, transaction_batch::TransactionBatch,
vote_sender_types::ReplayVoteSender, vote_sender_types::ReplayVoteSender,
@ -460,7 +460,7 @@ impl BankingStage {
fn record_transactions( fn record_transactions(
bank_slot: Slot, bank_slot: Slot,
txs: &[Transaction], txs: &[Transaction],
results: &[TransactionProcessResult], results: &[TransactionExecutionResult],
poh: &Arc<Mutex<PohRecorder>>, poh: &Arc<Mutex<PohRecorder>>,
) -> (Result<usize, PohRecorderError>, Vec<usize>) { ) -> (Result<usize, PohRecorderError>, Vec<usize>) {
let mut processed_generation = Measure::start("record::process_generation"); let mut processed_generation = Measure::start("record::process_generation");
@ -578,7 +578,7 @@ impl BankingStage {
bank.clone(), bank.clone(),
batch.transactions(), batch.transactions(),
batch.iteration_order_vec(), batch.iteration_order_vec(),
tx_results.processing_results, tx_results.execution_results,
TransactionBalancesSet::new(pre_balances, post_balances), TransactionBalancesSet::new(pre_balances, post_balances),
inner_instructions, inner_instructions,
transaction_logs, transaction_logs,
@ -719,7 +719,7 @@ impl BankingStage {
// This function returns a vector containing index of all valid transactions. A valid // This function returns a vector containing index of all valid transactions. A valid
// transaction has result Ok() as the value // transaction has result Ok() as the value
fn filter_valid_transaction_indexes( fn filter_valid_transaction_indexes(
valid_txs: &[TransactionProcessResult], valid_txs: &[TransactionCheckResult],
transaction_indexes: &[usize], transaction_indexes: &[usize],
) -> Vec<usize> { ) -> Vec<usize> {
let valid_transactions = valid_txs let valid_transactions = valid_txs
@ -1093,7 +1093,6 @@ mod tests {
get_tmp_ledger_path, get_tmp_ledger_path,
}; };
use solana_perf::packet::to_packets; use solana_perf::packet::to_packets;
use solana_runtime::bank::HashAgeKind;
use solana_sdk::{ use solana_sdk::{
instruction::InstructionError, instruction::InstructionError,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
@ -1457,10 +1456,7 @@ mod tests {
system_transaction::transfer(&keypair2, &pubkey2, 1, genesis_config.hash()), system_transaction::transfer(&keypair2, &pubkey2, 1, genesis_config.hash()),
]; ];
let mut results = vec![ let mut results = vec![(Ok(()), None), (Ok(()), None)];
(Ok(()), Some(HashAgeKind::Extant)),
(Ok(()), Some(HashAgeKind::Extant)),
];
let _ = BankingStage::record_transactions( let _ = BankingStage::record_transactions(
bank.slot(), bank.slot(),
&transactions, &transactions,
@ -1476,7 +1472,7 @@ mod tests {
1, 1,
SystemError::ResultWithNegativeLamports.into(), SystemError::ResultWithNegativeLamports.into(),
)), )),
Some(HashAgeKind::Extant), None,
); );
let (res, retryable) = BankingStage::record_transactions( let (res, retryable) = BankingStage::record_transactions(
bank.slot(), bank.slot(),
@ -1652,10 +1648,10 @@ mod tests {
&[ &[
(Err(TransactionError::BlockhashNotFound), None), (Err(TransactionError::BlockhashNotFound), None),
(Err(TransactionError::BlockhashNotFound), None), (Err(TransactionError::BlockhashNotFound), None),
(Ok(()), Some(HashAgeKind::Extant)), (Ok(()), None),
(Err(TransactionError::BlockhashNotFound), None), (Err(TransactionError::BlockhashNotFound), None),
(Ok(()), Some(HashAgeKind::Extant)), (Ok(()), None),
(Ok(()), Some(HashAgeKind::Extant)), (Ok(()), None),
], ],
&[2, 4, 5, 9, 11, 13] &[2, 4, 5, 9, 11, 13]
), ),
@ -1665,12 +1661,12 @@ mod tests {
assert_eq!( assert_eq!(
BankingStage::filter_valid_transaction_indexes( BankingStage::filter_valid_transaction_indexes(
&[ &[
(Ok(()), Some(HashAgeKind::Extant)), (Ok(()), None),
(Err(TransactionError::BlockhashNotFound), None), (Err(TransactionError::BlockhashNotFound), None),
(Err(TransactionError::BlockhashNotFound), None), (Err(TransactionError::BlockhashNotFound), None),
(Ok(()), Some(HashAgeKind::Extant)), (Ok(()), None),
(Ok(()), Some(HashAgeKind::Extant)), (Ok(()), None),
(Ok(()), Some(HashAgeKind::Extant)), (Ok(()), None),
], ],
&[1, 6, 7, 9, 31, 43] &[1, 6, 7, 9, 31, 43]
), ),

View File

@ -1,7 +1,10 @@
use crossbeam_channel::{Receiver, RecvTimeoutError}; use crossbeam_channel::{Receiver, RecvTimeoutError};
use itertools::izip; use itertools::izip;
use solana_ledger::{blockstore::Blockstore, blockstore_processor::TransactionStatusBatch}; use solana_ledger::{blockstore::Blockstore, blockstore_processor::TransactionStatusBatch};
use solana_runtime::{bank::Bank, transaction_utils::OrderedIterator}; use solana_runtime::{
bank::{Bank, NonceRollbackInfo},
transaction_utils::OrderedIterator,
};
use solana_transaction_status::{InnerInstructions, TransactionStatusMeta}; use solana_transaction_status::{InnerInstructions, TransactionStatusMeta};
use std::{ use std::{
sync::{ sync::{
@ -58,7 +61,7 @@ impl TransactionStatusService {
let slot = bank.slot(); let slot = bank.slot();
for ( for (
(_, transaction), (_, transaction),
(status, hash_age_kind), (status, nonce_rollback),
pre_balances, pre_balances,
post_balances, post_balances,
inner_instructions, inner_instructions,
@ -72,8 +75,8 @@ impl TransactionStatusService {
transaction_logs transaction_logs
) { ) {
if Bank::can_commit(&status) && !transaction.signatures.is_empty() { if Bank::can_commit(&status) && !transaction.signatures.is_empty() {
let fee_calculator = hash_age_kind let fee_calculator = nonce_rollback
.and_then(|hash_age_kind| hash_age_kind.fee_calculator()) .map(|nonce_rollback| nonce_rollback.fee_calculator())
.unwrap_or_else(|| { .unwrap_or_else(|| {
bank.get_fee_calculator(&transaction.message().recent_blockhash) bank.get_fee_calculator(&transaction.message().recent_blockhash)
}) })

View File

@ -16,8 +16,8 @@ use solana_metrics::{datapoint_error, inc_new_counter_debug};
use solana_rayon_threadlimit::get_thread_count; use solana_rayon_threadlimit::get_thread_count;
use solana_runtime::{ use solana_runtime::{
bank::{ bank::{
Bank, InnerInstructionsList, TransactionBalancesSet, TransactionLogMessages, Bank, InnerInstructionsList, TransactionBalancesSet, TransactionExecutionResult,
TransactionProcessResult, TransactionResults, TransactionLogMessages, TransactionResults,
}, },
bank_forks::BankForks, bank_forks::BankForks,
bank_utils, bank_utils,
@ -115,7 +115,7 @@ fn execute_batch(
let TransactionResults { let TransactionResults {
fee_collection_results, fee_collection_results,
processing_results, execution_results,
.. ..
} = tx_results; } = tx_results;
@ -124,7 +124,7 @@ fn execute_batch(
bank.clone(), bank.clone(),
batch.transactions(), batch.transactions(),
batch.iteration_order_vec(), batch.iteration_order_vec(),
processing_results, execution_results,
balances, balances,
inner_instructions, inner_instructions,
transaction_logs, transaction_logs,
@ -1029,7 +1029,7 @@ pub struct TransactionStatusBatch {
pub bank: Arc<Bank>, pub bank: Arc<Bank>,
pub transactions: Vec<Transaction>, pub transactions: Vec<Transaction>,
pub iteration_order: Option<Vec<usize>>, pub iteration_order: Option<Vec<usize>>,
pub statuses: Vec<TransactionProcessResult>, pub statuses: Vec<TransactionExecutionResult>,
pub balances: TransactionBalancesSet, pub balances: TransactionBalancesSet,
pub inner_instructions: Vec<Option<InnerInstructionsList>>, pub inner_instructions: Vec<Option<InnerInstructionsList>>,
pub transaction_logs: Vec<TransactionLogMessages>, pub transaction_logs: Vec<TransactionLogMessages>,
@ -1041,7 +1041,7 @@ pub fn send_transaction_status_batch(
bank: Arc<Bank>, bank: Arc<Bank>,
transactions: &[Transaction], transactions: &[Transaction],
iteration_order: Option<Vec<usize>>, iteration_order: Option<Vec<usize>>,
statuses: Vec<TransactionProcessResult>, statuses: Vec<TransactionExecutionResult>,
balances: TransactionBalancesSet, balances: TransactionBalancesSet,
inner_instructions: Vec<Option<InnerInstructionsList>>, inner_instructions: Vec<Option<InnerInstructionsList>>,
transaction_logs: Vec<TransactionLogMessages>, transaction_logs: Vec<TransactionLogMessages>,

View File

@ -4,7 +4,9 @@ use crate::{
}, },
accounts_index::{AccountsIndex, Ancestors}, accounts_index::{AccountsIndex, Ancestors},
append_vec::StoredAccount, append_vec::StoredAccount,
bank::{HashAgeKind, TransactionProcessResult}, bank::{
NonceRollbackFull, NonceRollbackInfo, TransactionCheckResult, TransactionExecutionResult,
},
blockhash_queue::BlockhashQueue, blockhash_queue::BlockhashQueue,
rent_collector::RentCollector, rent_collector::RentCollector,
system_instruction_processor::{get_system_account_kind, SystemAccountKind}, system_instruction_processor::{get_system_account_kind, SystemAccountKind},
@ -63,7 +65,10 @@ pub type TransactionAccounts = Vec<Account>;
pub type TransactionRent = u64; pub type TransactionRent = u64;
pub type TransactionLoaders = Vec<Vec<(Pubkey, Account)>>; pub type TransactionLoaders = Vec<Vec<(Pubkey, Account)>>;
pub type TransactionLoadResult = (TransactionAccounts, TransactionLoaders, TransactionRent); pub type TransactionLoadResult = (
Result<(TransactionAccounts, TransactionLoaders, TransactionRent)>,
Option<NonceRollbackFull>,
);
pub enum AccountAddressFilter { pub enum AccountAddressFilter {
Exclude, // exclude all addresses matching the filter Exclude, // exclude all addresses matching the filter
@ -300,12 +305,12 @@ impl Accounts {
ancestors: &Ancestors, ancestors: &Ancestors,
txs: &[Transaction], txs: &[Transaction],
txs_iteration_order: Option<&[usize]>, txs_iteration_order: Option<&[usize]>,
lock_results: Vec<TransactionProcessResult>, lock_results: Vec<TransactionCheckResult>,
hash_queue: &BlockhashQueue, hash_queue: &BlockhashQueue,
error_counters: &mut ErrorCounters, error_counters: &mut ErrorCounters,
rent_collector: &RentCollector, rent_collector: &RentCollector,
feature_set: &FeatureSet, feature_set: &FeatureSet,
) -> Vec<(Result<TransactionLoadResult>, Option<HashAgeKind>)> { ) -> Vec<TransactionLoadResult> {
let accounts_index = &self.accounts_db.accounts_index; let accounts_index = &self.accounts_db.accounts_index;
let fee_config = FeeConfig { let fee_config = FeeConfig {
@ -315,10 +320,10 @@ impl Accounts {
OrderedIterator::new(txs, txs_iteration_order) OrderedIterator::new(txs, txs_iteration_order)
.zip(lock_results.into_iter()) .zip(lock_results.into_iter())
.map(|etx| match etx { .map(|etx| match etx {
((_, tx), (Ok(()), hash_age_kind)) => { ((_, tx), (Ok(()), nonce_rollback)) => {
let fee_calculator = hash_age_kind let fee_calculator = nonce_rollback
.as_ref() .as_ref()
.and_then(|hash_age_kind| hash_age_kind.fee_calculator()) .map(|nonce_rollback| nonce_rollback.fee_calculator())
.unwrap_or_else(|| { .unwrap_or_else(|| {
hash_queue hash_queue
.get_fee_calculator(&tx.message().recent_blockhash) .get_fee_calculator(&tx.message().recent_blockhash)
@ -327,7 +332,7 @@ impl Accounts {
let fee = if let Some(fee_calculator) = fee_calculator { let fee = if let Some(fee_calculator) = fee_calculator {
fee_calculator.calculate_fee_with_config(tx.message(), &fee_config) fee_calculator.calculate_fee_with_config(tx.message(), &fee_config)
} else { } else {
return (Err(TransactionError::BlockhashNotFound), hash_age_kind); return (Err(TransactionError::BlockhashNotFound), None);
}; };
let load_res = self.load_tx_accounts( let load_res = self.load_tx_accounts(
@ -342,7 +347,7 @@ impl Accounts {
); );
let (accounts, rents) = match load_res { let (accounts, rents) = match load_res {
Ok((a, r)) => (a, r), Ok((a, r)) => (a, r),
Err(e) => return (Err(e), hash_age_kind), Err(e) => return (Err(e), None),
}; };
let load_res = Self::load_loaders( let load_res = Self::load_loaders(
@ -354,22 +359,26 @@ impl Accounts {
); );
let loaders = match load_res { let loaders = match load_res {
Ok(loaders) => loaders, Ok(loaders) => loaders,
Err(e) => return (Err(e), hash_age_kind), Err(e) => return (Err(e), None),
}; };
// Update hash_age_kind with fee-subtracted accounts // Update nonce_rollback with fee-subtracted accounts
let hash_age_kind = if let Some(hash_age_kind) = hash_age_kind { let nonce_rollback = if let Some(nonce_rollback) = nonce_rollback {
match hash_age_kind.finish_partial(tx.message(), &accounts) { match NonceRollbackFull::from_partial(
Ok(hash_age_kind) => Some(hash_age_kind), nonce_rollback,
Err(e) => return (Err(e), Some(hash_age_kind)), tx.message(),
&accounts,
) {
Ok(nonce_rollback) => Some(nonce_rollback),
Err(e) => return (Err(e), None),
} }
} else { } else {
None None
}; };
(Ok((accounts, loaders, rents)), hash_age_kind) (Ok((accounts, loaders, rents)), nonce_rollback)
} }
(_, (Err(e), hash_age_kind)) => (Err(e), hash_age_kind), (_, (Err(e), _nonce_rollback)) => (Err(e), None),
}) })
.collect() .collect()
} }
@ -754,8 +763,8 @@ impl Accounts {
slot: Slot, slot: Slot,
txs: &[Transaction], txs: &[Transaction],
txs_iteration_order: Option<&[usize]>, txs_iteration_order: Option<&[usize]>,
res: &[TransactionProcessResult], res: &[TransactionExecutionResult],
loaded: &mut [(Result<TransactionLoadResult>, Option<HashAgeKind>)], loaded: &mut [TransactionLoadResult],
rent_collector: &RentCollector, rent_collector: &RentCollector,
last_blockhash_with_fee_calculator: &(Hash, FeeCalculator), last_blockhash_with_fee_calculator: &(Hash, FeeCalculator),
fix_recent_blockhashes_sysvar_delay: bool, fix_recent_blockhashes_sysvar_delay: bool,
@ -792,15 +801,15 @@ impl Accounts {
&self, &self,
txs: &'a [Transaction], txs: &'a [Transaction],
txs_iteration_order: Option<&'a [usize]>, txs_iteration_order: Option<&'a [usize]>,
res: &'a [TransactionProcessResult], res: &'a [TransactionExecutionResult],
loaded: &'a mut [(Result<TransactionLoadResult>, Option<HashAgeKind>)], loaded: &'a mut [TransactionLoadResult],
rent_collector: &RentCollector, rent_collector: &RentCollector,
last_blockhash_with_fee_calculator: &(Hash, FeeCalculator), last_blockhash_with_fee_calculator: &(Hash, FeeCalculator),
fix_recent_blockhashes_sysvar_delay: bool, fix_recent_blockhashes_sysvar_delay: bool,
rent_fix_enabled: bool, rent_fix_enabled: bool,
) -> Vec<(&'a Pubkey, &'a Account)> { ) -> Vec<(&'a Pubkey, &'a Account)> {
let mut accounts = Vec::with_capacity(loaded.len()); let mut accounts = Vec::with_capacity(loaded.len());
for (i, ((raccs, _hash_age_kind), (_, tx))) in loaded for (i, ((raccs, _nonce_rollback), (_, tx))) in loaded
.iter_mut() .iter_mut()
.zip(OrderedIterator::new(txs, txs_iteration_order)) .zip(OrderedIterator::new(txs, txs_iteration_order))
.enumerate() .enumerate()
@ -808,20 +817,22 @@ impl Accounts {
if raccs.is_err() { if raccs.is_err() {
continue; continue;
} }
let (res, hash_age_kind) = &res[i]; let (res, nonce_rollback) = &res[i];
let maybe_nonce = match (res, hash_age_kind) { let maybe_nonce_rollback = match (res, nonce_rollback) {
(Ok(_), Some(HashAgeKind::DurableNonceFull(pubkey, acc, maybe_fee_account))) => { (Ok(_), Some(nonce_rollback)) => {
let pubkey = nonce_rollback.nonce_address();
let acc = nonce_rollback.nonce_account();
let maybe_fee_account = nonce_rollback.fee_account();
Some((pubkey, acc, maybe_fee_account)) Some((pubkey, acc, maybe_fee_account))
} }
( (Err(TransactionError::InstructionError(_, _)), Some(nonce_rollback)) => {
Err(TransactionError::InstructionError(_, _)), let pubkey = nonce_rollback.nonce_address();
Some(HashAgeKind::DurableNonceFull(pubkey, acc, maybe_fee_account)), let acc = nonce_rollback.nonce_account();
) => Some((pubkey, acc, maybe_fee_account)), let maybe_fee_account = nonce_rollback.fee_account();
(_, Some(HashAgeKind::DurableNoncePartial(_, _))) => { Some((pubkey, acc, maybe_fee_account))
panic!("collect: unexpected HashAgeKind variant")
} }
(Ok(_), _hash_age_kind) => None, (Ok(_), _nonce_rollback) => None,
(Err(_), _hash_age_kind) => continue, (Err(_), _nonce_rollback) => continue,
}; };
let message = &tx.message(); let message = &tx.message();
@ -838,7 +849,7 @@ impl Accounts {
account, account,
key, key,
res, res,
maybe_nonce, maybe_nonce_rollback,
last_blockhash_with_fee_calculator, last_blockhash_with_fee_calculator,
fix_recent_blockhashes_sysvar_delay, fix_recent_blockhashes_sysvar_delay,
); );
@ -848,10 +859,10 @@ impl Accounts {
let is_fee_payer = Some(i) == fee_payer_index; let is_fee_payer = Some(i) == fee_payer_index;
if message.is_writable(i) if message.is_writable(i)
&& (res.is_ok() && (res.is_ok()
|| (maybe_nonce.is_some() && (is_nonce_account || is_fee_payer))) || (maybe_nonce_rollback.is_some() && (is_nonce_account || is_fee_payer)))
{ {
if res.is_err() { if res.is_err() {
match (is_nonce_account, is_fee_payer, maybe_nonce) { match (is_nonce_account, is_fee_payer, maybe_nonce_rollback) {
// nonce is fee-payer, state updated in `prepare_if_nonce_account()` // nonce is fee-payer, state updated in `prepare_if_nonce_account()`
(true, true, Some((_, _, None))) => (), (true, true, Some((_, _, None))) => (),
// nonce not fee-payer, state updated in `prepare_if_nonce_account()` // nonce not fee-payer, state updated in `prepare_if_nonce_account()`
@ -882,11 +893,11 @@ pub fn prepare_if_nonce_account(
account: &mut Account, account: &mut Account,
account_pubkey: &Pubkey, account_pubkey: &Pubkey,
tx_result: &Result<()>, tx_result: &Result<()>,
maybe_nonce: Option<(&Pubkey, &Account, &Option<Account>)>, maybe_nonce_rollback: Option<(&Pubkey, &Account, Option<&Account>)>,
last_blockhash_with_fee_calculator: &(Hash, FeeCalculator), last_blockhash_with_fee_calculator: &(Hash, FeeCalculator),
fix_recent_blockhashes_sysvar_delay: bool, fix_recent_blockhashes_sysvar_delay: bool,
) -> bool { ) -> bool {
if let Some((nonce_key, nonce_acc, _maybe_fee_account)) = maybe_nonce { if let Some((nonce_key, nonce_acc, _maybe_fee_account)) = maybe_nonce_rollback {
if account_pubkey == nonce_key { if account_pubkey == nonce_key {
let overwrite = if tx_result.is_err() { let overwrite = if tx_result.is_err() {
// Nonce TX failed with an InstructionError. Roll back // Nonce TX failed with an InstructionError. Roll back
@ -947,7 +958,7 @@ mod tests {
// TODO: all the bank tests are bank specific, issue: 2194 // TODO: all the bank tests are bank specific, issue: 2194
use super::*; use super::*;
use crate::{bank::HashAgeKind, rent_collector::RentCollector}; use crate::rent_collector::RentCollector;
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
epoch_schedule::EpochSchedule, epoch_schedule::EpochSchedule,
@ -972,7 +983,7 @@ mod tests {
fee_calculator: &FeeCalculator, fee_calculator: &FeeCalculator,
rent_collector: &RentCollector, rent_collector: &RentCollector,
error_counters: &mut ErrorCounters, error_counters: &mut ErrorCounters,
) -> Vec<(Result<TransactionLoadResult>, Option<HashAgeKind>)> { ) -> Vec<TransactionLoadResult> {
let mut hash_queue = BlockhashQueue::new(100); let mut hash_queue = BlockhashQueue::new(100);
hash_queue.register_hash(&tx.message().recent_blockhash, &fee_calculator); hash_queue.register_hash(&tx.message().recent_blockhash, &fee_calculator);
let accounts = Accounts::new(Vec::new(), &ClusterType::Development); let accounts = Accounts::new(Vec::new(), &ClusterType::Development);
@ -985,7 +996,7 @@ mod tests {
&ancestors, &ancestors,
&[tx], &[tx],
None, None,
vec![(Ok(()), Some(HashAgeKind::Extant))], vec![(Ok(()), None)],
&hash_queue, &hash_queue,
error_counters, error_counters,
rent_collector, rent_collector,
@ -998,7 +1009,7 @@ mod tests {
ka: &[(Pubkey, Account)], ka: &[(Pubkey, Account)],
fee_calculator: &FeeCalculator, fee_calculator: &FeeCalculator,
error_counters: &mut ErrorCounters, error_counters: &mut ErrorCounters,
) -> Vec<(Result<TransactionLoadResult>, Option<HashAgeKind>)> { ) -> Vec<TransactionLoadResult> {
let rent_collector = RentCollector::default(); let rent_collector = RentCollector::default();
load_accounts_with_fee_and_rent(tx, ka, fee_calculator, &rent_collector, error_counters) load_accounts_with_fee_and_rent(tx, ka, fee_calculator, &rent_collector, error_counters)
} }
@ -1007,7 +1018,7 @@ mod tests {
tx: Transaction, tx: Transaction,
ka: &[(Pubkey, Account)], ka: &[(Pubkey, Account)],
error_counters: &mut ErrorCounters, error_counters: &mut ErrorCounters,
) -> Vec<(Result<TransactionLoadResult>, Option<HashAgeKind>)> { ) -> Vec<TransactionLoadResult> {
let fee_calculator = FeeCalculator::default(); let fee_calculator = FeeCalculator::default();
load_accounts_with_fee(tx, ka, &fee_calculator, error_counters) load_accounts_with_fee(tx, ka, &fee_calculator, error_counters)
} }
@ -1032,10 +1043,7 @@ mod tests {
assert_eq!(loaded_accounts.len(), 1); assert_eq!(loaded_accounts.len(), 1);
assert_eq!( assert_eq!(
loaded_accounts[0], loaded_accounts[0],
( (Err(TransactionError::AccountNotFound), None,)
Err(TransactionError::AccountNotFound),
Some(HashAgeKind::Extant)
)
); );
} }
@ -1061,10 +1069,7 @@ mod tests {
assert_eq!(loaded_accounts.len(), 1); assert_eq!(loaded_accounts.len(), 1);
assert_eq!( assert_eq!(
loaded_accounts[0], loaded_accounts[0],
( (Err(TransactionError::AccountNotFound), None,),
Err(TransactionError::AccountNotFound),
Some(HashAgeKind::Extant)
),
); );
} }
@ -1098,10 +1103,7 @@ mod tests {
assert_eq!(loaded_accounts.len(), 1); assert_eq!(loaded_accounts.len(), 1);
assert_eq!( assert_eq!(
loaded_accounts[0], loaded_accounts[0],
( (Err(TransactionError::ProgramAccountNotFound), None,)
Err(TransactionError::ProgramAccountNotFound),
Some(HashAgeKind::Extant)
)
); );
} }
@ -1135,10 +1137,7 @@ mod tests {
assert_eq!(loaded_accounts.len(), 1); assert_eq!(loaded_accounts.len(), 1);
assert_eq!( assert_eq!(
loaded_accounts[0].clone(), loaded_accounts[0].clone(),
( (Err(TransactionError::InsufficientFundsForFee), None,),
Err(TransactionError::InsufficientFundsForFee),
Some(HashAgeKind::Extant)
),
); );
} }
@ -1168,10 +1167,7 @@ mod tests {
assert_eq!(loaded_accounts.len(), 1); assert_eq!(loaded_accounts.len(), 1);
assert_eq!( assert_eq!(
loaded_accounts[0], loaded_accounts[0],
( (Err(TransactionError::InvalidAccountForFee), None,),
Err(TransactionError::InvalidAccountForFee),
Some(HashAgeKind::Extant)
),
); );
} }
@ -1219,7 +1215,7 @@ mod tests {
&mut error_counters, &mut error_counters,
); );
assert_eq!(loaded_accounts.len(), 1); assert_eq!(loaded_accounts.len(), 1);
let (load_res, _hash_age_kind) = &loaded_accounts[0]; let (load_res, _nonce_rollback) = &loaded_accounts[0];
let (tx_accounts, _loaders, _rents) = load_res.as_ref().unwrap(); let (tx_accounts, _loaders, _rents) = load_res.as_ref().unwrap();
assert_eq!(tx_accounts[0].lamports, min_balance); assert_eq!(tx_accounts[0].lamports, min_balance);
@ -1233,7 +1229,7 @@ mod tests {
&mut error_counters, &mut error_counters,
); );
assert_eq!(loaded_accounts.len(), 1); assert_eq!(loaded_accounts.len(), 1);
let (load_res, _hash_age_kind) = &loaded_accounts[0]; let (load_res, _nonce_rollback) = &loaded_accounts[0];
assert_eq!(*load_res, Err(TransactionError::InsufficientFundsForFee)); assert_eq!(*load_res, Err(TransactionError::InsufficientFundsForFee));
// Fee leaves non-zero, but sub-min_balance balance fails // Fee leaves non-zero, but sub-min_balance balance fails
@ -1246,7 +1242,7 @@ mod tests {
&mut error_counters, &mut error_counters,
); );
assert_eq!(loaded_accounts.len(), 1); assert_eq!(loaded_accounts.len(), 1);
let (load_res, _hash_age_kind) = &loaded_accounts[0]; let (load_res, _nonce_rollback) = &loaded_accounts[0];
assert_eq!(*load_res, Err(TransactionError::InsufficientFundsForFee)); assert_eq!(*load_res, Err(TransactionError::InsufficientFundsForFee));
} }
@ -1283,14 +1279,14 @@ mod tests {
match &loaded_accounts[0] { match &loaded_accounts[0] {
( (
Ok((transaction_accounts, transaction_loaders, _transaction_rents)), Ok((transaction_accounts, transaction_loaders, _transaction_rents)),
_hash_age_kind, _nonce_rollback,
) => { ) => {
assert_eq!(transaction_accounts.len(), 3); assert_eq!(transaction_accounts.len(), 3);
assert_eq!(transaction_accounts[0], accounts[0].1); assert_eq!(transaction_accounts[0], accounts[0].1);
assert_eq!(transaction_loaders.len(), 1); assert_eq!(transaction_loaders.len(), 1);
assert_eq!(transaction_loaders[0].len(), 0); assert_eq!(transaction_loaders[0].len(), 0);
} }
(Err(e), _hash_age_kind) => Err(e).unwrap(), (Err(e), _nonce_rollback) => Err(e).unwrap(),
} }
} }
@ -1356,10 +1352,7 @@ mod tests {
assert_eq!(loaded_accounts.len(), 1); assert_eq!(loaded_accounts.len(), 1);
assert_eq!( assert_eq!(
loaded_accounts[0], loaded_accounts[0],
( (Err(TransactionError::CallChainTooDeep), None,)
Err(TransactionError::CallChainTooDeep),
Some(HashAgeKind::Extant)
)
); );
} }
@ -1394,10 +1387,7 @@ mod tests {
assert_eq!(loaded_accounts.len(), 1); assert_eq!(loaded_accounts.len(), 1);
assert_eq!( assert_eq!(
loaded_accounts[0], loaded_accounts[0],
( (Err(TransactionError::InvalidProgramForExecution), None,)
Err(TransactionError::InvalidProgramForExecution),
Some(HashAgeKind::Extant)
)
); );
} }
@ -1432,10 +1422,7 @@ mod tests {
assert_eq!(loaded_accounts.len(), 1); assert_eq!(loaded_accounts.len(), 1);
assert_eq!( assert_eq!(
loaded_accounts[0], loaded_accounts[0],
( (Err(TransactionError::ProgramAccountNotFound), None,)
Err(TransactionError::ProgramAccountNotFound),
Some(HashAgeKind::Extant)
)
); );
} }
@ -1469,10 +1456,7 @@ mod tests {
assert_eq!(loaded_accounts.len(), 1); assert_eq!(loaded_accounts.len(), 1);
assert_eq!( assert_eq!(
loaded_accounts[0], loaded_accounts[0],
( (Err(TransactionError::InvalidProgramForExecution), None,)
Err(TransactionError::InvalidProgramForExecution),
Some(HashAgeKind::Extant)
)
); );
} }
@ -1521,7 +1505,7 @@ mod tests {
match &loaded_accounts[0] { match &loaded_accounts[0] {
( (
Ok((transaction_accounts, transaction_loaders, _transaction_rents)), Ok((transaction_accounts, transaction_loaders, _transaction_rents)),
_hash_age_kind, _nonce_rollback,
) => { ) => {
assert_eq!(transaction_accounts.len(), 3); assert_eq!(transaction_accounts.len(), 3);
assert_eq!(transaction_accounts[0], accounts[0].1); assert_eq!(transaction_accounts[0], accounts[0].1);
@ -1535,7 +1519,7 @@ mod tests {
} }
} }
} }
(Err(e), _hash_age_kind) => Err(e).unwrap(), (Err(e), _nonce_rollback) => Err(e).unwrap(),
} }
} }
@ -1807,10 +1791,7 @@ mod tests {
let tx1 = Transaction::new(&[&keypair1], message, Hash::default()); let tx1 = Transaction::new(&[&keypair1], message, Hash::default());
let txs = vec![tx0, tx1]; let txs = vec![tx0, tx1];
let loaders = vec![ let loaders = vec![(Ok(()), None), (Ok(()), None)];
(Ok(()), Some(HashAgeKind::Extant)),
(Ok(()), Some(HashAgeKind::Extant)),
];
let account0 = Account::new(1, 0, &Pubkey::default()); let account0 = Account::new(1, 0, &Pubkey::default());
let account1 = Account::new(2, 0, &Pubkey::default()); let account1 = Account::new(2, 0, &Pubkey::default());
@ -1825,7 +1806,7 @@ mod tests {
transaction_loaders0, transaction_loaders0,
transaction_rent0, transaction_rent0,
)), )),
Some(HashAgeKind::Extant), None,
); );
let transaction_accounts1 = vec![account1, account2]; let transaction_accounts1 = vec![account1, account2];
@ -1837,7 +1818,7 @@ mod tests {
transaction_loaders1, transaction_loaders1,
transaction_rent1, transaction_rent1,
)), )),
Some(HashAgeKind::Extant), None,
); );
let mut loaded = vec![loaded0, loaded1]; let mut loaded = vec![loaded0, loaded1];
@ -1913,10 +1894,7 @@ mod tests {
accounts.accounts_db.clean_accounts(None); accounts.accounts_db.clean_accounts(None);
} }
fn load_accounts_no_store( fn load_accounts_no_store(accounts: &Accounts, tx: Transaction) -> Vec<TransactionLoadResult> {
accounts: &Accounts,
tx: Transaction,
) -> Vec<(Result<TransactionLoadResult>, Option<HashAgeKind>)> {
let rent_collector = RentCollector::default(); let rent_collector = RentCollector::default();
let fee_calculator = FeeCalculator::new(10); let fee_calculator = FeeCalculator::new(10);
let mut hash_queue = BlockhashQueue::new(100); let mut hash_queue = BlockhashQueue::new(100);
@ -1928,7 +1906,7 @@ mod tests {
&ancestors, &ancestors,
&[tx], &[tx],
None, None,
vec![(Ok(()), Some(HashAgeKind::Extant))], vec![(Ok(()), None)],
&hash_queue, &hash_queue,
&mut error_counters, &mut error_counters,
&rent_collector, &rent_collector,
@ -1989,12 +1967,12 @@ mod tests {
account: &mut Account, account: &mut Account,
account_pubkey: &Pubkey, account_pubkey: &Pubkey,
tx_result: &Result<()>, tx_result: &Result<()>,
maybe_nonce: Option<(&Pubkey, &Account, &Option<Account>)>, maybe_nonce_rollback: Option<(&Pubkey, &Account, Option<&Account>)>,
last_blockhash_with_fee_calculator: &(Hash, FeeCalculator), last_blockhash_with_fee_calculator: &(Hash, FeeCalculator),
expect_account: &Account, expect_account: &Account,
) -> bool { ) -> bool {
// Verify expect_account's relationship // Verify expect_account's relationship
match maybe_nonce { match maybe_nonce_rollback {
Some((nonce_pubkey, _nonce_account, _maybe_fee_account)) Some((nonce_pubkey, _nonce_account, _maybe_fee_account))
if nonce_pubkey == account_pubkey && tx_result.is_ok() => if nonce_pubkey == account_pubkey && tx_result.is_ok() =>
{ {
@ -2012,7 +1990,7 @@ mod tests {
account, account,
account_pubkey, account_pubkey,
tx_result, tx_result,
maybe_nonce, maybe_nonce_rollback,
last_blockhash_with_fee_calculator, last_blockhash_with_fee_calculator,
true, true,
); );
@ -2041,7 +2019,11 @@ mod tests {
&mut post_account, &mut post_account,
&post_account_pubkey, &post_account_pubkey,
&Ok(()), &Ok(()),
Some((&pre_account_pubkey, &pre_account, &maybe_fee_account)), Some((
&pre_account_pubkey,
&pre_account,
maybe_fee_account.as_ref()
)),
&(last_blockhash, last_fee_calculator), &(last_blockhash, last_fee_calculator),
&expect_account, &expect_account,
)); ));
@ -2088,7 +2070,11 @@ mod tests {
&mut post_account, &mut post_account,
&Pubkey::new(&[1u8; 32]), &Pubkey::new(&[1u8; 32]),
&Ok(()), &Ok(()),
Some((&pre_account_pubkey, &pre_account, &maybe_fee_account)), Some((
&pre_account_pubkey,
&pre_account,
maybe_fee_account.as_ref()
)),
&(last_blockhash, last_fee_calculator), &(last_blockhash, last_fee_calculator),
&expect_account, &expect_account,
)); ));
@ -2124,7 +2110,11 @@ mod tests {
0, 0,
InstructionError::InvalidArgument, InstructionError::InvalidArgument,
)), )),
Some((&pre_account_pubkey, &pre_account, &maybe_fee_account)), Some((
&pre_account_pubkey,
&pre_account,
maybe_fee_account.as_ref()
)),
&(last_blockhash, last_fee_calculator), &(last_blockhash, last_fee_calculator),
&expect_account, &expect_account,
)); ));
@ -2158,7 +2148,7 @@ mod tests {
let nonce_account_pre = Account::new_data(42, &nonce_state, &system_program::id()).unwrap(); let nonce_account_pre = Account::new_data(42, &nonce_state, &system_program::id()).unwrap();
let from_account_pre = Account::new(4242, 0, &Pubkey::default()); let from_account_pre = Account::new(4242, 0, &Pubkey::default());
let hash_age_kind = Some(HashAgeKind::DurableNonceFull( let nonce_rollback = Some(NonceRollbackFull::new(
nonce_address, nonce_address,
nonce_account_pre.clone(), nonce_account_pre.clone(),
Some(from_account_pre.clone()), Some(from_account_pre.clone()),
@ -2168,7 +2158,7 @@ mod tests {
1, 1,
InstructionError::InvalidArgument, InstructionError::InvalidArgument,
)), )),
hash_age_kind.clone(), nonce_rollback.clone(),
)]; )];
let nonce_state = let nonce_state =
@ -2196,7 +2186,7 @@ mod tests {
let transaction_rent = 0; let transaction_rent = 0;
let loaded = ( let loaded = (
Ok((transaction_accounts, transaction_loaders, transaction_rent)), Ok((transaction_accounts, transaction_loaders, transaction_rent)),
hash_age_kind, nonce_rollback,
); );
let mut loaded = vec![loaded]; let mut loaded = vec![loaded];
@ -2263,7 +2253,7 @@ mod tests {
})); }));
let nonce_account_pre = Account::new_data(42, &nonce_state, &system_program::id()).unwrap(); let nonce_account_pre = Account::new_data(42, &nonce_state, &system_program::id()).unwrap();
let hash_age_kind = Some(HashAgeKind::DurableNonceFull( let nonce_rollback = Some(NonceRollbackFull::new(
nonce_address, nonce_address,
nonce_account_pre.clone(), nonce_account_pre.clone(),
None, None,
@ -2273,7 +2263,7 @@ mod tests {
1, 1,
InstructionError::InvalidArgument, InstructionError::InvalidArgument,
)), )),
hash_age_kind.clone(), nonce_rollback.clone(),
)]; )];
let nonce_state = let nonce_state =
@ -2301,7 +2291,7 @@ mod tests {
let transaction_rent = 0; let transaction_rent = 0;
let loaded = ( let loaded = (
Ok((transaction_accounts, transaction_loaders, transaction_rent)), Ok((transaction_accounts, transaction_loaders, transaction_rent)),
hash_age_kind, nonce_rollback,
); );
let mut loaded = vec![loaded]; let mut loaded = vec![loaded];

View File

@ -369,10 +369,11 @@ impl StatusCacheRc {
} }
} }
pub type TransactionProcessResult = (Result<()>, Option<HashAgeKind>); pub type TransactionCheckResult = (Result<()>, Option<NonceRollbackPartial>);
pub type TransactionExecutionResult = (Result<()>, Option<NonceRollbackFull>);
pub struct TransactionResults { pub struct TransactionResults {
pub fee_collection_results: Vec<Result<()>>, pub fee_collection_results: Vec<Result<()>>,
pub processing_results: Vec<TransactionProcessResult>, pub execution_results: Vec<TransactionExecutionResult>,
pub overwritten_vote_accounts: Vec<OverwrittenVoteAccount>, pub overwritten_vote_accounts: Vec<OverwrittenVoteAccount>,
} }
pub struct TransactionBalancesSet { pub struct TransactionBalancesSet {
@ -444,65 +445,113 @@ pub struct TransactionLogCollector {
pub mentioned_address_map: HashMap<Pubkey, Vec<usize>>, pub mentioned_address_map: HashMap<Pubkey, Vec<usize>>,
} }
#[derive(Clone, Debug, Eq, PartialEq)] pub trait NonceRollbackInfo {
pub enum HashAgeKind { fn nonce_address(&self) -> &Pubkey;
Extant, fn nonce_account(&self) -> &Account;
DurableNoncePartial(Pubkey, Account), fn fee_calculator(&self) -> Option<FeeCalculator>;
DurableNonceFull(Pubkey, Account, Option<Account>), fn fee_account(&self) -> Option<&Account>;
} }
impl HashAgeKind { #[derive(Clone, Debug, Default, PartialEq)]
pub fn is_durable_nonce(&self) -> bool { pub struct NonceRollbackPartial {
match self { nonce_address: Pubkey,
Self::Extant => false, nonce_account: Account,
Self::DurableNoncePartial(_, _) => true, }
Self::DurableNonceFull(_, _, _) => true,
impl NonceRollbackPartial {
pub fn new(nonce_address: Pubkey, nonce_account: Account) -> Self {
Self {
nonce_address,
nonce_account,
} }
} }
}
pub fn fee_calculator(&self) -> Option<Option<FeeCalculator>> { impl NonceRollbackInfo for NonceRollbackPartial {
match self { fn nonce_address(&self) -> &Pubkey {
Self::Extant => None, &self.nonce_address
Self::DurableNoncePartial(_, account) => { }
Some(nonce_account::fee_calculator_of(account)) fn nonce_account(&self) -> &Account {
} &self.nonce_account
Self::DurableNonceFull(_, account, _) => { }
Some(nonce_account::fee_calculator_of(account)) fn fee_calculator(&self) -> Option<FeeCalculator> {
} nonce_account::fee_calculator_of(&self.nonce_account)
}
fn fee_account(&self) -> Option<&Account> {
None
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct NonceRollbackFull {
nonce_address: Pubkey,
nonce_account: Account,
fee_account: Option<Account>,
}
impl NonceRollbackFull {
#[cfg(test)]
pub fn new(
nonce_address: Pubkey,
nonce_account: Account,
fee_account: Option<Account>,
) -> Self {
Self {
nonce_address,
nonce_account,
fee_account,
} }
} }
pub fn from_partial(
pub fn finish_partial(&self, message: &Message, accounts: &[Account]) -> Result<Self> { partial: NonceRollbackPartial,
match self { message: &Message,
HashAgeKind::Extant => Ok(HashAgeKind::Extant), accounts: &[Account],
HashAgeKind::DurableNoncePartial(pubkey, account) => { ) -> Result<Self> {
let fee_payer = message let NonceRollbackPartial {
.account_keys nonce_address,
.iter() nonce_account,
.enumerate() } = partial;
.find(|(i, k)| Accounts::is_non_loader_key(message, k, *i)) let fee_payer = message
.and_then(|(i, k)| accounts.get(i).cloned().map(|a| (*k, a))); .account_keys
if let Some((fee_pubkey, fee_account)) = fee_payer { .iter()
if fee_pubkey == *pubkey { .enumerate()
Ok(HashAgeKind::DurableNonceFull(*pubkey, fee_account, None)) .find(|(i, k)| Accounts::is_non_loader_key(message, k, *i))
} else { .and_then(|(i, k)| accounts.get(i).cloned().map(|a| (*k, a)));
Ok(HashAgeKind::DurableNonceFull( if let Some((fee_pubkey, fee_account)) = fee_payer {
*pubkey, if fee_pubkey == nonce_address {
account.clone(), Ok(Self {
Some(fee_account), nonce_address,
)) nonce_account: fee_account,
} fee_account: None,
} else { })
Err(TransactionError::AccountNotFound) } else {
} Ok(Self {
} nonce_address,
HashAgeKind::DurableNonceFull(_, _, _) => { nonce_account,
panic!("update: unexpected HashAgeKind variant") fee_account: Some(fee_account),
})
} }
} else {
Err(TransactionError::AccountNotFound)
} }
} }
} }
impl NonceRollbackInfo for NonceRollbackFull {
fn nonce_address(&self) -> &Pubkey {
&self.nonce_address
}
fn nonce_account(&self) -> &Account {
&self.nonce_account
}
fn fee_calculator(&self) -> Option<FeeCalculator> {
nonce_account::fee_calculator_of(&self.nonce_account)
}
fn fee_account(&self) -> Option<&Account> {
self.fee_account.as_ref()
}
}
// Bank's common fields shared by all supported snapshot versions for deserialization. // Bank's common fields shared by all supported snapshot versions for deserialization.
// Sync fields with BankFieldsToSerialize! This is paired with it. // Sync fields with BankFieldsToSerialize! This is paired with it.
// All members are made public to remain Bank's members private and to make versioned deserializer workable on this // All members are made public to remain Bank's members private and to make versioned deserializer workable on this
@ -2117,11 +2166,11 @@ impl Bank {
&self, &self,
txs: &[Transaction], txs: &[Transaction],
iteration_order: Option<&[usize]>, iteration_order: Option<&[usize]>,
res: &[TransactionProcessResult], res: &[TransactionExecutionResult],
) { ) {
let mut status_cache = self.src.status_cache.write().unwrap(); let mut status_cache = self.src.status_cache.write().unwrap();
for (i, (_, tx)) in OrderedIterator::new(txs, iteration_order).enumerate() { for (i, (_, tx)) in OrderedIterator::new(txs, iteration_order).enumerate() {
let (res, _hash_age_kind) = &res[i]; let (res, _nonce_rollback) = &res[i];
if Self::can_commit(res) && !tx.signatures.is_empty() { if Self::can_commit(res) && !tx.signatures.is_empty() {
status_cache.insert( status_cache.insert(
&tx.message().recent_blockhash, &tx.message().recent_blockhash,
@ -2255,9 +2304,9 @@ impl Bank {
&self, &self,
txs: &[Transaction], txs: &[Transaction],
iteration_order: Option<&[usize]>, iteration_order: Option<&[usize]>,
results: Vec<TransactionProcessResult>, results: Vec<TransactionCheckResult>,
error_counters: &mut ErrorCounters, error_counters: &mut ErrorCounters,
) -> Vec<(Result<TransactionLoadResult>, Option<HashAgeKind>)> { ) -> Vec<TransactionLoadResult> {
self.rc.accounts.load_accounts( self.rc.accounts.load_accounts(
&self.ancestors, &self.ancestors,
txs, txs,
@ -2277,7 +2326,7 @@ impl Bank {
lock_results: Vec<Result<()>>, lock_results: Vec<Result<()>>,
max_age: usize, max_age: usize,
error_counters: &mut ErrorCounters, error_counters: &mut ErrorCounters,
) -> Vec<TransactionProcessResult> { ) -> Vec<TransactionCheckResult> {
let hash_queue = self.blockhash_queue.read().unwrap(); let hash_queue = self.blockhash_queue.read().unwrap();
OrderedIterator::new(txs, iteration_order) OrderedIterator::new(txs, iteration_order)
.zip(lock_results.into_iter()) .zip(lock_results.into_iter())
@ -2286,9 +2335,9 @@ impl Bank {
let message = tx.message(); let message = tx.message();
let hash_age = hash_queue.check_hash_age(&message.recent_blockhash, max_age); let hash_age = hash_queue.check_hash_age(&message.recent_blockhash, max_age);
if hash_age == Some(true) { if hash_age == Some(true) {
(Ok(()), Some(HashAgeKind::Extant)) (Ok(()), None)
} else if let Some((pubkey, acc)) = self.check_tx_durable_nonce(&tx) { } else if let Some((pubkey, acc)) = self.check_tx_durable_nonce(&tx) {
(Ok(()), Some(HashAgeKind::DurableNoncePartial(pubkey, acc))) (Ok(()), Some(NonceRollbackPartial::new(pubkey, acc)))
} else if hash_age == Some(false) { } else if hash_age == Some(false) {
error_counters.blockhash_too_old += 1; error_counters.blockhash_too_old += 1;
(Err(TransactionError::BlockhashNotFound), None) (Err(TransactionError::BlockhashNotFound), None)
@ -2306,9 +2355,9 @@ impl Bank {
&self, &self,
txs: &[Transaction], txs: &[Transaction],
iteration_order: Option<&[usize]>, iteration_order: Option<&[usize]>,
lock_results: Vec<TransactionProcessResult>, lock_results: Vec<TransactionCheckResult>,
error_counters: &mut ErrorCounters, error_counters: &mut ErrorCounters,
) -> Vec<TransactionProcessResult> { ) -> Vec<TransactionCheckResult> {
let rcache = self.src.status_cache.read().unwrap(); let rcache = self.src.status_cache.read().unwrap();
OrderedIterator::new(txs, iteration_order) OrderedIterator::new(txs, iteration_order)
.zip(lock_results.into_iter()) .zip(lock_results.into_iter())
@ -2317,7 +2366,7 @@ impl Bank {
return lock_res; return lock_res;
} }
{ {
let (lock_res, hash_age_kind) = &lock_res; let (lock_res, _nonce_rollback) = &lock_res;
if lock_res.is_ok() if lock_res.is_ok()
&& rcache && rcache
.get_signature_status( .get_signature_status(
@ -2328,10 +2377,7 @@ impl Bank {
.is_some() .is_some()
{ {
error_counters.duplicate_signature += 1; error_counters.duplicate_signature += 1;
return ( return (Err(TransactionError::DuplicateSignature), None);
Err(TransactionError::DuplicateSignature),
hash_age_kind.clone(),
);
} }
} }
lock_res lock_res
@ -2343,9 +2389,9 @@ impl Bank {
&self, &self,
txs: &[Transaction], txs: &[Transaction],
iteration_order: Option<&[usize]>, iteration_order: Option<&[usize]>,
lock_results: Vec<TransactionProcessResult>, lock_results: Vec<TransactionCheckResult>,
error_counters: &mut ErrorCounters, error_counters: &mut ErrorCounters,
) -> Vec<TransactionProcessResult> { ) -> Vec<TransactionCheckResult> {
OrderedIterator::new(txs, iteration_order) OrderedIterator::new(txs, iteration_order)
.zip(lock_results.into_iter()) .zip(lock_results.into_iter())
.map(|((_, tx), lock_res)| { .map(|((_, tx), lock_res)| {
@ -2401,7 +2447,7 @@ impl Bank {
lock_results: &[Result<()>], lock_results: &[Result<()>],
max_age: usize, max_age: usize,
mut error_counters: &mut ErrorCounters, mut error_counters: &mut ErrorCounters,
) -> Vec<TransactionProcessResult> { ) -> Vec<TransactionCheckResult> {
let age_results = self.check_age( let age_results = self.check_age(
txs, txs,
iteration_order, iteration_order,
@ -2627,8 +2673,8 @@ impl Bank {
enable_cpi_recording: bool, enable_cpi_recording: bool,
enable_log_recording: bool, enable_log_recording: bool,
) -> ( ) -> (
Vec<(Result<TransactionLoadResult>, Option<HashAgeKind>)>, Vec<TransactionLoadResult>,
Vec<TransactionProcessResult>, Vec<TransactionExecutionResult>,
Vec<Option<InnerInstructionsList>>, Vec<Option<InnerInstructionsList>>,
Vec<TransactionLogMessages>, Vec<TransactionLogMessages>,
Vec<usize>, Vec<usize>,
@ -2678,12 +2724,12 @@ impl Bank {
.bpf_compute_budget .bpf_compute_budget
.unwrap_or_else(|| BpfComputeBudget::new(&self.feature_set)); .unwrap_or_else(|| BpfComputeBudget::new(&self.feature_set));
let executed: Vec<TransactionProcessResult> = loaded_accounts let executed: Vec<TransactionExecutionResult> = loaded_accounts
.iter_mut() .iter_mut()
.zip(OrderedIterator::new(txs, batch.iteration_order())) .zip(OrderedIterator::new(txs, batch.iteration_order()))
.map(|(accs, (_, tx))| match accs { .map(|(accs, (_, tx))| match accs {
(Err(e), hash_age_kind) => (Err(e.clone()), hash_age_kind.clone()), (Err(e), _nonce_rollback) => (Err(e.clone()), None),
(Ok((accounts, loaders, _rents)), hash_age_kind) => { (Ok((accounts, loaders, _rents)), nonce_rollback) => {
signature_count += u64::from(tx.message().header.num_required_signatures); signature_count += u64::from(tx.message().header.num_required_signatures);
let executors = self.get_executors(&tx.message, &loaders); let executors = self.get_executors(&tx.message, &loaders);
@ -2742,10 +2788,16 @@ impl Bank {
self.update_executors(executors); self.update_executors(executors);
if let Err(TransactionError::InstructionError(_, _)) = &process_result { let nonce_rollback =
error_counters.instruction_error += 1; if let Err(TransactionError::InstructionError(_, _)) = &process_result {
} error_counters.instruction_error += 1;
(process_result, hash_age_kind.clone()) nonce_rollback.clone()
} else if process_result.is_err() {
None
} else {
nonce_rollback.clone()
};
(process_result, nonce_rollback)
} }
}) })
.collect(); .collect();
@ -2764,7 +2816,7 @@ impl Bank {
let transaction_log_collector_config = let transaction_log_collector_config =
self.transaction_log_collector_config.read().unwrap(); self.transaction_log_collector_config.read().unwrap();
for (i, ((r, _hash_age_kind), tx)) in executed.iter().zip(txs.iter()).enumerate() { for (i, ((r, _nonce_rollback), tx)) in executed.iter().zip(txs.iter()).enumerate() {
if let Some(debug_keys) = &self.transaction_debug_keys { if let Some(debug_keys) = &self.transaction_debug_keys {
for key in &tx.message.account_keys { for key in &tx.message.account_keys {
if debug_keys.contains(key) { if debug_keys.contains(key) {
@ -2849,7 +2901,7 @@ impl Bank {
&self, &self,
txs: &[Transaction], txs: &[Transaction],
iteration_order: Option<&[usize]>, iteration_order: Option<&[usize]>,
executed: &[TransactionProcessResult], executed: &[TransactionExecutionResult],
) -> Vec<Result<()>> { ) -> Vec<Result<()>> {
let hash_queue = self.blockhash_queue.read().unwrap(); let hash_queue = self.blockhash_queue.read().unwrap();
let mut fees = 0; let mut fees = 0;
@ -2860,10 +2912,10 @@ impl Bank {
let results = OrderedIterator::new(txs, iteration_order) let results = OrderedIterator::new(txs, iteration_order)
.zip(executed.iter()) .zip(executed.iter())
.map(|((_, tx), (res, hash_age_kind))| { .map(|((_, tx), (res, nonce_rollback))| {
let (fee_calculator, is_durable_nonce) = hash_age_kind let (fee_calculator, is_durable_nonce) = nonce_rollback
.as_ref() .as_ref()
.and_then(|hash_age_kind| hash_age_kind.fee_calculator()) .map(|nonce_rollback| nonce_rollback.fee_calculator())
.map(|maybe_fee_calculator| (maybe_fee_calculator, true)) .map(|maybe_fee_calculator| (maybe_fee_calculator, true))
.unwrap_or_else(|| { .unwrap_or_else(|| {
( (
@ -2909,8 +2961,8 @@ impl Bank {
&self, &self,
txs: &[Transaction], txs: &[Transaction],
iteration_order: Option<&[usize]>, iteration_order: Option<&[usize]>,
loaded_accounts: &mut [(Result<TransactionLoadResult>, Option<HashAgeKind>)], loaded_accounts: &mut [TransactionLoadResult],
executed: &[TransactionProcessResult], executed: &[TransactionExecutionResult],
tx_count: u64, tx_count: u64,
signature_count: u64, signature_count: u64,
) -> TransactionResults { ) -> TransactionResults {
@ -2927,7 +2979,7 @@ impl Bank {
if executed if executed
.iter() .iter()
.any(|(res, _hash_age_kind)| Self::can_commit(res)) .any(|(res, _nonce_rollback)| Self::can_commit(res))
{ {
self.is_delta.store(true, Relaxed); self.is_delta.store(true, Relaxed);
} }
@ -2958,7 +3010,7 @@ impl Bank {
TransactionResults { TransactionResults {
fee_collection_results, fee_collection_results,
processing_results: executed.to_vec(), execution_results: executed.to_vec(),
overwritten_vote_accounts, overwritten_vote_accounts,
} }
} }
@ -3107,12 +3159,12 @@ impl Bank {
fn collect_rent( fn collect_rent(
&self, &self,
res: &[TransactionProcessResult], res: &[TransactionExecutionResult],
loaded_accounts: &[(Result<TransactionLoadResult>, Option<HashAgeKind>)], loaded_accounts: &[TransactionLoadResult],
) { ) {
let mut collected_rent: u64 = 0; let mut collected_rent: u64 = 0;
for (i, (raccs, _hash_age_kind)) in loaded_accounts.iter().enumerate() { for (i, (raccs, _nonce_rollback)) in loaded_accounts.iter().enumerate() {
let (res, _hash_age_kind) = &res[i]; let (res, _nonce_rollback) = &res[i];
if res.is_err() || raccs.is_err() { if res.is_err() || raccs.is_err() {
continue; continue;
} }
@ -4079,16 +4131,16 @@ impl Bank {
&self, &self,
txs: &[Transaction], txs: &[Transaction],
iteration_order: Option<&[usize]>, iteration_order: Option<&[usize]>,
res: &[TransactionProcessResult], res: &[TransactionExecutionResult],
loaded: &[(Result<TransactionLoadResult>, Option<HashAgeKind>)], loaded: &[TransactionLoadResult],
) -> Vec<OverwrittenVoteAccount> { ) -> Vec<OverwrittenVoteAccount> {
let mut overwritten_vote_accounts = vec![]; let mut overwritten_vote_accounts = vec![];
for (i, ((raccs, _load_hash_age_kind), (transaction_index, tx))) in loaded for (i, ((raccs, _load_nonce_rollback), (transaction_index, tx))) in loaded
.iter() .iter()
.zip(OrderedIterator::new(txs, iteration_order)) .zip(OrderedIterator::new(txs, iteration_order))
.enumerate() .enumerate()
{ {
let (res, _res_hash_age_kind) = &res[i]; let (res, _res_nonce_rollback) = &res[i];
if res.is_err() || raccs.is_err() { if res.is_err() || raccs.is_err() {
continue; continue;
} }
@ -4596,73 +4648,25 @@ pub(crate) mod tests {
use std::{result, thread::Builder, time::Duration}; use std::{result, thread::Builder, time::Duration};
#[test] #[test]
fn test_hash_age_kind_is_durable_nonce() { fn test_nonce_rollback_info() {
assert!( let nonce_authority = keypair_from_seed(&[0; 32]).unwrap();
HashAgeKind::DurableNoncePartial(Pubkey::default(), Account::default()) let nonce_address = nonce_authority.pubkey();
.is_durable_nonce() let fee_calculator = FeeCalculator::new(42);
);
assert!(
HashAgeKind::DurableNonceFull(Pubkey::default(), Account::default(), None)
.is_durable_nonce()
);
assert!(HashAgeKind::DurableNonceFull(
Pubkey::default(),
Account::default(),
Some(Account::default())
)
.is_durable_nonce());
assert!(!HashAgeKind::Extant.is_durable_nonce());
}
#[test]
fn test_hash_age_kind_fee_calculator() {
let state = let state =
nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data { nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data {
authority: Pubkey::default(), authority: Pubkey::default(),
blockhash: Hash::new_unique(), blockhash: Hash::new_unique(),
fee_calculator: FeeCalculator::default(), fee_calculator: fee_calculator.clone(),
})); }));
let account = Account::new_data(42, &state, &system_program::id()).unwrap(); let nonce_account = Account::new_data(43, &state, &system_program::id()).unwrap();
assert_eq!(HashAgeKind::Extant.fee_calculator(), None); // NonceRollbackPartial create + NonceRollbackInfo impl
assert_eq!( let partial = NonceRollbackPartial::new(nonce_address, nonce_account.clone());
HashAgeKind::DurableNoncePartial(Pubkey::default(), account.clone()).fee_calculator(), assert_eq!(*partial.nonce_address(), nonce_address);
Some(Some(FeeCalculator::default())) assert_eq!(*partial.nonce_account(), nonce_account);
); assert_eq!(partial.fee_calculator(), Some(fee_calculator.clone()));
assert_eq!( assert_eq!(partial.fee_account(), None);
HashAgeKind::DurableNoncePartial(Pubkey::default(), Account::default())
.fee_calculator(),
Some(None)
);
assert_eq!(
HashAgeKind::DurableNonceFull(Pubkey::default(), account, Some(Account::default()))
.fee_calculator(),
Some(Some(FeeCalculator::default()))
);
assert_eq!(
HashAgeKind::DurableNonceFull(
Pubkey::default(),
Account::default(),
Some(Account::default())
)
.fee_calculator(),
Some(None)
);
}
#[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 = keypair_from_seed(&[1; 32]).unwrap();
let from_address = from.pubkey(); let from_address = from.pubkey();
let to_address = Pubkey::new_unique(); let to_address = Pubkey::new_unique();
@ -4672,9 +4676,8 @@ pub(crate) mod tests {
]; ];
let message = Message::new(&instructions, Some(&from_address)); let message = Message::new(&instructions, Some(&from_address));
let from_account = Account::new(1, 0, &Pubkey::default()); let from_account = Account::new(44, 0, &Pubkey::default());
let nonce_account = Account::new(2, 0, &Pubkey::default()); let to_account = Account::new(45, 0, &Pubkey::default());
let to_account = Account::new(3, 0, &Pubkey::default());
let recent_blockhashes_sysvar_account = Account::new(4, 0, &Pubkey::default()); let recent_blockhashes_sysvar_account = Account::new(4, 0, &Pubkey::default());
let accounts = [ let accounts = [
from_account.clone(), from_account.clone(),
@ -4683,41 +4686,29 @@ pub(crate) mod tests {
recent_blockhashes_sysvar_account.clone(), recent_blockhashes_sysvar_account.clone(),
]; ];
assert_eq!( // NonceRollbackFull create + NonceRollbackInfo impl
HashAgeKind::Extant.finish_partial(&message, &accounts), let full = NonceRollbackFull::from_partial(partial.clone(), &message, &accounts).unwrap();
Ok(HashAgeKind::Extant) assert_eq!(*full.nonce_address(), nonce_address);
); assert_eq!(*full.nonce_account(), nonce_account);
assert_eq!(full.fee_calculator(), Some(fee_calculator));
let hash_age_kind = HashAgeKind::DurableNoncePartial(nonce_address, nonce_account.clone()); assert_eq!(full.fee_account(), Some(&from_account));
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 message = Message::new(&instructions, Some(&nonce_address));
let accounts = [ let accounts = [
nonce_account.clone(), nonce_account,
from_account, from_account,
to_account, to_account,
recent_blockhashes_sysvar_account, recent_blockhashes_sysvar_account,
]; ];
// Nonce account is fee-payer
let full = NonceRollbackFull::from_partial(partial.clone(), &message, &accounts).unwrap();
assert_eq!(full.fee_account(), None);
// NonceRollbackFull create, fee-payer not in account_keys fails
assert_eq!( assert_eq!(
hash_age_kind.finish_partial(&message, &accounts), NonceRollbackFull::from_partial(partial, &message, &[]).unwrap_err(),
Ok(HashAgeKind::DurableNonceFull( TransactionError::AccountNotFound,
nonce_address,
nonce_account,
None
)),
); );
} }
@ -7117,13 +7108,13 @@ pub(crate) mod tests {
system_transaction::transfer(&mint_keypair, &key.pubkey(), 5, genesis_config.hash()); system_transaction::transfer(&mint_keypair, &key.pubkey(), 5, genesis_config.hash());
let results = vec![ let results = vec![
(Ok(()), Some(HashAgeKind::Extant)), (Ok(()), None),
( (
Err(TransactionError::InstructionError( Err(TransactionError::InstructionError(
1, 1,
SystemError::ResultWithNegativeLamports.into(), SystemError::ResultWithNegativeLamports.into(),
)), )),
Some(HashAgeKind::Extant), None,
), ),
]; ];
let initial_balance = bank.get_balance(&leader); let initial_balance = bank.get_balance(&leader);
@ -9112,19 +9103,19 @@ pub(crate) mod tests {
assert_eq!(transaction_balances_set.pre_balances.len(), 3); assert_eq!(transaction_balances_set.pre_balances.len(), 3);
assert_eq!(transaction_balances_set.post_balances.len(), 3); assert_eq!(transaction_balances_set.post_balances.len(), 3);
assert!(transaction_results.processing_results[0].0.is_ok()); assert!(transaction_results.execution_results[0].0.is_ok());
assert_eq!(transaction_balances_set.pre_balances[0], vec![8, 11, 1]); assert_eq!(transaction_balances_set.pre_balances[0], vec![8, 11, 1]);
assert_eq!(transaction_balances_set.post_balances[0], vec![5, 13, 1]); assert_eq!(transaction_balances_set.post_balances[0], vec![5, 13, 1]);
// Failed transactions still produce balance sets // Failed transactions still produce balance sets
// This is a TransactionError - not possible to charge fees // This is a TransactionError - not possible to charge fees
assert!(transaction_results.processing_results[1].0.is_err()); assert!(transaction_results.execution_results[1].0.is_err());
assert_eq!(transaction_balances_set.pre_balances[1], vec![0, 0, 1]); assert_eq!(transaction_balances_set.pre_balances[1], vec![0, 0, 1]);
assert_eq!(transaction_balances_set.post_balances[1], vec![0, 0, 1]); assert_eq!(transaction_balances_set.post_balances[1], vec![0, 0, 1]);
// Failed transactions still produce balance sets // Failed transactions still produce balance sets
// This is an InstructionError - fees charged // This is an InstructionError - fees charged
assert!(transaction_results.processing_results[2].0.is_err()); assert!(transaction_results.execution_results[2].0.is_err());
assert_eq!(transaction_balances_set.pre_balances[2], vec![9, 0, 1]); assert_eq!(transaction_balances_set.pre_balances[2], vec![9, 0, 1]);
assert_eq!(transaction_balances_set.post_balances[2], vec![8, 0, 1]); assert_eq!(transaction_balances_set.post_balances[2], vec![8, 0, 1]);
} }

View File

@ -32,13 +32,13 @@ pub fn find_and_send_votes(
vote_sender: Option<&ReplayVoteSender>, vote_sender: Option<&ReplayVoteSender>,
) { ) {
let TransactionResults { let TransactionResults {
processing_results, execution_results,
overwritten_vote_accounts, overwritten_vote_accounts,
.. ..
} = tx_results; } = tx_results;
if let Some(vote_sender) = vote_sender { if let Some(vote_sender) = vote_sender {
for old_account in overwritten_vote_accounts { for old_account in overwritten_vote_accounts {
assert!(processing_results[old_account.transaction_result_index] assert!(execution_results[old_account.transaction_result_index]
.0 .0
.is_ok()); .is_ok());
let transaction = &txs[old_account.transaction_index]; let transaction = &txs[old_account.transaction_index];