Skip to content

Commit

Permalink
permanently disables durable nonces with chain blockhash domain (back…
Browse files Browse the repository at this point in the history
…port #25788) (#25871)

* permanently disables durable nonces with chain blockhash domain (#25788)

#25744
separated durable nonce and blockhash domains, which will stop double
execution going forward. However it is possible that a durable
transaction has *already* been executed once as a normal transaction and
it is now a valid durable transaction. #25744 cannot stop such
transactions to be re-executed until the nonce accounts are advanced.

This commit adds a new nonce version indicating that the nonce is moved
out of the blockhash domain, and permanently disables durable
transactions for legacy nonces which are in the blockhash domain.

(cherry picked from commit 3c1ce3c)

# Conflicts:
#	cli/src/nonce.rs
#	rpc/src/rpc.rs
#	runtime/src/nonce_keyed_account.rs
#	runtime/src/system_instruction_processor.rs
#	sdk/program/src/nonce/state/current.rs
#	send-transaction-service/src/send_transaction_service.rs

* removes mergify merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
  • Loading branch information
mergify[bot] and behzadnouri authored Jun 9, 2022
1 parent d385261 commit 23da4af
Show file tree
Hide file tree
Showing 15 changed files with 703 additions and 308 deletions.
5 changes: 4 additions & 1 deletion account-decoder/src/parse_account_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,10 @@ mod test {
assert_eq!(parsed.program, "vote".to_string());
assert_eq!(parsed.space, VoteState::size_of() as u64);

let nonce_data = Versions::new_current(State::Initialized(Data::default()));
let nonce_data = Versions::new(
State::Initialized(Data::default()),
true, // separate_domains
);
let nonce_account_data = bincode::serialize(&nonce_data).unwrap();
let parsed = parse_account_data(
&account_pubkey,
Expand Down
10 changes: 6 additions & 4 deletions account-decoder/src/parse_nonce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ use {
};

pub fn parse_nonce(data: &[u8]) -> Result<UiNonceState, ParseAccountError> {
let nonce_state: Versions = bincode::deserialize(data)
let nonce_versions: Versions = bincode::deserialize(data)
.map_err(|_| ParseAccountError::from(InstructionError::InvalidAccountData))?;
let nonce_state = nonce_state.convert_to_current();
match nonce_state {
match nonce_versions.state() {
// This prevents parsing an allocated System-owned account with empty data of any non-zero
// length as `uninitialized` nonce. An empty account of the wrong length can never be
// initialized as a nonce account, and an empty account of the correct length may not be an
Expand Down Expand Up @@ -58,7 +57,10 @@ mod test {

#[test]
fn test_parse_nonce() {
let nonce_data = Versions::new_current(State::Initialized(Data::default()));
let nonce_data = Versions::new(
State::Initialized(Data::default()),
true, // separate_domains
);
let nonce_account_data = bincode::serialize(&nonce_data).unwrap();
assert_eq!(
parse_nonce(&nonce_account_data).unwrap(),
Expand Down
56 changes: 35 additions & 21 deletions cli/src/nonce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -925,11 +925,10 @@ mod tests {
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,
durable_nonce,
0,
)));
let data = Versions::new(
State::Initialized(nonce::state::Data::new(nonce_pubkey, durable_nonce, 0)),
true, // separate_domains
);
let valid = Account::new_data(1, &data, &system_program::ID);
assert!(check_nonce_account(&valid.unwrap(), &nonce_pubkey, &blockhash).is_ok());

Expand All @@ -949,31 +948,37 @@ mod tests {

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,
invalid_durable_nonce,
0,
)));
let data = Versions::new(
State::Initialized(nonce::state::Data::new(
nonce_pubkey,
invalid_durable_nonce,
0,
)),
true, // separate_domains
);
let invalid_hash = Account::new_data(1, &data, &system_program::ID);
if let CliError::InvalidNonce(err) =
check_nonce_account(&invalid_hash.unwrap(), &nonce_pubkey, &blockhash).unwrap_err()
{
assert_eq!(err, Error::InvalidHash,);
}

let data = Versions::new_current(State::Initialized(nonce::state::Data::new(
solana_sdk::pubkey::new_rand(),
durable_nonce,
0,
)));
let data = Versions::new(
State::Initialized(nonce::state::Data::new(
solana_sdk::pubkey::new_rand(),
durable_nonce,
0,
)),
true, // separate_domains
);
let invalid_authority = Account::new_data(1, &data, &system_program::ID);
if let CliError::InvalidNonce(err) =
check_nonce_account(&invalid_authority.unwrap(), &nonce_pubkey, &blockhash).unwrap_err()
{
assert_eq!(err, Error::InvalidAuthority,);
}

let data = Versions::new_current(State::Uninitialized);
let data = Versions::new(State::Uninitialized, /*separate_domains:*/ true);
let invalid_state = Account::new_data(1, &data, &system_program::ID);
if let CliError::InvalidNonce(err) =
check_nonce_account(&invalid_state.unwrap(), &nonce_pubkey, &blockhash).unwrap_err()
Expand All @@ -984,7 +989,8 @@ mod tests {

#[test]
fn test_account_identity_ok() {
let nonce_account = nonce_account::create_account(1).into_inner();
let nonce_account =
nonce_account::create_account(1, /*separate_domains:*/ true).into_inner();
assert_eq!(account_identity_ok(&nonce_account), Ok(()));

let system_account = Account::new(1, 0, &system_program::id());
Expand All @@ -1003,14 +1009,18 @@ mod tests {

#[test]
fn test_state_from_account() {
let mut nonce_account = nonce_account::create_account(1).into_inner();
let mut nonce_account =
nonce_account::create_account(1, /*separate_domains:*/ true).into_inner();
assert_eq!(state_from_account(&nonce_account), Ok(State::Uninitialized));

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())))
.set_state(&Versions::new(
State::Initialized(data.clone()),
true, // separate_domains
))
.unwrap();
assert_eq!(
state_from_account(&nonce_account),
Expand All @@ -1026,7 +1036,8 @@ mod tests {

#[test]
fn test_data_from_helpers() {
let mut nonce_account = nonce_account::create_account(1).into_inner();
let mut nonce_account =
nonce_account::create_account(1, /*separate_domains:*/ true).into_inner();
let state = state_from_account(&nonce_account).unwrap();
assert_eq!(
data_from_state(&state),
Expand All @@ -1041,7 +1052,10 @@ mod tests {
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())))
.set_state(&Versions::new(
State::Initialized(data.clone()),
true, // separate_domains
))
.unwrap();
let state = state_from_account(&nonce_account).unwrap();
assert_eq!(data_from_state(&state), Ok(&data));
Expand Down
5 changes: 4 additions & 1 deletion client/src/blockhash_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,10 @@ mod tests {
};
let nonce_account = Account::new_data_with_space(
42,
&nonce::state::Versions::new_current(nonce::State::Initialized(data)),
&nonce::state::Versions::new(
nonce::State::Initialized(data),
true, // separate_domains
),
nonce::State::size(),
&system_program::id(),
)
Expand Down
5 changes: 2 additions & 3 deletions client/src/nonce_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,8 @@ pub fn state_from_account<T: ReadableAccount + StateMut<Versions>>(
account: &T,
) -> Result<State, Error> {
account_identity_ok(account)?;
StateMut::<Versions>::state(account)
.map_err(|_| Error::InvalidAccountData)
.map(|v| v.convert_to_current())
let versions = StateMut::<Versions>::state(account).map_err(|_| Error::InvalidAccountData)?;
Ok(State::from(versions))
}

pub fn data_from_account<T: ReadableAccount + StateMut<Versions>>(
Expand Down
2 changes: 1 addition & 1 deletion rpc/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5528,7 +5528,7 @@ pub mod tests {
let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
let accounts: Vec<RpcKeyedAccount> = serde_json::from_value(json["result"].clone())
.expect("actual response deserialization");
assert_eq!(accounts.len(), 0);
assert_eq!(accounts.len(), 2);

// Test dataSize filter
let req = format!(
Expand Down
6 changes: 4 additions & 2 deletions rpc/src/transaction_status_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,13 +306,15 @@ pub(crate) mod tests {
let expected_transaction = transaction.clone();
let pubkey = Pubkey::new_unique();

let mut nonce_account = nonce_account::create_account(1).into_inner();
let mut nonce_account =
nonce_account::create_account(1, /*separate_domains:*/ true).into_inner();
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(
.set_state(&nonce::state::Versions::new(
nonce::State::Initialized(data),
true, // separate_domains
))
.unwrap();

Expand Down
Loading

0 comments on commit 23da4af

Please sign in to comment.