Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create an api endpoint to call vaa payload parser component #596

Merged
merged 5 commits into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions api/docs/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

76 changes: 76 additions & 0 deletions api/docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,32 @@
}
}
},
"/api/v1/vaas/parse": {
"post": {
"description": "Parse a VAA.",
"tags": [
"Wormscan"
],
"operationId": "parse-vaa",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/parser.ParseVaaWithStandarizedPropertiesdResponse"
}
},
"400": {
"description": "Bad Request"
},
"404": {
"description": "Not Found"
},
"500": {
"description": "Internal Server Error"
}
}
}
},
"/api/v1/vaas/vaa-counts": {
"get": {
"description": "Returns the total number of VAAs emitted for each blockchain.",
Expand Down Expand Up @@ -2293,6 +2319,56 @@
}
}
},
"parser.ParseVaaWithStandarizedPropertiesdResponse": {
"type": "object",
"properties": {
"parsedPayload": {},
"standardizedProperties": {
"$ref": "#/definitions/parser.StandardizedProperties"
}
}
},
"parser.StandardizedProperties": {
"type": "object",
"properties": {
"amount": {
"type": "string"
},
"appIds": {
"type": "array",
"items": {
"type": "string"
}
},
"fee": {
"type": "string"
},
"feeAddress": {
"type": "string"
},
"feeChain": {
"$ref": "#/definitions/vaa.ChainID"
},
"fromAddress": {
"type": "string"
},
"fromChain": {
"$ref": "#/definitions/vaa.ChainID"
},
"toAddress": {
"type": "string"
},
"toChain": {
"$ref": "#/definitions/vaa.ChainID"
},
"tokenAddress": {
"type": "string"
},
"tokenChain": {
"$ref": "#/definitions/vaa.ChainID"
}
}
},
"response.Response-address_AddressOverview": {
"type": "object",
"properties": {
Expand Down
50 changes: 50 additions & 0 deletions api/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,39 @@ definitions:
updatedAt:
type: string
type: object
parser.ParseVaaWithStandarizedPropertiesdResponse:
properties:
parsedPayload: {}
standardizedProperties:
$ref: '#/definitions/parser.StandardizedProperties'
type: object
parser.StandardizedProperties:
properties:
amount:
type: string
appIds:
items:
type: string
type: array
fee:
type: string
feeAddress:
type: string
feeChain:
$ref: '#/definitions/vaa.ChainID'
fromAddress:
type: string
fromChain:
$ref: '#/definitions/vaa.ChainID'
toAddress:
type: string
toChain:
$ref: '#/definitions/vaa.ChainID'
tokenAddress:
type: string
tokenChain:
$ref: '#/definitions/vaa.ChainID'
type: object
response.Response-address_AddressOverview:
properties:
data:
Expand Down Expand Up @@ -1676,6 +1709,23 @@ paths:
description: Internal Server Error
tags:
- Wormscan
/api/v1/vaas/parse:
post:
description: Parse a VAA.
operationId: parse-vaa
responses:
"200":
description: OK
schema:
$ref: '#/definitions/parser.ParseVaaWithStandarizedPropertiesdResponse'
"400":
description: Bad Request
"404":
description: Not Found
"500":
description: Internal Server Error
tags:
- Wormscan
/api/v1/vaas/vaa-counts:
get:
description: Returns the total number of VAAs emitted for each blockchain.
Expand Down
28 changes: 27 additions & 1 deletion api/handlers/vaa/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/wormhole-foundation/wormhole-explorer/api/response"
"github.com/wormhole-foundation/wormhole-explorer/api/types"
"github.com/wormhole-foundation/wormhole-explorer/common/client/cache"
vaaPayloadParser "github.com/wormhole-foundation/wormhole-explorer/common/client/parser"
sdk "github.com/wormhole-foundation/wormhole/sdk/vaa"
"go.uber.org/zap"
)
Expand All @@ -19,15 +20,17 @@ import (
type Service struct {
repo *Repository
getCacheFunc cache.CacheGetFunc
parseVaaFunc vaaPayloadParser.ParseVaaFunc
logger *zap.Logger
}

// NewService creates a new VAA Service.
func NewService(r *Repository, getCacheFunc cache.CacheGetFunc, logger *zap.Logger) *Service {
func NewService(r *Repository, getCacheFunc cache.CacheGetFunc, parseVaaFunc vaaPayloadParser.ParseVaaFunc, logger *zap.Logger) *Service {

s := Service{
repo: r,
getCacheFunc: getCacheFunc,
parseVaaFunc: parseVaaFunc,
logger: logger.With(zap.String("module", "VaaService")),
}

Expand Down Expand Up @@ -245,3 +248,26 @@ func (s *Service) discardVaaNotIndexed(ctx context.Context, chain sdk.ChainID, e
}
return true
}

// ParseVaa parse a vaa payload.
func (s *Service) ParseVaa(ctx context.Context, vaaByte []byte) (vaaPayloadParser.ParseVaaWithStandarizedPropertiesdResponse, error) {
// unmarshal vaa
vaa, err := sdk.Unmarshal(vaaByte)
if err != nil {
requestID := fmt.Sprintf("%v", ctx.Value("requestid"))
s.logger.Error("error unmarshal vaa to parse", zap.Error(err), zap.String("requestID", requestID))
return vaaPayloadParser.ParseVaaWithStandarizedPropertiesdResponse{}, errs.ErrInternalError
}

// call vaa payload parser api
parsedVaa, err := s.parseVaaFunc(vaa)
if err != nil {
if errors.Is(err, vaaPayloadParser.ErrNotFound) {
return vaaPayloadParser.ParseVaaWithStandarizedPropertiesdResponse{}, errs.ErrNotFound
}
requestID := fmt.Sprintf("%v", ctx.Value("requestid"))
s.logger.Error("error parse vaa", zap.Error(err), zap.String("requestID", requestID))
return vaaPayloadParser.ParseVaaWithStandarizedPropertiesdResponse{}, errs.ErrInternalError
}
return *parsedVaa, nil
}
5 changes: 5 additions & 0 deletions api/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ type AppConfig struct {
Bucket30Days string
BucketInfinite string
}
VaaPayloadParser struct {
Enabled bool
URL string
Timeout int64
}
RateLimit struct {
Enabled bool
// Max number of requests per minute
Expand Down
25 changes: 24 additions & 1 deletion api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ import (
"github.com/wormhole-foundation/wormhole-explorer/api/routes/wormscan"
rpcApi "github.com/wormhole-foundation/wormhole-explorer/api/rpc"
wormscanCache "github.com/wormhole-foundation/wormhole-explorer/common/client/cache"
vaaPayloadParser "github.com/wormhole-foundation/wormhole-explorer/common/client/parser"
"github.com/wormhole-foundation/wormhole-explorer/common/dbutil"
xlogger "github.com/wormhole-foundation/wormhole-explorer/common/logger"
"github.com/wormhole-foundation/wormhole-explorer/common/utils"
sdk "github.com/wormhole-foundation/wormhole/sdk/vaa"
"go.uber.org/zap"
)

Expand Down Expand Up @@ -123,6 +125,12 @@ func main() {
rootLogger.Info("initializing InfluxDB client")
influxCli := newInfluxClient(cfg.Influx.URL, cfg.Influx.Token)

//VaaPayloadParser client
vaaParserFunc, err := NewVaaParserFunc(cfg, rootLogger)
if err != nil {
rootLogger.Fatal("failed to initialize VAA parser", zap.Error(err))
}

// Set up repositories
rootLogger.Info("initializing repositories")
addressRepo := address.NewRepository(db.Database, rootLogger)
Expand All @@ -145,7 +153,7 @@ func main() {
// Set up services
rootLogger.Info("initializing services")
addressService := address.NewService(addressRepo, rootLogger)
vaaService := vaa.NewService(vaaRepo, cache.Get, rootLogger)
vaaService := vaa.NewService(vaaRepo, cache.Get, vaaParserFunc, rootLogger)
obsService := observations.NewService(obsRepo, rootLogger)
governorService := governor.NewService(governorRepo, rootLogger)
infrastructureService := infrastructure.NewService(infrastructureRepo, rootLogger)
Expand Down Expand Up @@ -306,3 +314,18 @@ func NewRateLimiter(ctx context.Context, cfg *config.AppConfig, logger *zap.Logg
return router, nil

}

// NewVaaParserFunc returns a function to parse VAA payload.
func NewVaaParserFunc(cfg *config.AppConfig, logger *zap.Logger) (vaaPayloadParser.ParseVaaFunc, error) {
if cfg.RunMode == config.RunModeDevelopmernt && !cfg.VaaPayloadParser.Enabled {
return func(vaa *sdk.VAA) (*vaaPayloadParser.ParseVaaWithStandarizedPropertiesdResponse, error) {
return &vaaPayloadParser.ParseVaaWithStandarizedPropertiesdResponse{}, nil
}, nil
}
vaaPayloadParserClient, err := vaaPayloadParser.NewParserVAAAPIClient(cfg.VaaPayloadParser.Timeout,
cfg.VaaPayloadParser.URL, logger)
if err != nil {
return nil, fmt.Errorf("failed to initialize VAA parser client: %w", err)
}
return vaaPayloadParserClient.ParseVaaWithStandarizedProperties, nil
}
18 changes: 18 additions & 0 deletions api/response/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,21 @@ func NewInvalidQueryParamError(ctx *fiber.Ctx, message string, err error) APIErr
Details: []ErrorDetail{detail},
}
}

func NewRequestBodyError(ctx *fiber.Ctx, message string, err error) APIError {
if message == "" {
message = "INVALID BODY"
}
detail := ErrorDetail{
RequestID: fmt.Sprintf("%v", ctx.Locals("requestid")),
}
if enableStackTrace && err != nil {
detail.StackTrace = fmt.Sprintf("%+v\n", err)
}
return APIError{
StatusCode: fiber.StatusBadRequest,
Code: InvalidParam,
Message: message,
Details: []ErrorDetail{detail},
}
}
1 change: 1 addition & 0 deletions api/routes/wormscan/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ func RegisterRoutes(
vaas.Get("/:chain", vaaCtrl.FindByChain)
vaas.Get("/:chain/:emitter", vaaCtrl.FindByEmitter)
vaas.Get("/:chain/:emitter/:sequence", vaaCtrl.FindById)
vaas.Post("/parse", vaaCtrl.ParseVaa)

// oservations resource
observations := api.Group("/observations")
Expand Down
Loading
Loading