From d8723c056beabc0958894fb2bd75c46419054db9 Mon Sep 17 00:00:00 2001 From: Agustin Pazos Date: Thu, 11 May 2023 19:18:31 -0300 Subject: [PATCH] Add api endpoint to get total count and volume --- api/handlers/transactions/model.go | 5 +- api/handlers/transactions/repository.go | 64 +++++++++---------- api/main.go | 3 + .../wormscan/transactions/controller.go | 7 +- api/routes/wormscan/transactions/response.go | 7 +- common/storage/portalanalytic/model.go | 2 +- common/storage/portalanalytic/repository.go | 4 +- common/storage/types.go | 33 ---------- fly/migration/migration.go | 6 ++ 9 files changed, 57 insertions(+), 74 deletions(-) delete mode 100644 common/storage/types.go diff --git a/api/handlers/transactions/model.go b/api/handlers/transactions/model.go index 93b4d014..df8a88b4 100644 --- a/api/handlers/transactions/model.go +++ b/api/handlers/transactions/model.go @@ -9,9 +9,12 @@ import ( ) type Scorecards struct { - // Number of VAAs emitted since the creation of the network (does not include Pyth messages) + // Total number of VAAs emitted since the creation of the network (does not include Pyth messages). TotalTxCount string + // Volume transferred through the token bridge since the creation of the network, in USD. + TotalTxVolume string + // Number of VAAs emitted in the last 24 hours (does not include Pyth messages). TxCount24h string diff --git a/api/handlers/transactions/repository.go b/api/handlers/transactions/repository.go index 3666bd1f..f007b87c 100644 --- a/api/handlers/transactions/repository.go +++ b/api/handlers/transactions/repository.go @@ -13,6 +13,8 @@ import ( "github.com/pkg/errors" errs "github.com/wormhole-foundation/wormhole-explorer/api/internal/errors" "github.com/wormhole-foundation/wormhole-explorer/common/domain" + "github.com/wormhole-foundation/wormhole-explorer/common/storage/portalanalytic" + "github.com/wormhole-foundation/wormhole-explorer/fly/storage" sdk "github.com/wormhole-foundation/wormhole/sdk/vaa" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" @@ -92,6 +94,7 @@ type Repository struct { bucketInfiniteRetention string bucket30DaysRetention string bucket24HoursRetention string + portalAnalyticRepo *portalanalytic.Repository db *mongo.Database collections struct { globalTransactions *mongo.Collection @@ -104,6 +107,7 @@ func NewRepository( org string, bucket24HoursRetention, bucket30DaysRetention, bucketInfiniteRetention string, db *mongo.Database, + portalAnalyticRepo *portalanalytic.Repository, logger *zap.Logger, ) *Repository { @@ -113,6 +117,7 @@ func NewRepository( bucket24HoursRetention: bucket24HoursRetention, bucket30DaysRetention: bucket30DaysRetention, bucketInfiniteRetention: bucketInfiniteRetention, + portalAnalyticRepo: portalAnalyticRepo, db: db, collections: struct{ globalTransactions *mongo.Collection }{globalTransactions: db.Collection("globalTransactions")}, logger: logger, @@ -231,19 +236,19 @@ func (r *Repository) buildFindVolumeQuery(q *ChainActivityQuery) string { } func (r *Repository) GetScorecards(ctx context.Context) (*Scorecards, error) { + // get historic total count and volume. + totalTxCount, totalTxVolume, err := r.getTotalCountAndVolume(ctx) + if err != nil { + return nil, err + } - //TODO the underlying query in this code is not using pre-summarized data. - // We should fix that before re-enabling the metric. - //totalTxCount, err := r.getTotalTxCount(ctx) - //if err != nil { - // return nil, fmt.Errorf("failed to query all-time tx count") - //} - + // get 24h transactions txCount24h, err := r.getTxCount24h(ctx) if err != nil { return nil, fmt.Errorf("failed to query 24h transactions: %w", err) } + // get 24h volume volume24h, err := r.getVolume24h(ctx) if err != nil { return nil, fmt.Errorf("failed to query 24h volume: %w", err) @@ -251,40 +256,35 @@ func (r *Repository) GetScorecards(ctx context.Context) (*Scorecards, error) { // build the result and return scorecards := Scorecards{ - //TotalTxCount: totalTxCount, - TxCount24h: txCount24h, - Volume24h: volume24h, + TotalTxCount: fmt.Sprint(totalTxCount), + TotalTxVolume: fmt.Sprint(totalTxVolume), + TxCount24h: txCount24h, + Volume24h: volume24h, } return &scorecards, nil } -func (r *Repository) getTotalTxCount(ctx context.Context) (string, error) { - - // query 24h transactions - query := fmt.Sprintf(queryTemplateTotalTxCount, r.bucketInfiniteRetention) - result, err := r.queryAPI.Query(ctx, query) +// getTotalCountAndVolume get historic total count and volume. +func (r *Repository) getTotalCountAndVolume(ctx context.Context) (storage.Uint64, storage.Uint64, error) { + var totalTxCount, totalTxVolume storage.Uint64 + var ids = []string{"tx_volume_historic", "tx_volume", "tx_count_historic", "tx_count"} + portalAnalytics, err := r.portalAnalyticRepo.GetPortalAnalyticByIds(ctx, ids) if err != nil { - r.logger.Error("failed to query total transaction count", zap.Error(err)) - return "", err - } - if result.Err() != nil { - r.logger.Error("total transaction count query result has errors", zap.Error(err)) - return "", result.Err() - } - if !result.Next() { - return "", errors.New("expected at least one record in total transaction count query result") + return 0, 0, err } + for _, portalAnalytic := range portalAnalytics { + if portalAnalytic.ID == "tx_count_historic" || portalAnalytic.ID == "tx_count" { + totalTxCount = totalTxCount + portalAnalytic.Value + continue + } + if portalAnalytic.ID == "tx_volume_historic" || portalAnalytic.ID == "tx_volume" { + totalTxVolume = totalTxVolume + portalAnalytic.Value + continue + } - // deserialize the row returned - row := struct { - Value uint64 `mapstructure:"_value"` - }{} - if err := mapstructure.Decode(result.Record().Values(), &row); err != nil { - return "", fmt.Errorf("failed to decode total transaction count query response: %w", err) } - - return fmt.Sprint(row.Value), nil + return totalTxCount, totalTxVolume, nil } func (r *Repository) getTxCount24h(ctx context.Context) (string, error) { diff --git a/api/main.go b/api/main.go index b8954bec..7d89e0d0 100644 --- a/api/main.go +++ b/api/main.go @@ -38,6 +38,7 @@ import ( wormscanCache "github.com/wormhole-foundation/wormhole-explorer/common/client/cache" wormscanNotionalCache "github.com/wormhole-foundation/wormhole-explorer/common/client/cache/notional" xlogger "github.com/wormhole-foundation/wormhole-explorer/common/logger" + "github.com/wormhole-foundation/wormhole-explorer/common/storage/portalanalytic" "go.uber.org/zap" ) @@ -112,6 +113,7 @@ func main() { governorRepo := governor.NewRepository(db, rootLogger) infrastructureRepo := infrastructure.NewRepository(db, rootLogger) heartbeatsRepo := heartbeats.NewRepository(db, rootLogger) + portalAnalytcRepo := portalanalytic.NewPortalAnalytic(db, rootLogger) transactionsRepo := transactions.NewRepository( influxCli, cfg.Influx.Organization, @@ -119,6 +121,7 @@ func main() { cfg.Influx.Bucket30Days, cfg.Influx.BucketInfinite, db, + portalAnalytcRepo, rootLogger, ) diff --git a/api/routes/wormscan/transactions/controller.go b/api/routes/wormscan/transactions/controller.go index bbbc009c..14cd81d4 100644 --- a/api/routes/wormscan/transactions/controller.go +++ b/api/routes/wormscan/transactions/controller.go @@ -77,9 +77,10 @@ func (c *Controller) GetScorecards(ctx *fiber.Ctx) error { // Convert indicators to the response model response := ScorecardsResponse{ - TotalTxCount: scorecards.TotalTxCount, - TxCount24h: scorecards.TxCount24h, - Volume24h: scorecards.Volume24h, + TotalTxCount: scorecards.TotalTxCount, + TotalTxVolume: scorecards.TotalTxVolume, + TxCount24h: scorecards.TxCount24h, + Volume24h: scorecards.Volume24h, } return ctx.JSON(response) diff --git a/api/routes/wormscan/transactions/response.go b/api/routes/wormscan/transactions/response.go index 1303ca62..abfdcc53 100644 --- a/api/routes/wormscan/transactions/response.go +++ b/api/routes/wormscan/transactions/response.go @@ -30,10 +30,11 @@ type ScorecardsResponse struct { // Number of VAAs emitted in the last 24 hours (includes Pyth messages). //Messages24h string `json:"24h_messages"` - // Number of VAAs emitted since the creation of the network (does not include Pyth messages) - TotalTxCount string `json:"total_tx_count,omitempty"` + // Total number of VAAs emitted since the creation of the network (does not include Pyth messages). + TotalTxCount string `json:"total_tx_count"` - //TotalVolume string `json:"total_volume"` + // Volume transferred through the token bridge since the creation of the network, in USD. + TotalTxVolume string `json:"total_volume"` //TVL string `json:"tvl"` diff --git a/common/storage/portalanalytic/model.go b/common/storage/portalanalytic/model.go index 85532ebf..5b5b3d37 100644 --- a/common/storage/portalanalytic/model.go +++ b/common/storage/portalanalytic/model.go @@ -1,6 +1,6 @@ package portalanalytic -import "github.com/wormhole-foundation/wormhole-explorer/common/storage" +import "github.com/wormhole-foundation/wormhole-explorer/fly/storage" // PortalAnalyticDoc is a portal analytic document. type PortalAnalyticdDoc struct { diff --git a/common/storage/portalanalytic/repository.go b/common/storage/portalanalytic/repository.go index 77668c9f..2659ff29 100644 --- a/common/storage/portalanalytic/repository.go +++ b/common/storage/portalanalytic/repository.go @@ -1,6 +1,8 @@ package portalanalytic import ( + "context" + "go.mongodb.org/mongo-driver/mongo" "go.uber.org/zap" ) @@ -23,6 +25,6 @@ func NewPortalAnalytic(db *mongo.Database, log *zap.Logger) *Repository { } // GetPortalAnalytic get portal analytic. -func (r *Repository) GetPortalAnalyticByIds(ids []string) ([]*PortalAnalyticdDoc, error) { +func (r *Repository) GetPortalAnalyticByIds(ctx context.Context, ids []string) ([]*PortalAnalyticdDoc, error) { return []*PortalAnalyticdDoc{}, nil } diff --git a/common/storage/types.go b/common/storage/types.go deleted file mode 100644 index 34561a47..00000000 --- a/common/storage/types.go +++ /dev/null @@ -1,33 +0,0 @@ -package storage - -import ( - "errors" - "strconv" - - "go.mongodb.org/mongo-driver/bson/bsontype" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" -) - -type Uint64 uint64 - -func (u Uint64) MarshalBSONValue() (bsontype.Type, []byte, error) { - ui64Str := strconv.FormatUint(uint64(u), 10) - d128, err := primitive.ParseDecimal128(ui64Str) - return bsontype.Decimal128, bsoncore.AppendDecimal128(nil, d128), err -} - -func (u *Uint64) UnmarshalBSONValue(t bsontype.Type, b []byte) error { - d128, _, ok := bsoncore.ReadDecimal128(b) - if !ok { - return errors.New("Uint64 UnmarshalBSONValue error") - } - - ui64, err := strconv.ParseUint(d128.String(), 10, 64) - if err != nil { - return err - } - - *u = Uint64(ui64) - return nil -} diff --git a/fly/migration/migration.go b/fly/migration/migration.go index 4c60929d..4cb78475 100644 --- a/fly/migration/migration.go +++ b/fly/migration/migration.go @@ -65,6 +65,12 @@ func Run(db *mongo.Database) error { return err } + // Create vaaIdTxHash collection. + err = db.CreateCollection(context.TODO(), "portalAnalytic") + if err != nil && isNotAlreadyExistsError(err) { + return err + } + // create index in vaas collection by vaa key (emitterchain, emitterAddr, sequence) indexVaaByKey := mongo.IndexModel{ Keys: bson.D{