@@ -131,36 +131,63 @@ func (m *NonceManager) anySyncedKey() int {
131131 Interface ("Address" , m .Addresses [keyData .KeyNum ]).
132132 Msg ("Key selected" )
133133 go func () {
134+ addr := m .Addresses [keyData .KeyNum ]
135+ rpcTimeout := max (
136+ // Use retry delay as RPC timeout
137+ m .cfg .KeySyncRetryDelay .Duration (), 5 * time .Second )
138+
139+ // Track the last known nonce across retries for recovery
140+ var lastKnownNonce uint64
141+ hasValidNonce := false
142+
134143 err := retry .Do (
135144 func () error {
136145 m .rl .Take ()
137146 L .Trace ().
138147 Interface ("KeyNum" , keyData .KeyNum ).
139- Interface ("Address" , m . Addresses [ keyData . KeyNum ] ).
148+ Interface ("Address" , addr ).
140149 Msg ("Key is syncing" )
141- nonce , err := m .Client .Client .NonceAt (context .Background (), m .Addresses [keyData .KeyNum ], nil )
142- if err != nil {
143- return errors .New (ErrNonce )
150+
151+ rpcCtx , rpcCancel := context .WithTimeout (context .Background (), rpcTimeout )
152+ defer rpcCancel ()
153+
154+ // Check both pending and latest nonce to determine if key is available
155+ pendingNonce , pendingErr := m .Client .Client .PendingNonceAt (rpcCtx , addr )
156+ if pendingErr != nil {
157+ return errors .Wrap (pendingErr , ErrNonce )
158+ }
159+ latestNonce , latestErr := m .Client .Client .NonceAt (rpcCtx , addr , nil )
160+ if latestErr != nil {
161+ return errors .Wrap (latestErr , ErrNonce )
144162 }
145- if nonce == keyData .Nonce + 1 {
163+
164+ // Store for potential recovery use
165+ lastKnownNonce = latestNonce
166+ hasValidNonce = true
167+
168+ // Key is synced if there's no pending transaction (pending == latest)
169+ // OR if the nonce has incremented from what we expected
170+ if pendingNonce == latestNonce || latestNonce >= keyData .Nonce + 1 {
146171 L .Trace ().
147172 Interface ("KeyNum" , keyData .KeyNum ).
148- Uint64 ("Nonce" , nonce ).
149- Interface ("Address" , m .Addresses [keyData .KeyNum ]).
173+ Uint64 ("LatestNonce" , latestNonce ).
174+ Uint64 ("PendingNonce" , pendingNonce ).
175+ Interface ("Address" , addr ).
150176 Msg ("Key synced" )
151177 m .SyncedKeys <- & KeyNonce {
152178 KeyNum : keyData .KeyNum ,
153- Nonce : nonce ,
179+ Nonce : latestNonce ,
154180 }
155181 return nil
156182 }
157183
158184 L .Trace ().
159185 Interface ("KeyNum" , keyData .KeyNum ).
160- Uint64 ("Nonce" , nonce ).
161- Int ("Expected nonce" , mustSafeInt (keyData .Nonce + 1 )).
162- Interface ("Address" , m .Addresses [keyData .KeyNum ]).
163- Msg ("Key NOT synced" )
186+ Uint64 ("LatestNonce" , latestNonce ).
187+ Uint64 ("PendingNonce" , pendingNonce ).
188+ Uint64 ("ExpectedNonce" , keyData .Nonce + 1 ).
189+ Interface ("Address" , addr ).
190+ Msg ("Key NOT synced - has pending transaction" )
164191
165192 return errors .New (ErrKeySync )
166193 },
@@ -169,6 +196,29 @@ func (m *NonceManager) anySyncedKey() int {
169196 )
170197 if err != nil {
171198 m .Client .Errors = append (m .Client .Errors , errors .New (ErrKeySync ))
199+
200+ // NEVER leak the key - always return it to the pool
201+ var nonceToUse uint64
202+ if hasValidNonce {
203+ nonceToUse = lastKnownNonce
204+ L .Warn ().
205+ Interface ("KeyNum" , keyData .KeyNum ).
206+ Uint64 ("Nonce" , nonceToUse ).
207+ Interface ("Address" , addr ).
208+ Msg ("Key sync failed, returning key to pool with last known nonce" )
209+ } else {
210+ // Fall back to the original nonce when key was checked out
211+ nonceToUse = keyData .Nonce
212+ L .Warn ().
213+ Interface ("KeyNum" , keyData .KeyNum ).
214+ Uint64 ("Nonce" , nonceToUse ).
215+ Interface ("Address" , addr ).
216+ Msg ("Key sync failed, returning key to pool with original nonce" )
217+ }
218+ m .SyncedKeys <- & KeyNonce {
219+ KeyNum : keyData .KeyNum ,
220+ Nonce : nonceToUse ,
221+ }
172222 }
173223 }()
174224 return keyData .KeyNum
0 commit comments