diff --git a/api/batch.go b/api/batch.go index 8d90ce0..52573ab 100644 --- a/api/batch.go +++ b/api/batch.go @@ -109,7 +109,7 @@ func (a *API) getFullBatch(c *gin.Context) { // Fetch txs forged in the batch from historyDB maxTxsPerBatch := uint(2048) //nolint:gomnd txs, _, err := a.h.GetTxsAPI( - nil, nil, nil, nil, batchNum, nil, nil, &maxTxsPerBatch, historydb.OrderAsc, + nil, nil, nil, nil, nil, batchNum, nil, nil, &maxTxsPerBatch, historydb.OrderAsc, ) if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows { retSQLErr(err, c) diff --git a/api/parsers.go b/api/parsers.go index 6968552..e8b4113 100644 --- a/api/parsers.go +++ b/api/parsers.go @@ -219,6 +219,47 @@ func parseExitFilters(c querier) (*common.TokenID, *ethCommon.Address, *babyjub. return tokenID, addr, bjj, idx, nil } +func parseTxsHistoryFilters(c querier) (*common.TokenID, *ethCommon.Address, + *babyjub.PublicKeyComp, *common.Idx, *common.Idx, error) { + // TokenID + tid, err := parseQueryUint("tokenId", nil, 0, maxUint32, c) + if err != nil { + return nil, nil, nil, nil, nil, tracerr.Wrap(err) + } + var tokenID *common.TokenID + if tid != nil { + tokenID = new(common.TokenID) + *tokenID = common.TokenID(*tid) + } + // Hez Eth addr + addr, err := parseQueryHezEthAddr(c) + if err != nil { + return nil, nil, nil, nil, nil, tracerr.Wrap(err) + } + // BJJ + bjj, err := parseQueryBJJ(c) + if err != nil { + return nil, nil, nil, nil, nil, tracerr.Wrap(err) + } + if addr != nil && bjj != nil { + return nil, nil, nil, nil, nil, tracerr.Wrap(errors.New("bjj and hezEthereumAddress params are incompatible")) + } + // from Idx + fromIdx, err := parseFromIdx(c) + if err != nil { + return nil, nil, nil, nil, nil, tracerr.Wrap(err) + } + // to Idx + toIdx, err := parseToIdx(c) + if err != nil { + return nil, nil, nil, nil, nil, tracerr.Wrap(err) + } + if (fromIdx != nil || toIdx != nil) && (addr != nil || bjj != nil || tokenID != nil) { + return nil, nil, nil, nil, nil, tracerr.Wrap(errors.New("accountIndex is incompatible with BJJ, hezEthereumAddress and tokenId")) + } + return tokenID, addr, bjj, fromIdx, toIdx, nil +} + func parseTokenFilters(c querier) ([]common.TokenID, []string, string, error) { idsStr := c.Query("ids") symbolsStr := c.Query("symbols") diff --git a/api/swagger.yml b/api/swagger.yml index 9dd3caf..6b3d805 100644 --- a/api/swagger.yml +++ b/api/swagger.yml @@ -536,10 +536,16 @@ paths: required: false schema: $ref: '#/components/schemas/BJJ' - - name: accountIndex + - name: fromAccountIndex + in: query + required: false + description: Only get transactions sent from a specific account. Incompatible with the queries `tokenId`, `hezEthereumAddress` and `BJJ`. + schema: + $ref: '#/components/schemas/AccountIndex' + - name: toAccountIndex in: query required: false - description: Only get transactions sent from or to a specific account. Incompatible with the queries `tokenId`, `hezEthereumAddress` and `BJJ`. + description: Only get transactions sent to a specific account. Incompatible with the queries `tokenId`, `hezEthereumAddress` and `BJJ`. schema: $ref: '#/components/schemas/AccountIndex' - name: batchNum diff --git a/api/txshistory.go b/api/txshistory.go index d42dca6..dcfb0b3 100644 --- a/api/txshistory.go +++ b/api/txshistory.go @@ -9,7 +9,7 @@ import ( func (a *API) getHistoryTxs(c *gin.Context) { // Get query parameters - tokenID, addr, bjj, idx, err := parseExitFilters(c) + tokenID, addr, bjj, fromIdx, toIdx, err := parseTxsHistoryFilters(c) if err != nil { retBadReq(err, c) return @@ -35,7 +35,7 @@ func (a *API) getHistoryTxs(c *gin.Context) { // Fetch txs from historyDB txs, pendingItems, err := a.h.GetTxsAPI( - addr, bjj, tokenID, idx, batchNum, txType, fromItem, limit, order, + addr, bjj, tokenID, fromIdx, toIdx, batchNum, txType, fromItem, limit, order, ) if err != nil { retSQLErr(err, c) diff --git a/api/txshistory_test.go b/api/txshistory_test.go index 752ce74..6735f15 100644 --- a/api/txshistory_test.go +++ b/api/txshistory_test.go @@ -324,8 +324,8 @@ func TestGetHistoryTxs(t *testing.T) { idx, err := stringToIdx(idxStr, "") assert.NoError(t, err) path = fmt.Sprintf( - "%s?accountIndex=%s&limit=%d", - endpoint, idxStr, limit, + "%s?fromAccountIndex=%s&toAccountIndex=%s&limit=%d", + endpoint, idx, idx, limit, ) err = doGoodReqPaginated(path, historydb.OrderAsc, &testTxsResponse{}, appendIter) assert.NoError(t, err) @@ -431,8 +431,8 @@ func TestGetHistoryTxs(t *testing.T) { assertTxs(t, []testTx{}, fetchedTxs) // 400 path = fmt.Sprintf( - "%s?accountIndex=%s&hezEthereumAddress=%s", - endpoint, idx, account.EthAddr, + "%s?fromAccountIndex=%s&toAccountIndex=%s&hezEthereumAddress=%s", + endpoint, idx, idx, account.EthAddr, ) err = doBadReq("GET", path, nil, 400) assert.NoError(t, err) diff --git a/api/txspool_test.go b/api/txspool_test.go index e102ce7..be4648d 100644 --- a/api/txspool_test.go +++ b/api/txspool_test.go @@ -246,7 +246,6 @@ func TestPoolTxs(t *testing.T) { for _, v := range fetchedTxs.Txs { assert.Equal(t, common.PoolL2TxStatePending, v.State) } - // GET endpoint += "/" for _, tx := range tc.poolTxsToReceive { diff --git a/db/historydb/apiqueries.go b/db/historydb/apiqueries.go index e3dfad1..40366d5 100644 --- a/db/historydb/apiqueries.go +++ b/db/historydb/apiqueries.go @@ -456,7 +456,7 @@ func (hdb *HistoryDB) GetTxAPI(txID common.TxID) (*TxAPI, error) { // and pagination info func (hdb *HistoryDB) GetTxsAPI( ethAddr *ethCommon.Address, bjj *babyjub.PublicKeyComp, - tokenID *common.TokenID, idx *common.Idx, batchNum *uint, txType *common.TxType, + tokenID *common.TokenID, fromIdx, toIdx *common.Idx, batchNum *uint, txType *common.TxType, fromItem, limit *uint, order string, ) ([]TxAPI, uint64, error) { // Warning: amount_success and deposit_amount_success have true as default for @@ -508,14 +508,32 @@ func (hdb *HistoryDB) GetTxsAPI( nextIsAnd = true } // idx filter - if idx != nil { + if fromIdx != nil && toIdx != nil { + if nextIsAnd { + queryStr += "AND " + } else { + queryStr += "WHERE " + } + queryStr += "(tx.effective_from_idx = ? " + queryStr += "OR tx.to_idx = ?) " + args = append(args, fromIdx, toIdx) + nextIsAnd = true + } else if fromIdx != nil { + if nextIsAnd { + queryStr += "AND " + } else { + queryStr += "WHERE " + } + queryStr += "tx.effective_from_idx = ? " + nextIsAnd = true + } else if toIdx != nil { if nextIsAnd { queryStr += "AND " } else { queryStr += "WHERE " } - queryStr += "(tx.effective_from_idx = ? OR tx.to_idx = ?) " - args = append(args, idx, idx) + queryStr += "tx.to_idx = ? " + args = append(args, toIdx) nextIsAnd = true } // batchNum filter diff --git a/db/l2db/apiqueries.go b/db/l2db/apiqueries.go index a04e342..3c1fb7b 100644 --- a/db/l2db/apiqueries.go +++ b/db/l2db/apiqueries.go @@ -154,15 +154,14 @@ func (l2db *L2DB) GetPoolTxs(fromIdx, toIdx *common.Idx, state *common.PoolL2TxS } queryStr += "tx_pool.from_idx = ? " queryStr += "OR tx_pool.to_idx = ?) " - args = append(args, fromIdx) - args = append(args, toIdx) + args = append(args, fromIdx, toIdx) } else if fromIdx != nil { if nextIsAnd { queryStr += "AND " } else { queryStr += "WHERE " } - queryStr += "tx_pool.from_idx = ?" + queryStr += "tx_pool.from_idx = ? " args = append(args, fromIdx) } else if toIdx != nil { if nextIsAnd { @@ -170,7 +169,7 @@ func (l2db *L2DB) GetPoolTxs(fromIdx, toIdx *common.Idx, state *common.PoolL2TxS } else { queryStr += "WHERE " } - queryStr += "tx_pool.to_idx = ?" + queryStr += "tx_pool.to_idx = ? " args = append(args, toIdx) } queryStr += "AND NOT external_delete;"