From 7e717cf8fbbe07995464b65a83e3ec1a08857ca1 Mon Sep 17 00:00:00 2001 From: Kirill Date: Sun, 25 May 2025 19:31:55 +0400 Subject: [PATCH 1/2] Remove endpoint from swagger (#322) --- docs/docs.go | 77 ----------------------------- docs/swagger.json | 77 ----------------------------- docs/swagger.yaml | 50 ------------------- internal/v2/api/handlers/address.go | 10 ---- 4 files changed, 214 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 1b6e09ae..2929124d 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -21,53 +21,6 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { - "/address/screening": { - "get": { - "description": "Checks address risk", - "produces": [ - "application/json" - ], - "tags": [ - "v2" - ], - "summary": "Checks address risk", - "parameters": [ - { - "type": "string", - "description": "BTC address to check", - "name": "btc_address", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "Risk of provided address", - "schema": { - "$ref": "#/definitions/handler.PublicResponse-v2handlers_AddressScreeningResponse" - } - }, - "400": { - "description": "Error: Bad Request", - "schema": { - "$ref": "#/definitions/github_com_babylonlabs-io_staking-api-service_internal_shared_types.Error" - } - }, - "404": { - "description": "Error: Not Found", - "schema": { - "$ref": "#/definitions/github_com_babylonlabs-io_staking-api-service_internal_shared_types.Error" - } - }, - "500": { - "description": "Error: Internal Server Error", - "schema": { - "$ref": "#/definitions/github_com_babylonlabs-io_staking-api-service_internal_shared_types.Error" - } - } - } - } - }, "/healthcheck": { "get": { "description": "Health check the service, including ping database connection", @@ -566,12 +519,6 @@ const docTemplate = `{ "$ref": "#/definitions/handler.PublicResponse-array_v2service_FinalityProviderStatsPublic" } }, - "400": { - "description": "Invalid parameters or malformed request", - "schema": { - "$ref": "#/definitions/github_com_babylonlabs-io_staking-api-service_internal_shared_types.Error" - } - }, "404": { "description": "No finality providers found", "schema": { @@ -854,17 +801,6 @@ const docTemplate = `{ } } }, - "handler.PublicResponse-v2handlers_AddressScreeningResponse": { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/v2handlers.AddressScreeningResponse" - }, - "pagination": { - "$ref": "#/definitions/handler.paginationResponse" - } - } - }, "handler.PublicResponse-v2service_DelegationPublic": { "type": "object", "properties": { @@ -1280,19 +1216,6 @@ const docTemplate = `{ } } }, - "v2handlers.AddressScreeningResponse": { - "type": "object", - "properties": { - "btc_address": { - "type": "object", - "properties": { - "risk": { - "type": "string" - } - } - } - } - }, "v2service.CovenantSignature": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index d5985ad9..00fdc947 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -13,53 +13,6 @@ "version": "2.0" }, "paths": { - "/address/screening": { - "get": { - "description": "Checks address risk", - "produces": [ - "application/json" - ], - "tags": [ - "v2" - ], - "summary": "Checks address risk", - "parameters": [ - { - "type": "string", - "description": "BTC address to check", - "name": "btc_address", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "Risk of provided address", - "schema": { - "$ref": "#/definitions/handler.PublicResponse-v2handlers_AddressScreeningResponse" - } - }, - "400": { - "description": "Error: Bad Request", - "schema": { - "$ref": "#/definitions/github_com_babylonlabs-io_staking-api-service_internal_shared_types.Error" - } - }, - "404": { - "description": "Error: Not Found", - "schema": { - "$ref": "#/definitions/github_com_babylonlabs-io_staking-api-service_internal_shared_types.Error" - } - }, - "500": { - "description": "Error: Internal Server Error", - "schema": { - "$ref": "#/definitions/github_com_babylonlabs-io_staking-api-service_internal_shared_types.Error" - } - } - } - } - }, "/healthcheck": { "get": { "description": "Health check the service, including ping database connection", @@ -558,12 +511,6 @@ "$ref": "#/definitions/handler.PublicResponse-array_v2service_FinalityProviderStatsPublic" } }, - "400": { - "description": "Invalid parameters or malformed request", - "schema": { - "$ref": "#/definitions/github_com_babylonlabs-io_staking-api-service_internal_shared_types.Error" - } - }, "404": { "description": "No finality providers found", "schema": { @@ -846,17 +793,6 @@ } } }, - "handler.PublicResponse-v2handlers_AddressScreeningResponse": { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/v2handlers.AddressScreeningResponse" - }, - "pagination": { - "$ref": "#/definitions/handler.paginationResponse" - } - } - }, "handler.PublicResponse-v2service_DelegationPublic": { "type": "object", "properties": { @@ -1272,19 +1208,6 @@ } } }, - "v2handlers.AddressScreeningResponse": { - "type": "object", - "properties": { - "btc_address": { - "type": "object", - "properties": { - "risk": { - "type": "string" - } - } - } - } - }, "v2service.CovenantSignature": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 0e307ddb..ba4767df 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -87,13 +87,6 @@ definitions: pagination: $ref: '#/definitions/handler.paginationResponse' type: object - handler.PublicResponse-v2handlers_AddressScreeningResponse: - properties: - data: - $ref: '#/definitions/v2handlers.AddressScreeningResponse' - pagination: - $ref: '#/definitions/handler.paginationResponse' - type: object handler.PublicResponse-v2service_DelegationPublic: properties: data: @@ -370,14 +363,6 @@ definitions: version: type: integer type: object - v2handlers.AddressScreeningResponse: - properties: - btc_address: - properties: - risk: - type: string - type: object - type: object v2service.CovenantSignature: properties: covenant_btc_pk_hex: @@ -576,37 +561,6 @@ info: title: Babylon Staking API version: "2.0" paths: - /address/screening: - get: - description: Checks address risk - parameters: - - description: BTC address to check - in: query - name: btc_address - required: true - type: string - produces: - - application/json - responses: - "200": - description: Risk of provided address - schema: - $ref: '#/definitions/handler.PublicResponse-v2handlers_AddressScreeningResponse' - "400": - description: 'Error: Bad Request' - schema: - $ref: '#/definitions/github_com_babylonlabs-io_staking-api-service_internal_shared_types.Error' - "404": - description: 'Error: Not Found' - schema: - $ref: '#/definitions/github_com_babylonlabs-io_staking-api-service_internal_shared_types.Error' - "500": - description: 'Error: Internal Server Error' - schema: - $ref: '#/definitions/github_com_babylonlabs-io_staking-api-service_internal_shared_types.Error' - summary: Checks address risk - tags: - - v2 /healthcheck: get: description: Health check the service, including ping database connection @@ -961,10 +915,6 @@ paths: description: List of finality providers with its stats schema: $ref: '#/definitions/handler.PublicResponse-array_v2service_FinalityProviderStatsPublic' - "400": - description: Invalid parameters or malformed request - schema: - $ref: '#/definitions/github_com_babylonlabs-io_staking-api-service_internal_shared_types.Error' "404": description: No finality providers found schema: diff --git a/internal/v2/api/handlers/address.go b/internal/v2/api/handlers/address.go index 4defdce8..0c1bc724 100644 --- a/internal/v2/api/handlers/address.go +++ b/internal/v2/api/handlers/address.go @@ -13,16 +13,6 @@ type AddressScreeningResponse struct { } `json:"btc_address"` } -// AddressScreening checks address risk against address screening providers -// @Summary Checks address risk -// @Description Checks address risk -// @Produce json -// @Tags v2 -// @Param btc_address query string true "BTC address to check" -// @Success 200 {object} handler.PublicResponse[AddressScreeningResponse] "Risk of provided address" -// @Failure 400 {object} types.Error "Error: Bad Request" -// @Failure 500 {object} types.Error "Error: Internal Server Error" -// @Router /address/screening [get] func (h *V2Handler) AddressScreening(request *http.Request) (*handler.Result, *types.Error) { btcAddress := request.URL.Query().Get("btc_address") if btcAddress == "" { From 887e9a5bb91c4ab4a534b7bb1ab5b0df06b0633a Mon Sep 17 00:00:00 2001 From: Kirill Date: Mon, 26 May 2025 22:52:50 +0400 Subject: [PATCH 2/2] Add zero response in case CMC fails in /v2/stats endpoint (#323) --- internal/v2/service/stats.go | 12 ++--- internal/v2/service/stats_test.go | 87 +++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 internal/v2/service/stats_test.go diff --git a/internal/v2/service/stats.go b/internal/v2/service/stats.go index ec3ffe44..540ed396 100644 --- a/internal/v2/service/stats.go +++ b/internal/v2/service/stats.go @@ -87,13 +87,13 @@ func (s *V2Service) GetOverallStats( // Calculate the APR for BTC staking on Babylon Genesis // The APR is calculated based on the activeTvl of the overall stats - btcStakingAPR, errAprCalculation := s.GetBTCStakingAPR( + btcStakingAPR, errAprCalculation := s.getBTCStakingAPR( ctx, overallStats.ActiveTvl, ) if errAprCalculation != nil { log.Ctx(ctx).Error().Err(errAprCalculation). Msg("error while calculating BTC staking APR") - return nil, types.NewInternalServiceError(errAprCalculation) + // in case of error we use zero value in BTCStakingAPR } return &OverallStatsPublic{ @@ -107,9 +107,9 @@ func (s *V2Service) GetOverallStats( }, nil } -func (s *V2Service) GetBTCStakingAPR( +func (s *V2Service) getBTCStakingAPR( ctx context.Context, activeTvl int64, -) (float64, *types.Error) { +) (float64, error) { // Skip calculation if activeTvl is 0 if activeTvl <= 0 { return 0, nil @@ -128,12 +128,12 @@ func (s *V2Service) GetBTCStakingAPR( btcPrice, err := s.sharedService.GetLatestBTCPrice(ctx) if err != nil { - return 0, types.NewInternalServiceError(err) + return 0, err } babyPrice, err := s.sharedService.GetLatestBABYPrice(ctx) if err != nil { - return 0, types.NewInternalServiceError(err) + return 0, err } // Calculate the APR of the BTC staking on Babylon Genesis diff --git a/internal/v2/service/stats_test.go b/internal/v2/service/stats_test.go new file mode 100644 index 00000000..ec63b273 --- /dev/null +++ b/internal/v2/service/stats_test.go @@ -0,0 +1,87 @@ +package v2service + +import ( + "errors" + "testing" + + dbclients "github.com/babylonlabs-io/staking-api-service/internal/shared/db/clients" + "github.com/babylonlabs-io/staking-api-service/internal/shared/http/clients" + "github.com/babylonlabs-io/staking-api-service/internal/shared/services/service" + "github.com/babylonlabs-io/staking-api-service/internal/shared/types" + v1dbmodel "github.com/babylonlabs-io/staking-api-service/internal/v1/db/model" + v2dbmodel "github.com/babylonlabs-io/staking-api-service/internal/v2/db/model" + "github.com/babylonlabs-io/staking-api-service/tests/mocks" + cmc "github.com/miguelmota/go-coinmarketcap/pro/v1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func Test_GetOverallStats(t *testing.T) { + ctx := t.Context() + + dbShared := mocks.NewDBClient(t) + dbV1 := mocks.NewV1DBClient(t) + dbV2 := mocks.NewV2DBClient(t) + dbIndexer := mocks.NewIndexerDBClient(t) + s, err := New(&service.Service{ + DbClients: &dbclients.DbClients{ + SharedDBClient: dbShared, + V1DBClient: dbV1, + V2DBClient: dbV2, + IndexerDBClient: dbIndexer, + }, + Clients: &clients.Clients{ + CoinMarketCap: cmc.NewClient(nil), + }, + }) + require.NoError(t, err) + + t.Run("V2 DB failure", func(t *testing.T) { + err := errors.New("v2 err") + dbV2.On("GetOverallStats", ctx).Return(nil, err).Once() + + resp, respErr := s.GetOverallStats(ctx) + assert.Equal(t, types.NewInternalServiceError(err), respErr) + assert.Nil(t, resp) + }) + t.Run("Indexer DB failure", func(t *testing.T) { + // we pass zero value as 1st return value which is ok - we won't use its values anyway + dbV2.On("GetOverallStats", ctx).Return(&v2dbmodel.V2OverallStatsDocument{}, nil).Once() + err := errors.New("indexer err") + dbIndexer.On("GetFinalityProviders", ctx).Return(nil, err).Once() + + resp, respErr := s.GetOverallStats(ctx) + assert.Equal(t, types.NewInternalServiceError(err), respErr) + assert.Nil(t, resp) + }) + t.Run("V1 DB failure", func(t *testing.T) { + // we pass zero value as 1st return value which is ok - we won't use its values anyway + dbV2.On("GetOverallStats", ctx).Return(&v2dbmodel.V2OverallStatsDocument{}, nil).Once() + // note that first return value (finality providers) is nil which is ok (iteration over nil slice is valid) + dbIndexer.On("GetFinalityProviders", ctx).Return(nil, nil).Once() + err := errors.New("v1 err") + dbV1.On("GetOverallStats", ctx).Return(nil, err).Once() + + resp, respErr := s.GetOverallStats(ctx) + assert.Equal(t, types.NewInternalServiceError(err), respErr) + assert.Nil(t, resp) + }) + t.Run("Ok with GetLatestPrice failure", func(t *testing.T) { + dbV2.On("GetOverallStats", ctx).Return(&v2dbmodel.V2OverallStatsDocument{ + ActiveTvl: 777, // here is important to pass non-zero tvl so it triggers staking BTC calculation + }, nil).Once() + dbIndexer.On("GetFinalityProviders", ctx).Return(nil, nil).Once() + dbV1.On("GetOverallStats", ctx).Return(&v1dbmodel.OverallStatsDocument{}, nil).Once() + err := errors.New("db err") + // this error shouldn't trigger error in GetOverallStats method + dbShared.On("GetLatestPrice", ctx, mock.Anything).Return(float64(0), err).Once() + + resp, respErr := s.GetOverallStats(ctx) + assert.Nil(t, respErr) + assert.Equal(t, &OverallStatsPublic{ + ActiveTvl: 777, + TotalActiveTvl: 777, + }, resp) + }) +}