mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 11:26:44 +01:00
implemented get pool txs endpoint
This commit is contained in:
@@ -60,6 +60,7 @@ func NewAPI(
|
|||||||
// Transaction
|
// Transaction
|
||||||
v1.POST("/transactions-pool", a.postPoolTx)
|
v1.POST("/transactions-pool", a.postPoolTx)
|
||||||
v1.GET("/transactions-pool/:id", a.getPoolTx)
|
v1.GET("/transactions-pool/:id", a.getPoolTx)
|
||||||
|
v1.GET("/transactions-pool", a.getPoolTxs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add explorer endpoints
|
// Add explorer endpoints
|
||||||
|
|||||||
@@ -96,6 +96,32 @@ func parseQueryBJJ(c querier) (*babyjub.PublicKeyComp, error) {
|
|||||||
return hezStringToBJJ(bjjStr, name)
|
return hezStringToBJJ(bjjStr, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseQueryPoolL2TxState(c querier) (*common.PoolL2TxState, error) {
|
||||||
|
const name = "state"
|
||||||
|
stateStr := c.Query(name)
|
||||||
|
if stateStr == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
switch common.PoolL2TxState(stateStr) {
|
||||||
|
case common.PoolL2TxStatePending:
|
||||||
|
ret := common.PoolL2TxStatePending
|
||||||
|
return &ret, nil
|
||||||
|
case common.PoolL2TxStateForged:
|
||||||
|
ret := common.PoolL2TxStateForged
|
||||||
|
return &ret, nil
|
||||||
|
case common.PoolL2TxStateForging:
|
||||||
|
ret := common.PoolL2TxStateForging
|
||||||
|
return &ret, nil
|
||||||
|
case common.PoolL2TxStateInvalid:
|
||||||
|
ret := common.PoolL2TxStateInvalid
|
||||||
|
return &ret, nil
|
||||||
|
}
|
||||||
|
return nil, tracerr.Wrap(fmt.Errorf(
|
||||||
|
"invalid %s, %s is not a valid option. Check the valid options in the docmentation",
|
||||||
|
name, stateStr,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
func parseQueryTxType(c querier) (*common.TxType, error) {
|
func parseQueryTxType(c querier) (*common.TxType, error) {
|
||||||
const name = "type"
|
const name = "type"
|
||||||
typeStr := c.Query(name)
|
typeStr := c.Query(name)
|
||||||
|
|||||||
@@ -415,6 +415,49 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/Error500'
|
$ref: '#/components/schemas/Error500'
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Coordinator
|
||||||
|
summary: Get transactions that are in the pool.
|
||||||
|
operationId: getPoolTxs
|
||||||
|
parameters:
|
||||||
|
- name: state
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: State of the transactions, e.g. "pend"
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PoolL2TransactionState'
|
||||||
|
- name: accountIndex
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Id of the account
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/AccountIndex'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Successful operation.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PoolL2Transactions'
|
||||||
|
'400':
|
||||||
|
description: Bad request.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error400'
|
||||||
|
'404':
|
||||||
|
description: Not found.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error404'
|
||||||
|
'500':
|
||||||
|
description: Internal server error
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error500'
|
||||||
'/transactions-pool/{id}':
|
'/transactions-pool/{id}':
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -1439,6 +1482,14 @@ components:
|
|||||||
- requestFee
|
- requestFee
|
||||||
- requestNonce
|
- requestNonce
|
||||||
- token
|
- token
|
||||||
|
PoolL2Transactions:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
transactions:
|
||||||
|
type: array
|
||||||
|
description: List of pool l2 transactions
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/PoolL2Transaction'
|
||||||
TransactionId:
|
TransactionId:
|
||||||
type: string
|
type: string
|
||||||
description: Identifier for transactions. Used for any kind of transaction (both L1 and L2). More info on how the identifiers are built [here](https://idocs.hermez.io/#/spec/architecture/db/README?id=txid)
|
description: Identifier for transactions. Used for any kind of transaction (both L1 and L2). More info on how the identifiers are built [here](https://idocs.hermez.io/#/spec/architecture/db/README?id=txid)
|
||||||
|
|||||||
@@ -55,6 +55,35 @@ func (a *API) getPoolTx(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, tx)
|
c.JSON(http.StatusOK, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *API) getPoolTxs(c *gin.Context) {
|
||||||
|
// Get idx
|
||||||
|
idx, err := parseIdx(c)
|
||||||
|
if err != nil {
|
||||||
|
retBadReq(err, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Get state
|
||||||
|
state, err := parseQueryPoolL2TxState(c)
|
||||||
|
if err != nil {
|
||||||
|
retBadReq(err, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Fetch txs from l2DB
|
||||||
|
txs, err := a.l2.GetPoolTxs(idx, state)
|
||||||
|
if err != nil {
|
||||||
|
retSQLErr(err, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build successful response
|
||||||
|
type txsResponse struct {
|
||||||
|
Txs []*l2db.PoolTxAPI `json:"transactions"`
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, &txsResponse{
|
||||||
|
Txs: txs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type receivedPoolTx struct {
|
type receivedPoolTx struct {
|
||||||
TxID common.TxID `json:"id" binding:"required"`
|
TxID common.TxID `json:"id" binding:"required"`
|
||||||
Type common.TxType `json:"type" binding:"required"`
|
Type common.TxType `json:"type" binding:"required"`
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ type testPoolTxReceive struct {
|
|||||||
Token historydb.TokenWithUSD `json:"token"`
|
Token historydb.TokenWithUSD `json:"token"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type testPoolTxsResponse struct {
|
||||||
|
Txs []testPoolTxReceive `json:"transactions"`
|
||||||
|
}
|
||||||
|
|
||||||
// testPoolTxSend is a struct to be used as a JSON body
|
// testPoolTxSend is a struct to be used as a JSON body
|
||||||
// when testing POST /transactions-pool
|
// when testing POST /transactions-pool
|
||||||
type testPoolTxSend struct {
|
type testPoolTxSend struct {
|
||||||
@@ -224,6 +228,25 @@ func TestPoolTxs(t *testing.T) {
|
|||||||
jsonTxReader = bytes.NewReader(jsonTxBytes)
|
jsonTxReader = bytes.NewReader(jsonTxBytes)
|
||||||
err = doBadReq("POST", endpoint, jsonTxReader, 400)
|
err = doBadReq("POST", endpoint, jsonTxReader, 400)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
// GET
|
||||||
|
// get by idx
|
||||||
|
fetchedTxs := testPoolTxsResponse{}
|
||||||
|
require.NoError(t, doGoodReq(
|
||||||
|
"GET",
|
||||||
|
endpoint+"?accountIndex=hez:ETH:263",
|
||||||
|
nil, &fetchedTxs))
|
||||||
|
assert.Equal(t, 1, len(fetchedTxs.Txs))
|
||||||
|
assert.Equal(t, "hez:ETH:263", fetchedTxs.Txs[0].FromIdx)
|
||||||
|
// get by state
|
||||||
|
require.NoError(t, doGoodReq(
|
||||||
|
"GET",
|
||||||
|
endpoint+"?state=pend",
|
||||||
|
nil, &fetchedTxs))
|
||||||
|
assert.Equal(t, 4, len(fetchedTxs.Txs))
|
||||||
|
for _, v := range fetchedTxs.Txs {
|
||||||
|
assert.Equal(t, common.PoolL2TxStatePending, v.State)
|
||||||
|
}
|
||||||
|
|
||||||
// GET
|
// GET
|
||||||
endpoint += "/"
|
endpoint += "/"
|
||||||
for _, tx := range tc.poolTxsToReceive {
|
for _, tx := range tc.poolTxsToReceive {
|
||||||
|
|||||||
@@ -127,3 +127,41 @@ func (l2db *L2DB) GetTxAPI(txID common.TxID) (*PoolTxAPI, error) {
|
|||||||
txID,
|
txID,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l2db *L2DB) GetPoolTxs(idx *common.Idx, state *common.PoolL2TxState) ([]*PoolTxAPI, error) {
|
||||||
|
cancel, err := l2db.apiConnCon.Acquire()
|
||||||
|
defer cancel()
|
||||||
|
if err != nil {
|
||||||
|
return nil, tracerr.Wrap(err)
|
||||||
|
}
|
||||||
|
defer l2db.apiConnCon.Release()
|
||||||
|
// Apply filters
|
||||||
|
nextIsAnd := false
|
||||||
|
queryStr := selectPoolTxAPI
|
||||||
|
var args []interface{}
|
||||||
|
if state != nil {
|
||||||
|
queryStr += "WHERE state = ? "
|
||||||
|
args = append(args, state)
|
||||||
|
nextIsAnd = true
|
||||||
|
}
|
||||||
|
if idx != nil {
|
||||||
|
if nextIsAnd {
|
||||||
|
queryStr += "AND ("
|
||||||
|
} else {
|
||||||
|
queryStr += "WHERE ("
|
||||||
|
}
|
||||||
|
queryStr += "tx_pool.from_idx = ? "
|
||||||
|
queryStr += "OR tx_pool.to_idx = ?) "
|
||||||
|
args = append(args, idx)
|
||||||
|
args = append(args, idx)
|
||||||
|
nextIsAnd = true
|
||||||
|
}
|
||||||
|
queryStr += "AND NOT external_delete;"
|
||||||
|
query := l2db.dbRead.Rebind(queryStr)
|
||||||
|
txs := []*PoolTxAPI{}
|
||||||
|
err = meddler.QueryAll(
|
||||||
|
l2db.dbRead, &txs,
|
||||||
|
query,
|
||||||
|
args...)
|
||||||
|
return txs, tracerr.Wrap(err)
|
||||||
|
}
|
||||||
|
|||||||
@@ -311,6 +311,27 @@ func TestGetPending(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestL2DB_GetPoolTxs(t *testing.T) {
|
||||||
|
err := prepareHistoryDB(historyDB)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error prepare historyDB", err)
|
||||||
|
}
|
||||||
|
poolL2Txs, err := generatePoolL2Txs()
|
||||||
|
state := common.PoolL2TxState("pend")
|
||||||
|
idx := common.Idx(256)
|
||||||
|
var pendingTxs []*common.PoolL2Tx
|
||||||
|
for i := range poolL2Txs {
|
||||||
|
if poolL2Txs[i].FromIdx == idx || poolL2Txs[i].ToIdx == idx {
|
||||||
|
err := l2DB.AddTxTest(&poolL2Txs[i])
|
||||||
|
require.NoError(t, err)
|
||||||
|
pendingTxs = append(pendingTxs, &poolL2Txs[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetchedTxs, err := l2DBWithACC.GetPoolTxs(&idx, &state)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, len(pendingTxs), len(fetchedTxs))
|
||||||
|
}
|
||||||
|
|
||||||
func TestStartForging(t *testing.T) {
|
func TestStartForging(t *testing.T) {
|
||||||
// Generate txs
|
// Generate txs
|
||||||
var fakeBatchNum common.BatchNum = 33
|
var fakeBatchNum common.BatchNum = 33
|
||||||
|
|||||||
Reference in New Issue
Block a user