88 "net/http"
99 "strings"
1010 "sync"
11+ "time"
1112
1213 "go.uber.org/zap"
1314
@@ -293,11 +294,44 @@ func (a *Account) queryTx(txhash string) (map[string]interface{}, error) {
293294 return txMap , nil
294295}
295296
296- // sendTokens performs chain binary send txn from account
297- func (a * Account ) sendTokens (address string , denom string , amount string ) error {
297+ // queryTxWithRetry wraps queryTx with retry logic on tx "not found" error
298+ func (a * Account ) queryTxWithRetry (txhash string , maxRetries int ) (map [string ]interface {}, error ) {
299+ var (
300+ txMap map [string ]interface {}
301+ err error
302+ )
303+
304+ for attempt := 1 ; attempt <= maxRetries ; attempt ++ {
305+ txMap , err = a .queryTx (txhash )
306+ if err == nil {
307+ return txMap , nil
308+ }
309+
310+ // Check explicitly for the "not found" error condition
311+ if strings .Contains (err .Error (), "not found" ) {
312+ a .logger .Warn ("transaction not found, retrying" ,
313+ zap .String ("txhash" , txhash ),
314+ zap .Int ("attempt" , attempt ),
315+ zap .Int ("maxRetries" , maxRetries ),
316+ )
317+
318+ // Sleep 2-3 seconds before retry
319+ time .Sleep (2 * time .Second + time .Duration (rand .Intn (1000 ))* time .Millisecond )
320+ continue
321+ }
322+
323+ // If any other error occurs, return immediately
324+ return nil , err
325+ }
326+
327+ return nil , fmt .Errorf ("transaction not found after retries: txhash: %s" , txhash )
328+ }
329+
330+ // sendTokens performs chain binary send txn from account, returns txhash
331+ func (a * Account ) sendTokens (address string , denom string , amount string ) (string , error ) {
298332 ok := a .mu .TryLock ()
299333 if ! ok {
300- return fmt .Errorf ("account %s busy: %w" , a , ErrResourceInUse )
334+ return "" , fmt .Errorf ("account %s busy: %w" , a , ErrResourceInUse )
301335 }
302336 defer a .mu .Unlock ()
303337
@@ -306,29 +340,35 @@ func (a *Account) sendTokens(address string, denom string, amount string) error
306340 output , err := runCommand (cmdStr )
307341 if err != nil {
308342 a .logger .Error ("send token failed" , zap .String ("cmd" , cmdStr ), zap .Error (err ))
309- return err
343+ return "" , err
310344 }
311345 a .logger .Info ("ran cmd to send tokens" , zap .String ("cmd" , cmdStr ), zap .String ("stdout" , string (output )))
312346
313347 // Find the JSON line and extract the txhash using a regular expression
314348 txhash , err := extractTxHash (string (output ))
315349 if err != nil {
316350 a .logger .Error ("failed to extract txhash" , zap .Error (err ))
317- return err
351+ return "" , err
318352 }
319353
320354 a .logger .Debug ("send tokens txhash" , zap .String ("txhash" , txhash ))
321355
356+ return txhash , nil
357+ }
358+
359+ // confirmTx checks if the tx has gone through by checking the event
360+ func (a * Account ) confirmTx (txhash , eventType string ) error {
322361 // query tx to check if the tx was successful
323- txMap , err := a .queryTx (txhash )
362+ txMap , err := a .queryTxWithRetry (txhash , 3 )
324363 if err != nil {
325364 return err
326365 }
327366
328367 // check if the tx has the event
329- err = hasEvent (txMap , "transfer" )
368+ err = hasEvent (txMap , eventType )
330369 if err != nil {
331- a .logger .Error ("transfer event not found in tx" ,
370+ a .logger .Error ("event not found in tx" ,
371+ zap .String ("eventType" , eventType ),
332372 zap .String ("txhash" , txhash ),
333373 zap .Any ("txMap" , txMap ))
334374 return err
@@ -339,16 +379,23 @@ func (a *Account) sendTokens(address string, denom string, amount string) error
339379
340380// SendTokens will perform send tokens with retries based on errors
341381func (a * Account ) SendTokens (address string , denom string , amount string ) error {
342- err := a .sendTokens (address , denom , amount )
382+ txHash , err := a .sendTokens (address , denom , amount )
343383 if err == nil {
344384 return nil
345385 }
386+
346387 if strings .Contains (err .Error (), "account sequence mismatch" ) {
347388 // retry sendTokens
348389 a .logger .Debug ("got account sequence missmatch error, retrying send tokens recursively" )
349390 return a .SendTokens (address , denom , amount )
350391 }
351392
393+ // Confirm tx has gone through
394+ err = a .confirmTx (txHash , "transfer" )
395+ if err != nil {
396+ return err
397+ }
398+
352399 return err
353400}
354401
0 commit comments