From 98517741334fbc3946ca15ed5f387a733ed33cd2 Mon Sep 17 00:00:00 2001 From: behzad nouri Date: Fri, 3 Jun 2022 13:05:55 -0400 Subject: [PATCH] adds feature gate enabling durable nonce Previous commit separates durable nonce and blockhash domains with a feature gate. A 2nd feature added in this commit enables durable nonce at least one epoch after the 1st feature. By the time 2nd feature is activated, some nonce accounts will have an old blockhash, but no nonce account can have a recent blockhash. As a result no transaction (durable or normal) can be executed twice. --- runtime/src/bank.rs | 58 +++++++++++++++++++++++++++++------------- sdk/src/feature_set.rs | 5 ++++ 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 8494da8536..1c33742e84 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -4054,6 +4054,13 @@ impl Bank { max_age: usize, error_counters: &mut TransactionErrorMetrics, ) -> Vec { + let separate_nonce_from_blockhash = self + .feature_set + .is_active(&feature_set::separate_nonce_from_blockhash::id()); + let enable_durable_nonce = separate_nonce_from_blockhash + && self + .feature_set + .is_active(&feature_set::enable_durable_nonce::id()); let hash_queue = self.blockhash_queue.read().unwrap(); txs.zip(lock_results) .map(|(tx, lock_res)| match lock_res { @@ -4061,7 +4068,9 @@ impl Bank { let recent_blockhash = tx.message().recent_blockhash(); if hash_queue.is_hash_valid_for_age(recent_blockhash, max_age) { (Ok(()), None) - } else if let Some((address, account)) = self.check_transaction_for_nonce(tx) { + } else if let Some((address, account)) = + self.check_transaction_for_nonce(tx, enable_durable_nonce) + { (Ok(()), Some(NoncePartial::new(address, account))) } else { error_counters.blockhash_not_found += 1; @@ -4131,19 +4140,16 @@ impl Bank { }) } - pub fn check_transaction_for_nonce( + fn check_transaction_for_nonce( &self, tx: &SanitizedTransaction, + enable_durable_nonce: bool, ) -> Option { - if self.cluster_type() == ClusterType::MainnetBeta { - if self.slot() <= 135986379 { - self.check_message_for_nonce(tx.message()) - } else { - None - } - } else { - self.check_message_for_nonce(tx.message()) - } + (enable_durable_nonce + || self.slot() <= 135986379 + || self.cluster_type() != ClusterType::MainnetBeta) + .then(|| self.check_message_for_nonce(tx.message())) + .flatten() } pub fn check_transactions( @@ -12447,7 +12453,10 @@ pub(crate) mod tests { ); let nonce_account = bank.get_account(&nonce_pubkey).unwrap(); assert_eq!( - bank.check_transaction_for_nonce(&SanitizedTransaction::from_transaction_for_tests(tx)), + bank.check_transaction_for_nonce( + &SanitizedTransaction::from_transaction_for_tests(tx), + true, // enable_durable_nonce + ), Some((nonce_pubkey, nonce_account)) ); } @@ -12473,7 +12482,10 @@ pub(crate) mod tests { nonce_hash, ); assert!(bank - .check_transaction_for_nonce(&SanitizedTransaction::from_transaction_for_tests(tx,)) + .check_transaction_for_nonce( + &SanitizedTransaction::from_transaction_for_tests(tx,), + true, // enable_durable_nonce + ) .is_none()); } @@ -12499,7 +12511,10 @@ pub(crate) mod tests { ); tx.message.instructions[0].accounts.clear(); assert!(bank - .check_transaction_for_nonce(&SanitizedTransaction::from_transaction_for_tests(tx)) + .check_transaction_for_nonce( + &SanitizedTransaction::from_transaction_for_tests(tx), + true, // enable_durable_nonce + ) .is_none()); } @@ -12526,7 +12541,10 @@ pub(crate) mod tests { nonce_hash, ); assert!(bank - .check_transaction_for_nonce(&SanitizedTransaction::from_transaction_for_tests(tx)) + .check_transaction_for_nonce( + &SanitizedTransaction::from_transaction_for_tests(tx), + true, // enable_durable_nonce + ) .is_none()); } @@ -12550,7 +12568,10 @@ pub(crate) mod tests { Hash::default(), ); assert!(bank - .check_transaction_for_nonce(&SanitizedTransaction::from_transaction_for_tests(tx)) + .check_transaction_for_nonce( + &SanitizedTransaction::from_transaction_for_tests(tx), + true, // enable_durable_nonce + ) .is_none()); } @@ -13222,7 +13243,10 @@ pub(crate) mod tests { Err(TransactionError::BlockhashNotFound) ); assert_eq!( - bank.check_transaction_for_nonce(&SanitizedTransaction::from_transaction_for_tests(tx)), + bank.check_transaction_for_nonce( + &SanitizedTransaction::from_transaction_for_tests(tx), + true, // enable_durable_nonce + ), None ); } diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index e3ea9f99e6..12e2cc6648 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -420,6 +420,10 @@ pub mod separate_nonce_from_blockhash { solana_sdk::declare_id!("Gea3ZkK2N4pHuVZVxWcnAtS6UEDdyumdYt4pFcKjA3ar"); } +pub mod enable_durable_nonce { + solana_sdk::declare_id!("4EJQtF2pkRyawwcTVfQutzq4Sa5hRhibF6QAK1QXhtEX"); +} + lazy_static! { /// Map of feature identifiers to user-visible description pub static ref FEATURE_NAMES: HashMap = [ @@ -518,6 +522,7 @@ lazy_static! { (add_shred_type_to_shred_seed::id(), "add shred-type to shred seed #25556"), (warp_timestamp_with_a_vengeance::id(), "warp timestamp again, adjust bounding to 150% slow #25666"), (separate_nonce_from_blockhash::id(), "separate durable nonce and blockhash domains #25744"), + (enable_durable_nonce::id(), "enable durable nonce #25744"), /*************** ADD NEW FEATURES HERE ***************/ ] .iter()