separates durable nonce and blockhash domains
AdvanceNonceAccount instruction updates nonce to blockhash. This makes it possible that a durable transaction is executed twice both as a normal transaction and a nonce transaction if it uses blockhash (as opposed to nonce) for its recent_blockhash field. The commit prevents this double execution by separating nonce and blockhash domains; when advancing nonce account, blockhash is hashed with a fixed string. As a result a blockhash cannot be a valid nonce value; and if transaction was once executed as a normal transaction it cannot be re-executed as a durable transaction again and vice-versa.
This commit is contained in:
parent
8ca8a61272
commit
5ee157f43d
|
@ -20,7 +20,7 @@ pub fn parse_nonce(data: &[u8]) -> Result<UiNonceState, ParseAccountError> {
|
|||
)),
|
||||
State::Initialized(data) => Ok(UiNonceState::Initialized(UiNonceData {
|
||||
authority: data.authority.to_string(),
|
||||
blockhash: data.blockhash.to_string(),
|
||||
blockhash: data.blockhash().to_string(),
|
||||
fee_calculator: data.fee_calculator.into(),
|
||||
})),
|
||||
}
|
||||
|
|
|
@ -333,10 +333,10 @@ pub fn check_nonce_account(
|
|||
) -> Result<(), CliError> {
|
||||
match state_from_account(nonce_account)? {
|
||||
State::Initialized(ref data) => {
|
||||
if &data.blockhash != nonce_hash {
|
||||
if &data.blockhash() != nonce_hash {
|
||||
Err(Error::InvalidHash {
|
||||
provided: *nonce_hash,
|
||||
expected: data.blockhash,
|
||||
expected: data.blockhash(),
|
||||
}
|
||||
.into())
|
||||
} else if nonce_authority != &data.authority {
|
||||
|
@ -524,7 +524,7 @@ pub fn process_get_nonce(
|
|||
.and_then(|ref a| state_from_account(a))?
|
||||
{
|
||||
State::Uninitialized => Ok("Nonce account is uninitialized".to_string()),
|
||||
State::Initialized(ref data) => Ok(format!("{:?}", data.blockhash)),
|
||||
State::Initialized(ref data) => Ok(format!("{:?}", data.blockhash())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -598,7 +598,7 @@ pub fn process_show_nonce_account(
|
|||
..CliNonceAccount::default()
|
||||
};
|
||||
if let Some(data) = data {
|
||||
nonce_account.nonce = Some(data.blockhash.to_string());
|
||||
nonce_account.nonce = Some(data.blockhash().to_string());
|
||||
nonce_account.lamports_per_signature = Some(data.fee_calculator.lamports_per_signature);
|
||||
nonce_account.authority = Some(data.authority.to_string());
|
||||
}
|
||||
|
@ -665,7 +665,11 @@ mod tests {
|
|||
account::Account,
|
||||
account_utils::StateMut,
|
||||
hash::hash,
|
||||
nonce::{self, state::Versions, State},
|
||||
nonce::{
|
||||
self,
|
||||
state::{DurableNonce, Versions},
|
||||
State,
|
||||
},
|
||||
nonce_account,
|
||||
signature::{read_keypair_file, write_keypair, Keypair, Signer},
|
||||
system_program,
|
||||
|
@ -925,11 +929,13 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_check_nonce_account() {
|
||||
let blockhash = Hash::default();
|
||||
let durable_nonce =
|
||||
DurableNonce::from_blockhash(&Hash::default(), /*separate_domains:*/ true);
|
||||
let blockhash = *durable_nonce.as_hash();
|
||||
let nonce_pubkey = solana_sdk::pubkey::new_rand();
|
||||
let data = Versions::new_current(State::Initialized(nonce::state::Data::new(
|
||||
nonce_pubkey,
|
||||
blockhash,
|
||||
durable_nonce,
|
||||
0,
|
||||
)));
|
||||
let valid = Account::new_data(1, &data, &system_program::ID);
|
||||
|
@ -949,9 +955,11 @@ mod tests {
|
|||
assert_eq!(err, Error::InvalidAccountData,);
|
||||
}
|
||||
|
||||
let invalid_durable_nonce =
|
||||
DurableNonce::from_blockhash(&hash(b"invalid"), /*separate_domains:*/ true);
|
||||
let data = Versions::new_current(State::Initialized(nonce::state::Data::new(
|
||||
nonce_pubkey,
|
||||
hash(b"invalid"),
|
||||
invalid_durable_nonce,
|
||||
0,
|
||||
)));
|
||||
let invalid_hash = Account::new_data(1, &data, &system_program::ID).unwrap();
|
||||
|
@ -962,7 +970,7 @@ mod tests {
|
|||
err,
|
||||
Error::InvalidHash {
|
||||
provided: blockhash,
|
||||
expected: hash(b"invalid"),
|
||||
expected: *invalid_durable_nonce.as_hash(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -970,7 +978,7 @@ mod tests {
|
|||
let new_nonce_authority = solana_sdk::pubkey::new_rand();
|
||||
let data = Versions::new_current(State::Initialized(nonce::state::Data::new(
|
||||
new_nonce_authority,
|
||||
blockhash,
|
||||
durable_nonce,
|
||||
0,
|
||||
)));
|
||||
let invalid_authority = Account::new_data(1, &data, &system_program::ID);
|
||||
|
@ -1019,7 +1027,9 @@ mod tests {
|
|||
let mut nonce_account = nonce_account::create_account(1).into_inner();
|
||||
assert_eq!(state_from_account(&nonce_account), Ok(State::Uninitialized));
|
||||
|
||||
let data = nonce::state::Data::new(Pubkey::new(&[1u8; 32]), Hash::new(&[42u8; 32]), 42);
|
||||
let durable_nonce =
|
||||
DurableNonce::from_blockhash(&Hash::new(&[42u8; 32]), /*separate_domains:*/ true);
|
||||
let data = nonce::state::Data::new(Pubkey::new(&[1u8; 32]), durable_nonce, 42);
|
||||
nonce_account
|
||||
.set_state(&Versions::new_current(State::Initialized(data.clone())))
|
||||
.unwrap();
|
||||
|
@ -1048,7 +1058,9 @@ mod tests {
|
|||
Err(Error::InvalidStateForOperation)
|
||||
);
|
||||
|
||||
let data = nonce::state::Data::new(Pubkey::new(&[1u8; 32]), Hash::new(&[42u8; 32]), 42);
|
||||
let durable_nonce =
|
||||
DurableNonce::from_blockhash(&Hash::new(&[42u8; 32]), /*separate_domains:*/ true);
|
||||
let data = nonce::state::Data::new(Pubkey::new(&[1u8; 32]), durable_nonce, 42);
|
||||
nonce_account
|
||||
.set_state(&Versions::new_current(State::Initialized(data.clone())))
|
||||
.unwrap();
|
||||
|
|
|
@ -325,7 +325,7 @@ fn test_create_account_with_seed() {
|
|||
)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||
.unwrap()
|
||||
.blockhash;
|
||||
.blockhash();
|
||||
|
||||
// Test by creating transfer TX with nonce, fully offline
|
||||
let mut authority_config = CliConfig::recent_for_tests();
|
||||
|
|
|
@ -539,7 +539,7 @@ fn test_nonced_stake_delegation_and_deactivation() {
|
|||
)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||
.unwrap()
|
||||
.blockhash;
|
||||
.blockhash();
|
||||
|
||||
// Delegate stake
|
||||
config.signers = vec![&config_keypair];
|
||||
|
@ -569,7 +569,7 @@ fn test_nonced_stake_delegation_and_deactivation() {
|
|||
)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||
.unwrap()
|
||||
.blockhash;
|
||||
.blockhash();
|
||||
|
||||
// Deactivate stake
|
||||
config.command = CliCommand::DeactivateStake {
|
||||
|
@ -838,7 +838,7 @@ fn test_stake_authorize() {
|
|||
)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||
.unwrap()
|
||||
.blockhash;
|
||||
.blockhash();
|
||||
|
||||
// Nonced assignment of new online stake authority
|
||||
let online_authority = Keypair::new();
|
||||
|
@ -906,7 +906,7 @@ fn test_stake_authorize() {
|
|||
)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||
.unwrap()
|
||||
.blockhash;
|
||||
.blockhash();
|
||||
assert_ne!(nonce_hash, new_nonce_hash);
|
||||
}
|
||||
|
||||
|
@ -1188,7 +1188,7 @@ fn test_stake_split() {
|
|||
)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||
.unwrap()
|
||||
.blockhash;
|
||||
.blockhash();
|
||||
|
||||
// Nonced offline split
|
||||
let split_account = keypair_from_seed(&[2u8; 32]).unwrap();
|
||||
|
@ -1458,7 +1458,7 @@ fn test_stake_set_lockup() {
|
|||
)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||
.unwrap()
|
||||
.blockhash;
|
||||
.blockhash();
|
||||
|
||||
// Nonced offline set lockup
|
||||
let lockup = LockupArgs {
|
||||
|
@ -1584,7 +1584,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
|||
)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||
.unwrap()
|
||||
.blockhash;
|
||||
.blockhash();
|
||||
|
||||
// Create stake account offline
|
||||
let stake_keypair = keypair_from_seed(&[4u8; 32]).unwrap();
|
||||
|
@ -1645,7 +1645,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
|||
)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||
.unwrap()
|
||||
.blockhash;
|
||||
.blockhash();
|
||||
|
||||
// Offline, nonced stake-withdraw
|
||||
let recipient = keypair_from_seed(&[5u8; 32]).unwrap();
|
||||
|
@ -1699,7 +1699,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
|||
)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||
.unwrap()
|
||||
.blockhash;
|
||||
.blockhash();
|
||||
|
||||
// Create another stake account. This time with seed
|
||||
let seed = "seedy";
|
||||
|
|
|
@ -200,7 +200,7 @@ fn test_transfer() {
|
|||
)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||
.unwrap()
|
||||
.blockhash;
|
||||
.blockhash();
|
||||
|
||||
// Nonced transfer
|
||||
config.signers = vec![&default_signer];
|
||||
|
@ -237,7 +237,7 @@ fn test_transfer() {
|
|||
)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||
.unwrap()
|
||||
.blockhash;
|
||||
.blockhash();
|
||||
assert_ne!(nonce_hash, new_nonce_hash);
|
||||
|
||||
// Assign nonce authority to offline
|
||||
|
@ -263,7 +263,7 @@ fn test_transfer() {
|
|||
)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||
.unwrap()
|
||||
.blockhash;
|
||||
.blockhash();
|
||||
|
||||
// Offline, nonced transfer
|
||||
offline.signers = vec![&default_offline_signer];
|
||||
|
|
|
@ -37,7 +37,7 @@ impl Source {
|
|||
#[allow(clippy::redundant_closure)]
|
||||
let data = nonce_utils::get_account_with_commitment(rpc_client, pubkey, commitment)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))?;
|
||||
Ok((data.blockhash, data.fee_calculator))
|
||||
Ok((data.blockhash(), data.fee_calculator))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ impl Source {
|
|||
let res = nonce_utils::get_account_with_commitment(rpc_client, pubkey, commitment)?;
|
||||
let res = nonce_utils::data_from_account(&res)?;
|
||||
Ok(Some(res)
|
||||
.filter(|d| d.blockhash == *blockhash)
|
||||
.filter(|d| d.blockhash() == *blockhash)
|
||||
.map(|d| d.fee_calculator))
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ impl Source {
|
|||
#[allow(clippy::redundant_closure)]
|
||||
let data = nonce_utils::get_account_with_commitment(rpc_client, pubkey, commitment)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))?;
|
||||
Ok(data.blockhash)
|
||||
Ok(data.blockhash())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -193,7 +193,12 @@ mod tests {
|
|||
clap::App,
|
||||
serde_json::{self, json},
|
||||
solana_account_decoder::{UiAccount, UiAccountEncoding},
|
||||
solana_sdk::{account::Account, hash::hash, nonce, system_program},
|
||||
solana_sdk::{
|
||||
account::Account,
|
||||
hash::hash,
|
||||
nonce::{self, state::DurableNonce},
|
||||
system_program,
|
||||
},
|
||||
std::collections::HashMap,
|
||||
};
|
||||
|
||||
|
@ -411,11 +416,13 @@ mod tests {
|
|||
.get_blockhash_and_fee_calculator(&rpc_client, CommitmentConfig::default())
|
||||
.is_err());
|
||||
|
||||
let nonce_blockhash = Hash::new(&[2u8; 32]);
|
||||
let durable_nonce =
|
||||
DurableNonce::from_blockhash(&Hash::new(&[2u8; 32]), /*separate_domains:*/ true);
|
||||
let nonce_blockhash = *durable_nonce.as_hash();
|
||||
let nonce_fee_calc = FeeCalculator::new(4242);
|
||||
let data = nonce::state::Data {
|
||||
authority: Pubkey::new(&[3u8; 32]),
|
||||
blockhash: nonce_blockhash,
|
||||
durable_nonce,
|
||||
fee_calculator: nonce_fee_calc,
|
||||
};
|
||||
let nonce_account = Account::new_data_with_space(
|
||||
|
|
|
@ -199,7 +199,7 @@ pub fn state_from_account<T: ReadableAccount + StateMut<Versions>>(
|
|||
/// // network's latest blockhash.
|
||||
/// let nonce_account = client.get_account(nonce_account_pubkey)?;
|
||||
/// let nonce_data = nonce_utils::data_from_account(&nonce_account)?;
|
||||
/// let blockhash = nonce_data.blockhash;
|
||||
/// let blockhash = nonce_data.blockhash();
|
||||
///
|
||||
/// tx.try_sign(&[payer], blockhash)?;
|
||||
///
|
||||
|
|
|
@ -4570,7 +4570,8 @@ pub mod tests {
|
|||
hash::{hash, Hash},
|
||||
instruction::InstructionError,
|
||||
message::{v0, v0::MessageAddressTableLookup, MessageHeader, VersionedMessage},
|
||||
nonce, rpc_port,
|
||||
nonce::{self, state::DurableNonce},
|
||||
rpc_port,
|
||||
signature::{Keypair, Signer},
|
||||
slot_hashes::SlotHashes,
|
||||
system_program, system_transaction,
|
||||
|
@ -5550,7 +5551,7 @@ pub mod tests {
|
|||
42,
|
||||
&nonce::state::Versions::new_current(nonce::State::new_initialized(
|
||||
&authority,
|
||||
&Hash::default(),
|
||||
DurableNonce::default(),
|
||||
1000,
|
||||
)),
|
||||
&system_program::id(),
|
||||
|
|
|
@ -223,7 +223,8 @@ pub(crate) mod tests {
|
|||
hash::Hash,
|
||||
instruction::CompiledInstruction,
|
||||
message::{Message, MessageHeader, SanitizedMessage},
|
||||
nonce, nonce_account,
|
||||
nonce::{self, state::DurableNonce},
|
||||
nonce_account,
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, Signature, Signer},
|
||||
system_transaction,
|
||||
|
@ -323,7 +324,9 @@ pub(crate) mod tests {
|
|||
let pubkey = Pubkey::new_unique();
|
||||
|
||||
let mut nonce_account = nonce_account::create_account(1).into_inner();
|
||||
let data = nonce::state::Data::new(Pubkey::new(&[1u8; 32]), Hash::new(&[42u8; 32]), 42);
|
||||
let durable_nonce =
|
||||
DurableNonce::from_blockhash(&Hash::new(&[42u8; 32]), /*separate_domains:*/ true);
|
||||
let data = nonce::state::Data::new(Pubkey::new(&[1u8; 32]), durable_nonce, 42);
|
||||
nonce_account
|
||||
.set_state(&nonce::state::Versions::new_current(
|
||||
nonce::State::Initialized(data),
|
||||
|
|
|
@ -40,7 +40,10 @@ use {
|
|||
SanitizedMessage,
|
||||
},
|
||||
native_loader,
|
||||
nonce::{state::Versions as NonceVersions, State as NonceState},
|
||||
nonce::{
|
||||
state::{DurableNonce, Versions as NonceVersions},
|
||||
State as NonceState,
|
||||
},
|
||||
pubkey::Pubkey,
|
||||
slot_hashes::SlotHashes,
|
||||
system_program,
|
||||
|
@ -1193,7 +1196,7 @@ impl Accounts {
|
|||
res: &'a [TransactionExecutionResult],
|
||||
loaded: &'a mut [TransactionLoadResult],
|
||||
rent_collector: &RentCollector,
|
||||
blockhash: &Hash,
|
||||
durable_nonce: &DurableNonce,
|
||||
lamports_per_signature: u64,
|
||||
leave_nonce_on_success: bool,
|
||||
) {
|
||||
|
@ -1202,7 +1205,7 @@ impl Accounts {
|
|||
res,
|
||||
loaded,
|
||||
rent_collector,
|
||||
blockhash,
|
||||
durable_nonce,
|
||||
lamports_per_signature,
|
||||
leave_nonce_on_success,
|
||||
);
|
||||
|
@ -1225,7 +1228,7 @@ impl Accounts {
|
|||
execution_results: &'a [TransactionExecutionResult],
|
||||
load_results: &'a mut [TransactionLoadResult],
|
||||
rent_collector: &RentCollector,
|
||||
blockhash: &Hash,
|
||||
durable_nonce: &DurableNonce,
|
||||
lamports_per_signature: u64,
|
||||
leave_nonce_on_success: bool,
|
||||
) -> Vec<(&'a Pubkey, &'a AccountSharedData)> {
|
||||
|
@ -1279,7 +1282,7 @@ impl Accounts {
|
|||
execution_status,
|
||||
is_fee_payer,
|
||||
maybe_nonce,
|
||||
blockhash,
|
||||
durable_nonce,
|
||||
lamports_per_signature,
|
||||
);
|
||||
|
||||
|
@ -1306,13 +1309,13 @@ impl Accounts {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn prepare_if_nonce_account<'a>(
|
||||
fn prepare_if_nonce_account<'a>(
|
||||
address: &Pubkey,
|
||||
account: &mut AccountSharedData,
|
||||
execution_result: &Result<()>,
|
||||
is_fee_payer: bool,
|
||||
maybe_nonce: Option<(&'a NonceFull, bool)>,
|
||||
blockhash: &Hash,
|
||||
durable_nonce: &DurableNonce,
|
||||
lamports_per_signature: u64,
|
||||
) -> bool {
|
||||
if let Some((nonce, rollback)) = maybe_nonce {
|
||||
|
@ -1338,7 +1341,7 @@ pub fn prepare_if_nonce_account<'a>(
|
|||
account
|
||||
.set_state(&NonceVersions::new_current(NonceState::new_initialized(
|
||||
&data.authority,
|
||||
blockhash,
|
||||
*durable_nonce,
|
||||
lamports_per_signature,
|
||||
)))
|
||||
.unwrap();
|
||||
|
@ -3025,7 +3028,7 @@ mod tests {
|
|||
&execution_results,
|
||||
loaded.as_mut_slice(),
|
||||
&rent_collector,
|
||||
&Hash::default(),
|
||||
&DurableNonce::default(),
|
||||
0,
|
||||
true, // leave_nonce_on_success
|
||||
);
|
||||
|
@ -3171,7 +3174,7 @@ mod tests {
|
|||
Pubkey,
|
||||
AccountSharedData,
|
||||
AccountSharedData,
|
||||
Hash,
|
||||
DurableNonce,
|
||||
u64,
|
||||
Option<AccountSharedData>,
|
||||
) {
|
||||
|
@ -3184,7 +3187,7 @@ mod tests {
|
|||
Pubkey::default(),
|
||||
pre_account,
|
||||
account,
|
||||
Hash::new(&[1u8; 32]),
|
||||
DurableNonce::from_blockhash(&Hash::new(&[1u8; 32]), /*separate_domains:*/ true),
|
||||
1234,
|
||||
None,
|
||||
)
|
||||
|
@ -3196,7 +3199,7 @@ mod tests {
|
|||
tx_result: &Result<()>,
|
||||
is_fee_payer: bool,
|
||||
maybe_nonce: Option<(&NonceFull, bool)>,
|
||||
blockhash: &Hash,
|
||||
durable_nonce: &DurableNonce,
|
||||
lamports_per_signature: u64,
|
||||
expect_account: &AccountSharedData,
|
||||
) -> bool {
|
||||
|
@ -3216,7 +3219,7 @@ mod tests {
|
|||
tx_result,
|
||||
is_fee_payer,
|
||||
maybe_nonce,
|
||||
blockhash,
|
||||
durable_nonce,
|
||||
lamports_per_signature,
|
||||
);
|
||||
assert_eq!(expect_account, account);
|
||||
|
@ -3370,7 +3373,7 @@ mod tests {
|
|||
)),
|
||||
false,
|
||||
Some((&nonce, true)),
|
||||
&Hash::default(),
|
||||
&DurableNonce::default(),
|
||||
1,
|
||||
&post_fee_payer_account.clone(),
|
||||
));
|
||||
|
@ -3381,7 +3384,7 @@ mod tests {
|
|||
&Ok(()),
|
||||
true,
|
||||
Some((&nonce, true)),
|
||||
&Hash::default(),
|
||||
&DurableNonce::default(),
|
||||
1,
|
||||
&post_fee_payer_account.clone(),
|
||||
));
|
||||
|
@ -3395,7 +3398,7 @@ mod tests {
|
|||
)),
|
||||
true,
|
||||
None,
|
||||
&Hash::default(),
|
||||
&DurableNonce::default(),
|
||||
1,
|
||||
&post_fee_payer_account.clone(),
|
||||
));
|
||||
|
@ -3409,7 +3412,7 @@ mod tests {
|
|||
)),
|
||||
true,
|
||||
Some((&nonce, true)),
|
||||
&Hash::default(),
|
||||
&DurableNonce::default(),
|
||||
1,
|
||||
&pre_fee_payer_account,
|
||||
));
|
||||
|
@ -3424,8 +3427,10 @@ mod tests {
|
|||
let from = keypair_from_seed(&[1; 32]).unwrap();
|
||||
let from_address = from.pubkey();
|
||||
let to_address = Pubkey::new_unique();
|
||||
let durable_nonce =
|
||||
DurableNonce::from_blockhash(&Hash::new_unique(), /*separate_domains:*/ true);
|
||||
let nonce_state = NonceVersions::new_current(NonceState::Initialized(
|
||||
nonce::state::Data::new(nonce_authority.pubkey(), Hash::new_unique(), 0),
|
||||
nonce::state::Data::new(nonce_authority.pubkey(), durable_nonce, 0),
|
||||
));
|
||||
let nonce_account_post =
|
||||
AccountSharedData::new_data(43, &nonce_state, &system_program::id()).unwrap();
|
||||
|
@ -3449,8 +3454,10 @@ mod tests {
|
|||
];
|
||||
let tx = new_sanitized_tx(&[&nonce_authority, &from], message, blockhash);
|
||||
|
||||
let durable_nonce =
|
||||
DurableNonce::from_blockhash(&Hash::new_unique(), /*separate_domains:*/ true);
|
||||
let nonce_state = NonceVersions::new_current(NonceState::Initialized(
|
||||
nonce::state::Data::new(nonce_authority.pubkey(), Hash::new_unique(), 0),
|
||||
nonce::state::Data::new(nonce_authority.pubkey(), durable_nonce, 0),
|
||||
));
|
||||
let nonce_account_pre =
|
||||
AccountSharedData::new_data(42, &nonce_state, &system_program::id()).unwrap();
|
||||
|
@ -3474,7 +3481,8 @@ mod tests {
|
|||
|
||||
let mut loaded = vec![loaded];
|
||||
|
||||
let next_blockhash = Hash::new_unique();
|
||||
let durable_nonce =
|
||||
DurableNonce::from_blockhash(&Hash::new_unique(), /*separate_domains:*/ true);
|
||||
let accounts = Accounts::new_with_config_for_tests(
|
||||
Vec::new(),
|
||||
&ClusterType::Development,
|
||||
|
@ -3495,7 +3503,7 @@ mod tests {
|
|||
&execution_results,
|
||||
loaded.as_mut_slice(),
|
||||
&rent_collector,
|
||||
&next_blockhash,
|
||||
&durable_nonce,
|
||||
0,
|
||||
true, // leave_nonce_on_success
|
||||
);
|
||||
|
@ -3521,7 +3529,7 @@ mod tests {
|
|||
);
|
||||
assert!(nonce_account::verify_nonce_account(
|
||||
&collected_nonce_account,
|
||||
&next_blockhash
|
||||
durable_nonce.as_hash(),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -3534,8 +3542,10 @@ mod tests {
|
|||
let from = keypair_from_seed(&[1; 32]).unwrap();
|
||||
let from_address = from.pubkey();
|
||||
let to_address = Pubkey::new_unique();
|
||||
let durable_nonce =
|
||||
DurableNonce::from_blockhash(&Hash::new_unique(), /*separate_domains:*/ true);
|
||||
let nonce_state = NonceVersions::new_current(NonceState::Initialized(
|
||||
nonce::state::Data::new(nonce_authority.pubkey(), Hash::new_unique(), 0),
|
||||
nonce::state::Data::new(nonce_authority.pubkey(), durable_nonce, 0),
|
||||
));
|
||||
let nonce_account_post =
|
||||
AccountSharedData::new_data(43, &nonce_state, &system_program::id()).unwrap();
|
||||
|
@ -3559,8 +3569,10 @@ mod tests {
|
|||
];
|
||||
let tx = new_sanitized_tx(&[&nonce_authority, &from], message, blockhash);
|
||||
|
||||
let durable_nonce =
|
||||
DurableNonce::from_blockhash(&Hash::new_unique(), /*separate_domains:*/ true);
|
||||
let nonce_state = NonceVersions::new_current(NonceState::Initialized(
|
||||
nonce::state::Data::new(nonce_authority.pubkey(), Hash::new_unique(), 0),
|
||||
nonce::state::Data::new(nonce_authority.pubkey(), durable_nonce, 0),
|
||||
));
|
||||
let nonce_account_pre =
|
||||
AccountSharedData::new_data(42, &nonce_state, &system_program::id()).unwrap();
|
||||
|
@ -3583,7 +3595,8 @@ mod tests {
|
|||
|
||||
let mut loaded = vec![loaded];
|
||||
|
||||
let next_blockhash = Hash::new_unique();
|
||||
let durable_nonce =
|
||||
DurableNonce::from_blockhash(&Hash::new_unique(), /*separate_domains:*/ true);
|
||||
let accounts = Accounts::new_with_config_for_tests(
|
||||
Vec::new(),
|
||||
&ClusterType::Development,
|
||||
|
@ -3604,7 +3617,7 @@ mod tests {
|
|||
&execution_results,
|
||||
loaded.as_mut_slice(),
|
||||
&rent_collector,
|
||||
&next_blockhash,
|
||||
&durable_nonce,
|
||||
0,
|
||||
true, // leave_nonce_on_success
|
||||
);
|
||||
|
@ -3621,7 +3634,7 @@ mod tests {
|
|||
);
|
||||
assert!(nonce_account::verify_nonce_account(
|
||||
&collected_nonce_account,
|
||||
&next_blockhash
|
||||
durable_nonce.as_hash(),
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -124,7 +124,8 @@ use {
|
|||
message::{AccountKeys, SanitizedMessage},
|
||||
native_loader,
|
||||
native_token::sol_to_lamports,
|
||||
nonce, nonce_account,
|
||||
nonce::{self, state::DurableNonce},
|
||||
nonce_account,
|
||||
packet::PACKET_DATA_SIZE,
|
||||
precompiles::get_precompiles,
|
||||
pubkey::Pubkey,
|
||||
|
@ -4909,13 +4910,19 @@ impl Bank {
|
|||
}
|
||||
|
||||
let mut write_time = Measure::start("write_time");
|
||||
let durable_nonce = {
|
||||
let separate_nonce_from_blockhash = self
|
||||
.feature_set
|
||||
.is_active(&feature_set::separate_nonce_from_blockhash::id());
|
||||
DurableNonce::from_blockhash(&last_blockhash, separate_nonce_from_blockhash)
|
||||
};
|
||||
self.rc.accounts.store_cached(
|
||||
self.slot(),
|
||||
sanitized_txs,
|
||||
&execution_results,
|
||||
loaded_txs,
|
||||
&self.rent_collector,
|
||||
&last_blockhash,
|
||||
&durable_nonce,
|
||||
lamports_per_signature,
|
||||
self.leave_nonce_on_success(),
|
||||
);
|
||||
|
@ -7622,14 +7629,12 @@ pub(crate) mod tests {
|
|||
let from_address = from.pubkey();
|
||||
let to_address = Pubkey::new_unique();
|
||||
|
||||
let durable_nonce =
|
||||
DurableNonce::from_blockhash(&Hash::new_unique(), /*separate_domains:*/ true);
|
||||
let nonce_account = AccountSharedData::new_data(
|
||||
43,
|
||||
&nonce::state::Versions::new_current(nonce::State::Initialized(
|
||||
nonce::state::Data::new(
|
||||
Pubkey::default(),
|
||||
Hash::new_unique(),
|
||||
lamports_per_signature,
|
||||
),
|
||||
nonce::state::Data::new(Pubkey::default(), durable_nonce, lamports_per_signature),
|
||||
)),
|
||||
&system_program::id(),
|
||||
)
|
||||
|
@ -12347,7 +12352,7 @@ pub(crate) mod tests {
|
|||
let state =
|
||||
StateMut::<nonce::state::Versions>::state(&acc).map(|v| v.convert_to_current());
|
||||
match state {
|
||||
Ok(nonce::State::Initialized(ref data)) => Some(data.blockhash),
|
||||
Ok(nonce::State::Initialized(ref data)) => Some(data.blockhash()),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
|
@ -13049,7 +13054,7 @@ pub(crate) mod tests {
|
|||
StateMut::<nonce::state::Versions>::state(&acc).map(|v| v.convert_to_current());
|
||||
match state {
|
||||
Ok(nonce::State::Initialized(ref data)) => {
|
||||
Some((data.blockhash, data.fee_calculator))
|
||||
Some((data.blockhash(), data.fee_calculator))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
@ -13086,7 +13091,7 @@ pub(crate) mod tests {
|
|||
StateMut::<nonce::state::Versions>::state(&acc).map(|v| v.convert_to_current());
|
||||
match state {
|
||||
Ok(nonce::State::Initialized(ref data)) => {
|
||||
Some((data.blockhash, data.fee_calculator))
|
||||
Some((data.blockhash(), data.fee_calculator))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
@ -13119,7 +13124,7 @@ pub(crate) mod tests {
|
|||
StateMut::<nonce::state::Versions>::state(&acc).map(|v| v.convert_to_current());
|
||||
match state {
|
||||
Ok(nonce::State::Initialized(ref data)) => {
|
||||
Some((data.blockhash, data.fee_calculator))
|
||||
Some((data.blockhash(), data.fee_calculator))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
@ -13156,7 +13161,7 @@ pub(crate) mod tests {
|
|||
StateMut::<nonce::state::Versions>::state(&acc).map(|v| v.convert_to_current());
|
||||
match state {
|
||||
Ok(nonce::State::Initialized(ref data)) => {
|
||||
Some((data.blockhash, data.fee_calculator))
|
||||
Some((data.blockhash(), data.fee_calculator))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
@ -13198,13 +13203,13 @@ pub(crate) mod tests {
|
|||
&[&custodian_keypair, &nonce_keypair],
|
||||
nonce_hash,
|
||||
);
|
||||
// Caught by the system program because the tx hash is valid
|
||||
// SanitizedMessage::get_durable_nonce returns None because nonce
|
||||
// account is not writable. Durable nonce and blockhash domains are
|
||||
// separate, so the recent_blockhash (== durable nonce) in the
|
||||
// transaction is not found in the hash queue.
|
||||
assert_eq!(
|
||||
bank.process_transaction(&tx),
|
||||
Err(TransactionError::InstructionError(
|
||||
0,
|
||||
InstructionError::InvalidArgument
|
||||
))
|
||||
Err(TransactionError::BlockhashNotFound),
|
||||
);
|
||||
// Kick nonce hash off the blockhash_queue
|
||||
for _ in 0..MAX_RECENT_BLOCKHASHES + 1 {
|
||||
|
|
|
@ -3,7 +3,11 @@ use {
|
|||
solana_sdk::{
|
||||
feature_set::{self, nonce_must_be_writable},
|
||||
instruction::{checked_add, InstructionError},
|
||||
nonce::{self, state::Versions, State},
|
||||
nonce::{
|
||||
self,
|
||||
state::{DurableNonce, Versions},
|
||||
State,
|
||||
},
|
||||
pubkey::Pubkey,
|
||||
system_instruction::{nonce_to_instruction_error, NonceError},
|
||||
sysvar::rent::Rent,
|
||||
|
@ -12,6 +16,13 @@ use {
|
|||
std::collections::HashSet,
|
||||
};
|
||||
|
||||
fn get_durable_nonce(invoke_context: &InvokeContext) -> DurableNonce {
|
||||
let separate_nonce_from_blockhash = invoke_context
|
||||
.feature_set
|
||||
.is_active(&feature_set::separate_nonce_from_blockhash::id());
|
||||
DurableNonce::from_blockhash(&invoke_context.blockhash, separate_nonce_from_blockhash)
|
||||
}
|
||||
|
||||
pub fn advance_nonce_account(
|
||||
account: &mut BorrowedAccount,
|
||||
signers: &HashSet<Pubkey>,
|
||||
|
@ -45,8 +56,8 @@ pub fn advance_nonce_account(
|
|||
);
|
||||
return Err(InstructionError::MissingRequiredSignature);
|
||||
}
|
||||
let recent_blockhash = invoke_context.blockhash;
|
||||
if data.blockhash == recent_blockhash {
|
||||
let next_durable_nonce = get_durable_nonce(invoke_context);
|
||||
if data.durable_nonce == next_durable_nonce {
|
||||
ic_msg!(
|
||||
invoke_context,
|
||||
"Advance nonce account: nonce can only advance once per slot"
|
||||
|
@ -59,7 +70,7 @@ pub fn advance_nonce_account(
|
|||
|
||||
let new_data = nonce::state::Data::new(
|
||||
data.authority,
|
||||
recent_blockhash,
|
||||
next_durable_nonce,
|
||||
invoke_context.lamports_per_signature,
|
||||
);
|
||||
account.set_state(&Versions::new_current(State::Initialized(new_data)))
|
||||
|
@ -123,7 +134,7 @@ pub fn withdraw_nonce_account(
|
|||
}
|
||||
State::Initialized(ref data) => {
|
||||
if lamports == from.get_lamports() {
|
||||
if data.blockhash == invoke_context.blockhash {
|
||||
if data.durable_nonce == get_durable_nonce(invoke_context) {
|
||||
ic_msg!(
|
||||
invoke_context,
|
||||
"Withdraw nonce account: nonce can only advance once per slot"
|
||||
|
@ -208,7 +219,7 @@ pub fn initialize_nonce_account(
|
|||
}
|
||||
let data = nonce::state::Data::new(
|
||||
*nonce_authority,
|
||||
invoke_context.blockhash,
|
||||
get_durable_nonce(invoke_context),
|
||||
invoke_context.lamports_per_signature,
|
||||
);
|
||||
account.set_state(&Versions::new_current(State::Initialized(data)))
|
||||
|
@ -263,7 +274,7 @@ pub fn authorize_nonce_account(
|
|||
}
|
||||
let new_data = nonce::state::Data::new(
|
||||
*nonce_authority,
|
||||
data.blockhash,
|
||||
data.durable_nonce,
|
||||
data.get_lamports_per_signature(),
|
||||
);
|
||||
account.set_state(&Versions::new_current(State::Initialized(new_data)))
|
||||
|
@ -394,7 +405,7 @@ mod test {
|
|||
.convert_to_current();
|
||||
let data = nonce::state::Data::new(
|
||||
data.authority,
|
||||
invoke_context.blockhash,
|
||||
get_durable_nonce(&invoke_context),
|
||||
invoke_context.lamports_per_signature,
|
||||
);
|
||||
// First nonce instruction drives state from Uninitialized to Initialized
|
||||
|
@ -407,7 +418,7 @@ mod test {
|
|||
.convert_to_current();
|
||||
let data = nonce::state::Data::new(
|
||||
data.authority,
|
||||
invoke_context.blockhash,
|
||||
get_durable_nonce(&invoke_context),
|
||||
invoke_context.lamports_per_signature,
|
||||
);
|
||||
// Second nonce instruction consumes and replaces stored nonce
|
||||
|
@ -420,7 +431,7 @@ mod test {
|
|||
.convert_to_current();
|
||||
let data = nonce::state::Data::new(
|
||||
data.authority,
|
||||
invoke_context.blockhash,
|
||||
get_durable_nonce(&invoke_context),
|
||||
invoke_context.lamports_per_signature,
|
||||
);
|
||||
// Third nonce instruction for fun and profit
|
||||
|
@ -485,7 +496,7 @@ mod test {
|
|||
.convert_to_current();
|
||||
let data = nonce::state::Data::new(
|
||||
authority,
|
||||
invoke_context.blockhash,
|
||||
get_durable_nonce(&invoke_context),
|
||||
invoke_context.lamports_per_signature,
|
||||
);
|
||||
assert_eq!(state, State::Initialized(data));
|
||||
|
@ -818,7 +829,7 @@ mod test {
|
|||
.convert_to_current();
|
||||
let data = nonce::state::Data::new(
|
||||
authority,
|
||||
invoke_context.blockhash,
|
||||
get_durable_nonce(&invoke_context),
|
||||
invoke_context.lamports_per_signature,
|
||||
);
|
||||
assert_eq!(state, State::Initialized(data.clone()));
|
||||
|
@ -850,7 +861,7 @@ mod test {
|
|||
.convert_to_current();
|
||||
let data = nonce::state::Data::new(
|
||||
data.authority,
|
||||
invoke_context.blockhash,
|
||||
get_durable_nonce(&invoke_context),
|
||||
invoke_context.lamports_per_signature,
|
||||
);
|
||||
assert_eq!(state, State::Initialized(data));
|
||||
|
@ -1048,7 +1059,7 @@ mod test {
|
|||
initialize_nonce_account(&mut nonce_account, &authorized, &rent, &invoke_context);
|
||||
let data = nonce::state::Data::new(
|
||||
authorized,
|
||||
invoke_context.blockhash,
|
||||
get_durable_nonce(&invoke_context),
|
||||
invoke_context.lamports_per_signature,
|
||||
);
|
||||
assert_eq!(result, Ok(()));
|
||||
|
@ -1120,7 +1131,7 @@ mod test {
|
|||
let authority = Pubkey::default();
|
||||
let data = nonce::state::Data::new(
|
||||
authority,
|
||||
invoke_context.blockhash,
|
||||
get_durable_nonce(&invoke_context),
|
||||
invoke_context.lamports_per_signature,
|
||||
);
|
||||
authorize_nonce_account(&mut nonce_account, &authority, &signers, &invoke_context).unwrap();
|
||||
|
@ -1202,7 +1213,7 @@ mod test {
|
|||
.get_account_at_index(NONCE_ACCOUNT_INDEX)
|
||||
.unwrap()
|
||||
.borrow(),
|
||||
&invoke_context.blockhash,
|
||||
get_durable_nonce(&invoke_context).as_hash(),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -1257,7 +1268,7 @@ mod test {
|
|||
.get_account_at_index(NONCE_ACCOUNT_INDEX)
|
||||
.unwrap()
|
||||
.borrow(),
|
||||
&invoke_context.blockhash,
|
||||
get_durable_nonce(&invoke_context).as_hash(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,9 +24,9 @@ pub mod solana_client {
|
|||
pub mod nonce_utils {
|
||||
use {
|
||||
super::super::solana_sdk::{
|
||||
account::ReadableAccount, account_utils::StateMut, hash::Hash, pubkey::Pubkey,
|
||||
account::ReadableAccount, account_utils::StateMut, pubkey::Pubkey,
|
||||
},
|
||||
crate::nonce::state::{Data, Versions},
|
||||
crate::nonce::state::{Data, DurableNonce, Versions},
|
||||
};
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
|
@ -36,7 +36,11 @@ pub mod solana_client {
|
|||
pub fn data_from_account<T: ReadableAccount + StateMut<Versions>>(
|
||||
_account: &T,
|
||||
) -> Result<Data, Error> {
|
||||
Ok(Data::new(Pubkey::new_unique(), Hash::default(), 5000))
|
||||
Ok(Data::new(
|
||||
Pubkey::new_unique(),
|
||||
DurableNonce::default(),
|
||||
5000,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
use {
|
||||
crate::{fee_calculator::FeeCalculator, hash::Hash, pubkey::Pubkey},
|
||||
crate::{
|
||||
fee_calculator::FeeCalculator,
|
||||
hash::{hashv, Hash},
|
||||
pubkey::Pubkey,
|
||||
},
|
||||
serde_derive::{Deserialize, Serialize},
|
||||
};
|
||||
|
||||
const DURABLE_NONCE_HASH_PREFIX: &[u8] = "DURABLE_NONCE".as_bytes();
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
pub struct DurableNonce(Hash);
|
||||
|
||||
/// Initialized data of a durable transaction nonce account.
|
||||
///
|
||||
/// This is stored within [`State`] for initialized nonce accounts.
|
||||
|
@ -10,28 +19,54 @@ use {
|
|||
pub struct Data {
|
||||
/// Address of the account that signs transactions using the nonce account.
|
||||
pub authority: Pubkey,
|
||||
/// A valid previous blockhash.
|
||||
pub blockhash: Hash,
|
||||
/// Durable nonce value derived from a valid previous blockhash.
|
||||
pub durable_nonce: DurableNonce,
|
||||
/// The fee calculator associated with the blockhash.
|
||||
pub fee_calculator: FeeCalculator,
|
||||
}
|
||||
|
||||
impl Data {
|
||||
/// Create new durable transaction nonce data.
|
||||
pub fn new(authority: Pubkey, blockhash: Hash, lamports_per_signature: u64) -> Self {
|
||||
pub fn new(
|
||||
authority: Pubkey,
|
||||
durable_nonce: DurableNonce,
|
||||
lamports_per_signature: u64,
|
||||
) -> Self {
|
||||
Data {
|
||||
authority,
|
||||
blockhash,
|
||||
durable_nonce,
|
||||
fee_calculator: FeeCalculator::new(lamports_per_signature),
|
||||
}
|
||||
}
|
||||
|
||||
/// Hash value used as recent_blockhash field in Transactions.
|
||||
/// Named blockhash for legacy reasons, but durable nonce and blockhash
|
||||
/// have separate domains.
|
||||
pub fn blockhash(&self) -> Hash {
|
||||
self.durable_nonce.0
|
||||
}
|
||||
|
||||
/// Get the cost per signature for the next transaction to use this nonce.
|
||||
pub fn get_lamports_per_signature(&self) -> u64 {
|
||||
self.fee_calculator.lamports_per_signature
|
||||
}
|
||||
}
|
||||
|
||||
impl DurableNonce {
|
||||
pub fn from_blockhash(blockhash: &Hash, separate_domains: bool) -> Self {
|
||||
Self(if separate_domains {
|
||||
hashv(&[DURABLE_NONCE_HASH_PREFIX, blockhash.as_ref()])
|
||||
} else {
|
||||
*blockhash
|
||||
})
|
||||
}
|
||||
|
||||
/// Hash value used as recent_blockhash field in Transactions.
|
||||
pub fn as_hash(&self) -> &Hash {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// The state of a durable transaction nonce account.
|
||||
///
|
||||
/// When created in memory with [`State::default`] or when deserialized from an
|
||||
|
@ -52,10 +87,10 @@ impl State {
|
|||
/// Create new durable transaction nonce state.
|
||||
pub fn new_initialized(
|
||||
authority: &Pubkey,
|
||||
blockhash: &Hash,
|
||||
durable_nonce: DurableNonce,
|
||||
lamports_per_signature: u64,
|
||||
) -> Self {
|
||||
Self::Initialized(Data::new(*authority, *blockhash, lamports_per_signature))
|
||||
Self::Initialized(Data::new(*authority, durable_nonce, lamports_per_signature))
|
||||
}
|
||||
|
||||
/// Get the serialized size of the nonce state.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! State for durable transaction nonces.
|
||||
|
||||
mod current;
|
||||
pub use current::{Data, State};
|
||||
pub use current::{Data, DurableNonce, State};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||
|
|
|
@ -736,7 +736,7 @@ pub fn create_nonce_account(
|
|||
/// # });
|
||||
/// let nonce_account = client.get_account(nonce_account_pubkey)?;
|
||||
/// let nonce_data = nonce_utils::data_from_account(&nonce_account)?;
|
||||
/// let blockhash = nonce_data.blockhash;
|
||||
/// let blockhash = nonce_data.blockhash();
|
||||
///
|
||||
/// tx.try_sign(&[payer], blockhash)?;
|
||||
///
|
||||
|
|
|
@ -416,6 +416,10 @@ pub mod warp_timestamp_with_a_vengeance {
|
|||
solana_sdk::declare_id!("3BX6SBeEBibHaVQXywdkcgyUk6evfYZkHdztXiDtEpFS");
|
||||
}
|
||||
|
||||
pub mod separate_nonce_from_blockhash {
|
||||
solana_sdk::declare_id!("Gea3ZkK2N4pHuVZVxWcnAtS6UEDdyumdYt4pFcKjA3ar");
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Map of feature identifiers to user-visible description
|
||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||
|
@ -513,6 +517,7 @@ lazy_static! {
|
|||
(include_account_index_in_rent_error::id(), "include account index in rent tx error #25190"),
|
||||
(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"),
|
||||
/*************** ADD NEW FEATURES HERE ***************/
|
||||
]
|
||||
.iter()
|
||||
|
|
|
@ -20,12 +20,13 @@ pub fn create_account(lamports: u64) -> RefCell<AccountSharedData> {
|
|||
)
|
||||
}
|
||||
|
||||
// TODO: Consider changing argument from Hash to DurableNonce.
|
||||
pub fn verify_nonce_account(acc: &AccountSharedData, hash: &Hash) -> bool {
|
||||
if acc.owner() != &crate::system_program::id() {
|
||||
return false;
|
||||
}
|
||||
match StateMut::<Versions>::state(acc).map(|v| v.convert_to_current()) {
|
||||
Ok(State::Initialized(ref data)) => *hash == data.blockhash,
|
||||
Ok(State::Initialized(ref data)) => hash == &data.blockhash(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -764,8 +764,12 @@ mod test {
|
|||
crate::tpu_info::NullTpuInfo,
|
||||
crossbeam_channel::unbounded,
|
||||
solana_sdk::{
|
||||
account::AccountSharedData, genesis_config::create_genesis_config, nonce,
|
||||
pubkey::Pubkey, signature::Signer, system_program, system_transaction,
|
||||
account::AccountSharedData,
|
||||
genesis_config::create_genesis_config,
|
||||
nonce::{self, state::DurableNonce},
|
||||
pubkey::Pubkey,
|
||||
signature::Signer,
|
||||
system_program, system_transaction,
|
||||
},
|
||||
std::ops::Sub,
|
||||
};
|
||||
|
@ -1068,7 +1072,8 @@ mod test {
|
|||
.unwrap();
|
||||
|
||||
let nonce_address = Pubkey::new_unique();
|
||||
let durable_nonce = Hash::new_unique();
|
||||
let durable_nonce =
|
||||
DurableNonce::from_blockhash(&Hash::new_unique(), /*separate_domains:*/ true);
|
||||
let nonce_state = nonce::state::Versions::new_current(nonce::State::Initialized(
|
||||
nonce::state::Data::new(Pubkey::default(), durable_nonce, 42),
|
||||
));
|
||||
|
@ -1101,7 +1106,7 @@ mod test {
|
|||
rooted_signature,
|
||||
vec![],
|
||||
last_valid_block_height,
|
||||
Some((nonce_address, durable_nonce)),
|
||||
Some((nonce_address, *durable_nonce.as_hash())),
|
||||
None,
|
||||
Some(Instant::now()),
|
||||
),
|
||||
|
@ -1192,7 +1197,7 @@ mod test {
|
|||
Signature::default(),
|
||||
vec![],
|
||||
root_bank.block_height() - 1,
|
||||
Some((nonce_address, durable_nonce)),
|
||||
Some((nonce_address, *durable_nonce.as_hash())),
|
||||
None,
|
||||
Some(Instant::now()),
|
||||
),
|
||||
|
@ -1284,7 +1289,7 @@ mod test {
|
|||
Signature::default(),
|
||||
vec![],
|
||||
last_valid_block_height,
|
||||
Some((nonce_address, durable_nonce)),
|
||||
Some((nonce_address, *durable_nonce.as_hash())),
|
||||
None,
|
||||
Some(Instant::now().sub(Duration::from_millis(4000))),
|
||||
),
|
||||
|
@ -1311,7 +1316,8 @@ mod test {
|
|||
for mut transaction in transactions.values_mut() {
|
||||
transaction.last_sent_time = Some(Instant::now().sub(Duration::from_millis(4000)));
|
||||
}
|
||||
let new_durable_nonce = Hash::new_unique();
|
||||
let new_durable_nonce =
|
||||
DurableNonce::from_blockhash(&Hash::new_unique(), /*separate_domains:*/ true);
|
||||
let new_nonce_state = nonce::state::Versions::new_current(nonce::State::Initialized(
|
||||
nonce::state::Data::new(Pubkey::default(), new_durable_nonce, 42),
|
||||
));
|
||||
|
|
Loading…
Reference in New Issue