1+ use crate :: blockchain:: nonce_manager:: ZamaNonceManager ;
12use alloy:: {
23 consensus:: Account ,
34 eips:: { BlockId , BlockNumberOrTag , Encodable2718 } ,
@@ -7,29 +8,25 @@ use alloy::{
78 U256 ,
89 } ,
910 providers:: {
10- EthCall , EthCallMany , EthGetBlock , FilterPollerBuilder , GetSubscription ,
11- PendingTransaction , PendingTransactionBuilder , PendingTransactionConfig ,
12- PendingTransactionError , Provider , ProviderCall , RootProvider , RpcWithBlock , SendableTx ,
13- fillers:: {
14- BlobGasFiller , CachedNonceManager , FillProvider , GasFiller , JoinFill , NonceManager ,
15- TxFiller ,
16- } ,
11+ EthCall , EthCallMany , EthGetBlock , FilterPollerBuilder , PendingTransaction ,
12+ PendingTransactionBuilder , PendingTransactionConfig , PendingTransactionError , Provider ,
13+ ProviderCall , RootProvider , RpcWithBlock , SendableTx ,
14+ fillers:: { BlobGasFiller , FillProvider , GasFiller , JoinFill , NonceManager , TxFiller } ,
1715 } ,
1816 rpc:: {
1917 client:: NoParams ,
18+ json_rpc:: ErrorPayload ,
2019 types:: {
2120 AccessListResult , Bundle , EIP1186AccountProofResponse , EthCallResponse , FeeHistory ,
2221 Filter , FilterChanges , Index , Log , SyncStatus , TransactionReceipt , TransactionRequest ,
2322 erc4337:: TransactionConditional ,
24- pubsub:: { Params , SubscriptionKind } ,
2523 simulate:: { SimulatePayload , SimulatedBlock } ,
2624 } ,
2725 } ,
28- transports:: { TransportError , TransportResult } ,
26+ transports:: { RpcError , TransportError , TransportErrorKind , TransportResult } ,
2927} ;
30- use futures:: lock:: Mutex ;
3128use serde_json:: value:: RawValue ;
32- use std:: { borrow:: Cow , sync :: Arc } ;
29+ use std:: borrow:: Cow ;
3330
3431pub type FillersWithoutNonceManagement = JoinFill < GasFiller , BlobGasFiller > ;
3532
4643{
4744 inner : FillProvider < F , P , N > ,
4845 signer_address : Address ,
49- nonce_manager : Arc < Mutex < CachedNonceManager > > ,
46+ nonce_manager : ZamaNonceManager ,
5047}
5148
5249impl < F , P > NonceManagedProvider < F , P >
@@ -58,19 +55,18 @@ where
5855 Self {
5956 inner : provider,
6057 signer_address,
61- nonce_manager : Default :: default ( ) ,
58+ nonce_manager : ZamaNonceManager :: new ( ) ,
6259 }
6360 }
6461
6562 pub async fn send_transaction_sync (
6663 & self ,
6764 mut tx : TransactionRequest ,
6865 ) -> TransportResult < TransactionReceipt > {
66+ let signer_addr = self . signer_address ;
6967 let nonce = self
7068 . nonce_manager
71- . lock ( )
72- . await
73- . get_next_nonce ( & self . inner , self . signer_address )
69+ . get_next_nonce ( & self . inner , signer_addr)
7470 . await ?;
7571 tx. set_nonce ( nonce) ;
7672
@@ -82,15 +78,22 @@ where
8278 . map_err ( |e| TransportError :: LocalUsageError ( Box :: new ( e) ) ) ?
8379 . encode_2718 ( & mut tx_bytes) ;
8480
85- let res = self
81+ let send_tx_result = self
8682 . client ( )
8783 . request ( "eth_sendRawTransactionSync" , ( Bytes :: from ( tx_bytes) , ) )
8884 . await ;
89- if res. is_err ( ) {
90- // Reset the nonce manager if the transaction sending failed.
91- * self . nonce_manager . lock ( ) . await = Default :: default ( ) ;
85+
86+ match & send_tx_result {
87+ Err ( e) if is_nonce_too_low ( e) => {
88+ self . nonce_manager . confirm_nonce ( signer_addr, nonce) . await ;
89+ }
90+ Err ( _) => {
91+ self . nonce_manager . release_nonce ( signer_addr, nonce) . await ;
92+ }
93+ Ok ( _) => self . nonce_manager . confirm_nonce ( signer_addr, nonce) . await ,
9294 }
93- res
95+
96+ send_tx_result
9497 }
9598}
9699
@@ -109,6 +112,25 @@ where
109112 }
110113}
111114
115+ // See https://ethereum-json-rpc.com/errors
116+ const ETH_INVALID_INPUT_RPC_ERROR_CODE : i64 = -32000 ;
117+
118+ /// Returns `true` if the RPC error is "nonce too low" or "already known", `false` otherwise.
119+ fn is_nonce_too_low ( error : & RpcError < TransportErrorKind > ) -> bool {
120+ match error {
121+ RpcError :: ErrorResp ( ErrorPayload { code, message, .. } ) => {
122+ if * code == ETH_INVALID_INPUT_RPC_ERROR_CODE {
123+ let lowercase_msg = message. to_lowercase ( ) ;
124+ lowercase_msg. starts_with ( "nonce too low" )
125+ || lowercase_msg. starts_with ( "already known" )
126+ } else {
127+ false
128+ }
129+ }
130+ _ => false ,
131+ }
132+ }
133+
112134#[ async_trait:: async_trait]
113135impl < F , P , N > Provider < N > for NonceManagedProvider < F , P , N >
114136where
@@ -124,19 +146,25 @@ where
124146 & self ,
125147 mut tx : N :: TransactionRequest ,
126148 ) -> TransportResult < PendingTransactionBuilder < N > > {
149+ let signer_addr = self . signer_address ;
127150 let nonce = self
128151 . nonce_manager
129- . lock ( )
130- . await
131- . get_next_nonce ( & self . inner , self . signer_address )
152+ . get_next_nonce ( & self . inner , signer_addr)
132153 . await ?;
133154 tx. set_nonce ( nonce) ;
134- let res = self . inner . send_transaction ( tx) . await ;
135- if res. is_err ( ) {
136- // Reset the nonce manager if the transaction sending failed.
137- * self . nonce_manager . lock ( ) . await = Default :: default ( ) ;
155+ let send_tx_result = self . inner . send_transaction ( tx) . await ;
156+
157+ match & send_tx_result {
158+ Err ( e) if is_nonce_too_low ( e) => {
159+ self . nonce_manager . confirm_nonce ( signer_addr, nonce) . await ;
160+ }
161+ Err ( _) => {
162+ self . nonce_manager . release_nonce ( signer_addr, nonce) . await ;
163+ }
164+ Ok ( _) => self . nonce_manager . confirm_nonce ( signer_addr, nonce) . await ,
138165 }
139- res
166+
167+ send_tx_result
140168 }
141169
142170 fn get_accounts ( & self ) -> ProviderCall < NoParams , Vec < Address > > {
@@ -416,28 +444,6 @@ where
416444 self . inner . sign_transaction ( tx) . await
417445 }
418446
419- fn subscribe_blocks ( & self ) -> GetSubscription < ( SubscriptionKind , ) , N :: HeaderResponse > {
420- self . inner . subscribe_blocks ( )
421- }
422-
423- fn subscribe_pending_transactions ( & self ) -> GetSubscription < ( SubscriptionKind , ) , B256 > {
424- self . inner . subscribe_pending_transactions ( )
425- }
426-
427- fn subscribe_full_pending_transactions (
428- & self ,
429- ) -> GetSubscription < ( SubscriptionKind , Params ) , N :: TransactionResponse > {
430- self . inner . subscribe_full_pending_transactions ( )
431- }
432-
433- fn subscribe_logs ( & self , filter : & Filter ) -> GetSubscription < ( SubscriptionKind , Params ) , Log > {
434- self . inner . subscribe_logs ( filter)
435- }
436-
437- async fn unsubscribe ( & self , id : B256 ) -> TransportResult < ( ) > {
438- self . inner . unsubscribe ( id) . await
439- }
440-
441447 fn syncing ( & self ) -> ProviderCall < NoParams , SyncStatus > {
442448 self . inner . syncing ( )
443449 }
0 commit comments