@@ -190,46 +190,52 @@ func watchStart(watches []transactionWatch) time.Time {
190190 return start
191191}
192192
193- // check pending checks the given block (number) for confirmed or cancelled transactions
193+ // checkPending checks the given block for confirmed or cancelled transactions.
194194func (tm * transactionMonitor ) checkPending (block uint64 ) error {
195- confirmedNonces := make (map [uint64 ]* types.Receipt )
196- var cancelledNonces []uint64
197- for nonceGroup , watchMap := range tm .watchesByNonce {
195+ // Snapshot nonces and tx hashes to check (releases lock during slow RPC calls).
196+ tm .lock .Lock ()
197+ snapshot := make (map [uint64 ]map [common.Hash ]time.Time , len (tm .watchesByNonce ))
198+ for nonce , watchMap := range tm .watchesByNonce {
199+ snapshot [nonce ] = make (map [common.Hash ]time.Time , len (watchMap ))
198200 for txHash , watches := range watchMap {
201+ snapshot [nonce ][txHash ] = watchStart (watches )
202+ }
203+ }
204+ tm .lock .Unlock ()
205+
206+ // Check receipts without holding lock (RPC calls can be slow).
207+ confirmedNonces := make (map [uint64 ]* types.Receipt )
208+ for nonce , txMap := range snapshot {
209+ for txHash , start := range txMap {
199210 receipt , err := tm .backend .TransactionReceipt (tm .ctx , txHash )
200211 if err != nil {
201- // wait for a few blocks to be mined before considering a transaction not existing
202- transactionWatchNotFoundTimeout := 5 * tm .pollingInterval
203- if errors .Is (err , ethereum .NotFound ) && watchStart (watches ).Before (time .Now ().Add (transactionWatchNotFoundTimeout )) {
204- // if both err and receipt are nil, there is no receipt
205- // the reason why we consider this only potentially cancelled is to catch cases where after a reorg the original transaction wins
212+ if errors .Is (err , ethereum .NotFound ) && start .Before (time .Now ().Add (5 * tm .pollingInterval )) {
206213 continue
207214 }
208215 return err
209216 }
210217 if receipt != nil {
211- // if we have a receipt we have a confirmation
212- confirmedNonces [nonceGroup ] = receipt
218+ confirmedNonces [nonce ] = receipt
213219 }
214220 }
215221 }
216222
217- for nonceGroup := range tm .watchesByNonce {
218- if _ , ok := confirmedNonces [nonceGroup ]; ok {
223+ // Check for cancellations.
224+ var cancelledNonces []uint64
225+ for nonce := range snapshot {
226+ if _ , ok := confirmedNonces [nonce ]; ok {
219227 continue
220228 }
221-
222229 oldNonce , err := tm .backend .NonceAt (tm .ctx , tm .sender , new (big.Int ).SetUint64 (block - tm .cancellationDepth ))
223230 if err != nil {
224231 return err
225232 }
226-
227- if nonceGroup < oldNonce {
228- cancelledNonces = append (cancelledNonces , nonceGroup )
233+ if nonce < oldNonce {
234+ cancelledNonces = append (cancelledNonces , nonce )
229235 }
230236 }
231237
232- // notify the subscribers and remove watches for confirmed or cancelled transactions
238+ // Notify subscribers and cleanup.
233239 tm .lock .Lock ()
234240 defer tm .lock .Unlock ()
235241
0 commit comments