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.

1185 lines
35 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. package historydb
  2. import (
  3. "database/sql"
  4. "errors"
  5. "fmt"
  6. "math/big"
  7. "time"
  8. ethCommon "github.com/ethereum/go-ethereum/common"
  9. "github.com/hermeznetwork/hermez-node/common"
  10. "github.com/hermeznetwork/hermez-node/db"
  11. "github.com/hermeznetwork/tracerr"
  12. "github.com/iden3/go-iden3-crypto/babyjub"
  13. "github.com/jmoiron/sqlx"
  14. "github.com/russross/meddler"
  15. )
  16. // GetLastBlockAPI retrieve the block with the highest block number from the DB
  17. func (hdb *HistoryDB) GetLastBlockAPI() (*common.Block, error) {
  18. cancel, err := hdb.apiConnCon.Acquire()
  19. defer cancel()
  20. if err != nil {
  21. return nil, tracerr.Wrap(err)
  22. }
  23. defer hdb.apiConnCon.Release()
  24. return hdb.GetLastBlock()
  25. }
  26. // GetBatchAPI return the batch with the given batchNum
  27. func (hdb *HistoryDB) GetBatchAPI(batchNum common.BatchNum) (*BatchAPI, error) {
  28. cancel, err := hdb.apiConnCon.Acquire()
  29. defer cancel()
  30. if err != nil {
  31. return nil, tracerr.Wrap(err)
  32. }
  33. defer hdb.apiConnCon.Release()
  34. return hdb.getBatchAPI(hdb.dbRead, batchNum)
  35. }
  36. // GetBatchInternalAPI return the batch with the given batchNum
  37. func (hdb *HistoryDB) GetBatchInternalAPI(batchNum common.BatchNum) (*BatchAPI, error) {
  38. return hdb.getBatchAPI(hdb.dbRead, batchNum)
  39. }
  40. func (hdb *HistoryDB) getBatchAPI(d meddler.DB, batchNum common.BatchNum) (*BatchAPI, error) {
  41. batch := &BatchAPI{}
  42. return batch, tracerr.Wrap(meddler.QueryRow(
  43. d, batch,
  44. `SELECT batch.item_id, batch.batch_num, batch.eth_block_num,
  45. batch.forger_addr, batch.fees_collected, batch.total_fees_usd, batch.state_root,
  46. batch.num_accounts, batch.exit_root, batch.forge_l1_txs_num, batch.slot_num,
  47. block.timestamp, block.hash,
  48. COALESCE ((SELECT COUNT(*) FROM tx WHERE batch_num = batch.batch_num), 0) AS forged_txs
  49. FROM batch INNER JOIN block ON batch.eth_block_num = block.eth_block_num
  50. WHERE batch_num = $1;`, batchNum,
  51. ))
  52. }
  53. // GetBatchesAPI return the batches applying the given filters
  54. func (hdb *HistoryDB) GetBatchesAPI(
  55. minBatchNum, maxBatchNum, slotNum *uint,
  56. forgerAddr *ethCommon.Address,
  57. fromItem, limit *uint, order string,
  58. ) ([]BatchAPI, uint64, error) {
  59. cancel, err := hdb.apiConnCon.Acquire()
  60. defer cancel()
  61. if err != nil {
  62. return nil, 0, tracerr.Wrap(err)
  63. }
  64. defer hdb.apiConnCon.Release()
  65. var query string
  66. var args []interface{}
  67. queryStr := `SELECT batch.item_id, batch.batch_num, batch.eth_block_num,
  68. batch.forger_addr, batch.fees_collected, batch.total_fees_usd, batch.state_root,
  69. batch.num_accounts, batch.exit_root, batch.forge_l1_txs_num, batch.slot_num,
  70. block.timestamp, block.hash,
  71. COALESCE ((SELECT COUNT(*) FROM tx WHERE batch_num = batch.batch_num), 0) AS forged_txs,
  72. count(*) OVER() AS total_items
  73. FROM batch INNER JOIN block ON batch.eth_block_num = block.eth_block_num `
  74. // Apply filters
  75. nextIsAnd := false
  76. // minBatchNum filter
  77. if minBatchNum != nil {
  78. if nextIsAnd {
  79. queryStr += "AND "
  80. } else {
  81. queryStr += "WHERE "
  82. }
  83. queryStr += "batch.batch_num > ? "
  84. args = append(args, minBatchNum)
  85. nextIsAnd = true
  86. }
  87. // maxBatchNum filter
  88. if maxBatchNum != nil {
  89. if nextIsAnd {
  90. queryStr += "AND "
  91. } else {
  92. queryStr += "WHERE "
  93. }
  94. queryStr += "batch.batch_num < ? "
  95. args = append(args, maxBatchNum)
  96. nextIsAnd = true
  97. }
  98. // slotNum filter
  99. if slotNum != nil {
  100. if nextIsAnd {
  101. queryStr += "AND "
  102. } else {
  103. queryStr += "WHERE "
  104. }
  105. queryStr += "batch.slot_num = ? "
  106. args = append(args, slotNum)
  107. nextIsAnd = true
  108. }
  109. // forgerAddr filter
  110. if forgerAddr != nil {
  111. if nextIsAnd {
  112. queryStr += "AND "
  113. } else {
  114. queryStr += "WHERE "
  115. }
  116. queryStr += "batch.forger_addr = ? "
  117. args = append(args, forgerAddr)
  118. nextIsAnd = true
  119. }
  120. // pagination
  121. if fromItem != nil {
  122. if nextIsAnd {
  123. queryStr += "AND "
  124. } else {
  125. queryStr += "WHERE "
  126. }
  127. if order == OrderAsc {
  128. queryStr += "batch.item_id >= ? "
  129. } else {
  130. queryStr += "batch.item_id <= ? "
  131. }
  132. args = append(args, fromItem)
  133. }
  134. queryStr += "ORDER BY batch.item_id "
  135. if order == OrderAsc {
  136. queryStr += " ASC "
  137. } else {
  138. queryStr += " DESC "
  139. }
  140. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  141. query = hdb.dbRead.Rebind(queryStr)
  142. // log.Debug(query)
  143. batchPtrs := []*BatchAPI{}
  144. if err := meddler.QueryAll(hdb.dbRead, &batchPtrs, query, args...); err != nil {
  145. return nil, 0, tracerr.Wrap(err)
  146. }
  147. batches := db.SlicePtrsToSlice(batchPtrs).([]BatchAPI)
  148. if len(batches) == 0 {
  149. return batches, 0, nil
  150. }
  151. return batches, batches[0].TotalItems - uint64(len(batches)), nil
  152. }
  153. // GetBestBidAPI returns the best bid in specific slot by slotNum
  154. func (hdb *HistoryDB) GetBestBidAPI(slotNum *int64) (BidAPI, error) {
  155. bid := &BidAPI{}
  156. cancel, err := hdb.apiConnCon.Acquire()
  157. defer cancel()
  158. if err != nil {
  159. return *bid, tracerr.Wrap(err)
  160. }
  161. defer hdb.apiConnCon.Release()
  162. err = meddler.QueryRow(
  163. hdb.dbRead, bid, `SELECT bid.*, block.timestamp, coordinator.forger_addr, coordinator.url
  164. FROM bid INNER JOIN block ON bid.eth_block_num = block.eth_block_num
  165. INNER JOIN (
  166. SELECT bidder_addr, MAX(item_id) AS item_id FROM coordinator
  167. GROUP BY bidder_addr
  168. ) c ON bid.bidder_addr = c.bidder_addr
  169. INNER JOIN coordinator ON c.item_id = coordinator.item_id
  170. WHERE slot_num = $1 ORDER BY item_id DESC LIMIT 1;`, slotNum,
  171. )
  172. return *bid, tracerr.Wrap(err)
  173. }
  174. // GetBestBidsAPI returns the best bid in specific slot by slotNum
  175. func (hdb *HistoryDB) GetBestBidsAPI(
  176. minSlotNum, maxSlotNum *int64,
  177. bidderAddr *ethCommon.Address,
  178. limit *uint, order string,
  179. ) ([]BidAPI, uint64, error) {
  180. cancel, err := hdb.apiConnCon.Acquire()
  181. defer cancel()
  182. if err != nil {
  183. return nil, 0, tracerr.Wrap(err)
  184. }
  185. defer hdb.apiConnCon.Release()
  186. return hdb.getBestBidsAPI(hdb.dbRead, minSlotNum, maxSlotNum, bidderAddr, limit, order)
  187. }
  188. func (hdb *HistoryDB) getBestBidsAPI(
  189. d meddler.DB,
  190. minSlotNum, maxSlotNum *int64,
  191. bidderAddr *ethCommon.Address,
  192. limit *uint, order string,
  193. ) ([]BidAPI, uint64, error) {
  194. var query string
  195. var args []interface{}
  196. // JOIN the best bid of each slot with the latest update of each coordinator
  197. queryStr := `SELECT b.*, block.timestamp, coordinator.forger_addr, coordinator.url,
  198. COUNT(*) OVER() AS total_items FROM (
  199. SELECT slot_num, MAX(item_id) as maxitem
  200. FROM bid GROUP BY slot_num
  201. )
  202. AS x INNER JOIN bid AS b ON b.item_id = x.maxitem
  203. INNER JOIN block ON b.eth_block_num = block.eth_block_num
  204. INNER JOIN (
  205. SELECT bidder_addr, MAX(item_id) AS item_id FROM coordinator
  206. GROUP BY bidder_addr
  207. ) c ON b.bidder_addr = c.bidder_addr
  208. INNER JOIN coordinator ON c.item_id = coordinator.item_id
  209. WHERE (b.slot_num >= ? AND b.slot_num <= ?)`
  210. args = append(args, minSlotNum)
  211. args = append(args, maxSlotNum)
  212. // Apply filters
  213. if bidderAddr != nil {
  214. queryStr += " AND b.bidder_addr = ? "
  215. args = append(args, bidderAddr)
  216. }
  217. queryStr += " ORDER BY b.slot_num "
  218. if order == OrderAsc {
  219. queryStr += "ASC "
  220. } else {
  221. queryStr += "DESC "
  222. }
  223. if limit != nil {
  224. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  225. }
  226. query = hdb.dbRead.Rebind(queryStr)
  227. bidPtrs := []*BidAPI{}
  228. if err := meddler.QueryAll(d, &bidPtrs, query, args...); err != nil {
  229. return nil, 0, tracerr.Wrap(err)
  230. }
  231. // log.Debug(query)
  232. bids := db.SlicePtrsToSlice(bidPtrs).([]BidAPI)
  233. if len(bids) == 0 {
  234. return bids, 0, nil
  235. }
  236. return bids, bids[0].TotalItems - uint64(len(bids)), nil
  237. }
  238. // GetBidsAPI return the bids applying the given filters
  239. func (hdb *HistoryDB) GetBidsAPI(
  240. slotNum *int64, bidderAddr *ethCommon.Address,
  241. fromItem, limit *uint, order string,
  242. ) ([]BidAPI, uint64, error) {
  243. cancel, err := hdb.apiConnCon.Acquire()
  244. defer cancel()
  245. if err != nil {
  246. return nil, 0, tracerr.Wrap(err)
  247. }
  248. defer hdb.apiConnCon.Release()
  249. var query string
  250. var args []interface{}
  251. // JOIN each bid with the latest update of each coordinator
  252. queryStr := `SELECT bid.*, block.timestamp, coord.forger_addr, coord.url,
  253. COUNT(*) OVER() AS total_items
  254. FROM bid INNER JOIN block ON bid.eth_block_num = block.eth_block_num
  255. INNER JOIN (
  256. SELECT bidder_addr, MAX(item_id) AS item_id FROM coordinator
  257. GROUP BY bidder_addr
  258. ) c ON bid.bidder_addr = c.bidder_addr
  259. INNER JOIN coordinator coord ON c.item_id = coord.item_id `
  260. // Apply filters
  261. nextIsAnd := false
  262. // slotNum filter
  263. if slotNum != nil {
  264. if nextIsAnd {
  265. queryStr += "AND "
  266. } else {
  267. queryStr += "WHERE "
  268. }
  269. queryStr += "bid.slot_num = ? "
  270. args = append(args, slotNum)
  271. nextIsAnd = true
  272. }
  273. // bidder filter
  274. if bidderAddr != nil {
  275. if nextIsAnd {
  276. queryStr += "AND "
  277. } else {
  278. queryStr += "WHERE "
  279. }
  280. queryStr += "bid.bidder_addr = ? "
  281. args = append(args, bidderAddr)
  282. nextIsAnd = true
  283. }
  284. if fromItem != nil {
  285. if nextIsAnd {
  286. queryStr += "AND "
  287. } else {
  288. queryStr += "WHERE "
  289. }
  290. if order == OrderAsc {
  291. queryStr += "bid.item_id >= ? "
  292. } else {
  293. queryStr += "bid.item_id <= ? "
  294. }
  295. args = append(args, fromItem)
  296. }
  297. // pagination
  298. queryStr += "ORDER BY bid.item_id "
  299. if order == OrderAsc {
  300. queryStr += "ASC "
  301. } else {
  302. queryStr += "DESC "
  303. }
  304. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  305. query, argsQ, err := sqlx.In(queryStr, args...)
  306. if err != nil {
  307. return nil, 0, tracerr.Wrap(err)
  308. }
  309. query = hdb.dbRead.Rebind(query)
  310. bids := []*BidAPI{}
  311. if err := meddler.QueryAll(hdb.dbRead, &bids, query, argsQ...); err != nil {
  312. return nil, 0, tracerr.Wrap(err)
  313. }
  314. if len(bids) == 0 {
  315. return []BidAPI{}, 0, nil
  316. }
  317. return db.SlicePtrsToSlice(bids).([]BidAPI), bids[0].TotalItems - uint64(len(bids)), nil
  318. }
  319. // GetTokenAPI returns a token from the DB given a TokenID
  320. func (hdb *HistoryDB) GetTokenAPI(tokenID common.TokenID) (*TokenWithUSD, error) {
  321. cancel, err := hdb.apiConnCon.Acquire()
  322. defer cancel()
  323. if err != nil {
  324. return nil, tracerr.Wrap(err)
  325. }
  326. defer hdb.apiConnCon.Release()
  327. return hdb.GetToken(tokenID)
  328. }
  329. // GetTokensAPI returns a list of tokens from the DB
  330. func (hdb *HistoryDB) GetTokensAPI(
  331. ids []common.TokenID, symbols []string, name string, fromItem,
  332. limit *uint, order string,
  333. ) ([]TokenWithUSD, uint64, error) {
  334. cancel, err := hdb.apiConnCon.Acquire()
  335. defer cancel()
  336. if err != nil {
  337. return nil, 0, tracerr.Wrap(err)
  338. }
  339. defer hdb.apiConnCon.Release()
  340. var query string
  341. var args []interface{}
  342. queryStr := `SELECT * , COUNT(*) OVER() AS total_items FROM token `
  343. // Apply filters
  344. nextIsAnd := false
  345. if len(ids) > 0 {
  346. queryStr += "WHERE token_id IN (?) "
  347. nextIsAnd = true
  348. args = append(args, ids)
  349. }
  350. if len(symbols) > 0 {
  351. if nextIsAnd {
  352. queryStr += "AND "
  353. } else {
  354. queryStr += "WHERE "
  355. }
  356. queryStr += "symbol IN (?) "
  357. args = append(args, symbols)
  358. nextIsAnd = true
  359. }
  360. if name != "" {
  361. if nextIsAnd {
  362. queryStr += "AND "
  363. } else {
  364. queryStr += "WHERE "
  365. }
  366. queryStr += "name ~ ? "
  367. args = append(args, name)
  368. nextIsAnd = true
  369. }
  370. if fromItem != nil {
  371. if nextIsAnd {
  372. queryStr += "AND "
  373. } else {
  374. queryStr += "WHERE "
  375. }
  376. if order == OrderAsc {
  377. queryStr += "item_id >= ? "
  378. } else {
  379. queryStr += "item_id <= ? "
  380. }
  381. args = append(args, fromItem)
  382. }
  383. // pagination
  384. queryStr += "ORDER BY item_id "
  385. if order == OrderAsc {
  386. queryStr += "ASC "
  387. } else {
  388. queryStr += "DESC "
  389. }
  390. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  391. query, argsQ, err := sqlx.In(queryStr, args...)
  392. if err != nil {
  393. return nil, 0, tracerr.Wrap(err)
  394. }
  395. query = hdb.dbRead.Rebind(query)
  396. tokens := []*TokenWithUSD{}
  397. if err := meddler.QueryAll(hdb.dbRead, &tokens, query, argsQ...); err != nil {
  398. return nil, 0, tracerr.Wrap(err)
  399. }
  400. if len(tokens) == 0 {
  401. return []TokenWithUSD{}, 0, nil
  402. }
  403. return db.SlicePtrsToSlice(tokens).([]TokenWithUSD), uint64(len(tokens)) - tokens[0].TotalItems, nil
  404. }
  405. // GetTxAPI returns a tx from the DB given a TxID
  406. func (hdb *HistoryDB) GetTxAPI(txID common.TxID) (*TxAPI, error) {
  407. // Warning: amount_success and deposit_amount_success have true as default for
  408. // performance reasons. The expected default value is false (when txs are unforged)
  409. // this case is handled at the function func (tx TxAPI) MarshalJSON() ([]byte, error)
  410. cancel, err := hdb.apiConnCon.Acquire()
  411. defer cancel()
  412. if err != nil {
  413. return nil, tracerr.Wrap(err)
  414. }
  415. defer hdb.apiConnCon.Release()
  416. tx := &TxAPI{}
  417. err = meddler.QueryRow(
  418. hdb.dbRead, tx, `SELECT tx.item_id, tx.is_l1, tx.id, tx.type, tx.position,
  419. hez_idx(tx.effective_from_idx, token.symbol) AS from_idx, tx.from_eth_addr, tx.from_bjj,
  420. hez_idx(tx.to_idx, token.symbol) AS to_idx, tx.to_eth_addr, tx.to_bjj,
  421. tx.amount, tx.amount_success, tx.token_id, tx.amount_usd,
  422. tx.batch_num, tx.eth_block_num, tx.to_forge_l1_txs_num, tx.user_origin,
  423. tx.deposit_amount, tx.deposit_amount_usd, tx.deposit_amount_success, tx.fee, tx.fee_usd, tx.nonce,
  424. token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
  425. token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
  426. token.usd_update, block.timestamp
  427. FROM tx INNER JOIN token ON tx.token_id = token.token_id
  428. INNER JOIN block ON tx.eth_block_num = block.eth_block_num
  429. WHERE tx.id = $1;`, txID,
  430. )
  431. return tx, tracerr.Wrap(err)
  432. }
  433. // GetTxsAPI returns a list of txs from the DB using the HistoryTx struct
  434. // and pagination info
  435. func (hdb *HistoryDB) GetTxsAPI(
  436. ethAddr *ethCommon.Address, bjj *babyjub.PublicKeyComp,
  437. tokenID *common.TokenID, idx *common.Idx, batchNum *uint, txType *common.TxType,
  438. fromItem, limit *uint, order string,
  439. ) ([]TxAPI, uint64, error) {
  440. // Warning: amount_success and deposit_amount_success have true as default for
  441. // performance reasons. The expected default value is false (when txs are unforged)
  442. // this case is handled at the function func (tx TxAPI) MarshalJSON() ([]byte, error)
  443. cancel, err := hdb.apiConnCon.Acquire()
  444. defer cancel()
  445. if err != nil {
  446. return nil, 0, tracerr.Wrap(err)
  447. }
  448. defer hdb.apiConnCon.Release()
  449. if ethAddr != nil && bjj != nil {
  450. return nil, 0, tracerr.Wrap(errors.New("ethAddr and bjj are incompatible"))
  451. }
  452. var query string
  453. var args []interface{}
  454. queryStr := `SELECT tx.item_id, tx.is_l1, tx.id, tx.type, tx.position,
  455. hez_idx(tx.effective_from_idx, token.symbol) AS from_idx, tx.from_eth_addr, tx.from_bjj,
  456. hez_idx(tx.to_idx, token.symbol) AS to_idx, tx.to_eth_addr, tx.to_bjj,
  457. tx.amount, tx.amount_success, tx.token_id, tx.amount_usd,
  458. tx.batch_num, tx.eth_block_num, tx.to_forge_l1_txs_num, tx.user_origin,
  459. tx.deposit_amount, tx.deposit_amount_usd, tx.deposit_amount_success, tx.fee, tx.fee_usd, tx.nonce,
  460. token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
  461. token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
  462. token.usd_update, block.timestamp, count(*) OVER() AS total_items
  463. FROM tx INNER JOIN token ON tx.token_id = token.token_id
  464. INNER JOIN block ON tx.eth_block_num = block.eth_block_num `
  465. // Apply filters
  466. nextIsAnd := false
  467. // ethAddr filter
  468. if ethAddr != nil {
  469. queryStr += "WHERE (tx.from_eth_addr = ? OR tx.to_eth_addr = ?) "
  470. nextIsAnd = true
  471. args = append(args, ethAddr, ethAddr)
  472. } else if bjj != nil { // bjj filter
  473. queryStr += "WHERE (tx.from_bjj = ? OR tx.to_bjj = ?) "
  474. nextIsAnd = true
  475. args = append(args, bjj, bjj)
  476. }
  477. // tokenID filter
  478. if tokenID != nil {
  479. if nextIsAnd {
  480. queryStr += "AND "
  481. } else {
  482. queryStr += "WHERE "
  483. }
  484. queryStr += "tx.token_id = ? "
  485. args = append(args, tokenID)
  486. nextIsAnd = true
  487. }
  488. // idx filter
  489. if idx != nil {
  490. if nextIsAnd {
  491. queryStr += "AND "
  492. } else {
  493. queryStr += "WHERE "
  494. }
  495. queryStr += "(tx.effective_from_idx = ? OR tx.to_idx = ?) "
  496. args = append(args, idx, idx)
  497. nextIsAnd = true
  498. }
  499. // batchNum filter
  500. if batchNum != nil {
  501. if nextIsAnd {
  502. queryStr += "AND "
  503. } else {
  504. queryStr += "WHERE "
  505. }
  506. queryStr += "tx.batch_num = ? "
  507. args = append(args, batchNum)
  508. nextIsAnd = true
  509. }
  510. // txType filter
  511. if txType != nil {
  512. if nextIsAnd {
  513. queryStr += "AND "
  514. } else {
  515. queryStr += "WHERE "
  516. }
  517. queryStr += "tx.type = ? "
  518. args = append(args, txType)
  519. nextIsAnd = true
  520. }
  521. if fromItem != nil {
  522. if nextIsAnd {
  523. queryStr += "AND "
  524. } else {
  525. queryStr += "WHERE "
  526. }
  527. if order == OrderAsc {
  528. queryStr += "tx.item_id >= ? "
  529. } else {
  530. queryStr += "tx.item_id <= ? "
  531. }
  532. args = append(args, fromItem)
  533. nextIsAnd = true
  534. }
  535. if nextIsAnd {
  536. queryStr += "AND "
  537. } else {
  538. queryStr += "WHERE "
  539. }
  540. queryStr += "tx.batch_num IS NOT NULL "
  541. // pagination
  542. queryStr += "ORDER BY tx.item_id "
  543. if order == OrderAsc {
  544. queryStr += " ASC "
  545. } else {
  546. queryStr += " DESC "
  547. }
  548. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  549. query = hdb.dbRead.Rebind(queryStr)
  550. // log.Debug(query)
  551. txsPtrs := []*TxAPI{}
  552. if err := meddler.QueryAll(hdb.dbRead, &txsPtrs, query, args...); err != nil {
  553. return nil, 0, tracerr.Wrap(err)
  554. }
  555. txs := db.SlicePtrsToSlice(txsPtrs).([]TxAPI)
  556. if len(txs) == 0 {
  557. return txs, 0, nil
  558. }
  559. return txs, txs[0].TotalItems - uint64(len(txs)), nil
  560. }
  561. // GetExitAPI returns a exit from the DB
  562. func (hdb *HistoryDB) GetExitAPI(batchNum *uint, idx *common.Idx) (*ExitAPI, error) {
  563. cancel, err := hdb.apiConnCon.Acquire()
  564. defer cancel()
  565. if err != nil {
  566. return nil, tracerr.Wrap(err)
  567. }
  568. defer hdb.apiConnCon.Release()
  569. exit := &ExitAPI{}
  570. err = meddler.QueryRow(
  571. hdb.dbRead, exit, `SELECT exit_tree.item_id, exit_tree.batch_num,
  572. hez_idx(exit_tree.account_idx, token.symbol) AS account_idx,
  573. account.bjj, account.eth_addr,
  574. exit_tree.merkle_proof, exit_tree.balance, exit_tree.instant_withdrawn,
  575. exit_tree.delayed_withdraw_request, exit_tree.delayed_withdrawn,
  576. token.token_id, token.item_id AS token_item_id,
  577. token.eth_block_num AS token_block, token.eth_addr AS token_eth_addr, token.name, token.symbol,
  578. token.decimals, token.usd, token.usd_update
  579. FROM exit_tree INNER JOIN account ON exit_tree.account_idx = account.idx
  580. INNER JOIN token ON account.token_id = token.token_id
  581. WHERE exit_tree.batch_num = $1 AND exit_tree.account_idx = $2;`, batchNum, idx,
  582. )
  583. return exit, tracerr.Wrap(err)
  584. }
  585. // GetExitsAPI returns a list of exits from the DB and pagination info
  586. func (hdb *HistoryDB) GetExitsAPI(
  587. ethAddr *ethCommon.Address, bjj *babyjub.PublicKeyComp, tokenID *common.TokenID,
  588. idx *common.Idx, batchNum *uint, onlyPendingWithdraws *bool,
  589. fromItem, limit *uint, order string,
  590. ) ([]ExitAPI, uint64, error) {
  591. if ethAddr != nil && bjj != nil {
  592. return nil, 0, tracerr.Wrap(errors.New("ethAddr and bjj are incompatible"))
  593. }
  594. cancel, err := hdb.apiConnCon.Acquire()
  595. defer cancel()
  596. if err != nil {
  597. return nil, 0, tracerr.Wrap(err)
  598. }
  599. defer hdb.apiConnCon.Release()
  600. var query string
  601. var args []interface{}
  602. queryStr := `SELECT exit_tree.item_id, exit_tree.batch_num,
  603. hez_idx(exit_tree.account_idx, token.symbol) AS account_idx,
  604. account.bjj, account.eth_addr,
  605. exit_tree.merkle_proof, exit_tree.balance, exit_tree.instant_withdrawn,
  606. exit_tree.delayed_withdraw_request, exit_tree.delayed_withdrawn,
  607. token.token_id, token.item_id AS token_item_id,
  608. token.eth_block_num AS token_block, token.eth_addr AS token_eth_addr, token.name, token.symbol,
  609. token.decimals, token.usd, token.usd_update, COUNT(*) OVER() AS total_items
  610. FROM exit_tree INNER JOIN account ON exit_tree.account_idx = account.idx
  611. INNER JOIN token ON account.token_id = token.token_id `
  612. // Apply filters
  613. nextIsAnd := false
  614. // ethAddr filter
  615. if ethAddr != nil {
  616. queryStr += "WHERE account.eth_addr = ? "
  617. nextIsAnd = true
  618. args = append(args, ethAddr)
  619. } else if bjj != nil { // bjj filter
  620. queryStr += "WHERE account.bjj = ? "
  621. nextIsAnd = true
  622. args = append(args, bjj)
  623. }
  624. // tokenID filter
  625. if tokenID != nil {
  626. if nextIsAnd {
  627. queryStr += "AND "
  628. } else {
  629. queryStr += "WHERE "
  630. }
  631. queryStr += "account.token_id = ? "
  632. args = append(args, tokenID)
  633. nextIsAnd = true
  634. }
  635. // idx filter
  636. if idx != nil {
  637. if nextIsAnd {
  638. queryStr += "AND "
  639. } else {
  640. queryStr += "WHERE "
  641. }
  642. queryStr += "exit_tree.account_idx = ? "
  643. args = append(args, idx)
  644. nextIsAnd = true
  645. }
  646. // batchNum filter
  647. if batchNum != nil {
  648. if nextIsAnd {
  649. queryStr += "AND "
  650. } else {
  651. queryStr += "WHERE "
  652. }
  653. queryStr += "exit_tree.batch_num = ? "
  654. args = append(args, batchNum)
  655. nextIsAnd = true
  656. }
  657. // onlyPendingWithdraws
  658. if onlyPendingWithdraws != nil {
  659. if *onlyPendingWithdraws {
  660. if nextIsAnd {
  661. queryStr += "AND "
  662. } else {
  663. queryStr += "WHERE "
  664. }
  665. queryStr += "(exit_tree.instant_withdrawn IS NULL AND exit_tree.delayed_withdrawn IS NULL) "
  666. nextIsAnd = true
  667. }
  668. }
  669. if fromItem != nil {
  670. if nextIsAnd {
  671. queryStr += "AND "
  672. } else {
  673. queryStr += "WHERE "
  674. }
  675. if order == OrderAsc {
  676. queryStr += "exit_tree.item_id >= ? "
  677. } else {
  678. queryStr += "exit_tree.item_id <= ? "
  679. }
  680. args = append(args, fromItem)
  681. // nextIsAnd = true
  682. }
  683. // pagination
  684. queryStr += "ORDER BY exit_tree.item_id "
  685. if order == OrderAsc {
  686. queryStr += " ASC "
  687. } else {
  688. queryStr += " DESC "
  689. }
  690. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  691. query = hdb.dbRead.Rebind(queryStr)
  692. // log.Debug(query)
  693. exits := []*ExitAPI{}
  694. if err := meddler.QueryAll(hdb.dbRead, &exits, query, args...); err != nil {
  695. return nil, 0, tracerr.Wrap(err)
  696. }
  697. if len(exits) == 0 {
  698. return []ExitAPI{}, 0, nil
  699. }
  700. return db.SlicePtrsToSlice(exits).([]ExitAPI), exits[0].TotalItems - uint64(len(exits)), nil
  701. }
  702. // GetCoordinatorsAPI returns a list of coordinators from the DB and pagination info
  703. func (hdb *HistoryDB) GetCoordinatorsAPI(
  704. bidderAddr, forgerAddr *ethCommon.Address,
  705. fromItem, limit *uint, order string,
  706. ) ([]CoordinatorAPI, uint64, error) {
  707. cancel, err := hdb.apiConnCon.Acquire()
  708. defer cancel()
  709. if err != nil {
  710. return nil, 0, tracerr.Wrap(err)
  711. }
  712. defer hdb.apiConnCon.Release()
  713. var query string
  714. var args []interface{}
  715. queryStr := `SELECT coordinator.*, COUNT(*) OVER() AS total_items
  716. FROM coordinator INNER JOIN (
  717. SELECT MAX(item_id) AS item_id FROM coordinator
  718. GROUP BY bidder_addr
  719. ) c ON coordinator.item_id = c.item_id `
  720. // Apply filters
  721. nextIsAnd := false
  722. if bidderAddr != nil {
  723. queryStr += "WHERE bidder_addr = ? "
  724. nextIsAnd = true
  725. args = append(args, bidderAddr)
  726. }
  727. if forgerAddr != nil {
  728. if nextIsAnd {
  729. queryStr += "AND "
  730. } else {
  731. queryStr += "WHERE "
  732. }
  733. queryStr += "forger_addr = ? "
  734. nextIsAnd = true
  735. args = append(args, forgerAddr)
  736. }
  737. if fromItem != nil {
  738. if nextIsAnd {
  739. queryStr += "AND "
  740. } else {
  741. queryStr += "WHERE "
  742. }
  743. if order == OrderAsc {
  744. queryStr += "coordinator.item_id >= ? "
  745. } else {
  746. queryStr += "coordinator.item_id <= ? "
  747. }
  748. args = append(args, fromItem)
  749. }
  750. // pagination
  751. queryStr += "ORDER BY coordinator.item_id "
  752. if order == OrderAsc {
  753. queryStr += " ASC "
  754. } else {
  755. queryStr += " DESC "
  756. }
  757. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  758. query = hdb.dbRead.Rebind(queryStr)
  759. coordinators := []*CoordinatorAPI{}
  760. if err := meddler.QueryAll(hdb.dbRead, &coordinators, query, args...); err != nil {
  761. return nil, 0, tracerr.Wrap(err)
  762. }
  763. if len(coordinators) == 0 {
  764. return []CoordinatorAPI{}, 0, nil
  765. }
  766. return db.SlicePtrsToSlice(coordinators).([]CoordinatorAPI),
  767. coordinators[0].TotalItems - uint64(len(coordinators)), nil
  768. }
  769. // GetAuctionVarsAPI returns auction variables
  770. func (hdb *HistoryDB) GetAuctionVarsAPI() (*common.AuctionVariables, error) {
  771. cancel, err := hdb.apiConnCon.Acquire()
  772. defer cancel()
  773. if err != nil {
  774. return nil, tracerr.Wrap(err)
  775. }
  776. defer hdb.apiConnCon.Release()
  777. auctionVars := &common.AuctionVariables{}
  778. err = meddler.QueryRow(
  779. hdb.dbRead, auctionVars, `SELECT * FROM auction_vars;`,
  780. )
  781. return auctionVars, tracerr.Wrap(err)
  782. }
  783. // GetAccountAPI returns an account by its index
  784. func (hdb *HistoryDB) GetAccountAPI(idx common.Idx) (*AccountAPI, error) {
  785. cancel, err := hdb.apiConnCon.Acquire()
  786. defer cancel()
  787. if err != nil {
  788. return nil, tracerr.Wrap(err)
  789. }
  790. defer hdb.apiConnCon.Release()
  791. account := &AccountAPI{}
  792. err = meddler.QueryRow(hdb.dbRead, account, `SELECT account.item_id, hez_idx(account.idx,
  793. token.symbol) as idx, account.batch_num, account.bjj, account.eth_addr,
  794. token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
  795. token.eth_addr as token_eth_addr, token.name, token.symbol, token.decimals, token.usd,
  796. token.usd_update, account_update.nonce, account_update.balance
  797. FROM account inner JOIN (
  798. SELECT idx, nonce, balance
  799. FROM account_update
  800. WHERE idx = $1
  801. ORDER BY item_id DESC LIMIT 1
  802. ) AS account_update ON account_update.idx = account.idx
  803. INNER JOIN token ON account.token_id = token.token_id
  804. WHERE account.idx = $1;`, idx)
  805. if err != nil {
  806. return nil, tracerr.Wrap(err)
  807. }
  808. return account, nil
  809. }
  810. // GetAccountsAPI returns a list of accounts from the DB and pagination info
  811. func (hdb *HistoryDB) GetAccountsAPI(
  812. tokenIDs []common.TokenID, ethAddr *ethCommon.Address,
  813. bjj *babyjub.PublicKeyComp, fromItem, limit *uint, order string,
  814. ) ([]AccountAPI, uint64, error) {
  815. if ethAddr != nil && bjj != nil {
  816. return nil, 0, tracerr.Wrap(errors.New("ethAddr and bjj are incompatible"))
  817. }
  818. cancel, err := hdb.apiConnCon.Acquire()
  819. defer cancel()
  820. if err != nil {
  821. return nil, 0, tracerr.Wrap(err)
  822. }
  823. defer hdb.apiConnCon.Release()
  824. var query string
  825. var args []interface{}
  826. queryStr := `SELECT account.item_id, hez_idx(account.idx, token.symbol) as idx, account.batch_num,
  827. account.bjj, account.eth_addr, token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
  828. token.eth_addr as token_eth_addr, token.name, token.symbol, token.decimals, token.usd, token.usd_update,
  829. account_update.nonce, account_update.balance, COUNT(*) OVER() AS total_items
  830. FROM account inner JOIN (
  831. SELECT DISTINCT idx,
  832. first_value(nonce) over(partition by idx ORDER BY item_id DESC) as nonce,
  833. first_value(balance) over(partition by idx ORDER BY item_id DESC) as balance
  834. FROM account_update
  835. ) AS account_update ON account_update.idx = account.idx INNER JOIN token ON account.token_id = token.token_id `
  836. // Apply filters
  837. nextIsAnd := false
  838. // ethAddr filter
  839. if ethAddr != nil {
  840. queryStr += "WHERE account.eth_addr = ? "
  841. nextIsAnd = true
  842. args = append(args, ethAddr)
  843. } else if bjj != nil { // bjj filter
  844. queryStr += "WHERE account.bjj = ? "
  845. nextIsAnd = true
  846. args = append(args, bjj)
  847. }
  848. // tokenID filter
  849. if len(tokenIDs) > 0 {
  850. if nextIsAnd {
  851. queryStr += "AND "
  852. } else {
  853. queryStr += "WHERE "
  854. }
  855. queryStr += "account.token_id IN (?) "
  856. args = append(args, tokenIDs)
  857. nextIsAnd = true
  858. }
  859. if fromItem != nil {
  860. if nextIsAnd {
  861. queryStr += "AND "
  862. } else {
  863. queryStr += "WHERE "
  864. }
  865. if order == OrderAsc {
  866. queryStr += "account.item_id >= ? "
  867. } else {
  868. queryStr += "account.item_id <= ? "
  869. }
  870. args = append(args, fromItem)
  871. }
  872. // pagination
  873. queryStr += "ORDER BY account.item_id "
  874. if order == OrderAsc {
  875. queryStr += " ASC "
  876. } else {
  877. queryStr += " DESC "
  878. }
  879. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  880. query, argsQ, err := sqlx.In(queryStr, args...)
  881. if err != nil {
  882. return nil, 0, tracerr.Wrap(err)
  883. }
  884. query = hdb.dbRead.Rebind(query)
  885. accounts := []*AccountAPI{}
  886. if err := meddler.QueryAll(hdb.dbRead, &accounts, query, argsQ...); err != nil {
  887. return nil, 0, tracerr.Wrap(err)
  888. }
  889. if len(accounts) == 0 {
  890. return []AccountAPI{}, 0, nil
  891. }
  892. return db.SlicePtrsToSlice(accounts).([]AccountAPI),
  893. accounts[0].TotalItems - uint64(len(accounts)), nil
  894. }
  895. // GetCommonAccountAPI returns the account associated to an account idx
  896. func (hdb *HistoryDB) GetCommonAccountAPI(idx common.Idx) (*common.Account, error) {
  897. cancel, err := hdb.apiConnCon.Acquire()
  898. defer cancel()
  899. if err != nil {
  900. return nil, tracerr.Wrap(err)
  901. }
  902. defer hdb.apiConnCon.Release()
  903. account := &common.Account{}
  904. err = meddler.QueryRow(
  905. hdb.dbRead, account, `SELECT * FROM account WHERE idx = $1;`, idx,
  906. )
  907. return account, tracerr.Wrap(err)
  908. }
  909. // GetCoordinatorAPI returns a coordinator by its bidderAddr
  910. func (hdb *HistoryDB) GetCoordinatorAPI(bidderAddr ethCommon.Address) (*CoordinatorAPI, error) {
  911. cancel, err := hdb.apiConnCon.Acquire()
  912. defer cancel()
  913. if err != nil {
  914. return nil, tracerr.Wrap(err)
  915. }
  916. defer hdb.apiConnCon.Release()
  917. return hdb.getCoordinatorAPI(hdb.dbRead, bidderAddr)
  918. }
  919. func (hdb *HistoryDB) getCoordinatorAPI(d meddler.DB, bidderAddr ethCommon.Address) (*CoordinatorAPI, error) {
  920. coordinator := &CoordinatorAPI{}
  921. err := meddler.QueryRow(
  922. d, coordinator,
  923. "SELECT * FROM coordinator WHERE bidder_addr = $1 ORDER BY item_id DESC LIMIT 1;",
  924. bidderAddr,
  925. )
  926. return coordinator, tracerr.Wrap(err)
  927. }
  928. // GetNodeInfoAPI retusnt he NodeInfo
  929. func (hdb *HistoryDB) GetNodeInfoAPI() (*NodeInfo, error) {
  930. cancel, err := hdb.apiConnCon.Acquire()
  931. defer cancel()
  932. if err != nil {
  933. return nil, tracerr.Wrap(err)
  934. }
  935. defer hdb.apiConnCon.Release()
  936. return hdb.GetNodeInfo()
  937. }
  938. // GetBucketUpdatesInternalAPI returns the latest bucket updates
  939. func (hdb *HistoryDB) GetBucketUpdatesInternalAPI() ([]BucketUpdateAPI, error) {
  940. var bucketUpdates []*BucketUpdateAPI
  941. err := meddler.QueryAll(
  942. hdb.dbRead, &bucketUpdates,
  943. `SELECT num_bucket, withdrawals FROM bucket_update
  944. WHERE item_id in(SELECT max(item_id) FROM bucket_update
  945. group by num_bucket)
  946. ORDER BY num_bucket ASC;`,
  947. )
  948. return db.SlicePtrsToSlice(bucketUpdates).([]BucketUpdateAPI), tracerr.Wrap(err)
  949. }
  950. // GetNextForgersInternalAPI returns next forgers
  951. func (hdb *HistoryDB) GetNextForgersInternalAPI(auctionVars *common.AuctionVariables,
  952. auctionConsts *common.AuctionConstants,
  953. lastBlock common.Block, currentSlot, lastClosedSlot int64) ([]NextForgerAPI, error) {
  954. secondsPerBlock := int64(15) //nolint:gomnd
  955. // currentSlot and lastClosedSlot included
  956. limit := uint(lastClosedSlot - currentSlot + 1)
  957. bids, _, err := hdb.getBestBidsAPI(hdb.dbRead, &currentSlot, &lastClosedSlot, nil, &limit, "ASC")
  958. if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
  959. return nil, tracerr.Wrap(err)
  960. }
  961. nextForgers := []NextForgerAPI{}
  962. // Get min bid info
  963. var minBidInfo []MinBidInfo
  964. if currentSlot >= auctionVars.DefaultSlotSetBidSlotNum {
  965. // All min bids can be calculated with the last update of AuctionVariables
  966. minBidInfo = []MinBidInfo{{
  967. DefaultSlotSetBid: auctionVars.DefaultSlotSetBid,
  968. DefaultSlotSetBidSlotNum: auctionVars.DefaultSlotSetBidSlotNum,
  969. }}
  970. } else {
  971. // Get all the relevant updates from the DB
  972. minBidInfo, err = hdb.getMinBidInfo(hdb.dbRead, currentSlot, lastClosedSlot)
  973. if err != nil {
  974. return nil, tracerr.Wrap(err)
  975. }
  976. }
  977. // Create nextForger for each slot
  978. for i := currentSlot; i <= lastClosedSlot; i++ {
  979. fromBlock := i*int64(auctionConsts.BlocksPerSlot) +
  980. auctionConsts.GenesisBlockNum
  981. toBlock := (i+1)*int64(auctionConsts.BlocksPerSlot) +
  982. auctionConsts.GenesisBlockNum - 1
  983. nextForger := NextForgerAPI{
  984. Period: Period{
  985. SlotNum: i,
  986. FromBlock: fromBlock,
  987. ToBlock: toBlock,
  988. FromTimestamp: lastBlock.Timestamp.Add(time.Second *
  989. time.Duration(secondsPerBlock*(fromBlock-lastBlock.Num))),
  990. ToTimestamp: lastBlock.Timestamp.Add(time.Second *
  991. time.Duration(secondsPerBlock*(toBlock-lastBlock.Num))),
  992. },
  993. }
  994. foundForger := false
  995. // If there is a bid for a slot, get forger (coordinator)
  996. for j := range bids {
  997. slotNum := bids[j].SlotNum
  998. if slotNum == i {
  999. // There's a bid for the slot
  1000. // Check if the bid is greater than the minimum required
  1001. for i := 0; i < len(minBidInfo); i++ {
  1002. // Find the most recent update
  1003. if slotNum >= minBidInfo[i].DefaultSlotSetBidSlotNum {
  1004. // Get min bid
  1005. minBidSelector := slotNum % int64(len(auctionVars.DefaultSlotSetBid))
  1006. minBid := minBidInfo[i].DefaultSlotSetBid[minBidSelector]
  1007. // Check if the bid has beaten the minimum
  1008. bid, ok := new(big.Int).SetString(string(bids[j].BidValue), 10)
  1009. if !ok {
  1010. return nil, tracerr.New("Wrong bid value, error parsing it as big.Int")
  1011. }
  1012. if minBid.Cmp(bid) == 1 {
  1013. // Min bid is greater than bid, the slot will be forged by boot coordinator
  1014. break
  1015. }
  1016. foundForger = true
  1017. break
  1018. }
  1019. }
  1020. if !foundForger { // There is no bid or it's smaller than the minimum
  1021. break
  1022. }
  1023. coordinator, err := hdb.getCoordinatorAPI(hdb.dbRead, bids[j].Bidder)
  1024. if err != nil {
  1025. return nil, tracerr.Wrap(err)
  1026. }
  1027. nextForger.Coordinator = *coordinator
  1028. break
  1029. }
  1030. }
  1031. // If there is no bid, the coordinator that will forge is boot coordinator
  1032. if !foundForger {
  1033. nextForger.Coordinator = CoordinatorAPI{
  1034. Forger: auctionVars.BootCoordinator,
  1035. URL: auctionVars.BootCoordinatorURL,
  1036. }
  1037. }
  1038. nextForgers = append(nextForgers, nextForger)
  1039. }
  1040. return nextForgers, nil
  1041. }
  1042. // GetMetricsInternalAPI returns the MetricsAPI
  1043. func (hdb *HistoryDB) GetMetricsInternalAPI(lastBatchNum common.BatchNum) (*MetricsAPI, error) {
  1044. var metrics MetricsAPI
  1045. // Get the first and last batch of the last 24h and their timestamps
  1046. // if u.state.Network.LastBatch == nil {
  1047. // return &metrics, nil
  1048. // }
  1049. type period struct {
  1050. FromBatchNum common.BatchNum `meddler:"from_batch_num"`
  1051. FromTimestamp time.Time `meddler:"from_timestamp"`
  1052. ToBatchNum common.BatchNum `meddler:"-"`
  1053. ToTimestamp time.Time `meddler:"to_timestamp"`
  1054. }
  1055. p := &period{
  1056. ToBatchNum: lastBatchNum,
  1057. }
  1058. if err := meddler.QueryRow(
  1059. hdb.dbRead, p, `SELECT
  1060. COALESCE (MIN(batch.batch_num), 0) as from_batch_num,
  1061. COALESCE (MIN(block.timestamp), NOW()) AS from_timestamp,
  1062. COALESCE (MAX(block.timestamp), NOW()) AS to_timestamp
  1063. FROM batch INNER JOIN block ON batch.eth_block_num = block.eth_block_num
  1064. WHERE block.timestamp >= NOW() - INTERVAL '24 HOURS';`,
  1065. ); err != nil {
  1066. return nil, tracerr.Wrap(err)
  1067. }
  1068. // Get the amount of txs of that period
  1069. row := hdb.dbRead.QueryRow(
  1070. `SELECT COUNT(*) as total_txs FROM tx WHERE tx.batch_num between $1 AND $2;`,
  1071. p.FromBatchNum, p.ToBatchNum,
  1072. )
  1073. var nTxs int
  1074. if err := row.Scan(&nTxs); err != nil {
  1075. return nil, tracerr.Wrap(err)
  1076. }
  1077. // Set txs/s
  1078. seconds := p.ToTimestamp.Sub(p.FromTimestamp).Seconds()
  1079. if seconds == 0 { // Avoid dividing by 0
  1080. seconds++
  1081. }
  1082. metrics.TransactionsPerSecond = float64(nTxs) / seconds
  1083. // Set txs/batch
  1084. nBatches := p.ToBatchNum - p.FromBatchNum + 1
  1085. if nBatches == 0 { // Avoid dividing by 0
  1086. nBatches++
  1087. }
  1088. if (p.ToBatchNum - p.FromBatchNum) > 0 {
  1089. fmt.Printf("DBG ntxs: %v, nBatches: %v\n", nTxs, nBatches)
  1090. metrics.TransactionsPerBatch = float64(nTxs) /
  1091. float64(nBatches)
  1092. } else {
  1093. metrics.TransactionsPerBatch = 0
  1094. }
  1095. // Get total fee of that period
  1096. row = hdb.dbRead.QueryRow(
  1097. `SELECT COALESCE (SUM(total_fees_usd), 0) FROM batch WHERE batch_num between $1 AND $2;`,
  1098. p.FromBatchNum, p.ToBatchNum,
  1099. )
  1100. var totalFee float64
  1101. if err := row.Scan(&totalFee); err != nil {
  1102. return nil, tracerr.Wrap(err)
  1103. }
  1104. // Set batch frequency
  1105. metrics.BatchFrequency = seconds / float64(nBatches)
  1106. if nTxs > 0 {
  1107. metrics.AvgTransactionFee = totalFee / float64(nTxs)
  1108. } else {
  1109. metrics.AvgTransactionFee = 0
  1110. }
  1111. // Get and set amount of registered accounts
  1112. type registeredAccounts struct {
  1113. TotalIdx int64 `meddler:"total_idx"`
  1114. TotalBJJ int64 `meddler:"total_bjj"`
  1115. }
  1116. ra := &registeredAccounts{}
  1117. if err := meddler.QueryRow(
  1118. hdb.dbRead, ra,
  1119. `SELECT COUNT(*) AS total_bjj, COUNT(DISTINCT(bjj)) AS total_idx FROM account;`,
  1120. ); err != nil {
  1121. return nil, tracerr.Wrap(err)
  1122. }
  1123. metrics.TotalAccounts = ra.TotalIdx
  1124. metrics.TotalBJJs = ra.TotalBJJ
  1125. // Get and set estimated time to forge L1 tx
  1126. row = hdb.dbRead.QueryRow(
  1127. `SELECT COALESCE (AVG(EXTRACT(EPOCH FROM (forged.timestamp - added.timestamp))), 0) FROM tx
  1128. INNER JOIN block AS added ON tx.eth_block_num = added.eth_block_num
  1129. INNER JOIN batch AS forged_batch ON tx.batch_num = forged_batch.batch_num
  1130. INNER JOIN block AS forged ON forged_batch.eth_block_num = forged.eth_block_num
  1131. WHERE tx.batch_num between $1 and $2 AND tx.is_l1 AND tx.user_origin;`,
  1132. p.FromBatchNum, p.ToBatchNum,
  1133. )
  1134. var timeToForgeL1 float64
  1135. if err := row.Scan(&timeToForgeL1); err != nil {
  1136. return nil, tracerr.Wrap(err)
  1137. }
  1138. metrics.EstimatedTimeToForgeL1 = timeToForgeL1
  1139. return &metrics, nil
  1140. }
  1141. // GetStateAPI returns the StateAPI
  1142. func (hdb *HistoryDB) GetStateAPI() (*StateAPI, error) {
  1143. cancel, err := hdb.apiConnCon.Acquire()
  1144. defer cancel()
  1145. if err != nil {
  1146. return nil, tracerr.Wrap(err)
  1147. }
  1148. defer hdb.apiConnCon.Release()
  1149. return hdb.getStateAPI(hdb.dbRead)
  1150. }