From 1acfb3552087ea48d0a9be6d108d8e3e8fb734ec Mon Sep 17 00:00:00 2001 From: Gui Iribarren Date: Wed, 7 Aug 2024 14:39:01 +0200 Subject: [PATCH 1/2] api: hotfix 'api: paginated endpoints now return ErrAccountNotFound...' these filters now return an empty list (not an error) * /accounts?accountId=foobar * /elections?electionId=foobar * /chain/organizations?organizationId=foobar so the errors ErrAccountNotFound, ErrElectionNotFound, ErrOrgNotFound happen only on: * /chain/transfers?accountId=foobar * /chain/fees?accountId=foobar * /votes?electionId=foobar * /elections?organizationId=foobar --- api/accounts.go | 4 ---- api/chain.go | 4 ---- api/elections.go | 4 ---- test/apierror_test.go | 20 -------------------- vochain/indexer/indexer.go | 7 +++++-- vochain/indexer/process.go | 14 ++++++++++---- 6 files changed, 15 insertions(+), 38 deletions(-) diff --git a/api/accounts.go b/api/accounts.go index 70f4fa11a..baab86251 100644 --- a/api/accounts.go +++ b/api/accounts.go @@ -571,10 +571,6 @@ func (a *API) accountListHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext // // Errors returned are always of type APIerror. func (a *API) sendAccountList(ctx *httprouter.HTTPContext, params *AccountParams) error { - if params.AccountID != "" && !a.indexer.AccountExists(params.AccountID) { - return ErrAccountNotFound - } - accounts, total, err := a.indexer.AccountList( params.Limit, params.Page*params.Limit, diff --git a/api/chain.go b/api/chain.go index b0ac84669..a9393a1e5 100644 --- a/api/chain.go +++ b/api/chain.go @@ -332,10 +332,6 @@ func (a *API) organizationListByFilterAndPageHandler(msg *apirest.APIdata, ctx * // // Errors returned are always of type APIerror. func (a *API) sendOrganizationList(ctx *httprouter.HTTPContext, params *OrganizationParams) error { - if params.OrganizationID != "" && !a.indexer.EntityExists(params.OrganizationID) { - return ErrOrgNotFound - } - orgs, total, err := a.indexer.EntityList( params.Limit, params.Page*params.Limit, diff --git a/api/elections.go b/api/elections.go index 88ae90acc..136421cdc 100644 --- a/api/elections.go +++ b/api/elections.go @@ -262,10 +262,6 @@ func (a *API) electionListHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContex // // Errors returned are always of type APIerror. func (a *API) sendElectionList(ctx *httprouter.HTTPContext, params *ElectionParams) error { - if params.ElectionID != "" && !a.indexer.ProcessExists(params.ElectionID) { - return ErrElectionNotFound - } - if params.OrganizationID != "" && !a.indexer.EntityExists(params.OrganizationID) { return ErrOrgNotFound } diff --git a/test/apierror_test.go b/test/apierror_test.go index e1f967d8b..989f30962 100644 --- a/test/apierror_test.go +++ b/test/apierror_test.go @@ -176,22 +176,6 @@ func TestAPIerrorWithQuery(t *testing.T) { args: args{"GET", nil, []string{"accounts"}, "page=1234"}, want: api.ErrPageNotFound, }, - { - args: args{"GET", nil, []string{"accounts"}, "accountId=0123456789"}, - want: api.ErrAccountNotFound, - }, - { - args: args{"GET", nil, []string{"accounts"}, "accountId=0123456789&page=1234"}, - want: api.ErrAccountNotFound, - }, - { - args: args{"GET", nil, []string{"elections"}, "electionId=0123456789"}, - want: api.ErrElectionNotFound, - }, - { - args: args{"GET", nil, []string{"elections"}, "electionId=0123456789&page=1234"}, - want: api.ErrElectionNotFound, - }, { args: args{"GET", nil, []string{"elections"}, "organizationId=0123456789"}, want: api.ErrOrgNotFound, @@ -226,10 +210,6 @@ func TestAPIerrorWithQuery(t *testing.T) { // args: args{"GET", nil, []string{"chain", "transactions"}, "type=FOOBAR"}, // want: api.ErrParamTypeInvalid, // }, - { - args: args{"GET", nil, []string{"chain", "organizations"}, "organizationId=0123456789"}, - want: api.ErrOrgNotFound, - }, { args: args{"GET", nil, []string{"chain", "fees"}, "accountId=0123456789"}, want: api.ErrAccountNotFound, diff --git a/vochain/indexer/indexer.go b/vochain/indexer/indexer.go index 0981ba438..43b59323e 100644 --- a/vochain/indexer/indexer.go +++ b/vochain/indexer/indexer.go @@ -845,9 +845,12 @@ func (idx *Indexer) AccountList(limit, offset int, accountID string) ([]*indexer return list, uint64(results[0].TotalCount), nil } -// AccountExists returns whether the passed accountID matches at least one row in the db. -// accountID is a partial or full hex string. +// AccountExists returns whether the passed accountID exists in the db. +// If passed arg is not the full hex string, returns false (i.e. no substring matching) func (idx *Indexer) AccountExists(accountID string) bool { + if len(accountID) != 40 { + return false + } _, count, err := idx.AccountList(1, 0, accountID) if err != nil { log.Errorw(err, "indexer query failed") diff --git a/vochain/indexer/process.go b/vochain/indexer/process.go index 5a875c05b..cd96227a2 100644 --- a/vochain/indexer/process.go +++ b/vochain/indexer/process.go @@ -87,9 +87,12 @@ func (idx *Indexer) ProcessList(limit, offset int, entityID string, processID st return list, uint64(results[0].TotalCount), nil } -// ProcessExists returns whether the passed processID matches at least one row in the db. -// processID is a partial or full hex string. +// ProcessExists returns whether the passed processID exists in the db. +// If passed arg is not the full hex string, returns false (i.e. no substring matching) func (idx *Indexer) ProcessExists(processID string) bool { + if len(processID) != 64 { + return false + } _, count, err := idx.ProcessList(1, 0, "", processID, 0, 0, 0, nil, nil, nil) if err != nil { log.Errorw(err, "indexer query failed") @@ -138,9 +141,12 @@ func (idx *Indexer) EntityList(limit, offset int, entityID string) ([]indexertyp return list, uint64(results[0].TotalCount), nil } -// EntityExists returns whether the passed entityID matches at least one row in the db. -// entityID is a partial or full hex string. +// EntityExists returns whether the passed entityID exists in the db. +// If passed arg is not the full hex string, returns false (i.e. no substring matching) func (idx *Indexer) EntityExists(entityID string) bool { + if len(entityID) != 40 { + return false + } _, count, err := idx.EntityList(1, 0, entityID) if err != nil { log.Errorw(err, "indexer query failed") From 2491a75f6c7e7f1183565abca6bf7176b2248cbe Mon Sep 17 00:00:00 2001 From: Gui Iribarren Date: Wed, 7 Aug 2024 13:19:57 +0200 Subject: [PATCH 2/2] api: endpoint /accounts/{accountId} now includes transfersCount and feesCount --- api/accounts.go | 26 +++++++++++++++++++------- api/api_types.go | 18 ++++++++++-------- api/errors.go | 1 + 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/api/accounts.go b/api/accounts.go index baab86251..5e82e6741 100644 --- a/api/accounts.go +++ b/api/accounts.go @@ -193,15 +193,27 @@ func (a *API) accountHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) er return ErrGettingSIK.WithErr(err) } + _, transfersCount, err := a.indexer.TokenTransfersList(1, 0, hex.EncodeToString(addr.Bytes()), "", "") + if err != nil { + return ErrCantFetchTokenTransfers.WithErr(err) + } + + _, feesCount, err := a.indexer.TokenFeesList(1, 0, "", "", hex.EncodeToString(addr.Bytes())) + if err != nil { + return ErrCantFetchTokenFees.WithErr(err) + } + var data []byte if data, err = json.Marshal(Account{ - Address: addr.Bytes(), - Nonce: acc.GetNonce(), - Balance: acc.GetBalance(), - ElectionIndex: acc.GetProcessIndex(), - InfoURL: acc.GetInfoURI(), - Metadata: accMetadata, - SIK: types.HexBytes(sik), + Address: addr.Bytes(), + Nonce: acc.GetNonce(), + Balance: acc.GetBalance(), + ElectionIndex: acc.GetProcessIndex(), + TransfersCount: transfersCount, + FeesCount: feesCount, + InfoURL: acc.GetInfoURI(), + Metadata: accMetadata, + SIK: types.HexBytes(sik), }); err != nil { return err } diff --git a/api/api_types.go b/api/api_types.go index 778b8a9cc..e3b3ddd1c 100644 --- a/api/api_types.go +++ b/api/api_types.go @@ -305,14 +305,16 @@ type ChainInfo struct { } type Account struct { - Address types.HexBytes `json:"address" ` - Nonce uint32 `json:"nonce"` - Balance uint64 `json:"balance"` - ElectionIndex uint32 `json:"electionIndex"` - InfoURL string `json:"infoURL,omitempty"` - Token *uuid.UUID `json:"token,omitempty" swaggerignore:"true"` - Metadata *AccountMetadata `json:"metadata,omitempty"` - SIK types.HexBytes `json:"sik"` + Address types.HexBytes `json:"address" ` + Nonce uint32 `json:"nonce"` + Balance uint64 `json:"balance"` + ElectionIndex uint32 `json:"electionIndex"` + TransfersCount uint64 `json:"transfersCount,omitempty"` + FeesCount uint64 `json:"feesCount,omitempty"` + InfoURL string `json:"infoURL,omitempty"` + Token *uuid.UUID `json:"token,omitempty" swaggerignore:"true"` + Metadata *AccountMetadata `json:"metadata,omitempty"` + SIK types.HexBytes `json:"sik"` } type AccountsList struct { diff --git a/api/errors.go b/api/errors.go index f4df72b7c..3d4e4c31b 100644 --- a/api/errors.go +++ b/api/errors.go @@ -115,4 +115,5 @@ var ( ErrGettingSIK = apirest.APIerror{Code: 5031, HTTPstatus: apirest.HTTPstatusInternalErr, Err: fmt.Errorf("error getting SIK")} ErrCensusBuild = apirest.APIerror{Code: 5032, HTTPstatus: apirest.HTTPstatusInternalErr, Err: fmt.Errorf("error building census")} ErrIndexerQueryFailed = apirest.APIerror{Code: 5033, HTTPstatus: apirest.HTTPstatusInternalErr, Err: fmt.Errorf("indexer query failed")} + ErrCantFetchTokenFees = apirest.APIerror{Code: 5034, HTTPstatus: apirest.HTTPstatusInternalErr, Err: fmt.Errorf("cannot fetch token fees")} )