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.

996 lines
28 KiB

  1. package historydb
  2. import (
  3. "database/sql"
  4. "errors"
  5. "fmt"
  6. "math"
  7. "math/big"
  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/hermez-node/log"
  12. "github.com/iden3/go-iden3-crypto/babyjub"
  13. "github.com/jmoiron/sqlx"
  14. //nolint:errcheck // driver for postgres DB
  15. _ "github.com/lib/pq"
  16. "github.com/russross/meddler"
  17. )
  18. const (
  19. // OrderAsc indicates ascending order when using pagination
  20. OrderAsc = "ASC"
  21. // OrderDesc indicates descending order when using pagination
  22. OrderDesc = "DESC"
  23. )
  24. // TODO(Edu): Document here how HistoryDB is kept consistent
  25. // HistoryDB persist the historic of the rollup
  26. type HistoryDB struct {
  27. db *sqlx.DB
  28. }
  29. // BlockData contains the information of a Block
  30. type BlockData struct {
  31. Block *common.Block
  32. // Rollup
  33. // L1UserTxs that were submitted in the block
  34. L1UserTxs []common.L1Tx
  35. Batches []BatchData
  36. RegisteredTokens []common.Token
  37. RollupVars *common.RollupVars
  38. // Auction
  39. Bids []common.Bid
  40. Coordinators []common.Coordinator
  41. AuctionVars *common.AuctionVars
  42. WithdrawDelayerVars *common.WithdrawDelayerVars
  43. // TODO: enable when common.WithdrawalDelayerVars is Merged from Synchronizer PR
  44. // WithdrawalDelayerVars *common.WithdrawalDelayerVars
  45. }
  46. // BatchData contains the information of a Batch
  47. type BatchData struct {
  48. // L1UserTxs that were forged in the batch
  49. L1Batch bool // TODO: Remove once Batch.ForgeL1TxsNum is a pointer
  50. L1UserTxs []common.L1Tx
  51. L1CoordinatorTxs []common.L1Tx
  52. L2Txs []common.L2Tx
  53. CreatedAccounts []common.Account
  54. ExitTree []common.ExitInfo
  55. Batch *common.Batch
  56. }
  57. // NewBatchData creates an empty BatchData with the slices initialized.
  58. func NewBatchData() *BatchData {
  59. return &BatchData{
  60. L1Batch: false,
  61. L1UserTxs: make([]common.L1Tx, 0),
  62. L1CoordinatorTxs: make([]common.L1Tx, 0),
  63. L2Txs: make([]common.L2Tx, 0),
  64. CreatedAccounts: make([]common.Account, 0),
  65. ExitTree: make([]common.ExitInfo, 0),
  66. Batch: &common.Batch{},
  67. }
  68. }
  69. // NewHistoryDB initialize the DB
  70. func NewHistoryDB(db *sqlx.DB) *HistoryDB {
  71. return &HistoryDB{db: db}
  72. }
  73. // AddBlock insert a block into the DB
  74. func (hdb *HistoryDB) AddBlock(block *common.Block) error { return hdb.addBlock(hdb.db, block) }
  75. func (hdb *HistoryDB) addBlock(d meddler.DB, block *common.Block) error {
  76. return meddler.Insert(d, "block", block)
  77. }
  78. // AddBlocks inserts blocks into the DB
  79. func (hdb *HistoryDB) AddBlocks(blocks []common.Block) error {
  80. return hdb.addBlocks(hdb.db, blocks)
  81. }
  82. func (hdb *HistoryDB) addBlocks(d meddler.DB, blocks []common.Block) error {
  83. return db.BulkInsert(
  84. d,
  85. `INSERT INTO block (
  86. eth_block_num,
  87. timestamp,
  88. hash
  89. ) VALUES %s;`,
  90. blocks[:],
  91. )
  92. }
  93. // GetBlock retrieve a block from the DB, given a block number
  94. func (hdb *HistoryDB) GetBlock(blockNum int64) (*common.Block, error) {
  95. block := &common.Block{}
  96. err := meddler.QueryRow(
  97. hdb.db, block,
  98. "SELECT * FROM block WHERE eth_block_num = $1;", blockNum,
  99. )
  100. return block, err
  101. }
  102. // GetBlocks retrieve blocks from the DB, given a range of block numbers defined by from and to
  103. func (hdb *HistoryDB) GetBlocks(from, to int64) ([]common.Block, error) {
  104. var blocks []*common.Block
  105. err := meddler.QueryAll(
  106. hdb.db, &blocks,
  107. "SELECT * FROM block WHERE $1 <= eth_block_num AND eth_block_num < $2;",
  108. from, to,
  109. )
  110. return db.SlicePtrsToSlice(blocks).([]common.Block), err
  111. }
  112. // GetLastBlock retrieve the block with the highest block number from the DB
  113. func (hdb *HistoryDB) GetLastBlock() (*common.Block, error) {
  114. block := &common.Block{}
  115. err := meddler.QueryRow(
  116. hdb.db, block, "SELECT * FROM block ORDER BY eth_block_num DESC LIMIT 1;",
  117. )
  118. return block, err
  119. }
  120. // AddBatch insert a Batch into the DB
  121. func (hdb *HistoryDB) AddBatch(batch *common.Batch) error { return hdb.addBatch(hdb.db, batch) }
  122. func (hdb *HistoryDB) addBatch(d meddler.DB, batch *common.Batch) error {
  123. // Calculate total collected fees in USD
  124. // Get IDs of collected tokens for fees
  125. tokenIDs := []common.TokenID{}
  126. for id := range batch.CollectedFees {
  127. tokenIDs = append(tokenIDs, id)
  128. }
  129. // Get USD value of the tokens
  130. type tokenPrice struct {
  131. ID common.TokenID `meddler:"token_id"`
  132. USD *float64 `meddler:"usd"`
  133. Decimals int `meddler:"decimals"`
  134. }
  135. query, args, err := sqlx.In(
  136. "SELECT token_id, usd, decimals FROM token WHERE token_id IN (?)",
  137. tokenIDs,
  138. )
  139. if err != nil {
  140. return err
  141. }
  142. query = hdb.db.Rebind(query)
  143. var tokenPrices []*tokenPrice
  144. if err := meddler.QueryAll(
  145. hdb.db, &tokenPrices, query, args...,
  146. ); err != nil {
  147. return err
  148. }
  149. // Calculate total collected
  150. var total float64
  151. for _, tokenPrice := range tokenPrices {
  152. if tokenPrice.USD == nil {
  153. continue
  154. }
  155. f := new(big.Float).SetInt(batch.CollectedFees[tokenPrice.ID])
  156. amount, _ := f.Float64()
  157. total += *tokenPrice.USD * (amount / math.Pow(10, float64(tokenPrice.Decimals))) //nolint decimals have to be ^10
  158. }
  159. batch.TotalFeesUSD = &total
  160. // Insert to DB
  161. return meddler.Insert(d, "batch", batch)
  162. }
  163. // AddBatches insert Bids into the DB
  164. func (hdb *HistoryDB) AddBatches(batches []common.Batch) error {
  165. return hdb.addBatches(hdb.db, batches)
  166. }
  167. func (hdb *HistoryDB) addBatches(d meddler.DB, batches []common.Batch) error {
  168. for i := 0; i < len(batches); i++ {
  169. if err := hdb.addBatch(d, &batches[i]); err != nil {
  170. return err
  171. }
  172. }
  173. return nil
  174. }
  175. // GetBatches retrieve batches from the DB, given a range of batch numbers defined by from and to
  176. func (hdb *HistoryDB) GetBatches(from, to common.BatchNum) ([]common.Batch, error) {
  177. var batches []*common.Batch
  178. err := meddler.QueryAll(
  179. hdb.db, &batches,
  180. "SELECT * FROM batch WHERE $1 <= batch_num AND batch_num < $2;",
  181. from, to,
  182. )
  183. return db.SlicePtrsToSlice(batches).([]common.Batch), err
  184. }
  185. // GetLastBatchNum returns the BatchNum of the latest forged batch
  186. func (hdb *HistoryDB) GetLastBatchNum() (common.BatchNum, error) {
  187. row := hdb.db.QueryRow("SELECT batch_num FROM batch ORDER BY batch_num DESC LIMIT 1;")
  188. var batchNum common.BatchNum
  189. return batchNum, row.Scan(&batchNum)
  190. }
  191. // GetLastL1TxsNum returns the greatest ForgeL1TxsNum in the DB. If there's no
  192. // batch in the DB (nil, nil) is returned.
  193. func (hdb *HistoryDB) GetLastL1TxsNum() (*int64, error) {
  194. row := hdb.db.QueryRow("SELECT MAX(forge_l1_txs_num) FROM batch;")
  195. lastL1TxsNum := new(int64)
  196. return lastL1TxsNum, row.Scan(&lastL1TxsNum)
  197. }
  198. // Reorg deletes all the information that was added into the DB after the
  199. // lastValidBlock. If lastValidBlock is negative, all block information is
  200. // deleted.
  201. func (hdb *HistoryDB) Reorg(lastValidBlock int64) error {
  202. var err error
  203. if lastValidBlock < 0 {
  204. _, err = hdb.db.Exec("DELETE FROM block;")
  205. } else {
  206. _, err = hdb.db.Exec("DELETE FROM block WHERE eth_block_num > $1;", lastValidBlock)
  207. }
  208. return err
  209. }
  210. // SyncPoD stores all the data that can be changed / added on a block in the PoD SC
  211. func (hdb *HistoryDB) SyncPoD(
  212. blockNum uint64,
  213. bids []common.Bid,
  214. coordinators []common.Coordinator,
  215. vars *common.AuctionVars,
  216. ) error {
  217. return nil
  218. }
  219. // AddBids insert Bids into the DB
  220. func (hdb *HistoryDB) AddBids(bids []common.Bid) error { return hdb.addBids(hdb.db, bids) }
  221. func (hdb *HistoryDB) addBids(d meddler.DB, bids []common.Bid) error {
  222. // TODO: check the coordinator info
  223. return db.BulkInsert(
  224. d,
  225. "INSERT INTO bid (slot_num, bid_value, eth_block_num, bidder_addr) VALUES %s;",
  226. bids[:],
  227. )
  228. }
  229. // GetBids return the bids
  230. func (hdb *HistoryDB) GetBids() ([]common.Bid, error) {
  231. var bids []*common.Bid
  232. err := meddler.QueryAll(
  233. hdb.db, &bids,
  234. "SELECT * FROM bid;",
  235. )
  236. return db.SlicePtrsToSlice(bids).([]common.Bid), err
  237. }
  238. // AddCoordinators insert Coordinators into the DB
  239. func (hdb *HistoryDB) AddCoordinators(coordinators []common.Coordinator) error {
  240. return hdb.addCoordinators(hdb.db, coordinators)
  241. }
  242. func (hdb *HistoryDB) addCoordinators(d meddler.DB, coordinators []common.Coordinator) error {
  243. return db.BulkInsert(
  244. d,
  245. "INSERT INTO coordinator (bidder_addr, forger_addr, eth_block_num, url) VALUES %s;",
  246. coordinators[:],
  247. )
  248. }
  249. // AddExitTree insert Exit tree into the DB
  250. func (hdb *HistoryDB) AddExitTree(exitTree []common.ExitInfo) error {
  251. return hdb.addExitTree(hdb.db, exitTree)
  252. }
  253. func (hdb *HistoryDB) addExitTree(d meddler.DB, exitTree []common.ExitInfo) error {
  254. return db.BulkInsert(
  255. d,
  256. "INSERT INTO exit_tree (batch_num, account_idx, merkle_proof, balance, "+
  257. "instant_withdrawn, delayed_withdraw_request, delayed_withdrawn) VALUES %s;",
  258. exitTree[:],
  259. )
  260. }
  261. // AddToken insert a token into the DB
  262. func (hdb *HistoryDB) AddToken(token *common.Token) error {
  263. return meddler.Insert(hdb.db, "token", token)
  264. }
  265. // AddTokens insert tokens into the DB
  266. func (hdb *HistoryDB) AddTokens(tokens []common.Token) error { return hdb.addTokens(hdb.db, tokens) }
  267. func (hdb *HistoryDB) addTokens(d meddler.DB, tokens []common.Token) error {
  268. return db.BulkInsert(
  269. d,
  270. `INSERT INTO token (
  271. token_id,
  272. eth_block_num,
  273. eth_addr,
  274. name,
  275. symbol,
  276. decimals
  277. ) VALUES %s;`,
  278. tokens[:],
  279. )
  280. }
  281. // UpdateTokenValue updates the USD value of a token
  282. func (hdb *HistoryDB) UpdateTokenValue(tokenSymbol string, value float64) error {
  283. _, err := hdb.db.Exec(
  284. "UPDATE token SET usd = $1 WHERE symbol = $2;",
  285. value, tokenSymbol,
  286. )
  287. return err
  288. }
  289. // GetToken returns a token from the DB given a TokenID
  290. func (hdb *HistoryDB) GetToken(tokenID common.TokenID) (*TokenRead, error) {
  291. token := &TokenRead{}
  292. err := meddler.QueryRow(
  293. hdb.db, token, `SELECT * FROM token WHERE token_id = $1;`, tokenID,
  294. )
  295. return token, err
  296. }
  297. // GetTokens returns a list of tokens from the DB
  298. func (hdb *HistoryDB) GetTokens(ids []common.TokenID, symbols []string, name string, fromItem, limit *uint, order string) ([]TokenRead, *db.Pagination, error) {
  299. var query string
  300. var args []interface{}
  301. queryStr := `SELECT * , COUNT(*) OVER() AS total_items, MIN(token.item_id) OVER() AS first_item, MAX(token.item_id) OVER() AS last_item FROM token `
  302. // Apply filters
  303. nextIsAnd := false
  304. if len(ids) > 0 {
  305. queryStr += "WHERE token_id IN (?) "
  306. nextIsAnd = true
  307. args = append(args, ids)
  308. }
  309. if len(symbols) > 0 {
  310. if nextIsAnd {
  311. queryStr += "AND "
  312. } else {
  313. queryStr += "WHERE "
  314. }
  315. queryStr += "symbol IN (?) "
  316. args = append(args, symbols)
  317. nextIsAnd = true
  318. }
  319. if name != "" {
  320. if nextIsAnd {
  321. queryStr += "AND "
  322. } else {
  323. queryStr += "WHERE "
  324. }
  325. queryStr += "name ~ ? "
  326. args = append(args, name)
  327. nextIsAnd = true
  328. }
  329. if fromItem != nil {
  330. if nextIsAnd {
  331. queryStr += "AND "
  332. } else {
  333. queryStr += "WHERE "
  334. }
  335. if order == OrderAsc {
  336. queryStr += "item_id >= ? "
  337. } else {
  338. queryStr += "item_id <= ? "
  339. }
  340. args = append(args, fromItem)
  341. }
  342. // pagination
  343. queryStr += "ORDER BY item_id "
  344. if order == OrderAsc {
  345. queryStr += "ASC "
  346. } else {
  347. queryStr += "DESC "
  348. }
  349. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  350. query, argsQ, err := sqlx.In(queryStr, args...)
  351. if err != nil {
  352. return nil, nil, err
  353. }
  354. query = hdb.db.Rebind(query)
  355. tokens := []*TokenRead{}
  356. if err := meddler.QueryAll(hdb.db, &tokens, query, argsQ...); err != nil {
  357. return nil, nil, err
  358. }
  359. if len(tokens) == 0 {
  360. return nil, nil, sql.ErrNoRows
  361. }
  362. return db.SlicePtrsToSlice(tokens).([]TokenRead), &db.Pagination{
  363. TotalItems: tokens[0].TotalItems,
  364. FirstItem: tokens[0].FirstItem,
  365. LastItem: tokens[0].LastItem,
  366. }, nil
  367. }
  368. // GetTokenSymbols returns all the token symbols from the DB
  369. func (hdb *HistoryDB) GetTokenSymbols() ([]string, error) {
  370. var tokenSymbols []string
  371. rows, err := hdb.db.Query("SELECT symbol FROM token;")
  372. if err != nil {
  373. return nil, err
  374. }
  375. sym := new(string)
  376. for rows.Next() {
  377. err = rows.Scan(sym)
  378. if err != nil {
  379. return nil, err
  380. }
  381. tokenSymbols = append(tokenSymbols, *sym)
  382. }
  383. return tokenSymbols, nil
  384. }
  385. // AddAccounts insert accounts into the DB
  386. func (hdb *HistoryDB) AddAccounts(accounts []common.Account) error {
  387. return hdb.addAccounts(hdb.db, accounts)
  388. }
  389. func (hdb *HistoryDB) addAccounts(d meddler.DB, accounts []common.Account) error {
  390. return db.BulkInsert(
  391. d,
  392. `INSERT INTO account (
  393. idx,
  394. token_id,
  395. batch_num,
  396. bjj,
  397. eth_addr
  398. ) VALUES %s;`,
  399. accounts[:],
  400. )
  401. }
  402. // GetAccounts returns a list of accounts from the DB
  403. func (hdb *HistoryDB) GetAccounts() ([]common.Account, error) {
  404. var accs []*common.Account
  405. err := meddler.QueryAll(
  406. hdb.db, &accs,
  407. "SELECT * FROM account ORDER BY idx;",
  408. )
  409. return db.SlicePtrsToSlice(accs).([]common.Account), err
  410. }
  411. // AddL1Txs inserts L1 txs to the DB. USD and LoadAmountUSD will be set automatically before storing the tx.
  412. // If the tx is originated by a coordinator, BatchNum must be provided. If it's originated by a user,
  413. // BatchNum should be null, and the value will be setted by a trigger when a batch forges the tx.
  414. func (hdb *HistoryDB) AddL1Txs(l1txs []common.L1Tx) error { return hdb.addL1Txs(hdb.db, l1txs) }
  415. // addL1Txs inserts L1 txs to the DB. USD and LoadAmountUSD will be set automatically before storing the tx.
  416. // If the tx is originated by a coordinator, BatchNum must be provided. If it's originated by a user,
  417. // BatchNum should be null, and the value will be setted by a trigger when a batch forges the tx.
  418. func (hdb *HistoryDB) addL1Txs(d meddler.DB, l1txs []common.L1Tx) error {
  419. txs := []txWrite{}
  420. for i := 0; i < len(l1txs); i++ {
  421. af := new(big.Float).SetInt(l1txs[i].Amount)
  422. amountFloat, _ := af.Float64()
  423. laf := new(big.Float).SetInt(l1txs[i].LoadAmount)
  424. loadAmountFloat, _ := laf.Float64()
  425. txs = append(txs, txWrite{
  426. // Generic
  427. IsL1: true,
  428. TxID: l1txs[i].TxID,
  429. Type: l1txs[i].Type,
  430. Position: l1txs[i].Position,
  431. FromIdx: &l1txs[i].FromIdx,
  432. ToIdx: l1txs[i].ToIdx,
  433. Amount: l1txs[i].Amount,
  434. AmountFloat: amountFloat,
  435. TokenID: l1txs[i].TokenID,
  436. BatchNum: l1txs[i].BatchNum,
  437. EthBlockNum: l1txs[i].EthBlockNum,
  438. // L1
  439. ToForgeL1TxsNum: l1txs[i].ToForgeL1TxsNum,
  440. UserOrigin: &l1txs[i].UserOrigin,
  441. FromEthAddr: &l1txs[i].FromEthAddr,
  442. FromBJJ: l1txs[i].FromBJJ,
  443. LoadAmount: l1txs[i].LoadAmount,
  444. LoadAmountFloat: &loadAmountFloat,
  445. })
  446. }
  447. return hdb.addTxs(d, txs)
  448. }
  449. // AddL2Txs inserts L2 txs to the DB. TokenID, USD and FeeUSD will be set automatically before storing the tx.
  450. func (hdb *HistoryDB) AddL2Txs(l2txs []common.L2Tx) error { return hdb.addL2Txs(hdb.db, l2txs) }
  451. // addL2Txs inserts L2 txs to the DB. TokenID, USD and FeeUSD will be set automatically before storing the tx.
  452. func (hdb *HistoryDB) addL2Txs(d meddler.DB, l2txs []common.L2Tx) error {
  453. txs := []txWrite{}
  454. for i := 0; i < len(l2txs); i++ {
  455. f := new(big.Float).SetInt(l2txs[i].Amount)
  456. amountFloat, _ := f.Float64()
  457. txs = append(txs, txWrite{
  458. // Generic
  459. IsL1: false,
  460. TxID: l2txs[i].TxID,
  461. Type: l2txs[i].Type,
  462. Position: l2txs[i].Position,
  463. FromIdx: &l2txs[i].FromIdx,
  464. ToIdx: l2txs[i].ToIdx,
  465. Amount: l2txs[i].Amount,
  466. AmountFloat: amountFloat,
  467. BatchNum: &l2txs[i].BatchNum,
  468. EthBlockNum: l2txs[i].EthBlockNum,
  469. // L2
  470. Fee: &l2txs[i].Fee,
  471. Nonce: &l2txs[i].Nonce,
  472. })
  473. }
  474. return hdb.addTxs(d, txs)
  475. }
  476. func (hdb *HistoryDB) addTxs(d meddler.DB, txs []txWrite) error {
  477. return db.BulkInsert(
  478. d,
  479. `INSERT INTO tx (
  480. is_l1,
  481. id,
  482. type,
  483. position,
  484. from_idx,
  485. to_idx,
  486. amount,
  487. amount_f,
  488. token_id,
  489. batch_num,
  490. eth_block_num,
  491. to_forge_l1_txs_num,
  492. user_origin,
  493. from_eth_addr,
  494. from_bjj,
  495. load_amount,
  496. load_amount_f,
  497. fee,
  498. nonce
  499. ) VALUES %s;`,
  500. txs[:],
  501. )
  502. }
  503. // // GetTxs returns a list of txs from the DB
  504. // func (hdb *HistoryDB) GetTxs() ([]common.Tx, error) {
  505. // var txs []*common.Tx
  506. // err := meddler.QueryAll(
  507. // hdb.db, &txs,
  508. // `SELECT * FROM tx
  509. // ORDER BY (batch_num, position) ASC`,
  510. // )
  511. // return db.SlicePtrsToSlice(txs).([]common.Tx), err
  512. // }
  513. // GetHistoryTx returns a tx from the DB given a TxID
  514. func (hdb *HistoryDB) GetHistoryTx(txID common.TxID) (*HistoryTx, error) {
  515. tx := &HistoryTx{}
  516. err := meddler.QueryRow(
  517. hdb.db, tx, `SELECT tx.item_id, tx.is_l1, tx.id, tx.type, tx.position,
  518. tx.from_idx, tx.to_idx, tx.amount, tx.token_id, tx.amount_usd,
  519. tx.batch_num, tx.eth_block_num, tx.to_forge_l1_txs_num, tx.user_origin,
  520. tx.from_eth_addr, tx.from_bjj, tx.load_amount,
  521. tx.load_amount_usd, tx.fee, tx.fee_usd, tx.nonce,
  522. token.token_id, token.eth_block_num AS token_block,
  523. token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
  524. token.usd_update, block.timestamp
  525. FROM tx INNER JOIN token ON tx.token_id = token.token_id
  526. INNER JOIN block ON tx.eth_block_num = block.eth_block_num
  527. WHERE tx.id = $1;`, txID,
  528. )
  529. return tx, err
  530. }
  531. // GetHistoryTxs returns a list of txs from the DB using the HistoryTx struct
  532. // and pagination info
  533. func (hdb *HistoryDB) GetHistoryTxs(
  534. ethAddr *ethCommon.Address, bjj *babyjub.PublicKey,
  535. tokenID *common.TokenID, idx *common.Idx, batchNum *uint, txType *common.TxType,
  536. fromItem, limit *uint, order string,
  537. ) ([]HistoryTx, *db.Pagination, error) {
  538. if ethAddr != nil && bjj != nil {
  539. return nil, nil, errors.New("ethAddr and bjj are incompatible")
  540. }
  541. var query string
  542. var args []interface{}
  543. queryStr := `SELECT tx.item_id, tx.is_l1, tx.id, tx.type, tx.position,
  544. tx.from_idx, tx.to_idx, tx.amount, tx.token_id, tx.amount_usd,
  545. tx.batch_num, tx.eth_block_num, tx.to_forge_l1_txs_num, tx.user_origin,
  546. tx.from_eth_addr, tx.from_bjj, tx.load_amount,
  547. tx.load_amount_usd, tx.fee, tx.fee_usd, tx.nonce,
  548. token.token_id, token.eth_block_num AS token_block,
  549. token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
  550. token.usd_update, block.timestamp, count(*) OVER() AS total_items,
  551. MIN(tx.item_id) OVER() AS first_item, MAX(tx.item_id) OVER() AS last_item
  552. FROM tx INNER JOIN token ON tx.token_id = token.token_id
  553. INNER JOIN block ON tx.eth_block_num = block.eth_block_num `
  554. // Apply filters
  555. nextIsAnd := false
  556. // ethAddr filter
  557. if ethAddr != nil {
  558. queryStr = `WITH acc AS
  559. (select idx from account where eth_addr = ?) ` + queryStr
  560. queryStr += ", acc WHERE (tx.from_idx IN(acc.idx) OR tx.to_idx IN(acc.idx)) "
  561. nextIsAnd = true
  562. args = append(args, ethAddr)
  563. } else if bjj != nil { // bjj filter
  564. queryStr = `WITH acc AS
  565. (select idx from account where bjj = ?) ` + queryStr
  566. queryStr += ", acc WHERE (tx.from_idx IN(acc.idx) OR tx.to_idx IN(acc.idx)) "
  567. nextIsAnd = true
  568. args = append(args, bjj)
  569. }
  570. // tokenID filter
  571. if tokenID != nil {
  572. if nextIsAnd {
  573. queryStr += "AND "
  574. } else {
  575. queryStr += "WHERE "
  576. }
  577. queryStr += "tx.token_id = ? "
  578. args = append(args, tokenID)
  579. nextIsAnd = true
  580. }
  581. // idx filter
  582. if idx != nil {
  583. if nextIsAnd {
  584. queryStr += "AND "
  585. } else {
  586. queryStr += "WHERE "
  587. }
  588. queryStr += "(tx.from_idx = ? OR tx.to_idx = ?) "
  589. args = append(args, idx, idx)
  590. nextIsAnd = true
  591. }
  592. // batchNum filter
  593. if batchNum != nil {
  594. if nextIsAnd {
  595. queryStr += "AND "
  596. } else {
  597. queryStr += "WHERE "
  598. }
  599. queryStr += "tx.batch_num = ? "
  600. args = append(args, batchNum)
  601. nextIsAnd = true
  602. }
  603. // txType filter
  604. if txType != nil {
  605. if nextIsAnd {
  606. queryStr += "AND "
  607. } else {
  608. queryStr += "WHERE "
  609. }
  610. queryStr += "tx.type = ? "
  611. args = append(args, txType)
  612. nextIsAnd = true
  613. }
  614. if fromItem != nil {
  615. if nextIsAnd {
  616. queryStr += "AND "
  617. } else {
  618. queryStr += "WHERE "
  619. }
  620. if order == OrderAsc {
  621. queryStr += "tx.item_id >= ? "
  622. } else {
  623. queryStr += "tx.item_id <= ? "
  624. }
  625. args = append(args, fromItem)
  626. nextIsAnd = true
  627. }
  628. if nextIsAnd {
  629. queryStr += "AND "
  630. } else {
  631. queryStr += "WHERE "
  632. }
  633. queryStr += "tx.batch_num IS NOT NULL "
  634. // pagination
  635. queryStr += "ORDER BY tx.item_id "
  636. if order == OrderAsc {
  637. queryStr += " ASC "
  638. } else {
  639. queryStr += " DESC "
  640. }
  641. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  642. query = hdb.db.Rebind(queryStr)
  643. log.Debug(query)
  644. txsPtrs := []*HistoryTx{}
  645. if err := meddler.QueryAll(hdb.db, &txsPtrs, query, args...); err != nil {
  646. return nil, nil, err
  647. }
  648. txs := db.SlicePtrsToSlice(txsPtrs).([]HistoryTx)
  649. if len(txs) == 0 {
  650. return nil, nil, sql.ErrNoRows
  651. }
  652. return txs, &db.Pagination{
  653. TotalItems: txs[0].TotalItems,
  654. FirstItem: txs[0].FirstItem,
  655. LastItem: txs[0].LastItem,
  656. }, nil
  657. }
  658. // GetExit returns a exit from the DB
  659. func (hdb *HistoryDB) GetExit(batchNum *uint, idx *common.Idx) (*HistoryExit, error) {
  660. exit := &HistoryExit{}
  661. err := meddler.QueryRow(
  662. hdb.db, exit, `SELECT exit_tree.*, token.token_id, token.eth_block_num AS token_block,
  663. token.eth_addr, token.name, token.symbol, token.decimals, token.usd, token.usd_update
  664. FROM exit_tree INNER JOIN account ON exit_tree.account_idx = account.idx
  665. INNER JOIN token ON account.token_id = token.token_id
  666. WHERE exit_tree.batch_num = $1 AND exit_tree.account_idx = $2;`, batchNum, idx,
  667. )
  668. return exit, err
  669. }
  670. // GetExits returns a list of exits from the DB and pagination info
  671. func (hdb *HistoryDB) GetExits(
  672. ethAddr *ethCommon.Address, bjj *babyjub.PublicKey,
  673. tokenID *common.TokenID, idx *common.Idx, batchNum *uint,
  674. fromItem, limit *uint, order string,
  675. ) ([]HistoryExit, *db.Pagination, error) {
  676. if ethAddr != nil && bjj != nil {
  677. return nil, nil, errors.New("ethAddr and bjj are incompatible")
  678. }
  679. var query string
  680. var args []interface{}
  681. queryStr := `SELECT exit_tree.*, token.token_id, token.eth_block_num AS token_block,
  682. token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
  683. token.usd_update, COUNT(*) OVER() AS total_items, MIN(exit_tree.item_id) OVER() AS first_item, MAX(exit_tree.item_id) OVER() AS last_item
  684. FROM exit_tree INNER JOIN account ON exit_tree.account_idx = account.idx
  685. INNER JOIN token ON account.token_id = token.token_id `
  686. // Apply filters
  687. nextIsAnd := false
  688. // ethAddr filter
  689. if ethAddr != nil {
  690. queryStr += "WHERE account.eth_addr = ? "
  691. nextIsAnd = true
  692. args = append(args, ethAddr)
  693. } else if bjj != nil { // bjj filter
  694. queryStr += "WHERE account.bjj = ? "
  695. nextIsAnd = true
  696. args = append(args, bjj)
  697. }
  698. // tokenID filter
  699. if tokenID != nil {
  700. if nextIsAnd {
  701. queryStr += "AND "
  702. } else {
  703. queryStr += "WHERE "
  704. }
  705. queryStr += "account.token_id = ? "
  706. args = append(args, tokenID)
  707. nextIsAnd = true
  708. }
  709. // idx filter
  710. if idx != nil {
  711. if nextIsAnd {
  712. queryStr += "AND "
  713. } else {
  714. queryStr += "WHERE "
  715. }
  716. queryStr += "exit_tree.account_idx = ? "
  717. args = append(args, idx)
  718. nextIsAnd = true
  719. }
  720. // batchNum filter
  721. if batchNum != nil {
  722. if nextIsAnd {
  723. queryStr += "AND "
  724. } else {
  725. queryStr += "WHERE "
  726. }
  727. queryStr += "exit_tree.batch_num = ? "
  728. args = append(args, batchNum)
  729. nextIsAnd = true
  730. }
  731. if fromItem != nil {
  732. if nextIsAnd {
  733. queryStr += "AND "
  734. } else {
  735. queryStr += "WHERE "
  736. }
  737. if order == OrderAsc {
  738. queryStr += "exit_tree.item_id >= ? "
  739. } else {
  740. queryStr += "exit_tree.item_id <= ? "
  741. }
  742. args = append(args, fromItem)
  743. // nextIsAnd = true
  744. }
  745. // pagination
  746. queryStr += "ORDER BY exit_tree.item_id "
  747. if order == OrderAsc {
  748. queryStr += " ASC "
  749. } else {
  750. queryStr += " DESC "
  751. }
  752. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  753. query = hdb.db.Rebind(queryStr)
  754. // log.Debug(query)
  755. exits := []*HistoryExit{}
  756. if err := meddler.QueryAll(hdb.db, &exits, query, args...); err != nil {
  757. return nil, nil, err
  758. }
  759. if len(exits) == 0 {
  760. return nil, nil, sql.ErrNoRows
  761. }
  762. return db.SlicePtrsToSlice(exits).([]HistoryExit), &db.Pagination{
  763. TotalItems: exits[0].TotalItems,
  764. FirstItem: exits[0].FirstItem,
  765. LastItem: exits[0].LastItem,
  766. }, nil
  767. }
  768. // // GetTx returns a tx from the DB
  769. // func (hdb *HistoryDB) GetTx(txID common.TxID) (*common.Tx, error) {
  770. // tx := new(common.Tx)
  771. // return tx, meddler.QueryRow(
  772. // hdb.db, tx,
  773. // "SELECT * FROM tx WHERE id = $1;",
  774. // txID,
  775. // )
  776. // }
  777. // // GetL1UserTxs gets L1 User Txs to be forged in a batch that will create an account
  778. // // TODO: This is currently not used. Figure out if it should be used somewhere or removed.
  779. // func (hdb *HistoryDB) GetL1UserTxs(toForgeL1TxsNum int64) ([]*common.Tx, error) {
  780. // var txs []*common.Tx
  781. // err := meddler.QueryAll(
  782. // hdb.db, &txs,
  783. // "SELECT * FROM tx WHERE to_forge_l1_txs_num = $1 AND is_l1 = TRUE AND user_origin = TRUE;",
  784. // toForgeL1TxsNum,
  785. // )
  786. // return txs, err
  787. // }
  788. // TODO: Think about chaning all the queries that return a last value, to queries that return the next valid value.
  789. // GetLastTxsPosition for a given to_forge_l1_txs_num
  790. func (hdb *HistoryDB) GetLastTxsPosition(toForgeL1TxsNum int64) (int, error) {
  791. row := hdb.db.QueryRow("SELECT MAX(position) FROM tx WHERE to_forge_l1_txs_num = $1;", toForgeL1TxsNum)
  792. var lastL1TxsPosition int
  793. return lastL1TxsPosition, row.Scan(&lastL1TxsPosition)
  794. }
  795. // AddBlockSCData stores all the information of a block retrieved by the Synchronizer
  796. func (hdb *HistoryDB) AddBlockSCData(blockData *BlockData) (err error) {
  797. txn, err := hdb.db.Begin()
  798. if err != nil {
  799. return err
  800. }
  801. defer func() {
  802. if err != nil {
  803. errRollback := txn.Rollback()
  804. if errRollback != nil {
  805. log.Errorw("Rollback", "err", errRollback)
  806. }
  807. }
  808. }()
  809. // Add block
  810. err = hdb.addBlock(txn, blockData.Block)
  811. if err != nil {
  812. return err
  813. }
  814. // Add Coordinators
  815. if len(blockData.Coordinators) > 0 {
  816. err = hdb.addCoordinators(txn, blockData.Coordinators)
  817. if err != nil {
  818. return err
  819. }
  820. }
  821. // Add Bids
  822. if len(blockData.Bids) > 0 {
  823. err = hdb.addBids(txn, blockData.Bids)
  824. if err != nil {
  825. return err
  826. }
  827. }
  828. // Add Tokens
  829. if len(blockData.RegisteredTokens) > 0 {
  830. err = hdb.addTokens(txn, blockData.RegisteredTokens)
  831. if err != nil {
  832. return err
  833. }
  834. }
  835. // Add l1 Txs
  836. if len(blockData.L1UserTxs) > 0 {
  837. err = hdb.addL1Txs(txn, blockData.L1UserTxs)
  838. if err != nil {
  839. return err
  840. }
  841. }
  842. // Add Batches
  843. for _, batch := range blockData.Batches {
  844. // Add Batch: this will trigger an update on the DB
  845. // that will set the batch num of forged L1 txs in this batch
  846. err = hdb.addBatch(txn, batch.Batch)
  847. if err != nil {
  848. return err
  849. }
  850. // Add unforged l1 Txs
  851. if batch.L1Batch {
  852. if len(batch.L1CoordinatorTxs) > 0 {
  853. err = hdb.addL1Txs(txn, batch.L1CoordinatorTxs)
  854. if err != nil {
  855. return err
  856. }
  857. }
  858. }
  859. // Add l2 Txs
  860. if len(batch.L2Txs) > 0 {
  861. err = hdb.addL2Txs(txn, batch.L2Txs)
  862. if err != nil {
  863. return err
  864. }
  865. }
  866. // Add accounts
  867. if len(batch.CreatedAccounts) > 0 {
  868. err = hdb.addAccounts(txn, batch.CreatedAccounts)
  869. if err != nil {
  870. return err
  871. }
  872. }
  873. // Add exit tree
  874. if len(batch.ExitTree) > 0 {
  875. err = hdb.addExitTree(txn, batch.ExitTree)
  876. if err != nil {
  877. return err
  878. }
  879. }
  880. // TODO: INSERT CONTRACTS VARS
  881. }
  882. return txn.Commit()
  883. }
  884. // GetCoordinator returns a coordinator by its bidderAddr
  885. func (hdb *HistoryDB) GetCoordinator(bidderAddr ethCommon.Address) (*HistoryCoordinator, error) {
  886. coordinator := &HistoryCoordinator{}
  887. err := meddler.QueryRow(
  888. hdb.db, coordinator, `SELECT * FROM coordinator WHERE bidder_addr = $1;`, bidderAddr,
  889. )
  890. return coordinator, err
  891. }
  892. // GetCoordinators returns a list of coordinators from the DB and pagination info
  893. func (hdb *HistoryDB) GetCoordinators(fromItem, limit *uint, order string) ([]HistoryCoordinator, *db.Pagination, error) {
  894. var query string
  895. var args []interface{}
  896. queryStr := `SELECT coordinator.*,
  897. COUNT(*) OVER() AS total_items, MIN(coordinator.item_id) OVER() AS first_item, MAX(coordinator.item_id) OVER() AS last_item
  898. FROM coordinator `
  899. // Apply filters
  900. if fromItem != nil {
  901. queryStr += "WHERE "
  902. if order == OrderAsc {
  903. queryStr += "coordinator.item_id >= ? "
  904. } else {
  905. queryStr += "coordinator.item_id <= ? "
  906. }
  907. args = append(args, fromItem)
  908. }
  909. // pagination
  910. queryStr += "ORDER BY coordinator.item_id "
  911. if order == OrderAsc {
  912. queryStr += " ASC "
  913. } else {
  914. queryStr += " DESC "
  915. }
  916. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  917. query = hdb.db.Rebind(queryStr)
  918. coordinators := []*HistoryCoordinator{}
  919. if err := meddler.QueryAll(hdb.db, &coordinators, query, args...); err != nil {
  920. return nil, nil, err
  921. }
  922. if len(coordinators) == 0 {
  923. return nil, nil, sql.ErrNoRows
  924. }
  925. return db.SlicePtrsToSlice(coordinators).([]HistoryCoordinator), &db.Pagination{
  926. TotalItems: coordinators[0].TotalItems,
  927. FirstItem: coordinators[0].FirstItem,
  928. LastItem: coordinators[0].LastItem,
  929. }, nil
  930. }