Reject durable nonce txs that don't use an advanceable nonce (#25832)
* Reject durable nonce txs that use the latest durable nonce hash * feedback
This commit is contained in:
parent
3f47c83e5c
commit
6a7edc02c6
|
@ -4036,15 +4036,21 @@ impl Bank {
|
|||
.feature_set
|
||||
.is_active(&feature_set::enable_durable_nonce::id());
|
||||
let hash_queue = self.blockhash_queue.read().unwrap();
|
||||
let last_blockhash = hash_queue.last_hash();
|
||||
let next_durable_nonce =
|
||||
DurableNonce::from_blockhash(&last_blockhash, separate_nonce_from_blockhash);
|
||||
|
||||
txs.zip(lock_results)
|
||||
.map(|(tx, lock_res)| match lock_res {
|
||||
Ok(()) => {
|
||||
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, enable_durable_nonce)
|
||||
{
|
||||
} else if let Some((address, account)) = self.check_transaction_for_nonce(
|
||||
tx,
|
||||
enable_durable_nonce,
|
||||
&next_durable_nonce,
|
||||
) {
|
||||
(Ok(()), Some(NoncePartial::new(address, account)))
|
||||
} else {
|
||||
error_counters.blockhash_not_found += 1;
|
||||
|
@ -4128,10 +4134,16 @@ impl Bank {
|
|||
&self,
|
||||
tx: &SanitizedTransaction,
|
||||
enable_durable_nonce: bool,
|
||||
next_durable_nonce: &DurableNonce,
|
||||
) -> Option<TransactionAccount> {
|
||||
(enable_durable_nonce
|
||||
let durable_nonces_enabled = enable_durable_nonce
|
||||
|| self.slot() <= 135986379
|
||||
|| self.cluster_type() != ClusterType::MainnetBeta)
|
||||
|| self.cluster_type() != ClusterType::MainnetBeta;
|
||||
let nonce_must_be_advanceable = self
|
||||
.feature_set
|
||||
.is_active(&feature_set::nonce_must_be_advanceable::ID);
|
||||
let nonce_is_advanceable = tx.message().recent_blockhash() != next_durable_nonce.as_hash();
|
||||
(durable_nonces_enabled && (nonce_is_advanceable || !nonce_must_be_advanceable))
|
||||
.then(|| self.check_message_for_nonce(tx.message()))
|
||||
.flatten()
|
||||
}
|
||||
|
@ -12501,9 +12513,26 @@ pub(crate) mod tests {
|
|||
nonce_lamports,
|
||||
nonce_authority,
|
||||
)?;
|
||||
|
||||
// The setup nonce is not valid to be used until the next bank
|
||||
// so wait one more block
|
||||
goto_end_of_slot(Arc::get_mut(&mut bank).unwrap());
|
||||
bank = Arc::new(new_from_parent(&bank));
|
||||
|
||||
Ok((bank, mint_keypair, custodian_keypair, nonce_keypair))
|
||||
}
|
||||
|
||||
impl Bank {
|
||||
fn next_durable_nonce(&self) -> DurableNonce {
|
||||
let separate_nonce_from_blockhash = self
|
||||
.feature_set
|
||||
.is_active(&feature_set::separate_nonce_from_blockhash::id());
|
||||
let hash_queue = self.blockhash_queue.read().unwrap();
|
||||
let last_blockhash = hash_queue.last_hash();
|
||||
DurableNonce::from_blockhash(&last_blockhash, separate_nonce_from_blockhash)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_transaction_for_nonce_ok() {
|
||||
let mut feature_set = FeatureSet::all_enabled();
|
||||
|
@ -12529,6 +12558,7 @@ pub(crate) mod tests {
|
|||
bank.check_transaction_for_nonce(
|
||||
&SanitizedTransaction::from_transaction_for_tests(tx),
|
||||
true, // enable_durable_nonce
|
||||
&bank.next_durable_nonce(),
|
||||
),
|
||||
Some((nonce_pubkey, nonce_account))
|
||||
);
|
||||
|
@ -12558,6 +12588,7 @@ pub(crate) mod tests {
|
|||
.check_transaction_for_nonce(
|
||||
&SanitizedTransaction::from_transaction_for_tests(tx,),
|
||||
true, // enable_durable_nonce
|
||||
&bank.next_durable_nonce(),
|
||||
)
|
||||
.is_none());
|
||||
}
|
||||
|
@ -12587,6 +12618,7 @@ pub(crate) mod tests {
|
|||
.check_transaction_for_nonce(
|
||||
&SanitizedTransaction::from_transaction_for_tests(tx),
|
||||
true, // enable_durable_nonce
|
||||
&bank.next_durable_nonce(),
|
||||
)
|
||||
.is_none());
|
||||
}
|
||||
|
@ -12617,6 +12649,7 @@ pub(crate) mod tests {
|
|||
.check_transaction_for_nonce(
|
||||
&SanitizedTransaction::from_transaction_for_tests(tx),
|
||||
true, // enable_durable_nonce
|
||||
&bank.next_durable_nonce(),
|
||||
)
|
||||
.is_none());
|
||||
}
|
||||
|
@ -12644,6 +12677,7 @@ pub(crate) mod tests {
|
|||
.check_transaction_for_nonce(
|
||||
&SanitizedTransaction::from_transaction_for_tests(tx),
|
||||
true, // enable_durable_nonce
|
||||
&bank.next_durable_nonce(),
|
||||
)
|
||||
.is_none());
|
||||
}
|
||||
|
@ -12675,6 +12709,36 @@ pub(crate) mod tests {
|
|||
assert_eq!(bank.process_transaction(&tx), expect);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nonce_must_be_advanceable() {
|
||||
let (genesis_config, _mint_keypair) = create_genesis_config(100_000_000);
|
||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||
bank.feature_set = Arc::new(FeatureSet::all_enabled());
|
||||
let bank = Arc::new(bank);
|
||||
let nonce_keypair = Keypair::new();
|
||||
let nonce_authority = nonce_keypair.pubkey();
|
||||
let durable_nonce =
|
||||
DurableNonce::from_blockhash(&bank.last_blockhash(), true /* separate domains */);
|
||||
let nonce_account = AccountSharedData::new_data(
|
||||
42_424_242,
|
||||
&nonce::state::Versions::new_current(nonce::State::Initialized(
|
||||
nonce::state::Data::new(nonce_authority, durable_nonce, 5000),
|
||||
)),
|
||||
&system_program::id(),
|
||||
)
|
||||
.unwrap();
|
||||
bank.store_account(&nonce_keypair.pubkey(), &nonce_account);
|
||||
|
||||
let ix =
|
||||
system_instruction::advance_nonce_account(&nonce_keypair.pubkey(), &nonce_authority);
|
||||
let message = Message::new(&[ix], Some(&nonce_keypair.pubkey()));
|
||||
let tx = Transaction::new(&[&nonce_keypair], message, *durable_nonce.as_hash());
|
||||
assert_eq!(
|
||||
bank.process_transaction(&tx),
|
||||
Err(TransactionError::BlockhashNotFound)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nonce_transaction() {
|
||||
let mut feature_set = FeatureSet::all_enabled();
|
||||
|
@ -13313,6 +13377,7 @@ pub(crate) mod tests {
|
|||
bank.check_transaction_for_nonce(
|
||||
&SanitizedTransaction::from_transaction_for_tests(tx),
|
||||
true, // enable_durable_nonce
|
||||
&bank.next_durable_nonce(),
|
||||
),
|
||||
None
|
||||
);
|
||||
|
|
|
@ -436,6 +436,10 @@ pub mod nonce_must_be_authorized {
|
|||
solana_sdk::declare_id!("HxrEu1gXuH7iD3Puua1ohd5n4iUKJyFNtNxk9DVJkvgr");
|
||||
}
|
||||
|
||||
pub mod nonce_must_be_advanceable {
|
||||
solana_sdk::declare_id!("3u3Er5Vc2jVcwz4xr2GJeSAXT3fAj6ADHZ4BJMZiScFd");
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Map of feature identifiers to user-visible description
|
||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||
|
@ -538,6 +542,7 @@ lazy_static! {
|
|||
(vote_state_update_credit_per_dequeue::id(), "Calculate vote credits for VoteStateUpdate per vote dequeue to match credit awards for Vote instruction"),
|
||||
(quick_bail_on_panic::id(), "quick bail on panic"),
|
||||
(nonce_must_be_authorized::id(), "nonce must be authorized"),
|
||||
(nonce_must_be_advanceable::id(), "durable nonces must be advanceable"),
|
||||
/*************** ADD NEW FEATURES HERE ***************/
|
||||
]
|
||||
.iter()
|
||||
|
|
Loading…
Reference in New Issue