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.

855 lines
24 KiB

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