2023-07-04 11:25:08 -07:00
|
|
|
package consumer
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
2023-07-14 06:39:09 -07:00
|
|
|
"time"
|
2023-07-04 11:25:08 -07:00
|
|
|
|
|
|
|
"github.com/wormhole-foundation/wormhole-explorer/common/domain"
|
|
|
|
"github.com/wormhole-foundation/wormhole-explorer/txtracker/chains"
|
|
|
|
"github.com/wormhole-foundation/wormhole-explorer/txtracker/config"
|
2023-12-07 06:06:48 -08:00
|
|
|
"github.com/wormhole-foundation/wormhole-explorer/txtracker/internal/metrics"
|
2023-07-04 11:25:08 -07:00
|
|
|
sdk "github.com/wormhole-foundation/wormhole/sdk/vaa"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
)
|
|
|
|
|
2023-07-11 12:31:45 -07:00
|
|
|
var ErrAlreadyProcessed = errors.New("VAA was already processed")
|
|
|
|
|
2023-07-04 11:25:08 -07:00
|
|
|
// ProcessSourceTxParams is a struct that contains the parameters for the ProcessSourceTx method.
|
|
|
|
type ProcessSourceTxParams struct {
|
2023-11-27 07:31:35 -08:00
|
|
|
TrackID string
|
2023-07-14 06:39:09 -07:00
|
|
|
Timestamp *time.Time
|
|
|
|
ChainId sdk.ChainID
|
|
|
|
VaaId string
|
|
|
|
Emitter string
|
|
|
|
Sequence string
|
|
|
|
TxHash string
|
2023-07-11 12:31:45 -07:00
|
|
|
// Overwrite indicates whether to reprocess a VAA that has already been processed.
|
|
|
|
//
|
|
|
|
// In the context of backfilling, sometimes you want to overwrite old data (e.g.: because
|
|
|
|
// the schema changed).
|
|
|
|
// In the context of the service, you usually don't want to overwrite existing data
|
|
|
|
// to avoid processing the same VAA twice, which would result in performance degradation.
|
|
|
|
Overwrite bool
|
2023-12-07 06:06:48 -08:00
|
|
|
Metrics metrics.Metrics
|
2023-07-04 11:25:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func ProcessSourceTx(
|
|
|
|
ctx context.Context,
|
|
|
|
logger *zap.Logger,
|
|
|
|
rpcServiceProviderSettings *config.RpcProviderSettings,
|
|
|
|
repository *Repository,
|
|
|
|
params *ProcessSourceTxParams,
|
2023-09-04 11:17:23 -07:00
|
|
|
p2pNetwork string,
|
2023-11-15 07:11:24 -08:00
|
|
|
) (*chains.TxDetail, error) {
|
2023-07-04 11:25:08 -07:00
|
|
|
|
2023-07-13 08:26:38 -07:00
|
|
|
if !params.Overwrite {
|
|
|
|
// If the message has already been processed, skip it.
|
|
|
|
//
|
|
|
|
// Sometimes the SQS visibility timeout expires and the message is put back into the queue,
|
|
|
|
// even if the RPC nodes have been hit and data has been written to MongoDB.
|
|
|
|
// In those cases, when we fetch the message for the second time,
|
|
|
|
// we don't want to hit the RPC nodes again for performance reasons.
|
|
|
|
processed, err := repository.AlreadyProcessed(ctx, params.VaaId)
|
|
|
|
if err != nil {
|
2023-11-15 07:11:24 -08:00
|
|
|
return nil, err
|
2023-07-13 08:26:38 -07:00
|
|
|
} else if err == nil && processed {
|
2023-11-15 07:11:24 -08:00
|
|
|
return nil, ErrAlreadyProcessed
|
2023-07-04 11:25:08 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-14 06:39:09 -07:00
|
|
|
// The loop below tries to fetch transaction details from an external API / RPC node.
|
|
|
|
//
|
|
|
|
// It keeps retrying until both of these conditions are met:
|
|
|
|
// 1. A fixed amount of time has passed since the VAA was emitted (this is because
|
|
|
|
// some chains have awful finality times).
|
|
|
|
// 2. A minimum number of attempts have been made.
|
|
|
|
var txDetail *chains.TxDetail
|
|
|
|
var err error
|
|
|
|
|
2023-12-12 10:46:00 -08:00
|
|
|
if params.TxHash == "" {
|
|
|
|
// add metrics for vaa without txHash
|
|
|
|
params.Metrics.IncVaaWithoutTxHash(uint16(params.ChainId))
|
|
|
|
v, err := repository.GetVaaIdTxHash(ctx, params.VaaId)
|
|
|
|
if err != nil {
|
|
|
|
logger.Error("failed to find vaaIdTxHash",
|
2023-11-27 07:31:35 -08:00
|
|
|
zap.String("trackId", params.TrackID),
|
2023-07-14 06:39:09 -07:00
|
|
|
zap.String("vaaId", params.VaaId),
|
|
|
|
zap.Any("vaaTimestamp", params.Timestamp),
|
|
|
|
zap.Error(err),
|
|
|
|
)
|
2023-12-12 10:46:00 -08:00
|
|
|
} else {
|
|
|
|
// add metrics for vaa with txHash fixed
|
|
|
|
params.Metrics.IncVaaWithTxHashFixed(uint16(params.ChainId))
|
|
|
|
params.TxHash = v.TxHash
|
|
|
|
logger.Warn("fix txHash for vaa",
|
|
|
|
zap.String("trackId", params.TrackID),
|
|
|
|
zap.String("vaaId", params.VaaId),
|
|
|
|
zap.Any("vaaTimestamp", params.Timestamp),
|
|
|
|
zap.String("txHash", v.TxHash),
|
|
|
|
)
|
2023-07-14 06:39:09 -07:00
|
|
|
}
|
2023-07-13 08:26:38 -07:00
|
|
|
}
|
|
|
|
|
2023-12-12 10:46:00 -08:00
|
|
|
if params.TxHash == "" {
|
|
|
|
logger.Warn("txHash is empty",
|
|
|
|
zap.String("trackId", params.TrackID),
|
|
|
|
zap.String("vaaId", params.VaaId),
|
|
|
|
)
|
|
|
|
return nil, errors.New("txHash is empty")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get transaction details from the emitter blockchain
|
|
|
|
txDetail, err = chains.FetchTx(ctx, rpcServiceProviderSettings, params.ChainId, params.TxHash, params.Timestamp, p2pNetwork)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-07-04 11:25:08 -07:00
|
|
|
// Store source transaction details in the database
|
2024-01-15 05:22:05 -08:00
|
|
|
p := UpsertOriginTxParams{
|
2023-11-27 07:31:35 -08:00
|
|
|
VaaId: params.VaaId,
|
|
|
|
ChainId: params.ChainId,
|
|
|
|
Timestamp: params.Timestamp,
|
|
|
|
TxDetail: txDetail,
|
|
|
|
TxStatus: domain.SourceTxStatusConfirmed,
|
2023-07-04 11:25:08 -07:00
|
|
|
}
|
2023-11-15 07:11:24 -08:00
|
|
|
|
2024-01-15 05:22:05 -08:00
|
|
|
err = repository.UpsertOriginTx(ctx, &p)
|
2023-11-15 07:11:24 -08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return txDetail, nil
|
2023-07-04 11:25:08 -07:00
|
|
|
}
|