package watcher import ( "context" "errors" "github.com/wormhole-foundation/wormhole-explorer/common/domain" "github.com/wormhole-foundation/wormhole-explorer/contract-watcher/storage" sdk "github.com/wormhole-foundation/wormhole/sdk/vaa" "go.uber.org/zap" ) var ( ErrTxfailedCannotBeUpdated = errors.New("tx with status failed can not be updated because exists a confirmed tx for the same vaa ID") ErrTxUnknowCannotBeUpdated = errors.New("tx with status unknown can not be updated because exists a tx (confirmed|failed) for the same vaa ID") ErrInvalidTxStatus = errors.New("invalid tx status") ) type FuncGetGlobalTransactionById func(ctx context.Context, id string) (storage.TransactionUpdate, error) func updateGlobalTransaction(ctx context.Context, chainID sdk.ChainID, tx storage.TransactionUpdate, r *storage.Repository, log *zap.Logger) { updateGlobalTx, err := checkTxShouldBeUpdated(ctx, tx, r.GetGlobalTransactionByID) if !updateGlobalTx { log.Info("tx can not be updated", zap.String("id", tx.ID), zap.String("txHash", tx.Destination.TxHash), zap.String("status", tx.Destination.Status), zap.Error(err)) return } err = r.UpsertGlobalTransaction(ctx, chainID, tx) if err != nil { log.Error("cannot save redeemed tx", zap.Error(err)) } else { log.Info("saved redeemed tx", zap.String("vaa", tx.ID)) } } // checkTxShouldBeUpdated checks if the transaction should be updated. func checkTxShouldBeUpdated(ctx context.Context, tx storage.TransactionUpdate, getGlobalTransactionByIDFunc FuncGetGlobalTransactionById) (bool, error) { switch tx.Destination.Status { case domain.DstTxStatusConfirmed: return true, nil case domain.DstTxStatusFailedToProcess: // check if the transaction exists from the same vaa ID. oldTx, err := getGlobalTransactionByIDFunc(ctx, tx.ID) if err != nil { return true, nil } // if the transaction was already confirmed, then no update it. if oldTx.Destination.Status == domain.DstTxStatusConfirmed { return false, ErrTxfailedCannotBeUpdated } return true, nil case domain.DstTxStatusUnkonwn: // check if the transaction exists from the same vaa ID. oldTx, err := getGlobalTransactionByIDFunc(ctx, tx.ID) if err != nil { return true, nil } // if the transaction was already confirmed or failed to process, then no update it. if oldTx.Destination.Status == domain.DstTxStatusConfirmed || oldTx.Destination.Status == domain.DstTxStatusFailedToProcess { return false, ErrTxUnknowCannotBeUpdated } return true, nil default: return false, ErrInvalidTxStatus } }