You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

956 lines
28 KiB

  1. package historydb
  2. import (
  3. "errors"
  4. "fmt"
  5. ethCommon "github.com/ethereum/go-ethereum/common"
  6. "github.com/hermeznetwork/hermez-node/common"
  7. "github.com/hermeznetwork/hermez-node/db"
  8. "github.com/hermeznetwork/tracerr"
  9. "github.com/iden3/go-iden3-crypto/babyjub"
  10. "github.com/jmoiron/sqlx"
  11. "github.com/russross/meddler"
  12. )
  13. // GetLastBlockAPI retrieve the block with the highest block number from the DB
  14. func (hdb *HistoryDB) GetLastBlockAPI() (*common.Block, error) {
  15. cancel, err := hdb.apiConnCon.Acquire()
  16. defer cancel()
  17. if err != nil {
  18. return nil, tracerr.Wrap(err)
  19. }
  20. defer hdb.apiConnCon.Release()
  21. return hdb.GetLastBlock()
  22. }
  23. // GetBatchAPI return the batch with the given batchNum
  24. func (hdb *HistoryDB) GetBatchAPI(batchNum common.BatchNum) (*BatchAPI, error) {
  25. cancel, err := hdb.apiConnCon.Acquire()
  26. defer cancel()
  27. if err != nil {
  28. return nil, tracerr.Wrap(err)
  29. }
  30. defer hdb.apiConnCon.Release()
  31. return hdb.getBatchAPI(hdb.dbRead, batchNum)
  32. }
  33. func (hdb *HistoryDB) getBatchAPI(d meddler.DB, batchNum common.BatchNum) (*BatchAPI, error) {
  34. batch := &BatchAPI{}
  35. return batch, tracerr.Wrap(meddler.QueryRow(
  36. d, batch,
  37. `SELECT batch.item_id, batch.batch_num, batch.eth_block_num,
  38. batch.forger_addr, batch.fees_collected, batch.total_fees_usd, batch.state_root,
  39. batch.num_accounts, batch.exit_root, batch.forge_l1_txs_num, batch.slot_num,
  40. block.timestamp, block.hash,
  41. COALESCE ((SELECT COUNT(*) FROM tx WHERE batch_num = batch.batch_num), 0) AS forged_txs
  42. FROM batch INNER JOIN block ON batch.eth_block_num = block.eth_block_num
  43. WHERE batch_num = $1;`, batchNum,
  44. ))
  45. }
  46. // GetBatchesAPI return the batches applying the given filters
  47. func (hdb *HistoryDB) GetBatchesAPI(
  48. minBatchNum, maxBatchNum, slotNum *uint,
  49. forgerAddr *ethCommon.Address,
  50. fromItem, limit *uint, order string,
  51. ) ([]BatchAPI, uint64, error) {
  52. cancel, err := hdb.apiConnCon.Acquire()
  53. defer cancel()
  54. if err != nil {
  55. return nil, 0, tracerr.Wrap(err)
  56. }
  57. defer hdb.apiConnCon.Release()
  58. var query string
  59. var args []interface{}
  60. queryStr := `SELECT batch.item_id, batch.batch_num, batch.eth_block_num,
  61. batch.forger_addr, batch.fees_collected, batch.total_fees_usd, batch.state_root,
  62. batch.num_accounts, batch.exit_root, batch.forge_l1_txs_num, batch.slot_num,
  63. block.timestamp, block.hash,
  64. COALESCE ((SELECT COUNT(*) FROM tx WHERE batch_num = batch.batch_num), 0) AS forged_txs,
  65. count(*) OVER() AS total_items
  66. FROM batch INNER JOIN block ON batch.eth_block_num = block.eth_block_num `
  67. // Apply filters
  68. nextIsAnd := false
  69. // minBatchNum filter
  70. if minBatchNum != nil {
  71. if nextIsAnd {
  72. queryStr += "AND "
  73. } else {
  74. queryStr += "WHERE "
  75. }
  76. queryStr += "batch.batch_num > ? "
  77. args = append(args, minBatchNum)
  78. nextIsAnd = true
  79. }
  80. // maxBatchNum filter
  81. if maxBatchNum != nil {
  82. if nextIsAnd {
  83. queryStr += "AND "
  84. } else {
  85. queryStr += "WHERE "
  86. }
  87. queryStr += "batch.batch_num < ? "
  88. args = append(args, maxBatchNum)
  89. nextIsAnd = true
  90. }
  91. // slotNum filter
  92. if slotNum != nil {
  93. if nextIsAnd {
  94. queryStr += "AND "
  95. } else {
  96. queryStr += "WHERE "
  97. }
  98. queryStr += "batch.slot_num = ? "
  99. args = append(args, slotNum)
  100. nextIsAnd = true
  101. }
  102. // forgerAddr filter
  103. if forgerAddr != nil {
  104. if nextIsAnd {
  105. queryStr += "AND "
  106. } else {
  107. queryStr += "WHERE "
  108. }
  109. queryStr += "batch.forger_addr = ? "
  110. args = append(args, forgerAddr)
  111. nextIsAnd = true
  112. }
  113. // pagination
  114. if fromItem != nil {
  115. if nextIsAnd {
  116. queryStr += "AND "
  117. } else {
  118. queryStr += "WHERE "
  119. }
  120. if order == OrderAsc {
  121. queryStr += "batch.item_id >= ? "
  122. } else {
  123. queryStr += "batch.item_id <= ? "
  124. }
  125. args = append(args, fromItem)
  126. }
  127. queryStr += "ORDER BY batch.item_id "
  128. if order == OrderAsc {
  129. queryStr += " ASC "
  130. } else {
  131. queryStr += " DESC "
  132. }
  133. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  134. query = hdb.dbRead.Rebind(queryStr)
  135. // log.Debug(query)
  136. batchPtrs := []*BatchAPI{}
  137. if err := meddler.QueryAll(hdb.dbRead, &batchPtrs, query, args...); err != nil {
  138. return nil, 0, tracerr.Wrap(err)
  139. }
  140. batches := db.SlicePtrsToSlice(batchPtrs).([]BatchAPI)
  141. if len(batches) == 0 {
  142. return batches, 0, nil
  143. }
  144. return batches, batches[0].TotalItems - uint64(len(batches)), nil
  145. }
  146. // GetBestBidAPI returns the best bid in specific slot by slotNum
  147. func (hdb *HistoryDB) GetBestBidAPI(slotNum *int64) (BidAPI, error) {
  148. bid := &BidAPI{}
  149. cancel, err := hdb.apiConnCon.Acquire()
  150. defer cancel()
  151. if err != nil {
  152. return *bid, tracerr.Wrap(err)
  153. }
  154. defer hdb.apiConnCon.Release()
  155. err = meddler.QueryRow(
  156. hdb.dbRead, bid, `SELECT bid.*, block.timestamp, coordinator.forger_addr, coordinator.url
  157. FROM bid INNER JOIN block ON bid.eth_block_num = block.eth_block_num
  158. INNER JOIN (
  159. SELECT bidder_addr, MAX(item_id) AS item_id FROM coordinator
  160. GROUP BY bidder_addr
  161. ) c ON bid.bidder_addr = c.bidder_addr
  162. INNER JOIN coordinator ON c.item_id = coordinator.item_id
  163. WHERE slot_num = $1 ORDER BY item_id DESC LIMIT 1;`, slotNum,
  164. )
  165. return *bid, tracerr.Wrap(err)
  166. }
  167. // GetBestBidsAPI returns the best bid in specific slot by slotNum
  168. func (hdb *HistoryDB) GetBestBidsAPI(
  169. minSlotNum, maxSlotNum *int64,
  170. bidderAddr *ethCommon.Address,
  171. limit *uint, order string,
  172. ) ([]BidAPI, uint64, error) {
  173. cancel, err := hdb.apiConnCon.Acquire()
  174. defer cancel()
  175. if err != nil {
  176. return nil, 0, tracerr.Wrap(err)
  177. }
  178. defer hdb.apiConnCon.Release()
  179. return hdb.getBestBidsAPI(hdb.dbRead, minSlotNum, maxSlotNum, bidderAddr, limit, order)
  180. }
  181. func (hdb *HistoryDB) getBestBidsAPI(
  182. d meddler.DB,
  183. minSlotNum, maxSlotNum *int64,
  184. bidderAddr *ethCommon.Address,
  185. limit *uint, order string,
  186. ) ([]BidAPI, uint64, error) {
  187. var query string
  188. var args []interface{}
  189. // JOIN the best bid of each slot with the latest update of each coordinator
  190. queryStr := `SELECT b.*, block.timestamp, coordinator.forger_addr, coordinator.url,
  191. COUNT(*) OVER() AS total_items FROM (
  192. SELECT slot_num, MAX(item_id) as maxitem
  193. FROM bid GROUP BY slot_num
  194. )
  195. AS x INNER JOIN bid AS b ON b.item_id = x.maxitem
  196. INNER JOIN block ON b.eth_block_num = block.eth_block_num
  197. INNER JOIN (
  198. SELECT bidder_addr, MAX(item_id) AS item_id FROM coordinator
  199. GROUP BY bidder_addr
  200. ) c ON b.bidder_addr = c.bidder_addr
  201. INNER JOIN coordinator ON c.item_id = coordinator.item_id
  202. WHERE (b.slot_num >= ? AND b.slot_num <= ?)`
  203. args = append(args, minSlotNum)
  204. args = append(args, maxSlotNum)
  205. // Apply filters
  206. if bidderAddr != nil {
  207. queryStr += " AND b.bidder_addr = ? "
  208. args = append(args, bidderAddr)
  209. }
  210. queryStr += " ORDER BY b.slot_num "
  211. if order == OrderAsc {
  212. queryStr += "ASC "
  213. } else {
  214. queryStr += "DESC "
  215. }
  216. if limit != nil {
  217. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  218. }
  219. query = hdb.dbRead.Rebind(queryStr)
  220. bidPtrs := []*BidAPI{}
  221. if err := meddler.QueryAll(d, &bidPtrs, query, args...); err != nil {
  222. return nil, 0, tracerr.Wrap(err)
  223. }
  224. // log.Debug(query)
  225. bids := db.SlicePtrsToSlice(bidPtrs).([]BidAPI)
  226. if len(bids) == 0 {
  227. return bids, 0, nil
  228. }
  229. return bids, bids[0].TotalItems - uint64(len(bids)), nil
  230. }
  231. // GetBidsAPI return the bids applying the given filters
  232. func (hdb *HistoryDB) GetBidsAPI(
  233. slotNum *int64, bidderAddr *ethCommon.Address,
  234. fromItem, limit *uint, order string,
  235. ) ([]BidAPI, uint64, error) {
  236. cancel, err := hdb.apiConnCon.Acquire()
  237. defer cancel()
  238. if err != nil {
  239. return nil, 0, tracerr.Wrap(err)
  240. }
  241. defer hdb.apiConnCon.Release()
  242. var query string
  243. var args []interface{}
  244. // JOIN each bid with the latest update of each coordinator
  245. queryStr := `SELECT bid.*, block.timestamp, coord.forger_addr, coord.url,
  246. COUNT(*) OVER() AS total_items
  247. FROM bid INNER JOIN block ON bid.eth_block_num = block.eth_block_num
  248. INNER JOIN (
  249. SELECT bidder_addr, MAX(item_id) AS item_id FROM coordinator
  250. GROUP BY bidder_addr
  251. ) c ON bid.bidder_addr = c.bidder_addr
  252. INNER JOIN coordinator coord ON c.item_id = coord.item_id `
  253. // Apply filters
  254. nextIsAnd := false
  255. // slotNum filter
  256. if slotNum != nil {
  257. if nextIsAnd {
  258. queryStr += "AND "
  259. } else {
  260. queryStr += "WHERE "
  261. }
  262. queryStr += "bid.slot_num = ? "
  263. args = append(args, slotNum)
  264. nextIsAnd = true
  265. }
  266. // bidder filter
  267. if bidderAddr != nil {
  268. if nextIsAnd {
  269. queryStr += "AND "
  270. } else {
  271. queryStr += "WHERE "
  272. }
  273. queryStr += "bid.bidder_addr = ? "
  274. args = append(args, bidderAddr)
  275. nextIsAnd = true
  276. }
  277. if fromItem != nil {
  278. if nextIsAnd {
  279. queryStr += "AND "
  280. } else {
  281. queryStr += "WHERE "
  282. }
  283. if order == OrderAsc {
  284. queryStr += "bid.item_id >= ? "
  285. } else {
  286. queryStr += "bid.item_id <= ? "
  287. }
  288. args = append(args, fromItem)
  289. }
  290. // pagination
  291. queryStr += "ORDER BY bid.item_id "
  292. if order == OrderAsc {
  293. queryStr += "ASC "
  294. } else {
  295. queryStr += "DESC "
  296. }
  297. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  298. query, argsQ, err := sqlx.In(queryStr, args...)
  299. if err != nil {
  300. return nil, 0, tracerr.Wrap(err)
  301. }
  302. query = hdb.dbRead.Rebind(query)
  303. bids := []*BidAPI{}
  304. if err := meddler.QueryAll(hdb.dbRead, &bids, query, argsQ...); err != nil {
  305. return nil, 0, tracerr.Wrap(err)
  306. }
  307. if len(bids) == 0 {
  308. return []BidAPI{}, 0, nil
  309. }
  310. return db.SlicePtrsToSlice(bids).([]BidAPI), bids[0].TotalItems - uint64(len(bids)), nil
  311. }
  312. // GetTokenAPI returns a token from the DB given a TokenID
  313. func (hdb *HistoryDB) GetTokenAPI(tokenID common.TokenID) (*TokenWithUSD, error) {
  314. cancel, err := hdb.apiConnCon.Acquire()
  315. defer cancel()
  316. if err != nil {
  317. return nil, tracerr.Wrap(err)
  318. }
  319. defer hdb.apiConnCon.Release()
  320. return hdb.GetToken(tokenID)
  321. }
  322. // GetTokensAPI returns a list of tokens from the DB
  323. func (hdb *HistoryDB) GetTokensAPI(
  324. ids []common.TokenID, symbols []string, name string, fromItem,
  325. limit *uint, order string,
  326. ) ([]TokenWithUSD, uint64, error) {
  327. cancel, err := hdb.apiConnCon.Acquire()
  328. defer cancel()
  329. if err != nil {
  330. return nil, 0, tracerr.Wrap(err)
  331. }
  332. defer hdb.apiConnCon.Release()
  333. var query string
  334. var args []interface{}
  335. queryStr := `SELECT * , COUNT(*) OVER() AS total_items FROM token `
  336. // Apply filters
  337. nextIsAnd := false
  338. if len(ids) > 0 {
  339. queryStr += "WHERE token_id IN (?) "
  340. nextIsAnd = true
  341. args = append(args, ids)
  342. }
  343. if len(symbols) > 0 {
  344. if nextIsAnd {
  345. queryStr += "AND "
  346. } else {
  347. queryStr += "WHERE "
  348. }
  349. queryStr += "symbol IN (?) "
  350. args = append(args, symbols)
  351. nextIsAnd = true
  352. }
  353. if name != "" {
  354. if nextIsAnd {
  355. queryStr += "AND "
  356. } else {
  357. queryStr += "WHERE "
  358. }
  359. queryStr += "name ~ ? "
  360. args = append(args, name)
  361. nextIsAnd = true
  362. }
  363. if fromItem != nil {
  364. if nextIsAnd {
  365. queryStr += "AND "
  366. } else {
  367. queryStr += "WHERE "
  368. }
  369. if order == OrderAsc {
  370. queryStr += "item_id >= ? "
  371. } else {
  372. queryStr += "item_id <= ? "
  373. }
  374. args = append(args, fromItem)
  375. }
  376. // pagination
  377. queryStr += "ORDER BY item_id "
  378. if order == OrderAsc {
  379. queryStr += "ASC "
  380. } else {
  381. queryStr += "DESC "
  382. }
  383. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  384. query, argsQ, err := sqlx.In(queryStr, args...)
  385. if err != nil {
  386. return nil, 0, tracerr.Wrap(err)
  387. }
  388. query = hdb.dbRead.Rebind(query)
  389. tokens := []*TokenWithUSD{}
  390. if err := meddler.QueryAll(hdb.dbRead, &tokens, query, argsQ...); err != nil {
  391. return nil, 0, tracerr.Wrap(err)
  392. }
  393. if len(tokens) == 0 {
  394. return []TokenWithUSD{}, 0, nil
  395. }
  396. return db.SlicePtrsToSlice(tokens).([]TokenWithUSD), uint64(len(tokens)) - tokens[0].TotalItems, nil
  397. }
  398. // GetTxAPI returns a tx from the DB given a TxID
  399. func (hdb *HistoryDB) GetTxAPI(txID common.TxID) (*TxAPI, error) {
  400. // Warning: amount_success and deposit_amount_success have true as default for
  401. // performance reasons. The expected default value is false (when txs are unforged)
  402. // this case is handled at the function func (tx TxAPI) MarshalJSON() ([]byte, error)
  403. cancel, err := hdb.apiConnCon.Acquire()
  404. defer cancel()
  405. if err != nil {
  406. return nil, tracerr.Wrap(err)
  407. }
  408. defer hdb.apiConnCon.Release()
  409. tx := &TxAPI{}
  410. err = meddler.QueryRow(
  411. hdb.dbRead, tx, `SELECT tx.item_id, tx.is_l1, tx.id, tx.type, tx.position,
  412. hez_idx(tx.effective_from_idx, token.symbol) AS from_idx, tx.from_eth_addr, tx.from_bjj,
  413. hez_idx(tx.to_idx, token.symbol) AS to_idx, tx.to_eth_addr, tx.to_bjj,
  414. tx.amount, tx.amount_success, tx.token_id, tx.amount_usd,
  415. tx.batch_num, tx.eth_block_num, tx.to_forge_l1_txs_num, tx.user_origin,
  416. tx.deposit_amount, tx.deposit_amount_usd, tx.deposit_amount_success, tx.fee, tx.fee_usd, tx.nonce,
  417. token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
  418. token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
  419. token.usd_update, block.timestamp
  420. FROM tx INNER JOIN token ON tx.token_id = token.token_id
  421. INNER JOIN block ON tx.eth_block_num = block.eth_block_num
  422. WHERE tx.id = $1;`, txID,
  423. )
  424. return tx, tracerr.Wrap(err)
  425. }
  426. // GetTxsAPI returns a list of txs from the DB using the HistoryTx struct
  427. // and pagination info
  428. func (hdb *HistoryDB) GetTxsAPI(
  429. ethAddr *ethCommon.Address, bjj *babyjub.PublicKeyComp,
  430. tokenID *common.TokenID, idx *common.Idx, batchNum *uint, txType *common.TxType,
  431. fromItem, limit *uint, order string,
  432. ) ([]TxAPI, uint64, error) {
  433. // Warning: amount_success and deposit_amount_success have true as default for
  434. // performance reasons. The expected default value is false (when txs are unforged)
  435. // this case is handled at the function func (tx TxAPI) MarshalJSON() ([]byte, error)
  436. cancel, err := hdb.apiConnCon.Acquire()
  437. defer cancel()
  438. if err != nil {
  439. return nil, 0, tracerr.Wrap(err)
  440. }
  441. defer hdb.apiConnCon.Release()
  442. if ethAddr != nil && bjj != nil {
  443. return nil, 0, tracerr.Wrap(errors.New("ethAddr and bjj are incompatible"))
  444. }
  445. var query string
  446. var args []interface{}
  447. queryStr := `SELECT tx.item_id, tx.is_l1, tx.id, tx.type, tx.position,
  448. hez_idx(tx.effective_from_idx, token.symbol) AS from_idx, tx.from_eth_addr, tx.from_bjj,
  449. hez_idx(tx.to_idx, token.symbol) AS to_idx, tx.to_eth_addr, tx.to_bjj,
  450. tx.amount, tx.amount_success, tx.token_id, tx.amount_usd,
  451. tx.batch_num, tx.eth_block_num, tx.to_forge_l1_txs_num, tx.user_origin,
  452. tx.deposit_amount, tx.deposit_amount_usd, tx.deposit_amount_success, tx.fee, tx.fee_usd, tx.nonce,
  453. token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
  454. token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
  455. token.usd_update, block.timestamp, count(*) OVER() AS total_items
  456. FROM tx INNER JOIN token ON tx.token_id = token.token_id
  457. INNER JOIN block ON tx.eth_block_num = block.eth_block_num `
  458. // Apply filters
  459. nextIsAnd := false
  460. // ethAddr filter
  461. if ethAddr != nil {
  462. queryStr += "WHERE (tx.from_eth_addr = ? OR tx.to_eth_addr = ?) "
  463. nextIsAnd = true
  464. args = append(args, ethAddr, ethAddr)
  465. } else if bjj != nil { // bjj filter
  466. queryStr += "WHERE (tx.from_bjj = ? OR tx.to_bjj = ?) "
  467. nextIsAnd = true
  468. args = append(args, bjj, bjj)
  469. }
  470. // tokenID filter
  471. if tokenID != nil {
  472. if nextIsAnd {
  473. queryStr += "AND "
  474. } else {
  475. queryStr += "WHERE "
  476. }
  477. queryStr += "tx.token_id = ? "
  478. args = append(args, tokenID)
  479. nextIsAnd = true
  480. }
  481. // idx filter
  482. if idx != nil {
  483. if nextIsAnd {
  484. queryStr += "AND "
  485. } else {
  486. queryStr += "WHERE "
  487. }
  488. queryStr += "(tx.effective_from_idx = ? OR tx.to_idx = ?) "
  489. args = append(args, idx, idx)
  490. nextIsAnd = true
  491. }
  492. // batchNum filter
  493. if batchNum != nil {
  494. if nextIsAnd {
  495. queryStr += "AND "
  496. } else {
  497. queryStr += "WHERE "
  498. }
  499. queryStr += "tx.batch_num = ? "
  500. args = append(args, batchNum)
  501. nextIsAnd = true
  502. }
  503. // txType filter
  504. if txType != nil {
  505. if nextIsAnd {
  506. queryStr += "AND "
  507. } else {
  508. queryStr += "WHERE "
  509. }
  510. queryStr += "tx.type = ? "
  511. args = append(args, txType)
  512. nextIsAnd = true
  513. }
  514. if fromItem != nil {
  515. if nextIsAnd {
  516. queryStr += "AND "
  517. } else {
  518. queryStr += "WHERE "
  519. }
  520. if order == OrderAsc {
  521. queryStr += "tx.item_id >= ? "
  522. } else {
  523. queryStr += "tx.item_id <= ? "
  524. }
  525. args = append(args, fromItem)
  526. nextIsAnd = true
  527. }
  528. if nextIsAnd {
  529. queryStr += "AND "
  530. } else {
  531. queryStr += "WHERE "
  532. }
  533. queryStr += "tx.batch_num IS NOT NULL "
  534. // pagination
  535. queryStr += "ORDER BY tx.item_id "
  536. if order == OrderAsc {
  537. queryStr += " ASC "
  538. } else {
  539. queryStr += " DESC "
  540. }
  541. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  542. query = hdb.dbRead.Rebind(queryStr)
  543. // log.Debug(query)
  544. txsPtrs := []*TxAPI{}
  545. if err := meddler.QueryAll(hdb.dbRead, &txsPtrs, query, args...); err != nil {
  546. return nil, 0, tracerr.Wrap(err)
  547. }
  548. txs := db.SlicePtrsToSlice(txsPtrs).([]TxAPI)
  549. if len(txs) == 0 {
  550. return txs, 0, nil
  551. }
  552. return txs, txs[0].TotalItems - uint64(len(txs)), nil
  553. }
  554. // GetExitAPI returns a exit from the DB
  555. func (hdb *HistoryDB) GetExitAPI(batchNum *uint, idx *common.Idx) (*ExitAPI, error) {
  556. cancel, err := hdb.apiConnCon.Acquire()
  557. defer cancel()
  558. if err != nil {
  559. return nil, tracerr.Wrap(err)
  560. }
  561. defer hdb.apiConnCon.Release()
  562. exit := &ExitAPI{}
  563. err = meddler.QueryRow(
  564. hdb.dbRead, exit, `SELECT exit_tree.item_id, exit_tree.batch_num,
  565. hez_idx(exit_tree.account_idx, token.symbol) AS account_idx,
  566. account.bjj, account.eth_addr,
  567. exit_tree.merkle_proof, exit_tree.balance, exit_tree.instant_withdrawn,
  568. exit_tree.delayed_withdraw_request, exit_tree.delayed_withdrawn,
  569. token.token_id, token.item_id AS token_item_id,
  570. token.eth_block_num AS token_block, token.eth_addr AS token_eth_addr, token.name, token.symbol,
  571. token.decimals, token.usd, token.usd_update
  572. FROM exit_tree INNER JOIN account ON exit_tree.account_idx = account.idx
  573. INNER JOIN token ON account.token_id = token.token_id
  574. WHERE exit_tree.batch_num = $1 AND exit_tree.account_idx = $2;`, batchNum, idx,
  575. )
  576. return exit, tracerr.Wrap(err)
  577. }
  578. // GetExitsAPI returns a list of exits from the DB and pagination info
  579. func (hdb *HistoryDB) GetExitsAPI(
  580. ethAddr *ethCommon.Address, bjj *babyjub.PublicKeyComp, tokenID *common.TokenID,
  581. idx *common.Idx, batchNum *uint, onlyPendingWithdraws *bool,
  582. fromItem, limit *uint, order string,
  583. ) ([]ExitAPI, uint64, error) {
  584. if ethAddr != nil && bjj != nil {
  585. return nil, 0, tracerr.Wrap(errors.New("ethAddr and bjj are incompatible"))
  586. }
  587. cancel, err := hdb.apiConnCon.Acquire()
  588. defer cancel()
  589. if err != nil {
  590. return nil, 0, tracerr.Wrap(err)
  591. }
  592. defer hdb.apiConnCon.Release()
  593. var query string
  594. var args []interface{}
  595. queryStr := `SELECT exit_tree.item_id, exit_tree.batch_num,
  596. hez_idx(exit_tree.account_idx, token.symbol) AS account_idx,
  597. account.bjj, account.eth_addr,
  598. exit_tree.merkle_proof, exit_tree.balance, exit_tree.instant_withdrawn,
  599. exit_tree.delayed_withdraw_request, exit_tree.delayed_withdrawn,
  600. token.token_id, token.item_id AS token_item_id,
  601. token.eth_block_num AS token_block, token.eth_addr AS token_eth_addr, token.name, token.symbol,
  602. token.decimals, token.usd, token.usd_update, COUNT(*) OVER() AS total_items
  603. FROM exit_tree INNER JOIN account ON exit_tree.account_idx = account.idx
  604. INNER JOIN token ON account.token_id = token.token_id `
  605. // Apply filters
  606. nextIsAnd := false
  607. // ethAddr filter
  608. if ethAddr != nil {
  609. queryStr += "WHERE account.eth_addr = ? "
  610. nextIsAnd = true
  611. args = append(args, ethAddr)
  612. } else if bjj != nil { // bjj filter
  613. queryStr += "WHERE account.bjj = ? "
  614. nextIsAnd = true
  615. args = append(args, bjj)
  616. }
  617. // tokenID filter
  618. if tokenID != nil {
  619. if nextIsAnd {
  620. queryStr += "AND "
  621. } else {
  622. queryStr += "WHERE "
  623. }
  624. queryStr += "account.token_id = ? "
  625. args = append(args, tokenID)
  626. nextIsAnd = true
  627. }
  628. // idx filter
  629. if idx != nil {
  630. if nextIsAnd {
  631. queryStr += "AND "
  632. } else {
  633. queryStr += "WHERE "
  634. }
  635. queryStr += "exit_tree.account_idx = ? "
  636. args = append(args, idx)
  637. nextIsAnd = true
  638. }
  639. // batchNum filter
  640. if batchNum != nil {
  641. if nextIsAnd {
  642. queryStr += "AND "
  643. } else {
  644. queryStr += "WHERE "
  645. }
  646. queryStr += "exit_tree.batch_num = ? "
  647. args = append(args, batchNum)
  648. nextIsAnd = true
  649. }
  650. // onlyPendingWithdraws
  651. if onlyPendingWithdraws != nil {
  652. if *onlyPendingWithdraws {
  653. if nextIsAnd {
  654. queryStr += "AND "
  655. } else {
  656. queryStr += "WHERE "
  657. }
  658. queryStr += "(exit_tree.instant_withdrawn IS NULL AND exit_tree.delayed_withdrawn IS NULL) "
  659. nextIsAnd = true
  660. }
  661. }
  662. if fromItem != nil {
  663. if nextIsAnd {
  664. queryStr += "AND "
  665. } else {
  666. queryStr += "WHERE "
  667. }
  668. if order == OrderAsc {
  669. queryStr += "exit_tree.item_id >= ? "
  670. } else {
  671. queryStr += "exit_tree.item_id <= ? "
  672. }
  673. args = append(args, fromItem)
  674. // nextIsAnd = true
  675. }
  676. // pagination
  677. queryStr += "ORDER BY exit_tree.item_id "
  678. if order == OrderAsc {
  679. queryStr += " ASC "
  680. } else {
  681. queryStr += " DESC "
  682. }
  683. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  684. query = hdb.dbRead.Rebind(queryStr)
  685. // log.Debug(query)
  686. exits := []*ExitAPI{}
  687. if err := meddler.QueryAll(hdb.dbRead, &exits, query, args...); err != nil {
  688. return nil, 0, tracerr.Wrap(err)
  689. }
  690. if len(exits) == 0 {
  691. return []ExitAPI{}, 0, nil
  692. }
  693. return db.SlicePtrsToSlice(exits).([]ExitAPI), exits[0].TotalItems - uint64(len(exits)), nil
  694. }
  695. // GetCoordinatorsAPI returns a list of coordinators from the DB and pagination info
  696. func (hdb *HistoryDB) GetCoordinatorsAPI(
  697. bidderAddr, forgerAddr *ethCommon.Address,
  698. fromItem, limit *uint, order string,
  699. ) ([]CoordinatorAPI, uint64, error) {
  700. cancel, err := hdb.apiConnCon.Acquire()
  701. defer cancel()
  702. if err != nil {
  703. return nil, 0, tracerr.Wrap(err)
  704. }
  705. defer hdb.apiConnCon.Release()
  706. var query string
  707. var args []interface{}
  708. queryStr := `SELECT coordinator.*, COUNT(*) OVER() AS total_items
  709. FROM coordinator INNER JOIN (
  710. SELECT MAX(item_id) AS item_id FROM coordinator
  711. GROUP BY bidder_addr
  712. ) c ON coordinator.item_id = c.item_id `
  713. // Apply filters
  714. nextIsAnd := false
  715. if bidderAddr != nil {
  716. queryStr += "WHERE bidder_addr = ? "
  717. nextIsAnd = true
  718. args = append(args, bidderAddr)
  719. }
  720. if forgerAddr != nil {
  721. if nextIsAnd {
  722. queryStr += "AND "
  723. } else {
  724. queryStr += "WHERE "
  725. }
  726. queryStr += "forger_addr = ? "
  727. nextIsAnd = true
  728. args = append(args, forgerAddr)
  729. }
  730. if fromItem != nil {
  731. if nextIsAnd {
  732. queryStr += "AND "
  733. } else {
  734. queryStr += "WHERE "
  735. }
  736. if order == OrderAsc {
  737. queryStr += "coordinator.item_id >= ? "
  738. } else {
  739. queryStr += "coordinator.item_id <= ? "
  740. }
  741. args = append(args, fromItem)
  742. }
  743. // pagination
  744. queryStr += "ORDER BY coordinator.item_id "
  745. if order == OrderAsc {
  746. queryStr += " ASC "
  747. } else {
  748. queryStr += " DESC "
  749. }
  750. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  751. query = hdb.dbRead.Rebind(queryStr)
  752. coordinators := []*CoordinatorAPI{}
  753. if err := meddler.QueryAll(hdb.dbRead, &coordinators, query, args...); err != nil {
  754. return nil, 0, tracerr.Wrap(err)
  755. }
  756. if len(coordinators) == 0 {
  757. return []CoordinatorAPI{}, 0, nil
  758. }
  759. return db.SlicePtrsToSlice(coordinators).([]CoordinatorAPI),
  760. coordinators[0].TotalItems - uint64(len(coordinators)), nil
  761. }
  762. // GetAuctionVarsAPI returns auction variables
  763. func (hdb *HistoryDB) GetAuctionVarsAPI() (*common.AuctionVariables, error) {
  764. cancel, err := hdb.apiConnCon.Acquire()
  765. defer cancel()
  766. if err != nil {
  767. return nil, tracerr.Wrap(err)
  768. }
  769. defer hdb.apiConnCon.Release()
  770. auctionVars := &common.AuctionVariables{}
  771. err = meddler.QueryRow(
  772. hdb.dbRead, auctionVars, `SELECT * FROM auction_vars;`,
  773. )
  774. return auctionVars, tracerr.Wrap(err)
  775. }
  776. // GetAccountAPI returns an account by its index
  777. func (hdb *HistoryDB) GetAccountAPI(idx common.Idx) (*AccountAPI, error) {
  778. cancel, err := hdb.apiConnCon.Acquire()
  779. defer cancel()
  780. if err != nil {
  781. return nil, tracerr.Wrap(err)
  782. }
  783. defer hdb.apiConnCon.Release()
  784. account := &AccountAPI{}
  785. err = meddler.QueryRow(hdb.dbRead, account, `SELECT account.item_id, hez_idx(account.idx,
  786. token.symbol) as idx, account.batch_num, account.bjj, account.eth_addr,
  787. token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
  788. token.eth_addr as token_eth_addr, token.name, token.symbol, token.decimals, token.usd,
  789. token.usd_update, account_update.nonce, account_update.balance
  790. FROM account inner JOIN (
  791. SELECT idx, nonce, balance
  792. FROM account_update
  793. WHERE idx = $1
  794. ORDER BY item_id DESC LIMIT 1
  795. ) AS account_update ON account_update.idx = account.idx
  796. INNER JOIN token ON account.token_id = token.token_id
  797. WHERE account.idx = $1;`, idx)
  798. if err != nil {
  799. return nil, tracerr.Wrap(err)
  800. }
  801. return account, nil
  802. }
  803. // GetAccountsAPI returns a list of accounts from the DB and pagination info
  804. func (hdb *HistoryDB) GetAccountsAPI(
  805. tokenIDs []common.TokenID, ethAddr *ethCommon.Address,
  806. bjj *babyjub.PublicKeyComp, fromItem, limit *uint, order string,
  807. ) ([]AccountAPI, uint64, error) {
  808. if ethAddr != nil && bjj != nil {
  809. return nil, 0, tracerr.Wrap(errors.New("ethAddr and bjj are incompatible"))
  810. }
  811. cancel, err := hdb.apiConnCon.Acquire()
  812. defer cancel()
  813. if err != nil {
  814. return nil, 0, tracerr.Wrap(err)
  815. }
  816. defer hdb.apiConnCon.Release()
  817. var query string
  818. var args []interface{}
  819. queryStr := `SELECT account.item_id, hez_idx(account.idx, token.symbol) as idx, account.batch_num,
  820. account.bjj, account.eth_addr, token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
  821. token.eth_addr as token_eth_addr, token.name, token.symbol, token.decimals, token.usd, token.usd_update,
  822. account_update.nonce, account_update.balance, COUNT(*) OVER() AS total_items
  823. FROM account inner JOIN (
  824. SELECT DISTINCT idx,
  825. first_value(nonce) over(partition by idx ORDER BY item_id DESC) as nonce,
  826. first_value(balance) over(partition by idx ORDER BY item_id DESC) as balance
  827. FROM account_update
  828. ) AS account_update ON account_update.idx = account.idx INNER JOIN token ON account.token_id = token.token_id `
  829. // Apply filters
  830. nextIsAnd := false
  831. // ethAddr filter
  832. if ethAddr != nil {
  833. queryStr += "WHERE account.eth_addr = ? "
  834. nextIsAnd = true
  835. args = append(args, ethAddr)
  836. } else if bjj != nil { // bjj filter
  837. queryStr += "WHERE account.bjj = ? "
  838. nextIsAnd = true
  839. args = append(args, bjj)
  840. }
  841. // tokenID filter
  842. if len(tokenIDs) > 0 {
  843. if nextIsAnd {
  844. queryStr += "AND "
  845. } else {
  846. queryStr += "WHERE "
  847. }
  848. queryStr += "account.token_id IN (?) "
  849. args = append(args, tokenIDs)
  850. nextIsAnd = true
  851. }
  852. if fromItem != nil {
  853. if nextIsAnd {
  854. queryStr += "AND "
  855. } else {
  856. queryStr += "WHERE "
  857. }
  858. if order == OrderAsc {
  859. queryStr += "account.item_id >= ? "
  860. } else {
  861. queryStr += "account.item_id <= ? "
  862. }
  863. args = append(args, fromItem)
  864. }
  865. // pagination
  866. queryStr += "ORDER BY account.item_id "
  867. if order == OrderAsc {
  868. queryStr += " ASC "
  869. } else {
  870. queryStr += " DESC "
  871. }
  872. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  873. query, argsQ, err := sqlx.In(queryStr, args...)
  874. if err != nil {
  875. return nil, 0, tracerr.Wrap(err)
  876. }
  877. query = hdb.dbRead.Rebind(query)
  878. accounts := []*AccountAPI{}
  879. if err := meddler.QueryAll(hdb.dbRead, &accounts, query, argsQ...); err != nil {
  880. return nil, 0, tracerr.Wrap(err)
  881. }
  882. if len(accounts) == 0 {
  883. return []AccountAPI{}, 0, nil
  884. }
  885. return db.SlicePtrsToSlice(accounts).([]AccountAPI),
  886. accounts[0].TotalItems - uint64(len(accounts)), nil
  887. }
  888. // GetCommonAccountAPI returns the account associated to an account idx
  889. func (hdb *HistoryDB) GetCommonAccountAPI(idx common.Idx) (*common.Account, error) {
  890. cancel, err := hdb.apiConnCon.Acquire()
  891. defer cancel()
  892. if err != nil {
  893. return nil, tracerr.Wrap(err)
  894. }
  895. defer hdb.apiConnCon.Release()
  896. account := &common.Account{}
  897. err = meddler.QueryRow(
  898. hdb.dbRead, account, `SELECT * FROM account WHERE idx = $1;`, idx,
  899. )
  900. return account, tracerr.Wrap(err)
  901. }
  902. // GetCoordinatorAPI returns a coordinator by its bidderAddr
  903. func (hdb *HistoryDB) GetCoordinatorAPI(bidderAddr ethCommon.Address) (*CoordinatorAPI, error) {
  904. cancel, err := hdb.apiConnCon.Acquire()
  905. defer cancel()
  906. if err != nil {
  907. return nil, tracerr.Wrap(err)
  908. }
  909. defer hdb.apiConnCon.Release()
  910. return hdb.getCoordinatorAPI(hdb.dbRead, bidderAddr)
  911. }
  912. func (hdb *HistoryDB) getCoordinatorAPI(d meddler.DB, bidderAddr ethCommon.Address) (*CoordinatorAPI, error) {
  913. coordinator := &CoordinatorAPI{}
  914. err := meddler.QueryRow(
  915. d, coordinator,
  916. "SELECT * FROM coordinator WHERE bidder_addr = $1 ORDER BY item_id DESC LIMIT 1;",
  917. bidderAddr,
  918. )
  919. return coordinator, tracerr.Wrap(err)
  920. }
  921. func (hdb *HistoryDB) GetNodeInfoAPI() (*NodeInfo, error) {
  922. cancel, err := hdb.apiConnCon.Acquire()
  923. defer cancel()
  924. if err != nil {
  925. return nil, tracerr.Wrap(err)
  926. }
  927. defer hdb.apiConnCon.Release()
  928. return hdb.GetNodeInfo()
  929. }