diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index a2381c8c61..61261f0490 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -61,7 +61,7 @@ use solana_sdk::{ system_transaction, sysvar::{self, Sysvar}, timing::years_as_slots, - transaction::{Result, Transaction, TransactionError}, + transaction::{self, Result, Transaction, TransactionError}, }; use solana_stake_program::stake_state::{self, Delegation, PointValue}; use solana_vote_program::{vote_instruction::VoteInstruction, vote_state::VoteState}; @@ -1821,8 +1821,8 @@ impl Bank { } pub fn check_tx_durable_nonce(&self, tx: &Transaction) -> Option<(Pubkey, Account)> { - nonce_utils::transaction_uses_durable_nonce(&tx) - .and_then(|nonce_ix| nonce_utils::get_nonce_pubkey_from_instruction(&nonce_ix, &tx)) + transaction::uses_durable_nonce(&tx) + .and_then(|nonce_ix| transaction::get_nonce_pubkey_from_instruction(&nonce_ix, &tx)) .and_then(|nonce_pubkey| { self.get_account(&nonce_pubkey) .map(|acc| (*nonce_pubkey, acc)) diff --git a/runtime/src/nonce_utils.rs b/runtime/src/nonce_utils.rs index 524cf45f0f..9c6ccfc2d3 100644 --- a/runtime/src/nonce_utils.rs +++ b/runtime/src/nonce_utils.rs @@ -3,40 +3,9 @@ use solana_sdk::{ account_utils::StateMut, fee_calculator::FeeCalculator, hash::Hash, - instruction::CompiledInstruction, nonce::{state::Versions, State}, - program_utils::limited_deserialize, - pubkey::Pubkey, - system_instruction::SystemInstruction, - system_program, - transaction::{Transaction}, }; -pub fn transaction_uses_durable_nonce(tx: &Transaction) -> Option<&CompiledInstruction> { - let message = tx.message(); - message - .instructions - .get(0) - .filter(|maybe_ix| { - let prog_id_idx = maybe_ix.program_id_index as usize; - match message.account_keys.get(prog_id_idx) { - Some(program_id) => system_program::check_id(&program_id), - _ => false, - } - } && matches!(limited_deserialize(&maybe_ix.data), Ok(SystemInstruction::AdvanceNonceAccount)) - ) -} - -pub fn get_nonce_pubkey_from_instruction<'a>( - ix: &CompiledInstruction, - tx: &'a Transaction, -) -> Option<&'a Pubkey> { - ix.accounts.get(0).and_then(|idx| { - let idx = *idx as usize; - tx.message().account_keys.get(idx) - }) -} - pub fn verify_nonce_account(acc: &Account, hash: &Hash) -> bool { match StateMut::::state(acc).map(|v| v.convert_to_current()) { Ok(State::Initialized(ref data)) => *hash == data.blockhash, @@ -60,110 +29,11 @@ mod tests { use solana_sdk::{ account_utils::State as AccountUtilsState, hash::Hash, - message::Message, nonce::{account::with_test_keyed_account, Account as NonceAccount, State}, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, sysvar::{recent_blockhashes::create_test_recent_blockhashes, rent::Rent}, }; use std::collections::HashSet; - fn nonced_transfer_tx() -> (Pubkey, Pubkey, Transaction) { - let from_keypair = Keypair::new(); - let from_pubkey = from_keypair.pubkey(); - let nonce_keypair = Keypair::new(); - let nonce_pubkey = nonce_keypair.pubkey(); - let instructions = [ - system_instruction::advance_nonce_account(&nonce_pubkey, &nonce_pubkey), - system_instruction::transfer(&from_pubkey, &nonce_pubkey, 42), - ]; - let message = Message::new(&instructions, Some(&nonce_pubkey)); - let tx = Transaction::new(&[&from_keypair, &nonce_keypair], message, Hash::default()); - (from_pubkey, nonce_pubkey, tx) - } - - #[test] - fn tx_uses_nonce_ok() { - let (_, _, tx) = nonced_transfer_tx(); - assert!(transaction_uses_durable_nonce(&tx).is_some()); - } - - #[test] - fn tx_uses_nonce_empty_ix_fail() { - assert!(transaction_uses_durable_nonce(&Transaction::default()).is_none()); - } - - #[test] - fn tx_uses_nonce_bad_prog_id_idx_fail() { - let (_, _, mut tx) = nonced_transfer_tx(); - tx.message.instructions.get_mut(0).unwrap().program_id_index = 255u8; - assert!(transaction_uses_durable_nonce(&tx).is_none()); - } - - #[test] - fn tx_uses_nonce_first_prog_id_not_nonce_fail() { - let from_keypair = Keypair::new(); - let from_pubkey = from_keypair.pubkey(); - let nonce_keypair = Keypair::new(); - let nonce_pubkey = nonce_keypair.pubkey(); - let instructions = [ - system_instruction::transfer(&from_pubkey, &nonce_pubkey, 42), - system_instruction::advance_nonce_account(&nonce_pubkey, &nonce_pubkey), - ]; - let message = Message::new(&instructions, Some(&from_pubkey)); - let tx = Transaction::new(&[&from_keypair, &nonce_keypair], message, Hash::default()); - assert!(transaction_uses_durable_nonce(&tx).is_none()); - } - - #[test] - fn tx_uses_nonce_wrong_first_nonce_ix_fail() { - let from_keypair = Keypair::new(); - let from_pubkey = from_keypair.pubkey(); - let nonce_keypair = Keypair::new(); - let nonce_pubkey = nonce_keypair.pubkey(); - let instructions = [ - system_instruction::withdraw_nonce_account( - &nonce_pubkey, - &nonce_pubkey, - &from_pubkey, - 42, - ), - system_instruction::transfer(&from_pubkey, &nonce_pubkey, 42), - ]; - let message = Message::new(&instructions, Some(&nonce_pubkey)); - let tx = Transaction::new(&[&from_keypair, &nonce_keypair], message, Hash::default()); - assert!(transaction_uses_durable_nonce(&tx).is_none()); - } - - #[test] - fn get_nonce_pub_from_ix_ok() { - let (_, nonce_pubkey, tx) = nonced_transfer_tx(); - let nonce_ix = transaction_uses_durable_nonce(&tx).unwrap(); - assert_eq!( - get_nonce_pubkey_from_instruction(&nonce_ix, &tx), - Some(&nonce_pubkey), - ); - } - - #[test] - fn get_nonce_pub_from_ix_no_accounts_fail() { - let (_, _, tx) = nonced_transfer_tx(); - let nonce_ix = transaction_uses_durable_nonce(&tx).unwrap(); - let mut nonce_ix = nonce_ix.clone(); - nonce_ix.accounts.clear(); - assert_eq!(get_nonce_pubkey_from_instruction(&nonce_ix, &tx), None,); - } - - #[test] - fn get_nonce_pub_from_ix_bad_acc_idx_fail() { - let (_, _, tx) = nonced_transfer_tx(); - let nonce_ix = transaction_uses_durable_nonce(&tx).unwrap(); - let mut nonce_ix = nonce_ix.clone(); - nonce_ix.accounts[0] = 255u8; - assert_eq!(get_nonce_pubkey_from_instruction(&nonce_ix, &tx), None,); - } - #[test] fn verify_nonce_ok() { with_test_keyed_account(42, true, |nonce_account| { diff --git a/sdk/src/transaction.rs b/sdk/src/transaction.rs index e9e61a8531..69c0c09dae 100644 --- a/sdk/src/transaction.rs +++ b/sdk/src/transaction.rs @@ -6,10 +6,13 @@ use crate::{ hash::Hash, instruction::{CompiledInstruction, Instruction, InstructionError}, message::Message, + program_utils::limited_deserialize, pubkey::Pubkey, short_vec, signature::{Signature, SignerError}, signers::Signers, + system_instruction::SystemInstruction, + system_program, }; use std::result; use thiserror::Error; @@ -395,6 +398,31 @@ impl Transaction { } } +pub fn uses_durable_nonce(tx: &Transaction) -> Option<&CompiledInstruction> { + let message = tx.message(); + message + .instructions + .get(0) + .filter(|maybe_ix| { + let prog_id_idx = maybe_ix.program_id_index as usize; + match message.account_keys.get(prog_id_idx) { + Some(program_id) => system_program::check_id(&program_id), + _ => false, + } + } && matches!(limited_deserialize(&maybe_ix.data), Ok(SystemInstruction::AdvanceNonceAccount)) + ) +} + +pub fn get_nonce_pubkey_from_instruction<'a>( + ix: &CompiledInstruction, + tx: &'a Transaction, +) -> Option<&'a Pubkey> { + ix.accounts.get(0).and_then(|idx| { + let idx = *idx as usize; + tx.message().account_keys.get(idx) + }) +} + #[cfg(test)] mod tests { use super::*; @@ -812,4 +840,99 @@ mod tests { vec![Signature::default(), Signature::default()] ); } + + fn nonced_transfer_tx() -> (Pubkey, Pubkey, Transaction) { + let from_keypair = Keypair::new(); + let from_pubkey = from_keypair.pubkey(); + let nonce_keypair = Keypair::new(); + let nonce_pubkey = nonce_keypair.pubkey(); + let instructions = [ + system_instruction::advance_nonce_account(&nonce_pubkey, &nonce_pubkey), + system_instruction::transfer(&from_pubkey, &nonce_pubkey, 42), + ]; + let message = Message::new(&instructions, Some(&nonce_pubkey)); + let tx = Transaction::new(&[&from_keypair, &nonce_keypair], message, Hash::default()); + (from_pubkey, nonce_pubkey, tx) + } + + #[test] + fn tx_uses_nonce_ok() { + let (_, _, tx) = nonced_transfer_tx(); + assert!(uses_durable_nonce(&tx).is_some()); + } + + #[test] + fn tx_uses_nonce_empty_ix_fail() { + assert!(uses_durable_nonce(&Transaction::default()).is_none()); + } + + #[test] + fn tx_uses_nonce_bad_prog_id_idx_fail() { + let (_, _, mut tx) = nonced_transfer_tx(); + tx.message.instructions.get_mut(0).unwrap().program_id_index = 255u8; + assert!(uses_durable_nonce(&tx).is_none()); + } + + #[test] + fn tx_uses_nonce_first_prog_id_not_nonce_fail() { + let from_keypair = Keypair::new(); + let from_pubkey = from_keypair.pubkey(); + let nonce_keypair = Keypair::new(); + let nonce_pubkey = nonce_keypair.pubkey(); + let instructions = [ + system_instruction::transfer(&from_pubkey, &nonce_pubkey, 42), + system_instruction::advance_nonce_account(&nonce_pubkey, &nonce_pubkey), + ]; + let message = Message::new(&instructions, Some(&from_pubkey)); + let tx = Transaction::new(&[&from_keypair, &nonce_keypair], message, Hash::default()); + assert!(uses_durable_nonce(&tx).is_none()); + } + + #[test] + fn tx_uses_nonce_wrong_first_nonce_ix_fail() { + let from_keypair = Keypair::new(); + let from_pubkey = from_keypair.pubkey(); + let nonce_keypair = Keypair::new(); + let nonce_pubkey = nonce_keypair.pubkey(); + let instructions = [ + system_instruction::withdraw_nonce_account( + &nonce_pubkey, + &nonce_pubkey, + &from_pubkey, + 42, + ), + system_instruction::transfer(&from_pubkey, &nonce_pubkey, 42), + ]; + let message = Message::new(&instructions, Some(&nonce_pubkey)); + let tx = Transaction::new(&[&from_keypair, &nonce_keypair], message, Hash::default()); + assert!(uses_durable_nonce(&tx).is_none()); + } + + #[test] + fn get_nonce_pub_from_ix_ok() { + let (_, nonce_pubkey, tx) = nonced_transfer_tx(); + let nonce_ix = uses_durable_nonce(&tx).unwrap(); + assert_eq!( + get_nonce_pubkey_from_instruction(&nonce_ix, &tx), + Some(&nonce_pubkey), + ); + } + + #[test] + fn get_nonce_pub_from_ix_no_accounts_fail() { + let (_, _, tx) = nonced_transfer_tx(); + let nonce_ix = uses_durable_nonce(&tx).unwrap(); + let mut nonce_ix = nonce_ix.clone(); + nonce_ix.accounts.clear(); + assert_eq!(get_nonce_pubkey_from_instruction(&nonce_ix, &tx), None,); + } + + #[test] + fn get_nonce_pub_from_ix_bad_acc_idx_fail() { + let (_, _, tx) = nonced_transfer_tx(); + let nonce_ix = uses_durable_nonce(&tx).unwrap(); + let mut nonce_ix = nonce_ix.clone(); + nonce_ix.accounts[0] = 255u8; + assert_eq!(get_nonce_pubkey_from_instruction(&nonce_ix, &tx), None,); + } }