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:
parent
5ee157f43d
commit
9851774133
|
@ -4054,6 +4054,13 @@ impl Bank {
|
|||
max_age: usize,
|
||||
error_counters: &mut TransactionErrorMetrics,
|
||||
) -> 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();
|
||||
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<TransactionAccount> {
|
||||
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
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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<Pubkey, &'static str> = [
|
||||
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue