mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-06 19:06:42 +01:00
Refactor api pagination
This commit is contained in:
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/hermeznetwork/hermez-node/apitypes"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
)
|
||||
|
||||
@@ -49,7 +48,7 @@ func (a *API) getAccounts(c *gin.Context) {
|
||||
}
|
||||
|
||||
// Fetch Accounts from historyDB
|
||||
apiAccounts, pagination, err := a.h.GetAccountsAPI(tokenIDs, addr, bjj, fromItem, limit, order)
|
||||
apiAccounts, pendingItems, err := a.h.GetAccountsAPI(tokenIDs, addr, bjj, fromItem, limit, order)
|
||||
if err != nil {
|
||||
retSQLErr(err, c)
|
||||
return
|
||||
@@ -72,11 +71,11 @@ func (a *API) getAccounts(c *gin.Context) {
|
||||
|
||||
// Build succesfull response
|
||||
type accountResponse struct {
|
||||
Accounts []historydb.AccountAPI `json:"accounts"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
Accounts []historydb.AccountAPI `json:"accounts"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
c.JSON(http.StatusOK, &accountResponse{
|
||||
Accounts: apiAccounts,
|
||||
Pagination: pagination,
|
||||
Accounts: apiAccounts,
|
||||
PendingItems: pendingItems,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
"github.com/hermeznetwork/hermez-node/apitypes"
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
"github.com/mitchellh/copystructure"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -25,10 +24,18 @@ type testAccount struct {
|
||||
}
|
||||
|
||||
type testAccountsResponse struct {
|
||||
Accounts []testAccount `json:"accounts"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
Accounts []testAccount `json:"accounts"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
|
||||
func (t testAccountsResponse) GetPending() (pendingItems, lastItemID uint64) {
|
||||
pendingItems = t.PendingItems
|
||||
lastItemID = t.Accounts[len(t.Accounts)-1].ItemID
|
||||
return pendingItems, lastItemID
|
||||
}
|
||||
|
||||
func (t *testAccountsResponse) Len() int { return len(t.Accounts) }
|
||||
|
||||
func genTestAccounts(accounts []common.Account, tokens []historydb.TokenWithUSD) []testAccount {
|
||||
tAccounts := []testAccount{}
|
||||
for x, account := range accounts {
|
||||
@@ -47,19 +54,6 @@ func genTestAccounts(accounts []common.Account, tokens []historydb.TokenWithUSD)
|
||||
return tAccounts
|
||||
}
|
||||
|
||||
func (t *testAccountsResponse) GetPagination() *db.Pagination {
|
||||
if t.Accounts[0].ItemID < t.Accounts[len(t.Accounts)-1].ItemID {
|
||||
t.Pagination.FirstReturnedItem = t.Accounts[0].ItemID
|
||||
t.Pagination.LastReturnedItem = t.Accounts[len(t.Accounts)-1].ItemID
|
||||
} else {
|
||||
t.Pagination.LastReturnedItem = t.Accounts[0].ItemID
|
||||
t.Pagination.FirstReturnedItem = t.Accounts[len(t.Accounts)-1].ItemID
|
||||
}
|
||||
return t.Pagination
|
||||
}
|
||||
|
||||
func (t *testAccountsResponse) Len() int { return len(t.Accounts) }
|
||||
|
||||
func TestGetAccounts(t *testing.T) {
|
||||
endpoint := apiURL + "accounts"
|
||||
fetchedAccounts := []testAccount{}
|
||||
|
||||
@@ -28,6 +28,13 @@ import (
|
||||
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||
)
|
||||
|
||||
// Pendinger is an interface that allows getting last returned item ID and PendingItems to be used for building fromItem
|
||||
// when testing paginated endpoints.
|
||||
type Pendinger interface {
|
||||
GetPending() (pendingItems, lastItemID uint64)
|
||||
Len() int
|
||||
}
|
||||
|
||||
const apiPort = ":4010"
|
||||
const apiURL = "http://localhost" + apiPort + "/"
|
||||
|
||||
@@ -339,41 +346,52 @@ func TestMain(m *testing.M) {
|
||||
|
||||
func doGoodReqPaginated(
|
||||
path, order string,
|
||||
iterStruct db.Paginationer,
|
||||
iterStruct Pendinger,
|
||||
appendIter func(res interface{}),
|
||||
) error {
|
||||
next := -1
|
||||
var next uint64
|
||||
firstIte := true
|
||||
expectedTotal := 0
|
||||
totalReceived := 0
|
||||
for {
|
||||
// Call API to get this iteration items
|
||||
// Calculate fromItem
|
||||
iterPath := path
|
||||
if next == -1 && order == historydb.OrderDesc {
|
||||
// Fetch first item in reverse order
|
||||
iterPath += "99999"
|
||||
} else {
|
||||
// Fetch from next item or 0 if it's ascending order
|
||||
if next == -1 {
|
||||
next = 0
|
||||
if firstIte {
|
||||
if order == historydb.OrderDesc {
|
||||
// Fetch first item in reverse order
|
||||
iterPath += "99999" // Asumption that for testing there won't be any itemID > 99999
|
||||
} else {
|
||||
iterPath += "0"
|
||||
}
|
||||
iterPath += strconv.Itoa(next)
|
||||
} else {
|
||||
iterPath += strconv.Itoa(int(next))
|
||||
}
|
||||
// Call API to get this iteration items
|
||||
if err := doGoodReq("GET", iterPath+"&order="+order, nil, iterStruct); err != nil {
|
||||
return err
|
||||
}
|
||||
appendIter(iterStruct)
|
||||
// Keep iterating?
|
||||
pag := iterStruct.GetPagination()
|
||||
if order == historydb.OrderAsc {
|
||||
if pag.LastReturnedItem == pag.LastItem { // No
|
||||
break
|
||||
} else { // Yes
|
||||
next = int(pag.LastReturnedItem + 1)
|
||||
}
|
||||
remaining, lastID := iterStruct.GetPending()
|
||||
if remaining == 0 {
|
||||
break
|
||||
}
|
||||
if order == historydb.OrderDesc {
|
||||
next = lastID - 1
|
||||
} else {
|
||||
if pag.FirstReturnedItem == pag.FirstItem { // No
|
||||
break
|
||||
} else { // Yes
|
||||
next = int(pag.FirstReturnedItem - 1)
|
||||
}
|
||||
next = lastID + 1
|
||||
}
|
||||
// Check that the expected amount of items is consistent across iterations
|
||||
totalReceived += iterStruct.Len()
|
||||
if firstIte {
|
||||
firstIte = false
|
||||
expectedTotal = totalReceived + int(remaining)
|
||||
}
|
||||
if expectedTotal != totalReceived+int(remaining) {
|
||||
panic(fmt.Sprintf(
|
||||
"pagination error, totalReceived + remaining should be %d, but is %d",
|
||||
expectedTotal, totalReceived+int(remaining),
|
||||
))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
11
api/batch.go
11
api/batch.go
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
)
|
||||
|
||||
@@ -43,7 +42,7 @@ func (a *API) getBatches(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
// Fetch batches from historyDB
|
||||
batches, pagination, err := a.h.GetBatchesAPI(
|
||||
batches, pendingItems, err := a.h.GetBatchesAPI(
|
||||
minBatchNum, maxBatchNum, slotNum, forgerAddr, fromItem, limit, order,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -53,12 +52,12 @@ func (a *API) getBatches(c *gin.Context) {
|
||||
|
||||
// Build succesfull response
|
||||
type batchesResponse struct {
|
||||
Batches []historydb.BatchAPI `json:"batches"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
Batches []historydb.BatchAPI `json:"batches"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
c.JSON(http.StatusOK, &batchesResponse{
|
||||
Batches: batches,
|
||||
Pagination: pagination,
|
||||
Batches: batches,
|
||||
PendingItems: pendingItems,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
"github.com/mitchellh/copystructure"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -30,19 +29,14 @@ type testBatch struct {
|
||||
SlotNum int64 `json:"slotNum"`
|
||||
}
|
||||
type testBatchesResponse struct {
|
||||
Batches []testBatch `json:"batches"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
Batches []testBatch `json:"batches"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
|
||||
func (t testBatchesResponse) GetPagination() *db.Pagination {
|
||||
if t.Batches[0].ItemID < t.Batches[len(t.Batches)-1].ItemID {
|
||||
t.Pagination.FirstReturnedItem = t.Batches[0].ItemID
|
||||
t.Pagination.LastReturnedItem = t.Batches[len(t.Batches)-1].ItemID
|
||||
} else {
|
||||
t.Pagination.LastReturnedItem = t.Batches[0].ItemID
|
||||
t.Pagination.FirstReturnedItem = t.Batches[len(t.Batches)-1].ItemID
|
||||
}
|
||||
return t.Pagination
|
||||
func (t testBatchesResponse) GetPending() (pendingItems, lastItemID uint64) {
|
||||
pendingItems = t.PendingItems
|
||||
lastItemID = t.Batches[len(t.Batches)-1].ItemID
|
||||
return pendingItems, lastItemID
|
||||
}
|
||||
|
||||
func (t testBatchesResponse) Len() int {
|
||||
|
||||
11
api/bids.go
11
api/bids.go
@@ -5,7 +5,6 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
)
|
||||
|
||||
@@ -26,7 +25,7 @@ func (a *API) getBids(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
bids, pagination, err := a.h.GetBidsAPI(
|
||||
bids, pendingItems, err := a.h.GetBidsAPI(
|
||||
slotNum, bidderAddr, fromItem, limit, order,
|
||||
)
|
||||
|
||||
@@ -37,11 +36,11 @@ func (a *API) getBids(c *gin.Context) {
|
||||
|
||||
// Build succesfull response
|
||||
type bidsResponse struct {
|
||||
Bids []historydb.BidAPI `json:"bids"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
Bids []historydb.BidAPI `json:"bids"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
c.JSON(http.StatusOK, &bidsResponse{
|
||||
Bids: bids,
|
||||
Pagination: pagination,
|
||||
Bids: bids,
|
||||
PendingItems: pendingItems,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
"github.com/mitchellh/copystructure"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -25,19 +24,14 @@ type testBid struct {
|
||||
}
|
||||
|
||||
type testBidsResponse struct {
|
||||
Bids []testBid `json:"bids"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
Bids []testBid `json:"bids"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
|
||||
func (t testBidsResponse) GetPagination() *db.Pagination {
|
||||
if t.Bids[0].ItemID < t.Bids[len(t.Bids)-1].ItemID {
|
||||
t.Pagination.FirstReturnedItem = t.Bids[0].ItemID
|
||||
t.Pagination.LastReturnedItem = t.Bids[len(t.Bids)-1].ItemID
|
||||
} else {
|
||||
t.Pagination.LastReturnedItem = t.Bids[0].ItemID
|
||||
t.Pagination.FirstReturnedItem = t.Bids[len(t.Bids)-1].ItemID
|
||||
}
|
||||
return t.Pagination
|
||||
func (t testBidsResponse) GetPending() (pendingItems, lastItemID uint64) {
|
||||
pendingItems = t.PendingItems
|
||||
lastItemID = t.Bids[len(t.Bids)-1].ItemID
|
||||
return pendingItems, lastItemID
|
||||
}
|
||||
|
||||
func (t testBidsResponse) Len() int {
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
)
|
||||
|
||||
@@ -39,7 +38,7 @@ func (a *API) getCoordinators(c *gin.Context) {
|
||||
}
|
||||
|
||||
// Fetch coordinators from historyDB
|
||||
coordinators, pagination, err := a.h.GetCoordinatorsAPI(fromItem, limit, order)
|
||||
coordinators, pendingItems, err := a.h.GetCoordinatorsAPI(fromItem, limit, order)
|
||||
if err != nil {
|
||||
retSQLErr(err, c)
|
||||
return
|
||||
@@ -48,10 +47,10 @@ func (a *API) getCoordinators(c *gin.Context) {
|
||||
// Build succesfull response
|
||||
type coordinatorsResponse struct {
|
||||
Coordinators []historydb.CoordinatorAPI `json:"coordinators"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
c.JSON(http.StatusOK, &coordinatorsResponse{
|
||||
Coordinators: coordinators,
|
||||
Pagination: pagination,
|
||||
PendingItems: pendingItems,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
"github.com/mitchellh/copystructure"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -12,18 +11,13 @@ import (
|
||||
|
||||
type testCoordinatorsResponse struct {
|
||||
Coordinators []historydb.CoordinatorAPI `json:"coordinators"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
|
||||
func (t *testCoordinatorsResponse) GetPagination() *db.Pagination {
|
||||
if t.Coordinators[0].ItemID < t.Coordinators[len(t.Coordinators)-1].ItemID {
|
||||
t.Pagination.FirstReturnedItem = t.Coordinators[0].ItemID
|
||||
t.Pagination.LastReturnedItem = t.Coordinators[len(t.Coordinators)-1].ItemID
|
||||
} else {
|
||||
t.Pagination.LastReturnedItem = t.Coordinators[0].ItemID
|
||||
t.Pagination.FirstReturnedItem = t.Coordinators[len(t.Coordinators)-1].ItemID
|
||||
}
|
||||
return t.Pagination
|
||||
func (t testCoordinatorsResponse) GetPending() (pendingItems, lastItemID uint64) {
|
||||
pendingItems = t.PendingItems
|
||||
lastItemID = t.Coordinators[len(t.Coordinators)-1].ItemID
|
||||
return pendingItems, lastItemID
|
||||
}
|
||||
|
||||
func (t *testCoordinatorsResponse) Len() int { return len(t.Coordinators) }
|
||||
|
||||
11
api/exits.go
11
api/exits.go
@@ -4,7 +4,6 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
)
|
||||
|
||||
@@ -36,7 +35,7 @@ func (a *API) getExits(c *gin.Context) {
|
||||
}
|
||||
|
||||
// Fetch exits from historyDB
|
||||
exits, pagination, err := a.h.GetExitsAPI(
|
||||
exits, pendingItems, err := a.h.GetExitsAPI(
|
||||
addr, bjj, tokenID, idx, batchNum, onlyPendingWithdraws, fromItem, limit, order,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -46,12 +45,12 @@ func (a *API) getExits(c *gin.Context) {
|
||||
|
||||
// Build succesfull response
|
||||
type exitsResponse struct {
|
||||
Exits []historydb.ExitAPI `json:"exits"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
Exits []historydb.ExitAPI `json:"exits"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
c.JSON(http.StatusOK, &exitsResponse{
|
||||
Exits: exits,
|
||||
Pagination: pagination,
|
||||
Exits: exits,
|
||||
PendingItems: pendingItems,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
"github.com/mitchellh/copystructure"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -36,19 +35,14 @@ type testExit struct {
|
||||
}
|
||||
|
||||
type testExitsResponse struct {
|
||||
Exits []testExit `json:"exits"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
Exits []testExit `json:"exits"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
|
||||
func (t *testExitsResponse) GetPagination() *db.Pagination {
|
||||
if t.Exits[0].ItemID < t.Exits[len(t.Exits)-1].ItemID {
|
||||
t.Pagination.FirstReturnedItem = t.Exits[0].ItemID
|
||||
t.Pagination.LastReturnedItem = t.Exits[len(t.Exits)-1].ItemID
|
||||
} else {
|
||||
t.Pagination.LastReturnedItem = t.Exits[0].ItemID
|
||||
t.Pagination.FirstReturnedItem = t.Exits[len(t.Exits)-1].ItemID
|
||||
}
|
||||
return t.Pagination
|
||||
func (t testExitsResponse) GetPending() (pendingItems, lastItemID uint64) {
|
||||
pendingItems = t.PendingItems
|
||||
lastItemID = t.Exits[len(t.Exits)-1].ItemID
|
||||
return pendingItems, lastItemID
|
||||
}
|
||||
|
||||
func (t *testExitsResponse) Len() int {
|
||||
|
||||
85
api/slots.go
85
api/slots.go
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
)
|
||||
|
||||
@@ -49,18 +48,6 @@ func (a *API) isOpenAuction(currentBlock, slotNum int64, auctionVars common.Auct
|
||||
return false
|
||||
}
|
||||
|
||||
func getPagination(totalItems uint64, minSlotNum, maxSlotNum *int64) *db.Pagination {
|
||||
// itemID is slotNum
|
||||
firstItem := *minSlotNum
|
||||
lastItem := *maxSlotNum
|
||||
pagination := &db.Pagination{
|
||||
TotalItems: totalItems,
|
||||
FirstItem: uint64(firstItem),
|
||||
LastItem: uint64(lastItem),
|
||||
}
|
||||
return pagination
|
||||
}
|
||||
|
||||
func (a *API) newSlotAPI(slotNum, currentBlockNum int64, bid *historydb.BidAPI, auctionVars *common.AuctionVariables) SlotAPI {
|
||||
firstBlock, lastBlock := a.getFirstLastBlock(slotNum)
|
||||
openAuction := a.isOpenAuction(currentBlockNum, slotNum, *auctionVars)
|
||||
@@ -141,34 +128,35 @@ func (a *API) getSlot(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, slot)
|
||||
}
|
||||
|
||||
func getLimits(minSlotNum, maxSlotNum *int64, fromItem, limit *uint, order string) (int64, int64) {
|
||||
var minLim, maxLim int64
|
||||
if fromItem != nil {
|
||||
if order == historydb.OrderAsc {
|
||||
if int64(*fromItem) > *minSlotNum {
|
||||
minLim = int64(*fromItem)
|
||||
} else {
|
||||
minLim = *minSlotNum
|
||||
}
|
||||
if (minLim + int64(*limit-1)) < *maxSlotNum {
|
||||
maxLim = minLim + int64(*limit-1)
|
||||
} else {
|
||||
maxLim = *maxSlotNum
|
||||
}
|
||||
func getLimits(
|
||||
minSlotNum, maxSlotNum int64, fromItem, limit *uint, order string,
|
||||
) (minLimit, maxLimit int64, pendingItems uint64) {
|
||||
if order == historydb.OrderAsc {
|
||||
if fromItem != nil && int64(*fromItem) > minSlotNum {
|
||||
minLimit = int64(*fromItem)
|
||||
} else {
|
||||
if int64(*fromItem) < *maxSlotNum {
|
||||
maxLim = int64(*fromItem)
|
||||
} else {
|
||||
maxLim = *maxSlotNum
|
||||
}
|
||||
if (maxLim - int64(*limit-1)) < *minSlotNum {
|
||||
minLim = *minSlotNum
|
||||
} else {
|
||||
minLim = maxLim - int64(*limit-1)
|
||||
}
|
||||
minLimit = minSlotNum
|
||||
}
|
||||
if limit != nil && (minLimit+int64(*limit-1)) < maxSlotNum {
|
||||
maxLimit = minLimit + int64(*limit-1)
|
||||
} else {
|
||||
maxLimit = maxSlotNum
|
||||
}
|
||||
pendingItems = uint64(maxSlotNum - maxLimit)
|
||||
} else {
|
||||
if fromItem != nil && int64(*fromItem) < maxSlotNum {
|
||||
maxLimit = int64(*fromItem)
|
||||
} else {
|
||||
maxLimit = maxSlotNum
|
||||
}
|
||||
if limit != nil && (maxLimit-int64(*limit-1)) < minSlotNum {
|
||||
minLimit = minSlotNum
|
||||
} else {
|
||||
minLimit = maxLimit - int64(*limit-1)
|
||||
}
|
||||
pendingItems = uint64(-(minSlotNum - minLimit))
|
||||
}
|
||||
return minLim, maxLim
|
||||
return minLimit, maxLimit, pendingItems
|
||||
}
|
||||
|
||||
func getLimitsWithAddr(minSlotNum, maxSlotNum *int64, fromItem, limit *uint, order string) (int64, int64) {
|
||||
@@ -262,29 +250,22 @@ func (a *API) getSlots(c *gin.Context) {
|
||||
// Get bids and pagination according to filters
|
||||
var slotMinLim, slotMaxLim int64
|
||||
var bids []historydb.BidAPI
|
||||
var pag *db.Pagination
|
||||
totalItems := uint64(0)
|
||||
var pendingItems uint64
|
||||
if wonByEthereumAddress == nil {
|
||||
slotMinLim, slotMaxLim = getLimits(minSlotNum, maxSlotNum, fromItem, limit, order)
|
||||
slotMinLim, slotMaxLim, pendingItems = getLimits(*minSlotNum, *maxSlotNum, fromItem, limit, order)
|
||||
// Get best bids in range maxSlotNum - minSlotNum
|
||||
bids, _, err = a.h.GetBestBidsAPI(&slotMinLim, &slotMaxLim, wonByEthereumAddress, nil, order)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
retSQLErr(err, c)
|
||||
return
|
||||
}
|
||||
totalItems = uint64(*maxSlotNum) - uint64(*minSlotNum) + 1
|
||||
} else {
|
||||
slotMinLim, slotMaxLim = getLimitsWithAddr(minSlotNum, maxSlotNum, fromItem, limit, order)
|
||||
bids, pag, err = a.h.GetBestBidsAPI(&slotMinLim, &slotMaxLim, wonByEthereumAddress, limit, order)
|
||||
bids, pendingItems, err = a.h.GetBestBidsAPI(&slotMinLim, &slotMaxLim, wonByEthereumAddress, limit, order)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
retSQLErr(err, c)
|
||||
return
|
||||
}
|
||||
if len(bids) > 0 {
|
||||
totalItems = uint64(pag.TotalItems)
|
||||
*maxSlotNum = int64(pag.LastItem)
|
||||
*minSlotNum = int64(pag.FirstItem)
|
||||
}
|
||||
}
|
||||
|
||||
// Build the slot information with previous bids
|
||||
@@ -336,11 +317,11 @@ func (a *API) getSlots(c *gin.Context) {
|
||||
|
||||
// Build succesfull response
|
||||
type slotsResponse struct {
|
||||
Slots []SlotAPI `json:"slots"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
Slots []SlotAPI `json:"slots"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
c.JSON(http.StatusOK, &slotsResponse{
|
||||
Slots: slots,
|
||||
Pagination: getPagination(totalItems, minSlotNum, maxSlotNum),
|
||||
Slots: slots,
|
||||
PendingItems: pendingItems,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,14 +6,13 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
"github.com/mitchellh/copystructure"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type testSlot struct {
|
||||
ItemID int `json:"itemId"`
|
||||
ItemID uint64 `json:"itemId"`
|
||||
SlotNum int64 `json:"slotNum"`
|
||||
FirstBlock int64 `json:"firstBlock"`
|
||||
LastBlock int64 `json:"lastBlock"`
|
||||
@@ -22,19 +21,14 @@ type testSlot struct {
|
||||
}
|
||||
|
||||
type testSlotsResponse struct {
|
||||
Slots []testSlot `json:"slots"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
Slots []testSlot `json:"slots"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
|
||||
func (t testSlotsResponse) GetPagination() *db.Pagination {
|
||||
if t.Slots[0].ItemID < t.Slots[len(t.Slots)-1].ItemID {
|
||||
t.Pagination.FirstReturnedItem = uint64(t.Slots[0].ItemID)
|
||||
t.Pagination.LastReturnedItem = uint64(t.Slots[len(t.Slots)-1].ItemID)
|
||||
} else {
|
||||
t.Pagination.LastReturnedItem = uint64(t.Slots[0].ItemID)
|
||||
t.Pagination.FirstReturnedItem = uint64(t.Slots[len(t.Slots)-1].ItemID)
|
||||
}
|
||||
return t.Pagination
|
||||
func (t testSlotsResponse) GetPending() (pendingItems, lastItemID uint64) {
|
||||
pendingItems = t.PendingItems
|
||||
lastItemID = t.Slots[len(t.Slots)-1].ItemID
|
||||
return pendingItems, lastItemID
|
||||
}
|
||||
|
||||
func (t testSlotsResponse) Len() int {
|
||||
|
||||
@@ -17,7 +17,9 @@ info:
|
||||
* `order`: all pginated items are ordered chronologicaly. However the specific fields to guarantee this order depend on each endpoint. For this purpose, `itemId` is used (itemId follows ascending chronological order except for unforged L1 user transactions). If the parameter is not provided, ascending order will be used by default.
|
||||
* `limit`: maximum amount of items to include in each response. Default is 20, maximum 2049.
|
||||
|
||||
Responses for those endpoint will always include a `pagination` object. This object includes the total amount of items that the endpoint will return at a given time with the given filters. Apart from that, it also includes the `itemId` of the last and first items that will be returned (not in a single response but within the total items). These two properties can be used to know when to stop querying.
|
||||
Responses for those endpoint will always include a `pendingItems` property. This property includes the amount of items that are not fetched yet. his can be used to:
|
||||
* Calculate the amount of items that match the filters: `totalItems = length(alreadyFetchedItems) + pendingItems`
|
||||
* Know when all items have been fetched: `if pendingItems == 0 {/* all items have been fetched */}`
|
||||
|
||||
#### Reorgs and safetyness
|
||||
|
||||
@@ -1739,11 +1741,11 @@ components:
|
||||
description: List of history transactions.
|
||||
items:
|
||||
$ref: '#/components/schemas/HistoryTransaction'
|
||||
pagination:
|
||||
$ref: '#/components/schemas/PaginationInfo'
|
||||
pendingItems:
|
||||
$ref: '#/components/schemas/PendingItems'
|
||||
required:
|
||||
- transactions
|
||||
- pagination
|
||||
- pendingItems
|
||||
additionalProperties: false
|
||||
EthBlockNum:
|
||||
type: integer
|
||||
@@ -1877,12 +1879,12 @@ components:
|
||||
description: List of batches.
|
||||
items:
|
||||
$ref: '#/components/schemas/Batch'
|
||||
pagination:
|
||||
$ref: '#/components/schemas/PaginationInfo'
|
||||
pendingItems:
|
||||
$ref: '#/components/schemas/PendingItems'
|
||||
additionalProperties: false
|
||||
required:
|
||||
- batches
|
||||
- pagination
|
||||
- pendingItems
|
||||
Coordinator:
|
||||
type: object
|
||||
properties:
|
||||
@@ -1914,12 +1916,12 @@ components:
|
||||
description: List of coordinators.
|
||||
items:
|
||||
$ref: '#/components/schemas/Coordinator'
|
||||
pagination:
|
||||
$ref: '#/components/schemas/PaginationInfo'
|
||||
pendingItems:
|
||||
$ref: '#/components/schemas/PendingItems'
|
||||
additionalProperties: false
|
||||
required:
|
||||
- coordinators
|
||||
- pagination
|
||||
- pendingItems
|
||||
Bid:
|
||||
type: object
|
||||
description: Tokens placed in an auction by a coordinator to gain the right to forge batches during a specific slot.
|
||||
@@ -1958,12 +1960,12 @@ components:
|
||||
description: List of bids.
|
||||
items:
|
||||
$ref: '#/components/schemas/Bid'
|
||||
pagination:
|
||||
$ref: '#/components/schemas/PaginationInfo'
|
||||
pendingItems:
|
||||
$ref: '#/components/schemas/PendingItems'
|
||||
additionalProperties: false
|
||||
require:
|
||||
- bids
|
||||
- pagination
|
||||
- pendingItems
|
||||
RecommendedFee:
|
||||
type: object
|
||||
description: Fee that the coordinator recommends per transaction in USD.
|
||||
@@ -2042,8 +2044,8 @@ components:
|
||||
description: List of tokens.
|
||||
items:
|
||||
$ref: '#/components/schemas/Token'
|
||||
pagination:
|
||||
$ref: '#/components/schemas/PaginationInfo'
|
||||
pendingItems:
|
||||
$ref: '#/components/schemas/PendingItems'
|
||||
Exit:
|
||||
type: object
|
||||
description: Exit tree leaf. It Contains the necessary information to perform a withdrawal.
|
||||
@@ -2135,11 +2137,11 @@ components:
|
||||
description: List of exits.
|
||||
items:
|
||||
$ref: '#/components/schemas/Exit'
|
||||
pagination:
|
||||
$ref: '#/components/schemas/PaginationInfo'
|
||||
pendingItems:
|
||||
$ref: '#/components/schemas/PendingItems'
|
||||
required:
|
||||
- exits
|
||||
- pagination
|
||||
- pendingItems
|
||||
additionalProperties: false
|
||||
Account:
|
||||
type: object
|
||||
@@ -2176,12 +2178,12 @@ components:
|
||||
description: List of accounts.
|
||||
items:
|
||||
$ref: '#/components/schemas/Account'
|
||||
pagination:
|
||||
$ref: '#/components/schemas/PaginationInfo'
|
||||
pendingItems:
|
||||
$ref: '#/components/schemas/PendingItems'
|
||||
additionalProperties: false
|
||||
required:
|
||||
- accounts
|
||||
- pagination
|
||||
- pendingItems
|
||||
Slot:
|
||||
type: object
|
||||
description: Slot information.
|
||||
@@ -2255,12 +2257,12 @@ components:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/Slot'
|
||||
- description: Last synchronized Etherum block.
|
||||
pagination:
|
||||
$ref: '#/components/schemas/PaginationInfo'
|
||||
pendingItems:
|
||||
$ref: '#/components/schemas/PendingItems'
|
||||
additionalProperties: false
|
||||
require:
|
||||
- slots
|
||||
- pagination
|
||||
- pendingItems
|
||||
NextForger:
|
||||
type: object
|
||||
description: Coordinator information along with the scheduled forging period
|
||||
@@ -2289,8 +2291,8 @@ components:
|
||||
description: List of next coordinators to forge.
|
||||
items:
|
||||
$ref: '#/components/schemas/NextForger'
|
||||
pagination:
|
||||
$ref: '#/components/schemas/PaginationInfo'
|
||||
pendingItems:
|
||||
$ref: '#/components/schemas/PendingItems'
|
||||
State:
|
||||
type: object
|
||||
description: Gobal variables of the network
|
||||
@@ -2517,22 +2519,10 @@ components:
|
||||
- auction
|
||||
- withdrawalDelayer
|
||||
- recomendedFee
|
||||
PaginationInfo:
|
||||
type: object
|
||||
description: Give pagination information
|
||||
properties:
|
||||
totalItems:
|
||||
type: integer
|
||||
description: Amount of items that the endpoint can return given the filters and the current state of the database.
|
||||
example: 2048
|
||||
firstItem:
|
||||
type: integer
|
||||
description: The smallest itemId that the endpoint will return with the given filters.
|
||||
example: 50
|
||||
lastItem:
|
||||
type: integer
|
||||
description: The greatest itemId that the endpoint will return with the given filters.
|
||||
example: 2130
|
||||
PendingItems:
|
||||
type: integer
|
||||
description: Amount of items that will be returned in subsequent calls to the endpoint, as long as they are done with same filters. When the value is 0 it means that all items have been sent.
|
||||
example: 15
|
||||
Config:
|
||||
type: object
|
||||
description: Configuration parameters of the different smart contracts that power the Hermez network.
|
||||
|
||||
11
api/token.go
11
api/token.go
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
)
|
||||
|
||||
@@ -46,7 +45,7 @@ func (a *API) getTokens(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
// Fetch exits from historyDB
|
||||
tokens, pagination, err := a.h.GetTokens(
|
||||
tokens, pendingItems, err := a.h.GetTokens(
|
||||
tokenIDs, symbols, name, fromItem, limit, order,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -56,11 +55,11 @@ func (a *API) getTokens(c *gin.Context) {
|
||||
|
||||
// Build succesfull response
|
||||
type tokensResponse struct {
|
||||
Tokens []historydb.TokenWithUSD `json:"tokens"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
Tokens []historydb.TokenWithUSD `json:"tokens"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
c.JSON(http.StatusOK, &tokensResponse{
|
||||
Tokens: tokens,
|
||||
Pagination: pagination,
|
||||
Tokens: tokens,
|
||||
PendingItems: pendingItems,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
"github.com/mitchellh/copystructure"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -13,19 +12,14 @@ import (
|
||||
)
|
||||
|
||||
type testTokensResponse struct {
|
||||
Tokens []historydb.TokenWithUSD `json:"tokens"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
Tokens []historydb.TokenWithUSD `json:"tokens"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
|
||||
func (t *testTokensResponse) GetPagination() *db.Pagination {
|
||||
if t.Tokens[0].ItemID < t.Tokens[len(t.Tokens)-1].ItemID {
|
||||
t.Pagination.FirstReturnedItem = t.Tokens[0].ItemID
|
||||
t.Pagination.LastReturnedItem = t.Tokens[len(t.Tokens)-1].ItemID
|
||||
} else {
|
||||
t.Pagination.LastReturnedItem = t.Tokens[0].ItemID
|
||||
t.Pagination.FirstReturnedItem = t.Tokens[len(t.Tokens)-1].ItemID
|
||||
}
|
||||
return t.Pagination
|
||||
func (t testTokensResponse) GetPending() (pendingItems, lastItemID uint64) {
|
||||
pendingItems = t.PendingItems
|
||||
lastItemID = t.Tokens[len(t.Tokens)-1].ItemID
|
||||
return pendingItems, lastItemID
|
||||
}
|
||||
|
||||
func (t *testTokensResponse) Len() int {
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
)
|
||||
|
||||
@@ -35,7 +34,7 @@ func (a *API) getHistoryTxs(c *gin.Context) {
|
||||
}
|
||||
|
||||
// Fetch txs from historyDB
|
||||
txs, pagination, err := a.h.GetHistoryTxs(
|
||||
txs, pendingItems, err := a.h.GetHistoryTxs(
|
||||
addr, bjj, tokenID, idx, batchNum, txType, fromItem, limit, order,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -45,12 +44,12 @@ func (a *API) getHistoryTxs(c *gin.Context) {
|
||||
|
||||
// Build succesfull response
|
||||
type txsResponse struct {
|
||||
Txs []historydb.TxAPI `json:"transactions"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
Txs []historydb.TxAPI `json:"transactions"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
c.JSON(http.StatusOK, &txsResponse{
|
||||
Txs: txs,
|
||||
Pagination: pagination,
|
||||
Txs: txs,
|
||||
PendingItems: pendingItems,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/hermeznetwork/hermez-node/apitypes"
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
"github.com/hermeznetwork/hermez-node/test"
|
||||
"github.com/mitchellh/copystructure"
|
||||
@@ -53,19 +52,14 @@ type testTx struct {
|
||||
}
|
||||
|
||||
type testTxsResponse struct {
|
||||
Txs []testTx `json:"transactions"`
|
||||
Pagination *db.Pagination `json:"pagination"`
|
||||
Txs []testTx `json:"transactions"`
|
||||
PendingItems uint64 `json:"pendingItems"`
|
||||
}
|
||||
|
||||
func (t testTxsResponse) GetPagination() *db.Pagination {
|
||||
if t.Txs[0].ItemID < t.Txs[len(t.Txs)-1].ItemID {
|
||||
t.Pagination.FirstReturnedItem = t.Txs[0].ItemID
|
||||
t.Pagination.LastReturnedItem = t.Txs[len(t.Txs)-1].ItemID
|
||||
} else {
|
||||
t.Pagination.LastReturnedItem = t.Txs[0].ItemID
|
||||
t.Pagination.FirstReturnedItem = t.Txs[len(t.Txs)-1].ItemID
|
||||
}
|
||||
return t.Pagination
|
||||
func (t testTxsResponse) GetPending() (pendingItems, lastItemID uint64) {
|
||||
pendingItems = t.PendingItems
|
||||
lastItemID = t.Txs[len(t.Txs)-1].ItemID
|
||||
return pendingItems, lastItemID
|
||||
}
|
||||
|
||||
func (t testTxsResponse) Len() int {
|
||||
|
||||
@@ -181,12 +181,11 @@ func (hdb *HistoryDB) GetBatchesAPI(
|
||||
minBatchNum, maxBatchNum, slotNum *uint,
|
||||
forgerAddr *ethCommon.Address,
|
||||
fromItem, limit *uint, order string,
|
||||
) ([]BatchAPI, *db.Pagination, error) {
|
||||
) ([]BatchAPI, uint64, error) {
|
||||
var query string
|
||||
var args []interface{}
|
||||
queryStr := `SELECT batch.*, block.timestamp, block.hash,
|
||||
count(*) OVER() AS total_items, MIN(batch.item_id) OVER() AS first_item,
|
||||
MAX(batch.item_id) OVER() AS last_item
|
||||
count(*) OVER() AS total_items
|
||||
FROM batch INNER JOIN block ON batch.eth_block_num = block.eth_block_num `
|
||||
// Apply filters
|
||||
nextIsAnd := false
|
||||
@@ -259,17 +258,13 @@ func (hdb *HistoryDB) GetBatchesAPI(
|
||||
// log.Debug(query)
|
||||
batchPtrs := []*BatchAPI{}
|
||||
if err := meddler.QueryAll(hdb.db, &batchPtrs, query, args...); err != nil {
|
||||
return nil, nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
batches := db.SlicePtrsToSlice(batchPtrs).([]BatchAPI)
|
||||
if len(batches) == 0 {
|
||||
return nil, nil, sql.ErrNoRows
|
||||
return nil, 0, sql.ErrNoRows
|
||||
}
|
||||
return batches, &db.Pagination{
|
||||
TotalItems: batches[0].TotalItems,
|
||||
FirstItem: batches[0].FirstItem,
|
||||
LastItem: batches[0].LastItem,
|
||||
}, nil
|
||||
return batches, batches[0].TotalItems - uint64(len(batches)), nil
|
||||
}
|
||||
|
||||
// GetAllBatches retrieve all batches from the DB
|
||||
@@ -367,12 +362,15 @@ func (hdb *HistoryDB) GetBestBidAPI(slotNum *int64) (BidAPI, error) {
|
||||
}
|
||||
|
||||
// GetBestBidsAPI returns the best bid in specific slot by slotNum
|
||||
func (hdb *HistoryDB) GetBestBidsAPI(minSlotNum, maxSlotNum *int64, bidderAddr *ethCommon.Address, limit *uint, order string) ([]BidAPI, *db.Pagination, error) {
|
||||
func (hdb *HistoryDB) GetBestBidsAPI(
|
||||
minSlotNum, maxSlotNum *int64,
|
||||
bidderAddr *ethCommon.Address,
|
||||
limit *uint, order string,
|
||||
) ([]BidAPI, uint64, error) {
|
||||
var query string
|
||||
var args []interface{}
|
||||
queryStr := `SELECT b.*, block.timestamp, coordinator.forger_addr, coordinator.url,
|
||||
COUNT(*) OVER() AS total_items, MIN(b.slot_num) OVER() AS first_item,
|
||||
MAX(b.slot_num) OVER() AS last_item FROM (
|
||||
COUNT(*) OVER() AS total_items FROM (
|
||||
SELECT slot_num, MAX(item_id) as maxitem
|
||||
FROM bid GROUP BY slot_num
|
||||
)
|
||||
@@ -399,28 +397,26 @@ func (hdb *HistoryDB) GetBestBidsAPI(minSlotNum, maxSlotNum *int64, bidderAddr *
|
||||
query = hdb.db.Rebind(queryStr)
|
||||
bidPtrs := []*BidAPI{}
|
||||
if err := meddler.QueryAll(hdb.db, &bidPtrs, query, args...); err != nil {
|
||||
return nil, nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
// log.Debug(query)
|
||||
bids := db.SlicePtrsToSlice(bidPtrs).([]BidAPI)
|
||||
if len(bids) == 0 {
|
||||
return nil, nil, sql.ErrNoRows
|
||||
return nil, 0, sql.ErrNoRows
|
||||
}
|
||||
return bids, &db.Pagination{
|
||||
TotalItems: bids[0].TotalItems,
|
||||
FirstItem: bids[0].FirstItem,
|
||||
LastItem: bids[0].LastItem,
|
||||
}, nil
|
||||
return bids, bids[0].TotalItems - uint64(len(bids)), nil
|
||||
}
|
||||
|
||||
// GetBidsAPI return the bids applying the given filters
|
||||
func (hdb *HistoryDB) GetBidsAPI(slotNum *int64, forgerAddr *ethCommon.Address, fromItem, limit *uint, order string) ([]BidAPI, *db.Pagination, error) {
|
||||
func (hdb *HistoryDB) GetBidsAPI(
|
||||
slotNum *int64, forgerAddr *ethCommon.Address,
|
||||
fromItem, limit *uint, order string,
|
||||
) ([]BidAPI, uint64, error) {
|
||||
var query string
|
||||
var args []interface{}
|
||||
queryStr := `SELECT bid.*, block.timestamp, coordinator.forger_addr, coordinator.url,
|
||||
COUNT(*) OVER() AS total_items, MIN(bid.item_id) OVER() AS first_item,
|
||||
MAX(bid.item_id) OVER() AS last_item FROM bid
|
||||
INNER JOIN block ON bid.eth_block_num = block.eth_block_num
|
||||
COUNT(*) OVER() AS total_items
|
||||
FROM bid INNER JOIN block ON bid.eth_block_num = block.eth_block_num
|
||||
INNER JOIN coordinator ON bid.bidder_addr = coordinator.bidder_addr `
|
||||
// Apply filters
|
||||
nextIsAnd := false
|
||||
@@ -469,21 +465,17 @@ func (hdb *HistoryDB) GetBidsAPI(slotNum *int64, forgerAddr *ethCommon.Address,
|
||||
queryStr += fmt.Sprintf("LIMIT %d;", *limit)
|
||||
query, argsQ, err := sqlx.In(queryStr, args...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
query = hdb.db.Rebind(query)
|
||||
bids := []*BidAPI{}
|
||||
if err := meddler.QueryAll(hdb.db, &bids, query, argsQ...); err != nil {
|
||||
return nil, nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(bids) == 0 {
|
||||
return nil, nil, sql.ErrNoRows
|
||||
return nil, 0, sql.ErrNoRows
|
||||
}
|
||||
return db.SlicePtrsToSlice(bids).([]BidAPI), &db.Pagination{
|
||||
TotalItems: bids[0].TotalItems,
|
||||
FirstItem: bids[0].FirstItem,
|
||||
LastItem: bids[0].LastItem,
|
||||
}, nil
|
||||
return db.SlicePtrsToSlice(bids).([]BidAPI), bids[0].TotalItems - uint64(len(bids)), nil
|
||||
}
|
||||
|
||||
// AddCoordinators insert Coordinators into the DB
|
||||
@@ -562,10 +554,13 @@ func (hdb *HistoryDB) GetAllTokens() ([]TokenWithUSD, error) {
|
||||
}
|
||||
|
||||
// GetTokens returns a list of tokens from the DB
|
||||
func (hdb *HistoryDB) GetTokens(ids []common.TokenID, symbols []string, name string, fromItem, limit *uint, order string) ([]TokenWithUSD, *db.Pagination, error) {
|
||||
func (hdb *HistoryDB) GetTokens(
|
||||
ids []common.TokenID, symbols []string, name string, fromItem,
|
||||
limit *uint, order string,
|
||||
) ([]TokenWithUSD, uint64, error) {
|
||||
var query string
|
||||
var args []interface{}
|
||||
queryStr := `SELECT * , COUNT(*) OVER() AS total_items, MIN(token.item_id) OVER() AS first_item, MAX(token.item_id) OVER() AS last_item FROM token `
|
||||
queryStr := `SELECT * , COUNT(*) OVER() AS total_items FROM token `
|
||||
// Apply filters
|
||||
nextIsAnd := false
|
||||
if len(ids) > 0 {
|
||||
@@ -616,21 +611,17 @@ func (hdb *HistoryDB) GetTokens(ids []common.TokenID, symbols []string, name str
|
||||
queryStr += fmt.Sprintf("LIMIT %d;", *limit)
|
||||
query, argsQ, err := sqlx.In(queryStr, args...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
query = hdb.db.Rebind(query)
|
||||
tokens := []*TokenWithUSD{}
|
||||
if err := meddler.QueryAll(hdb.db, &tokens, query, argsQ...); err != nil {
|
||||
return nil, nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(tokens) == 0 {
|
||||
return nil, nil, sql.ErrNoRows
|
||||
return nil, 0, sql.ErrNoRows
|
||||
}
|
||||
return db.SlicePtrsToSlice(tokens).([]TokenWithUSD), &db.Pagination{
|
||||
TotalItems: tokens[0].TotalItems,
|
||||
FirstItem: tokens[0].FirstItem,
|
||||
LastItem: tokens[0].LastItem,
|
||||
}, nil
|
||||
return db.SlicePtrsToSlice(tokens).([]TokenWithUSD), uint64(len(tokens)) - tokens[0].TotalItems, nil
|
||||
}
|
||||
|
||||
// GetTokenSymbols returns all the token symbols from the DB
|
||||
@@ -813,9 +804,9 @@ func (hdb *HistoryDB) GetHistoryTxs(
|
||||
ethAddr *ethCommon.Address, bjj *babyjub.PublicKey,
|
||||
tokenID *common.TokenID, idx *common.Idx, batchNum *uint, txType *common.TxType,
|
||||
fromItem, limit *uint, order string,
|
||||
) ([]TxAPI, *db.Pagination, error) {
|
||||
) ([]TxAPI, uint64, error) {
|
||||
if ethAddr != nil && bjj != nil {
|
||||
return nil, nil, errors.New("ethAddr and bjj are incompatible")
|
||||
return nil, 0, errors.New("ethAddr and bjj are incompatible")
|
||||
}
|
||||
var query string
|
||||
var args []interface{}
|
||||
@@ -827,8 +818,7 @@ func (hdb *HistoryDB) GetHistoryTxs(
|
||||
tx.load_amount, tx.load_amount_usd, tx.fee, tx.fee_usd, tx.nonce,
|
||||
token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
|
||||
token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
|
||||
token.usd_update, block.timestamp, count(*) OVER() AS total_items,
|
||||
MIN(tx.item_id) OVER() AS first_item, MAX(tx.item_id) OVER() AS last_item
|
||||
token.usd_update, block.timestamp, count(*) OVER() AS total_items
|
||||
FROM tx INNER JOIN token ON tx.token_id = token.token_id
|
||||
INNER JOIN block ON tx.eth_block_num = block.eth_block_num `
|
||||
// Apply filters
|
||||
@@ -924,17 +914,13 @@ func (hdb *HistoryDB) GetHistoryTxs(
|
||||
// log.Debug(query)
|
||||
txsPtrs := []*TxAPI{}
|
||||
if err := meddler.QueryAll(hdb.db, &txsPtrs, query, args...); err != nil {
|
||||
return nil, nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
txs := db.SlicePtrsToSlice(txsPtrs).([]TxAPI)
|
||||
if len(txs) == 0 {
|
||||
return nil, nil, sql.ErrNoRows
|
||||
return nil, 0, sql.ErrNoRows
|
||||
}
|
||||
return txs, &db.Pagination{
|
||||
TotalItems: txs[0].TotalItems,
|
||||
FirstItem: txs[0].FirstItem,
|
||||
LastItem: txs[0].LastItem,
|
||||
}, nil
|
||||
return txs, txs[0].TotalItems - uint64(len(txs)), nil
|
||||
}
|
||||
|
||||
// GetAllExits returns all exit from the DB
|
||||
@@ -972,9 +958,9 @@ func (hdb *HistoryDB) GetExitsAPI(
|
||||
ethAddr *ethCommon.Address, bjj *babyjub.PublicKey, tokenID *common.TokenID,
|
||||
idx *common.Idx, batchNum *uint, onlyPendingWithdraws *bool,
|
||||
fromItem, limit *uint, order string,
|
||||
) ([]ExitAPI, *db.Pagination, error) {
|
||||
) ([]ExitAPI, uint64, error) {
|
||||
if ethAddr != nil && bjj != nil {
|
||||
return nil, nil, errors.New("ethAddr and bjj are incompatible")
|
||||
return nil, 0, errors.New("ethAddr and bjj are incompatible")
|
||||
}
|
||||
var query string
|
||||
var args []interface{}
|
||||
@@ -984,8 +970,7 @@ func (hdb *HistoryDB) GetExitsAPI(
|
||||
exit_tree.delayed_withdraw_request, exit_tree.delayed_withdrawn,
|
||||
token.token_id, token.item_id AS token_item_id,
|
||||
token.eth_block_num AS token_block, token.eth_addr, token.name, token.symbol,
|
||||
token.decimals, token.usd, token.usd_update, COUNT(*) OVER() AS total_items,
|
||||
MIN(exit_tree.item_id) OVER() AS first_item, MAX(exit_tree.item_id) OVER() AS last_item
|
||||
token.decimals, token.usd, token.usd_update, COUNT(*) OVER() AS total_items
|
||||
FROM exit_tree INNER JOIN account ON exit_tree.account_idx = account.idx
|
||||
INNER JOIN token ON account.token_id = token.token_id `
|
||||
// Apply filters
|
||||
@@ -1071,16 +1056,12 @@ func (hdb *HistoryDB) GetExitsAPI(
|
||||
// log.Debug(query)
|
||||
exits := []*ExitAPI{}
|
||||
if err := meddler.QueryAll(hdb.db, &exits, query, args...); err != nil {
|
||||
return nil, nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(exits) == 0 {
|
||||
return nil, nil, sql.ErrNoRows
|
||||
return nil, 0, sql.ErrNoRows
|
||||
}
|
||||
return db.SlicePtrsToSlice(exits).([]ExitAPI), &db.Pagination{
|
||||
TotalItems: exits[0].TotalItems,
|
||||
FirstItem: exits[0].FirstItem,
|
||||
LastItem: exits[0].LastItem,
|
||||
}, nil
|
||||
return db.SlicePtrsToSlice(exits).([]ExitAPI), exits[0].TotalItems - uint64(len(exits)), nil
|
||||
}
|
||||
|
||||
// // GetTx returns a tx from the DB
|
||||
@@ -1337,11 +1318,11 @@ func (hdb *HistoryDB) GetCoordinatorAPI(bidderAddr ethCommon.Address) (*Coordina
|
||||
}
|
||||
|
||||
// GetCoordinatorsAPI returns a list of coordinators from the DB and pagination info
|
||||
func (hdb *HistoryDB) GetCoordinatorsAPI(fromItem, limit *uint, order string) ([]CoordinatorAPI, *db.Pagination, error) {
|
||||
func (hdb *HistoryDB) GetCoordinatorsAPI(fromItem, limit *uint, order string) ([]CoordinatorAPI, uint64, error) {
|
||||
var query string
|
||||
var args []interface{}
|
||||
queryStr := `SELECT coordinator.*,
|
||||
COUNT(*) OVER() AS total_items, MIN(coordinator.item_id) OVER() AS first_item, MAX(coordinator.item_id) OVER() AS last_item
|
||||
COUNT(*) OVER() AS total_items
|
||||
FROM coordinator `
|
||||
// Apply filters
|
||||
if fromItem != nil {
|
||||
@@ -1365,16 +1346,13 @@ func (hdb *HistoryDB) GetCoordinatorsAPI(fromItem, limit *uint, order string) ([
|
||||
|
||||
coordinators := []*CoordinatorAPI{}
|
||||
if err := meddler.QueryAll(hdb.db, &coordinators, query, args...); err != nil {
|
||||
return nil, nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(coordinators) == 0 {
|
||||
return nil, nil, sql.ErrNoRows
|
||||
return nil, 0, sql.ErrNoRows
|
||||
}
|
||||
return db.SlicePtrsToSlice(coordinators).([]CoordinatorAPI), &db.Pagination{
|
||||
TotalItems: coordinators[0].TotalItems,
|
||||
FirstItem: coordinators[0].FirstItem,
|
||||
LastItem: coordinators[0].LastItem,
|
||||
}, nil
|
||||
return db.SlicePtrsToSlice(coordinators).([]CoordinatorAPI),
|
||||
coordinators[0].TotalItems - uint64(len(coordinators)), nil
|
||||
}
|
||||
|
||||
// AddAuctionVars insert auction vars into the DB
|
||||
@@ -1394,7 +1372,8 @@ func (hdb *HistoryDB) GetAuctionVars() (*common.AuctionVariables, error) {
|
||||
// GetAccountAPI returns an account by its index
|
||||
func (hdb *HistoryDB) GetAccountAPI(idx common.Idx) (*AccountAPI, error) {
|
||||
account := &AccountAPI{}
|
||||
err := meddler.QueryRow(hdb.db, account, `SELECT account.item_id, hez_idx(account.idx, token.symbol) as idx, account.batch_num, account.bjj, account.eth_addr,
|
||||
err := meddler.QueryRow(hdb.db, account, `SELECT account.item_id, hez_idx(account.idx,
|
||||
token.symbol) as idx, account.batch_num, account.bjj, account.eth_addr,
|
||||
token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
|
||||
token.eth_addr as token_eth_addr, token.name, token.symbol, token.decimals, token.usd, token.usd_update
|
||||
FROM account INNER JOIN token ON account.token_id = token.token_id WHERE idx = $1;`, idx)
|
||||
@@ -1407,16 +1386,19 @@ func (hdb *HistoryDB) GetAccountAPI(idx common.Idx) (*AccountAPI, error) {
|
||||
}
|
||||
|
||||
// GetAccountsAPI returns a list of accounts from the DB and pagination info
|
||||
func (hdb *HistoryDB) GetAccountsAPI(tokenIDs []common.TokenID, ethAddr *ethCommon.Address, bjj *babyjub.PublicKey, fromItem, limit *uint, order string) ([]AccountAPI, *db.Pagination, error) {
|
||||
func (hdb *HistoryDB) GetAccountsAPI(
|
||||
tokenIDs []common.TokenID, ethAddr *ethCommon.Address,
|
||||
bjj *babyjub.PublicKey, fromItem, limit *uint, order string,
|
||||
) ([]AccountAPI, uint64, error) {
|
||||
if ethAddr != nil && bjj != nil {
|
||||
return nil, nil, errors.New("ethAddr and bjj are incompatible")
|
||||
return nil, 0, errors.New("ethAddr and bjj are incompatible")
|
||||
}
|
||||
var query string
|
||||
var args []interface{}
|
||||
queryStr := `SELECT account.item_id, hez_idx(account.idx, token.symbol) as idx, account.batch_num, account.bjj, account.eth_addr,
|
||||
token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
|
||||
queryStr := `SELECT account.item_id, hez_idx(account.idx, token.symbol) as idx, account.batch_num,
|
||||
account.bjj, account.eth_addr, token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
|
||||
token.eth_addr as token_eth_addr, token.name, token.symbol, token.decimals, token.usd, token.usd_update,
|
||||
COUNT(*) OVER() AS total_items, MIN(account.item_id) OVER() AS first_item, MAX(account.item_id) OVER() AS last_item
|
||||
COUNT(*) OVER() AS total_items
|
||||
FROM account INNER JOIN token ON account.token_id = token.token_id `
|
||||
// Apply filters
|
||||
nextIsAnd := false
|
||||
@@ -1464,21 +1446,18 @@ func (hdb *HistoryDB) GetAccountsAPI(tokenIDs []common.TokenID, ethAddr *ethComm
|
||||
queryStr += fmt.Sprintf("LIMIT %d;", *limit)
|
||||
query, argsQ, err := sqlx.In(queryStr, args...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
query = hdb.db.Rebind(query)
|
||||
|
||||
accounts := []*AccountAPI{}
|
||||
if err := meddler.QueryAll(hdb.db, &accounts, query, argsQ...); err != nil {
|
||||
return nil, nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(accounts) == 0 {
|
||||
return nil, nil, sql.ErrNoRows
|
||||
return nil, 0, sql.ErrNoRows
|
||||
}
|
||||
|
||||
return db.SlicePtrsToSlice(accounts).([]AccountAPI), &db.Pagination{
|
||||
TotalItems: accounts[0].TotalItems,
|
||||
FirstItem: accounts[0].FirstItem,
|
||||
LastItem: accounts[0].LastItem,
|
||||
}, nil
|
||||
return db.SlicePtrsToSlice(accounts).([]AccountAPI),
|
||||
accounts[0].TotalItems - uint64(len(accounts)), nil
|
||||
}
|
||||
|
||||
15
db/utils.go
15
db/utils.go
@@ -179,21 +179,6 @@ func SlicePtrsToSlice(slice interface{}) interface{} {
|
||||
return res.Interface()
|
||||
}
|
||||
|
||||
// Pagination give information on the items of a query
|
||||
type Pagination struct {
|
||||
TotalItems uint64 `json:"totalItems"`
|
||||
FirstItem uint64 `json:"firstItem"`
|
||||
LastItem uint64 `json:"lastItem"`
|
||||
FirstReturnedItem uint64 `json:"-"`
|
||||
LastReturnedItem uint64 `json:"-"`
|
||||
}
|
||||
|
||||
// Paginationer is an interface that allows getting pagination info on any struct
|
||||
type Paginationer interface {
|
||||
GetPagination() *Pagination
|
||||
Len() int
|
||||
}
|
||||
|
||||
// Rollback an sql transaction, and log the error if it's not nil
|
||||
func Rollback(txn *sql.Tx) {
|
||||
err := txn.Rollback()
|
||||
|
||||
Reference in New Issue
Block a user