diff --git a/core/src/banking_stage.rs b/core/src/banking_stage.rs index dc28fcaaa..5134ded31 100644 --- a/core/src/banking_stage.rs +++ b/core/src/banking_stage.rs @@ -1115,9 +1115,12 @@ impl BankingStage { let tx: VersionedTransaction = limited_deserialize(&p.data[0..p.meta.size]).ok()?; let message_bytes = Self::packet_message(p)?; let message_hash = Message::hash_raw_message(message_bytes); - let tx = SanitizedTransaction::try_create(tx, message_hash, |_| { - Err(TransactionError::UnsupportedVersion) - }) + let tx = SanitizedTransaction::try_create( + tx, + message_hash, + Some(p.meta.is_simple_vote_tx), + |_| Err(TransactionError::UnsupportedVersion), + ) .ok()?; tx.verify_precompiles(feature_set).ok()?; Some((tx, *tx_index)) diff --git a/ledger-tool/src/main.rs b/ledger-tool/src/main.rs index 41c0101fe..2b3c8fb6f 100644 --- a/ledger-tool/src/main.rs +++ b/ledger-tool/src/main.rs @@ -223,7 +223,7 @@ fn output_slot( for transaction in entry.transactions { let tx_signature = transaction.signatures[0]; let sanitize_result = - SanitizedTransaction::try_create(transaction, Hash::default(), |_| { + SanitizedTransaction::try_create(transaction, Hash::default(), None, |_| { Err(TransactionError::UnsupportedVersion) }); @@ -779,7 +779,7 @@ fn compute_slot_cost(blockstore: &Blockstore, slot: Slot) -> Result<(), String> .transactions .into_iter() .filter_map(|transaction| { - SanitizedTransaction::try_create(transaction, Hash::default(), |_| { + SanitizedTransaction::try_create(transaction, Hash::default(), None, |_| { Err(TransactionError::UnsupportedVersion) }) .map_err(|err| { diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index 047d85aad..b6627bd63 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -4172,7 +4172,7 @@ where fn sanitize_transaction(transaction: VersionedTransaction) -> Result { let message_hash = transaction.message.hash(); - SanitizedTransaction::try_create(transaction, message_hash, |_| { + SanitizedTransaction::try_create(transaction, message_hash, None, |_| { Err(TransactionError::UnsupportedVersion) }) .map_err(|err| Error::invalid_params(format!("invalid transaction: {}", err))) diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index a358123f5..7115a61b8 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -489,7 +489,6 @@ pub type TransactionExecutionResult = (Result<()>, Option); pub struct TransactionResults { pub fee_collection_results: Vec>, pub execution_results: Vec, - pub overwritten_vote_accounts: Vec, pub rent_debits: Vec, } pub struct TransactionSimulationResult { @@ -502,11 +501,6 @@ pub struct TransactionBalancesSet { pub pre_balances: TransactionBalances, pub post_balances: TransactionBalances, } -pub struct OverwrittenVoteAccount { - pub account: VoteAccount, - pub transaction_index: usize, - pub transaction_result_index: usize, -} impl TransactionBalancesSet { pub fn new(pre_balances: TransactionBalances, post_balances: TransactionBalances) -> Self { @@ -3273,7 +3267,7 @@ impl Bank { .into_iter() .map(|tx| { let message_hash = tx.message.hash(); - SanitizedTransaction::try_create(tx, message_hash, |_| { + SanitizedTransaction::try_create(tx, message_hash, None, |_| { Err(TransactionError::UnsupportedVersion) }) }) @@ -4133,8 +4127,7 @@ impl Bank { let rent_debits = self.collect_rent(executed, loaded_txs); let mut update_stakes_cache_time = Measure::start("update_stakes_cache_time"); - let overwritten_vote_accounts = - self.update_stakes_cache(sanitized_txs, executed, loaded_txs); + self.update_stakes_cache(sanitized_txs, executed, loaded_txs); update_stakes_cache_time.stop(); // once committed there is no way to unroll @@ -4155,7 +4148,6 @@ impl Bank { TransactionResults { fee_collection_results, execution_results: executed.to_vec(), - overwritten_vote_accounts, rent_debits, } } @@ -5486,7 +5478,7 @@ impl Bank { tx.message.hash() }; - SanitizedTransaction::try_create(tx, message_hash, |_| { + SanitizedTransaction::try_create(tx, message_hash, None, |_| { Err(TransactionError::UnsupportedVersion) }) }?; @@ -5721,8 +5713,7 @@ impl Bank { txs: &[SanitizedTransaction], res: &[TransactionExecutionResult], loaded_txs: &[TransactionLoadResult], - ) -> Vec { - let mut overwritten_vote_accounts = vec![]; + ) { for (i, ((raccs, _load_nonce_rollback), tx)) in loaded_txs.iter().zip(txs).enumerate() { let (res, _res_nonce_rollback) = &res[i]; if res.is_err() || raccs.is_err() { @@ -5736,22 +5727,13 @@ impl Bank { .zip(loaded_transaction.accounts.iter()) .filter(|(_i, (_pubkey, account))| (Stakes::is_stake(account))) { - if let Some(old_vote_account) = self.stakes.write().unwrap().store( + self.stakes.write().unwrap().store( pubkey, account, self.stakes_remove_delegation_if_inactive_enabled(), - ) { - // TODO: one of the indices is redundant. - overwritten_vote_accounts.push(OverwrittenVoteAccount { - account: old_vote_account, - transaction_index: i, - transaction_result_index: i, - }); - } + ); } } - - overwritten_vote_accounts } /// current stake delegations for this bank diff --git a/runtime/src/bank_utils.rs b/runtime/src/bank_utils.rs index 1f5ed67aa..9f8280c68 100644 --- a/runtime/src/bank_utils.rs +++ b/runtime/src/bank_utils.rs @@ -35,21 +35,21 @@ pub fn find_and_send_votes( vote_sender: Option<&ReplayVoteSender>, ) { let TransactionResults { - execution_results, - overwritten_vote_accounts, - .. + execution_results, .. } = tx_results; if let Some(vote_sender) = vote_sender { - for old_account in overwritten_vote_accounts { - assert!(execution_results[old_account.transaction_result_index] - .0 - .is_ok()); - let tx = &sanitized_txs[old_account.transaction_index]; - if let Some(parsed_vote) = vote_transaction::parse_sanitized_vote_transaction(tx) { - if parsed_vote.1.slots.last().is_some() { - let _ = vote_sender.send(parsed_vote); + sanitized_txs.iter().zip(execution_results.iter()).for_each( + |(tx, (result, _nonce_rollback))| { + if tx.is_simple_vote_transaction() && result.is_ok() { + if let Some(parsed_vote) = + vote_transaction::parse_sanitized_vote_transaction(tx) + { + if parsed_vote.1.slots.last().is_some() { + let _ = vote_sender.send(parsed_vote); + } + } } - } - } + }, + ); } } diff --git a/runtime/src/stakes.rs b/runtime/src/stakes.rs index ac2e745f8..10b87b459 100644 --- a/runtime/src/stakes.rs +++ b/runtime/src/stakes.rs @@ -196,7 +196,7 @@ impl Stakes { pubkey: &Pubkey, account: &AccountSharedData, remove_delegation_on_inactive: bool, - ) -> Option { + ) { if solana_vote_program::check_id(account.owner()) { // unconditionally remove existing at first; there is no dependent calculated state for // votes, not like stakes (stake codepath maintains calculated stake value grouped by @@ -213,7 +213,6 @@ impl Stakes { self.vote_accounts .insert(*pubkey, (stake, VoteAccount::from(account.clone()))); } - old.map(|(_, account)| account) } else if stake::program::check_id(account.owner()) { // old_stake is stake lamports and voter_pubkey from the pre-store() version let old_stake = self.stake_delegations.get(pubkey).map(|delegation| { @@ -263,13 +262,11 @@ impl Stakes { } else if let Some(delegation) = delegation { self.stake_delegations.insert(*pubkey, delegation); } - None } else { // there is no need to remove possibly existing Stakes cache entries with given // `pubkey` because this isn't possible, first of all. // Runtime always enforces an intermediary write of account.lamports == 0, // when not-System111-owned account.owner is swapped. - None } } diff --git a/sdk/src/transaction/sanitized.rs b/sdk/src/transaction/sanitized.rs index bc602e9cc..bbc4e61e4 100644 --- a/sdk/src/transaction/sanitized.rs +++ b/sdk/src/transaction/sanitized.rs @@ -22,6 +22,7 @@ use { pub struct SanitizedTransaction { message: SanitizedMessage, message_hash: Hash, + is_simple_vote_tx: bool, signatures: Vec, } @@ -41,6 +42,7 @@ impl SanitizedTransaction { pub fn try_create( tx: VersionedTransaction, message_hash: Hash, + is_simple_vote_tx: Option, address_mapper: impl Fn(&v0::Message) -> Result, ) -> Result { tx.sanitize()?; @@ -58,9 +60,15 @@ impl SanitizedTransaction { return Err(TransactionError::AccountLoadedTwice); } + let is_simple_vote_tx = is_simple_vote_tx.unwrap_or_else(|| { + let mut ix_iter = message.program_instructions_iter(); + ix_iter.next().map(|(program_id, _ix)| program_id) == Some(&crate::vote::program::id()) + }); + Ok(Self { message, message_hash, + is_simple_vote_tx, signatures, }) } @@ -76,6 +84,7 @@ impl SanitizedTransaction { Self { message_hash: tx.message.hash(), message: SanitizedMessage::Legacy(tx.message), + is_simple_vote_tx: false, signatures: tx.signatures, } } @@ -106,6 +115,11 @@ impl SanitizedTransaction { &self.message_hash } + /// Returns true if this transaction is a simple vote + pub fn is_simple_vote_transaction(&self) -> bool { + self.is_simple_vote_tx + } + /// Convert this sanitized transaction into a versioned transaction for /// recording in the ledger. pub fn to_versioned_transaction(&self) -> VersionedTransaction {