Skip to content

Commit

Permalink
add new table accounts and queries: GetListAccounts, CountAccounts, C…
Browse files Browse the repository at this point in the history
…reateAccount

add new queries in token_transfers: GetTokenTransfersByToAccount, GetTokenTransfersByAccount, CountTokenTransfersByAccount
indexer: update method onSetAccount
integration test: update TestaccountAPI, add new test TestAPIAccountTokentxs
api: update GetTransfers, add countAccounts

swagger documentation
  • Loading branch information
mariajdab committed Oct 23, 2023
1 parent 2c357eb commit 27cc966
Show file tree
Hide file tree
Showing 17 changed files with 788 additions and 60 deletions.
133 changes: 129 additions & 4 deletions api/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,30 @@ func (a *API) enableAccountHandlers() error {
); err != nil {
return err
}
if err := a.endpoint.RegisterMethod(
"/accounts/{accountID}/transfers/count",
"GET",
apirest.MethodAccessTypePublic,
a.tokenTransfersCountHandler,
); err != nil {
return err
}
if err := a.endpoint.RegisterMethod(
"/accounts/count",
"GET",
apirest.MethodAccessTypePublic,
a.accountCountHandler,
); err != nil {
return err
}
if err := a.endpoint.RegisterMethod(
"/accounts/page/{page}",
"GET",
apirest.MethodAccessTypePublic,
a.accountsListHandler,
); err != nil {
return err
}

return nil
}
Expand Down Expand Up @@ -125,7 +149,7 @@ func (a *API) accountHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) er

sik, err := a.vocapp.State.SIKFromAddress(addr)
if err != nil && !errors.Is(err, state.ErrSIKNotFound) {
log.Warnf("uknown error getting SIK: %v", err)
log.Warnf("unknown error getting SIK: %v", err)
return ErrGettingSIK.WithErr(err)
}

Expand Down Expand Up @@ -235,6 +259,33 @@ func (a *API) accountSetHandler(msg *apirest.APIdata, ctx *httprouter.HTTPContex
return ctx.Send(data, apirest.HTTPstatusOK)
}

// accountCountHandler
//
// @Summary Total number of accounts
// @Description Returns the count of total number of existing accounts
// @Tags Accounts
// @Accept json
// @Produce json
// @Success 200 {object} object{count=int}
// @Router /accounts/count [get]
func (a *API) accountCountHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) error {
count, err := a.indexer.CountTotalAccounts()
if err != nil {
return err
}

data, err := json.Marshal(
struct {
Count uint64 `json:"count"`
}{Count: count},
)
if err != nil {
return ErrMarshalingServerJSONFailed.WithErr(err)
}

return ctx.Send(data, apirest.HTTPstatusOK)
}

// electionListHandler
//
// @Summary List organization elections
Expand Down Expand Up @@ -351,7 +402,7 @@ func (a *API) electionCountHandler(_ *apirest.APIdata, ctx *httprouter.HTTPConte

// tokenTransfersHandler
//
// @Summary List account transfers
// @Summary List account received and sent token transfers
// @Description Returns the token transfers for an account. A transfer is a token transference from one account to other (excepting the burn address).
// @Tags Accounts
// @Accept json
Expand Down Expand Up @@ -380,13 +431,13 @@ func (a *API) tokenTransfersHandler(_ *apirest.APIdata, ctx *httprouter.HTTPCont
}
}
page = page * MaxPageSize
transfers, err := a.indexer.GetTokenTransfersByFromAccount(accountID, int32(page), MaxPageSize)
transfers, err := a.indexer.GetTokenTransfersAccount(accountID, int32(page), MaxPageSize)
if err != nil {
return ErrCantFetchTokenTransfers.WithErr(err)
}
data, err := json.Marshal(
struct {
Transfers []*indexertypes.TokenTransferMeta `json:"transfers"`
Transfers map[string][]*indexertypes.TokenTransferMeta `json:"transfers"`
}{Transfers: transfers},
)
if err != nil {
Expand Down Expand Up @@ -441,3 +492,77 @@ func (a *API) tokenFeesHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext)
}
return ctx.Send(data, apirest.HTTPstatusOK)
}

// tokenTransfersCountHandler
//
// @Summary Total number of sent and received transactions
// @Description Returns the count of total number of sent and received transactions for an account. A transaction is a token transfer from one account to another existing account
// @Tags Accounts
// @Accept json
// @Produce json
// @Param accountID path string true "Specific accountID"
// @Success 200 {object} object{count=int} "Number of transaction sent and received for the account"
// @Router /accounts/{accountID}/transfers/count [get]
func (a *API) tokenTransfersCountHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) error {
accountID, err := hex.DecodeString(util.TrimHex(ctx.URLParam("accountID")))
if err != nil || accountID == nil {
return ErrCantParseAccountID.Withf("%q", ctx.URLParam("accountID"))
}
acc, err := a.vocapp.State.GetAccount(common.BytesToAddress(accountID), true)
if acc == nil {
return ErrAccountNotFound
}
if err != nil {
return err
}

count, err := a.indexer.CountTokenTransfersAccount(accountID)
if err != nil {
return err
}
data, err := json.Marshal(
struct {
Count uint64 `json:"count"`
}{Count: count},
)
if err != nil {
return ErrMarshalingServerJSONFailed.WithErr(err)
}

return ctx.Send(data, apirest.HTTPstatusOK)
}

// accountsListHandler
//
// @Summary List of the existing accounts
// @Description Returns information (address, balance and nonce) of the existing accounts
// @Tags Accounts
// @Accept json
// @Produce json
// @Param page path string true "Paginator page"
// @Success 200 {object} object{accounts=[]indexertypes.Account}
// @Router /accounts/page/{page} [get]
func (a *API) accountsListHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) error {
var err error
page := 0
if ctx.URLParam("page") != "" {
page, err = strconv.Atoi(ctx.URLParam("page"))
if err != nil {
return ErrCantParsePageNumber
}
}
page = page * MaxPageSize
accounts, err := a.indexer.GetListAccounts(int32(page), MaxPageSize)
if err != nil {
return ErrCantFetchTokenTransfers.WithErr(err)
}
data, err := json.Marshal(
struct {
Accounts []indexertypes.Account `json:"accounts"`
}{Accounts: accounts},
)
if err != nil {
return ErrMarshalingServerJSONFailed.WithErr(err)
}
return ctx.Send(data, apirest.HTTPstatusOK)
}
2 changes: 1 addition & 1 deletion api/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ func (a *API) chainTxListPaginated(_ *apirest.APIdata, ctx *httprouter.HTTPConte
}
return err
}
// wrap list in a struct to consistently return list in a object, return empty
// wrap list in a struct to consistently return list in an object, return empty
// object if the list does not contains any result
type response struct {
Txs []*indexertypes.Transaction `json:"transactions"`
Expand Down
50 changes: 45 additions & 5 deletions apiclient/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"go.vocdoni.io/dvote/data/ipfs"
"go.vocdoni.io/dvote/httprouter/apirest"
"go.vocdoni.io/dvote/types"
indexertypes "go.vocdoni.io/dvote/vochain/indexer/indexertypes"
"go.vocdoni.io/dvote/vochain/indexer/indexertypes"
"go.vocdoni.io/proto/build/go/models"
"google.golang.org/protobuf/proto"
)
Expand Down Expand Up @@ -263,19 +263,21 @@ func (c *HTTPclient) AccountSetMetadata(metadata *api.AccountMetadata) (types.He
}

// GetTransfers returns the list of token transfers associated with an account
func (c *HTTPclient) GetTransfers(from common.Address, page int) ([]*indexertypes.TokenTransferMeta, error) {
func (c *HTTPclient) GetTransfers(from common.Address, page int) (map[string][]*indexertypes.TokenTransferMeta, error) {
resp, code, err := c.Request(HTTPGET, nil, "accounts", from.Hex(), "transfers", "page", strconv.Itoa(page))
if err != nil {
return nil, err
}
if code != apirest.HTTPstatusOK {
return nil, fmt.Errorf("%s: %d (%s)", errCodeNot200, code, resp)
}
var transfers []*indexertypes.TokenTransferMeta
if err := json.Unmarshal(resp, &transfers); err != nil {
trnsfs := new(struct {
Transfers map[string][]*indexertypes.TokenTransferMeta `json:"transfers"`
})
if err := json.Unmarshal(resp, &trnsfs); err != nil {
return nil, err
}
return transfers, nil
return trnsfs.Transfers, nil
}

// SetSIK function allows to update the Secret Identity Key for the current
Expand Down Expand Up @@ -419,3 +421,41 @@ func (c *HTTPclient) RegisterSIKForVote(electionId types.HexBytes, proof *Census
}
return hash, nil
}

func (c *HTTPclient) ListAccounts(page int) ([]indexertypes.Account, error) {
resp, code, err := c.Request(HTTPGET, nil, "accounts", "page", strconv.Itoa(page))
if err != nil {
return nil, err
}
if code != apirest.HTTPstatusOK {
return nil, fmt.Errorf("%s: %d (%s)", errCodeNot200, code, resp)
}
accts := new(struct {
Accounts []indexertypes.Account `json:"accounts"`
})

if err := json.Unmarshal(resp, &accts); err != nil {
return nil, err
}

return accts.Accounts, nil
}

// AccountCount returns the count of accounts
func (c *HTTPclient) AccountCount() (uint64, error) {
resp, code, err := c.Request(HTTPGET, nil, "accounts", "count")
if err != nil {
return 0, err
}
if code != apirest.HTTPstatusOK {
return 0, fmt.Errorf("%s: %d (%s)", errCodeNot200, code, resp)
}
accts := new(struct {
Count uint64 `json:"count"`
})

if err := json.Unmarshal(resp, accts); err != nil {
return 0, err
}
return accts.Count, nil
}
Loading

0 comments on commit 27cc966

Please sign in to comment.