Browse Source

implemented get pool txs endpoint

feature/getPoolTxs
Mikelle 3 years ago
parent
commit
c84b3a4d0f
7 changed files with 189 additions and 0 deletions
  1. +1
    -0
      api/api.go
  2. +26
    -0
      api/parsers.go
  3. +51
    -0
      api/swagger.yml
  4. +29
    -0
      api/txspool.go
  5. +23
    -0
      api/txspool_test.go
  6. +38
    -0
      db/l2db/apiqueries.go
  7. +21
    -0
      db/l2db/l2db_test.go

+ 1
- 0
api/api.go

@ -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

+ 26
- 0
api/parsers.go

@ -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)

+ 51
- 0
api/swagger.yml

@ -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)

+ 29
- 0
api/txspool.go

@ -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"`

+ 23
- 0
api/txspool_test.go

@ -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 {

+ 38
- 0
db/l2db/apiqueries.go

@ -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)
}

+ 21
- 0
db/l2db/l2db_test.go

@ -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

Loading…
Cancel
Save