@@ -183,7 +183,16 @@ pub type TransactionBalances = Vec<Vec<u64>>;
183183#[ derive( Clone , Debug , Eq , PartialEq ) ]
184184pub enum HashAgeKind {
185185 Extant ,
186- DurableNonce ,
186+ DurableNonce ( Pubkey , Account ) ,
187+ }
188+
189+ impl HashAgeKind {
190+ pub fn is_durable_nonce ( & self ) -> bool {
191+ match self {
192+ HashAgeKind :: DurableNonce ( _, _) => true ,
193+ _ => false ,
194+ }
195+ }
187196}
188197
189198/// Manager for the state of all accounts and programs after processing its entries.
@@ -969,8 +978,8 @@ impl Bank {
969978 let message = tx. message ( ) ;
970979 if hash_queue. check_hash_age ( & message. recent_blockhash , max_age) {
971980 ( Ok ( ( ) ) , Some ( HashAgeKind :: Extant ) )
972- } else if self . check_tx_durable_nonce ( & tx) {
973- ( Ok ( ( ) ) , Some ( HashAgeKind :: DurableNonce ) )
981+ } else if let Some ( ( pubkey , acc ) ) = self . check_tx_durable_nonce ( & tx) {
982+ ( Ok ( ( ) ) , Some ( HashAgeKind :: DurableNonce ( pubkey , acc ) ) )
974983 } else {
975984 error_counters. reserve_blockhash += 1 ;
976985 ( Err ( TransactionError :: BlockhashNotFound ) , None )
@@ -1024,16 +1033,16 @@ impl Bank {
10241033 . check_hash_age ( hash, max_age)
10251034 }
10261035
1027- pub fn check_tx_durable_nonce ( & self , tx : & Transaction ) -> bool {
1036+ pub fn check_tx_durable_nonce ( & self , tx : & Transaction ) -> Option < ( Pubkey , Account ) > {
10281037 nonce_utils:: transaction_uses_durable_nonce ( & tx)
10291038 . and_then ( |nonce_ix| nonce_utils:: get_nonce_pubkey_from_instruction ( & nonce_ix, & tx) )
1030- . and_then ( |nonce_pubkey| self . get_account ( & nonce_pubkey ) )
1031- . map_or_else (
1032- || false ,
1033- |nonce_account| {
1034- nonce_utils :: verify_nonce ( & nonce_account , & tx . message ( ) . recent_blockhash )
1035- } ,
1036- )
1039+ . and_then ( |nonce_pubkey| {
1040+ self . get_account ( & nonce_pubkey )
1041+ . map ( |acc| ( * nonce_pubkey , acc ) )
1042+ } )
1043+ . filter ( | ( _pubkey , nonce_account ) | {
1044+ nonce_utils :: verify_nonce ( nonce_account , & tx . message ( ) . recent_blockhash )
1045+ } )
10371046 }
10381047
10391048 pub fn check_transactions (
@@ -1223,7 +1232,11 @@ impl Bank {
12231232 let results = OrderedIterator :: new ( txs, iteration_order)
12241233 . zip ( executed. iter ( ) )
12251234 . map ( |( tx, ( res, hash_age_kind) ) | {
1226- let fee_hash = if let Some ( HashAgeKind :: DurableNonce ) = hash_age_kind {
1235+ let is_durable_nonce = hash_age_kind
1236+ . as_ref ( )
1237+ . map ( |hash_age_kind| hash_age_kind. is_durable_nonce ( ) )
1238+ . unwrap_or ( false ) ;
1239+ let fee_hash = if is_durable_nonce {
12271240 self . last_blockhash ( )
12281241 } else {
12291242 tx. message ( ) . recent_blockhash
@@ -1239,7 +1252,12 @@ impl Bank {
12391252 // credit the transaction fee even in case of InstructionError
12401253 // necessary to withdraw from account[0] here because previous
12411254 // work of doing so (in accounts.load()) is ignored by store_account()
1242- self . withdraw ( & message. account_keys [ 0 ] , fee) ?;
1255+ //
1256+ // ...except nonce accounts, which will have their post-load,
1257+ // pre-execute account state stored
1258+ if !is_durable_nonce {
1259+ self . withdraw ( & message. account_keys [ 0 ] , fee) ?;
1260+ }
12431261 fees += fee;
12441262 Ok ( ( ) )
12451263 }
@@ -1291,6 +1309,7 @@ impl Bank {
12911309 executed,
12921310 loaded_accounts,
12931311 & self . rent_collector ,
1312+ & self . last_blockhash ( ) ,
12941313 ) ;
12951314 self . collect_rent ( executed, loaded_accounts) ;
12961315
@@ -1905,6 +1924,14 @@ mod tests {
19051924 use std:: { io:: Cursor , result, time:: Duration } ;
19061925 use tempfile:: TempDir ;
19071926
1927+ #[ test]
1928+ fn test_hash_age_kind_is_durable_nonce ( ) {
1929+ assert ! (
1930+ HashAgeKind :: DurableNonce ( Pubkey :: default ( ) , Account :: default ( ) ) . is_durable_nonce( )
1931+ ) ;
1932+ assert ! ( !HashAgeKind :: Extant . is_durable_nonce( ) ) ;
1933+ }
1934+
19081935 #[ test]
19091936 fn test_bank_unix_timestamp ( ) {
19101937 let ( genesis_config, _mint_keypair) = create_genesis_config ( 1 ) ;
@@ -4713,7 +4740,11 @@ mod tests {
47134740 & [ & custodian_keypair, & nonce_keypair] ,
47144741 nonce_hash,
47154742 ) ;
4716- assert ! ( bank. check_tx_durable_nonce( & tx) ) ;
4743+ let nonce_account = bank. get_account ( & nonce_pubkey) . unwrap ( ) ;
4744+ assert_eq ! (
4745+ bank. check_tx_durable_nonce( & tx) ,
4746+ Some ( ( nonce_pubkey, nonce_account) )
4747+ ) ;
47174748 }
47184749
47194750 #[ test]
@@ -4733,7 +4764,7 @@ mod tests {
47334764 & [ & custodian_keypair, & nonce_keypair] ,
47344765 nonce_hash,
47354766 ) ;
4736- assert ! ( ! bank. check_tx_durable_nonce( & tx) ) ;
4767+ assert ! ( bank. check_tx_durable_nonce( & tx) . is_none ( ) ) ;
47374768 }
47384769
47394770 #[ test]
@@ -4754,7 +4785,7 @@ mod tests {
47544785 nonce_hash,
47554786 ) ;
47564787 tx. message . instructions [ 0 ] . accounts . clear ( ) ;
4757- assert ! ( ! bank. check_tx_durable_nonce( & tx) ) ;
4788+ assert ! ( bank. check_tx_durable_nonce( & tx) . is_none ( ) ) ;
47584789 }
47594790
47604791 #[ test]
@@ -4776,7 +4807,7 @@ mod tests {
47764807 & [ & custodian_keypair, & nonce_keypair] ,
47774808 nonce_hash,
47784809 ) ;
4779- assert ! ( ! bank. check_tx_durable_nonce( & tx) ) ;
4810+ assert ! ( bank. check_tx_durable_nonce( & tx) . is_none ( ) ) ;
47804811 }
47814812
47824813 #[ test]
@@ -4795,7 +4826,7 @@ mod tests {
47954826 & [ & custodian_keypair, & nonce_keypair] ,
47964827 Hash :: default ( ) ,
47974828 ) ;
4798- assert ! ( ! bank. check_tx_durable_nonce( & tx) ) ;
4829+ assert ! ( bank. check_tx_durable_nonce( & tx) . is_none ( ) ) ;
47994830 }
48004831
48014832 #[ test]
@@ -4908,10 +4939,11 @@ mod tests {
49084939 bank. process_transaction( & durable_tx) ,
49094940 Err ( TransactionError :: BlockhashNotFound )
49104941 ) ;
4911- /* Check fee not charged */
4942+ /* Check fee not charged and nonce not advanced */
49124943 assert_eq ! ( bank. get_balance( & custodian_pubkey) , 4_640_000 ) ;
4944+ assert_eq ! ( new_nonce, get_nonce( & bank, & nonce_pubkey) . unwrap( ) ) ;
49134945
4914- let nonce_hash = get_nonce ( & bank , & nonce_pubkey ) . unwrap ( ) ;
4946+ let nonce_hash = new_nonce ;
49154947
49164948 /* Kick nonce hash off the blockhash_queue */
49174949 for _ in 0 ..MAX_RECENT_BLOCKHASHES + 1 {
@@ -4935,8 +4967,16 @@ mod tests {
49354967 system_instruction:: SystemError :: ResultWithNegativeLamports . into( )
49364968 ) )
49374969 ) ;
4938- /* Check fee charged */
4970+ /* Check fee charged and nonce has advanced */
49394971 assert_eq ! ( bank. get_balance( & custodian_pubkey) , 4_630_000 ) ;
4972+ assert_ne ! ( nonce_hash, get_nonce( & bank, & nonce_pubkey) . unwrap( ) ) ;
4973+ /* Confirm replaying a TX that failed with InstructionError::* now
4974+ * fails with TransactionError::BlockhashNotFound
4975+ */
4976+ assert_eq ! (
4977+ bank. process_transaction( & durable_tx) ,
4978+ Err ( TransactionError :: BlockhashNotFound ) ,
4979+ ) ;
49404980 }
49414981
49424982 #[ test]
0 commit comments