11//! Accounts module.
22use std:: {
3+ cmp:: Ordering ,
34 collections:: { BTreeMap , BTreeSet } ,
45 convert:: TryInto ,
56} ;
@@ -16,7 +17,9 @@ use crate::{
1617 modules,
1718 modules:: core:: { Error as CoreError , API as _} ,
1819 runtime:: Runtime ,
19- sdk_derive, storage,
20+ sdk_derive,
21+ sender:: SenderMeta ,
22+ storage,
2023 storage:: Prefix ,
2124 types:: {
2225 address:: { Address , SignatureAddressSpec } ,
@@ -32,6 +35,10 @@ pub mod types;
3235/// Unique module name.
3336const MODULE_NAME : & str = "accounts" ;
3437
38+ /// Maximum delta that the transaction nonce can be in the future from the current nonce to still
39+ /// be accepted during transaction checks.
40+ const MAX_CHECK_NONCE_FUTURE_DELTA : u64 = 10 ;
41+
3542/// Errors emitted by the accounts module.
3643#[ derive( Error , Debug , oasis_runtime_sdk_macros:: Error ) ]
3744pub enum Error {
@@ -230,7 +237,7 @@ pub trait API {
230237 fn check_signer_nonces < C : Context > (
231238 ctx : & mut C ,
232239 tx_auth_info : & AuthInfo ,
233- ) -> Result < Option < Address > , modules:: core:: Error > ;
240+ ) -> Result < Address , modules:: core:: Error > ;
234241
235242 /// Update transaction signer account nonces.
236243 fn update_signer_nonces < C : Context > (
@@ -623,31 +630,73 @@ impl API for Module {
623630 fn check_signer_nonces < C : Context > (
624631 ctx : & mut C ,
625632 auth_info : & AuthInfo ,
626- ) -> Result < Option < Address > , modules:: core:: Error > {
633+ ) -> Result < Address , modules:: core:: Error > {
634+ let is_pre_schedule = ctx. is_pre_schedule ( ) ;
635+ let is_check_only = ctx. is_check_only ( ) ;
636+
627637 // TODO: Optimize the check/update pair so that the accounts are
628638 // fetched only once.
629639 let params = Self :: params ( ctx. runtime_state ( ) ) ;
630640 // Fetch information about each signer.
631641 let mut store = storage:: PrefixStore :: new ( ctx. runtime_state ( ) , & MODULE_NAME ) ;
632642 let accounts =
633643 storage:: TypedStore :: new ( storage:: PrefixStore :: new ( & mut store, & state:: ACCOUNTS ) ) ;
634- let mut payer = None ;
644+ let mut sender = None ;
635645 for si in auth_info. signer_info . iter ( ) {
636646 let address = si. address_spec . address ( ) ;
637647 let account: types:: Account = accounts. get ( & address) . unwrap_or_default ( ) ;
638- if account. nonce != si. nonce {
639- // Reject unles nonce checking is disabled.
640- if !params. debug_disable_nonce_check {
648+
649+ // First signer pays for the fees and is considered the sender.
650+ if sender. is_none ( ) {
651+ sender = Some ( SenderMeta {
652+ address,
653+ tx_nonce : si. nonce ,
654+ state_nonce : account. nonce ,
655+ } ) ;
656+ }
657+
658+ // When nonce checking is disabled, skip the rest of the checks.
659+ if params. debug_disable_nonce_check {
660+ continue ;
661+ }
662+
663+ // Check signer nonce against the corresponding account nonce.
664+ match si. nonce . cmp ( & account. nonce ) {
665+ Ordering :: Less => {
666+ // In the past and will never become valid, reject.
641667 return Err ( modules:: core:: Error :: InvalidNonce ) ;
642668 }
643- }
669+ Ordering :: Equal => { } // Ok.
670+ Ordering :: Greater => {
671+ // If too much in the future, reject.
672+ if si. nonce - account. nonce > MAX_CHECK_NONCE_FUTURE_DELTA {
673+ return Err ( modules:: core:: Error :: InvalidNonce ) ;
674+ }
644675
645- // First signer pays for the fees.
646- if payer. is_none ( ) {
647- payer = Some ( address) ;
676+ // If in the future and this is before scheduling, reject with separate error
677+ // that will make the scheduler skip the transaction.
678+ if is_pre_schedule {
679+ return Err ( modules:: core:: Error :: FutureNonce ) ;
680+ }
681+
682+ // If in the future and this is during execution, reject.
683+ if !is_check_only {
684+ return Err ( modules:: core:: Error :: InvalidNonce ) ;
685+ }
686+
687+ // If in the future and this is during checks, accept.
688+ }
648689 }
649690 }
650- Ok ( payer)
691+
692+ // Configure the sender.
693+ let sender = sender. expect ( "at least one signer is always present" ) ;
694+ let sender_address = sender. address ;
695+ if is_check_only {
696+ <C :: Runtime as Runtime >:: Core :: set_sender_meta ( ctx, sender) ;
697+ }
698+
699+ Ok ( sender_address)
651700 }
652701
653702 fn update_signer_nonces < C : Context > (
@@ -869,8 +918,6 @@ impl module::TransactionHandler for Module {
869918
870919 // Charge the specified amount of fees.
871920 if !tx. auth_info . fee . amount . amount ( ) . is_zero ( ) {
872- let payer = payer. expect ( "at least one signer is always present" ) ;
873-
874921 if ctx. is_check_only ( ) {
875922 // Do not update balances during transaction checks. In case of checks, only do it
876923 // after all the other checks have already passed as otherwise retrying the
@@ -918,7 +965,6 @@ impl module::TransactionHandler for Module {
918965
919966 // Update payer balance.
920967 let payer = Self :: check_signer_nonces ( ctx, tx_auth_info) . unwrap ( ) ; // Already checked.
921- let payer = payer. unwrap ( ) ; // Already checked.
922968 let amount = & tx_auth_info. fee . amount ;
923969 Self :: sub_amount ( ctx. runtime_state ( ) , payer, amount) . unwrap ( ) ; // Already checked.
924970
0 commit comments