@@ -183,7 +183,16 @@ pub type TransactionBalances = Vec<Vec<u64>>;
183
183
#[ derive( Clone , Debug , Eq , PartialEq ) ]
184
184
pub enum HashAgeKind {
185
185
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
+ }
187
196
}
188
197
189
198
/// Manager for the state of all accounts and programs after processing its entries.
@@ -969,8 +978,8 @@ impl Bank {
969
978
let message = tx. message ( ) ;
970
979
if hash_queue. check_hash_age ( & message. recent_blockhash , max_age) {
971
980
( 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 ) ) )
974
983
} else {
975
984
error_counters. reserve_blockhash += 1 ;
976
985
( Err ( TransactionError :: BlockhashNotFound ) , None )
@@ -1024,16 +1033,16 @@ impl Bank {
1024
1033
. check_hash_age ( hash, max_age)
1025
1034
}
1026
1035
1027
- pub fn check_tx_durable_nonce ( & self , tx : & Transaction ) -> bool {
1036
+ pub fn check_tx_durable_nonce ( & self , tx : & Transaction ) -> Option < ( Pubkey , Account ) > {
1028
1037
nonce_utils:: transaction_uses_durable_nonce ( & tx)
1029
1038
. 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
+ } )
1037
1046
}
1038
1047
1039
1048
pub fn check_transactions (
@@ -1223,7 +1232,11 @@ impl Bank {
1223
1232
let results = OrderedIterator :: new ( txs, iteration_order)
1224
1233
. zip ( executed. iter ( ) )
1225
1234
. 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 {
1227
1240
self . last_blockhash ( )
1228
1241
} else {
1229
1242
tx. message ( ) . recent_blockhash
@@ -1239,7 +1252,12 @@ impl Bank {
1239
1252
// credit the transaction fee even in case of InstructionError
1240
1253
// necessary to withdraw from account[0] here because previous
1241
1254
// 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
+ }
1243
1261
fees += fee;
1244
1262
Ok ( ( ) )
1245
1263
}
@@ -1291,6 +1309,7 @@ impl Bank {
1291
1309
executed,
1292
1310
loaded_accounts,
1293
1311
& self . rent_collector ,
1312
+ & self . last_blockhash ( ) ,
1294
1313
) ;
1295
1314
self . collect_rent ( executed, loaded_accounts) ;
1296
1315
@@ -1905,6 +1924,14 @@ mod tests {
1905
1924
use std:: { io:: Cursor , result, time:: Duration } ;
1906
1925
use tempfile:: TempDir ;
1907
1926
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
+
1908
1935
#[ test]
1909
1936
fn test_bank_unix_timestamp ( ) {
1910
1937
let ( genesis_config, _mint_keypair) = create_genesis_config ( 1 ) ;
@@ -4713,7 +4740,11 @@ mod tests {
4713
4740
& [ & custodian_keypair, & nonce_keypair] ,
4714
4741
nonce_hash,
4715
4742
) ;
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
+ ) ;
4717
4748
}
4718
4749
4719
4750
#[ test]
@@ -4733,7 +4764,7 @@ mod tests {
4733
4764
& [ & custodian_keypair, & nonce_keypair] ,
4734
4765
nonce_hash,
4735
4766
) ;
4736
- assert ! ( ! bank. check_tx_durable_nonce( & tx) ) ;
4767
+ assert ! ( bank. check_tx_durable_nonce( & tx) . is_none ( ) ) ;
4737
4768
}
4738
4769
4739
4770
#[ test]
@@ -4754,7 +4785,7 @@ mod tests {
4754
4785
nonce_hash,
4755
4786
) ;
4756
4787
tx. message . instructions [ 0 ] . accounts . clear ( ) ;
4757
- assert ! ( ! bank. check_tx_durable_nonce( & tx) ) ;
4788
+ assert ! ( bank. check_tx_durable_nonce( & tx) . is_none ( ) ) ;
4758
4789
}
4759
4790
4760
4791
#[ test]
@@ -4776,7 +4807,7 @@ mod tests {
4776
4807
& [ & custodian_keypair, & nonce_keypair] ,
4777
4808
nonce_hash,
4778
4809
) ;
4779
- assert ! ( ! bank. check_tx_durable_nonce( & tx) ) ;
4810
+ assert ! ( bank. check_tx_durable_nonce( & tx) . is_none ( ) ) ;
4780
4811
}
4781
4812
4782
4813
#[ test]
@@ -4795,7 +4826,7 @@ mod tests {
4795
4826
& [ & custodian_keypair, & nonce_keypair] ,
4796
4827
Hash :: default ( ) ,
4797
4828
) ;
4798
- assert ! ( ! bank. check_tx_durable_nonce( & tx) ) ;
4829
+ assert ! ( bank. check_tx_durable_nonce( & tx) . is_none ( ) ) ;
4799
4830
}
4800
4831
4801
4832
#[ test]
@@ -4908,10 +4939,11 @@ mod tests {
4908
4939
bank. process_transaction( & durable_tx) ,
4909
4940
Err ( TransactionError :: BlockhashNotFound )
4910
4941
) ;
4911
- /* Check fee not charged */
4942
+ /* Check fee not charged and nonce not advanced */
4912
4943
assert_eq ! ( bank. get_balance( & custodian_pubkey) , 4_640_000 ) ;
4944
+ assert_eq ! ( new_nonce, get_nonce( & bank, & nonce_pubkey) . unwrap( ) ) ;
4913
4945
4914
- let nonce_hash = get_nonce ( & bank , & nonce_pubkey ) . unwrap ( ) ;
4946
+ let nonce_hash = new_nonce ;
4915
4947
4916
4948
/* Kick nonce hash off the blockhash_queue */
4917
4949
for _ in 0 ..MAX_RECENT_BLOCKHASHES + 1 {
@@ -4935,8 +4967,16 @@ mod tests {
4935
4967
system_instruction:: SystemError :: ResultWithNegativeLamports . into( )
4936
4968
) )
4937
4969
) ;
4938
- /* Check fee charged */
4970
+ /* Check fee charged and nonce has advanced */
4939
4971
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
+ ) ;
4940
4980
}
4941
4981
4942
4982
#[ test]
0 commit comments