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.
This commit is contained in:
behzad nouri 2022-06-03 13:05:55 -04:00
parent 5ee157f43d
commit 9851774133
2 changed files with 46 additions and 17 deletions

View File

@ -4054,6 +4054,13 @@ impl Bank {
max_age: usize, max_age: usize,
error_counters: &mut TransactionErrorMetrics, error_counters: &mut TransactionErrorMetrics,
) -> Vec<TransactionCheckResult> { ) -> Vec<TransactionCheckResult> {
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(); let hash_queue = self.blockhash_queue.read().unwrap();
txs.zip(lock_results) txs.zip(lock_results)
.map(|(tx, lock_res)| match lock_res { .map(|(tx, lock_res)| match lock_res {
@ -4061,7 +4068,9 @@ impl Bank {
let recent_blockhash = tx.message().recent_blockhash(); let recent_blockhash = tx.message().recent_blockhash();
if hash_queue.is_hash_valid_for_age(recent_blockhash, max_age) { if hash_queue.is_hash_valid_for_age(recent_blockhash, max_age) {
(Ok(()), None) (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))) (Ok(()), Some(NoncePartial::new(address, account)))
} else { } else {
error_counters.blockhash_not_found += 1; error_counters.blockhash_not_found += 1;
@ -4131,19 +4140,16 @@ impl Bank {
}) })
} }
pub fn check_transaction_for_nonce( fn check_transaction_for_nonce(
&self, &self,
tx: &SanitizedTransaction, tx: &SanitizedTransaction,
enable_durable_nonce: bool,
) -> Option<TransactionAccount> { ) -> Option<TransactionAccount> {
if self.cluster_type() == ClusterType::MainnetBeta { (enable_durable_nonce
if self.slot() <= 135986379 { || self.slot() <= 135986379
self.check_message_for_nonce(tx.message()) || self.cluster_type() != ClusterType::MainnetBeta)
} else { .then(|| self.check_message_for_nonce(tx.message()))
None .flatten()
}
} else {
self.check_message_for_nonce(tx.message())
}
} }
pub fn check_transactions( pub fn check_transactions(
@ -12447,7 +12453,10 @@ pub(crate) mod tests {
); );
let nonce_account = bank.get_account(&nonce_pubkey).unwrap(); let nonce_account = bank.get_account(&nonce_pubkey).unwrap();
assert_eq!( 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)) Some((nonce_pubkey, nonce_account))
); );
} }
@ -12473,7 +12482,10 @@ pub(crate) mod tests {
nonce_hash, nonce_hash,
); );
assert!(bank 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()); .is_none());
} }
@ -12499,7 +12511,10 @@ pub(crate) mod tests {
); );
tx.message.instructions[0].accounts.clear(); tx.message.instructions[0].accounts.clear();
assert!(bank 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()); .is_none());
} }
@ -12526,7 +12541,10 @@ pub(crate) mod tests {
nonce_hash, nonce_hash,
); );
assert!(bank 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()); .is_none());
} }
@ -12550,7 +12568,10 @@ pub(crate) mod tests {
Hash::default(), Hash::default(),
); );
assert!(bank 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()); .is_none());
} }
@ -13222,7 +13243,10 @@ pub(crate) mod tests {
Err(TransactionError::BlockhashNotFound) Err(TransactionError::BlockhashNotFound)
); );
assert_eq!( 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 None
); );
} }

View File

@ -420,6 +420,10 @@ pub mod separate_nonce_from_blockhash {
solana_sdk::declare_id!("Gea3ZkK2N4pHuVZVxWcnAtS6UEDdyumdYt4pFcKjA3ar"); solana_sdk::declare_id!("Gea3ZkK2N4pHuVZVxWcnAtS6UEDdyumdYt4pFcKjA3ar");
} }
pub mod enable_durable_nonce {
solana_sdk::declare_id!("4EJQtF2pkRyawwcTVfQutzq4Sa5hRhibF6QAK1QXhtEX");
}
lazy_static! { lazy_static! {
/// Map of feature identifiers to user-visible description /// Map of feature identifiers to user-visible description
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [ pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
@ -518,6 +522,7 @@ lazy_static! {
(add_shred_type_to_shred_seed::id(), "add shred-type to shred seed #25556"), (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"), (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"), (separate_nonce_from_blockhash::id(), "separate durable nonce and blockhash domains #25744"),
(enable_durable_nonce::id(), "enable durable nonce #25744"),
/*************** ADD NEW FEATURES HERE ***************/ /*************** ADD NEW FEATURES HERE ***************/
] ]
.iter() .iter()