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.

628 lines
17 KiB

  1. package historydb
  2. import (
  3. "database/sql"
  4. "errors"
  5. "fmt"
  6. ethCommon "github.com/ethereum/go-ethereum/common"
  7. "github.com/hermeznetwork/hermez-node/common"
  8. "github.com/hermeznetwork/hermez-node/db"
  9. "github.com/iden3/go-iden3-crypto/babyjub"
  10. "github.com/jmoiron/sqlx"
  11. //nolint:errcheck // driver for postgres DB
  12. _ "github.com/lib/pq"
  13. "github.com/russross/meddler"
  14. )
  15. // TODO(Edu): Document here how HistoryDB is kept consistent
  16. // HistoryDB persist the historic of the rollup
  17. type HistoryDB struct {
  18. db *sqlx.DB
  19. }
  20. // BlockData contains the information of a Block
  21. type BlockData struct {
  22. block *common.Block
  23. // Rollup
  24. // L1UserTxs that were submitted in the block
  25. L1UserTxs []common.L1Tx
  26. Batches []BatchData
  27. RegisteredTokens []common.Token
  28. RollupVars *common.RollupVars
  29. // Auction
  30. Bids []common.Bid
  31. Coordinators []common.Coordinator
  32. AuctionVars *common.AuctionVars
  33. // WithdrawalDelayer
  34. // TODO: enable when common.WithdrawalDelayerVars is Merged from Synchronizer PR
  35. // WithdrawalDelayerVars *common.WithdrawalDelayerVars
  36. }
  37. // BatchData contains the information of a Batch
  38. type BatchData struct {
  39. // L1UserTxs that were forged in the batch
  40. L1Batch bool // TODO: Remove once Batch.ForgeL1TxsNum is a pointer
  41. L1UserTxs []common.L1Tx
  42. L1CoordinatorTxs []common.L1Tx
  43. L2Txs []common.L2Tx
  44. CreatedAccounts []common.Account
  45. ExitTree []common.ExitInfo
  46. Batch *common.Batch
  47. }
  48. // NewHistoryDB initialize the DB
  49. func NewHistoryDB(db *sqlx.DB) *HistoryDB {
  50. return &HistoryDB{db: db}
  51. }
  52. // AddBlock insert a block into the DB
  53. func (hdb *HistoryDB) AddBlock(block *common.Block) error { return hdb.addBlock(hdb.db, block) }
  54. func (hdb *HistoryDB) addBlock(d meddler.DB, block *common.Block) error {
  55. return meddler.Insert(d, "block", block)
  56. }
  57. // AddBlocks inserts blocks into the DB
  58. func (hdb *HistoryDB) AddBlocks(blocks []common.Block) error {
  59. return hdb.addBlocks(hdb.db, blocks)
  60. }
  61. func (hdb *HistoryDB) addBlocks(d meddler.DB, blocks []common.Block) error {
  62. return db.BulkInsert(
  63. d,
  64. `INSERT INTO block (
  65. eth_block_num,
  66. timestamp,
  67. hash
  68. ) VALUES %s;`,
  69. blocks[:],
  70. )
  71. }
  72. // GetBlock retrieve a block from the DB, given a block number
  73. func (hdb *HistoryDB) GetBlock(blockNum int64) (*common.Block, error) {
  74. block := &common.Block{}
  75. err := meddler.QueryRow(
  76. hdb.db, block,
  77. "SELECT * FROM block WHERE eth_block_num = $1;", blockNum,
  78. )
  79. return block, err
  80. }
  81. // GetBlocks retrieve blocks from the DB, given a range of block numbers defined by from and to
  82. func (hdb *HistoryDB) GetBlocks(from, to int64) ([]*common.Block, error) {
  83. var blocks []*common.Block
  84. err := meddler.QueryAll(
  85. hdb.db, &blocks,
  86. "SELECT * FROM block WHERE $1 <= eth_block_num AND eth_block_num < $2;",
  87. from, to,
  88. )
  89. return blocks, err
  90. }
  91. // GetLastBlock retrieve the block with the highest block number from the DB
  92. func (hdb *HistoryDB) GetLastBlock() (*common.Block, error) {
  93. block := &common.Block{}
  94. err := meddler.QueryRow(
  95. hdb.db, block, "SELECT * FROM block ORDER BY eth_block_num DESC LIMIT 1;",
  96. )
  97. return block, err
  98. }
  99. // AddBatch insert a Batch into the DB
  100. func (hdb *HistoryDB) AddBatch(batch *common.Batch) error { return hdb.addBatch(hdb.db, batch) }
  101. func (hdb *HistoryDB) addBatch(d meddler.DB, batch *common.Batch) error {
  102. return meddler.Insert(d, "batch", batch)
  103. }
  104. // AddBatches insert Bids into the DB
  105. func (hdb *HistoryDB) AddBatches(batches []common.Batch) error {
  106. return hdb.addBatches(hdb.db, batches)
  107. }
  108. func (hdb *HistoryDB) addBatches(d meddler.DB, batches []common.Batch) error {
  109. return db.BulkInsert(
  110. d,
  111. `INSERT INTO batch (
  112. batch_num,
  113. eth_block_num,
  114. forger_addr,
  115. fees_collected,
  116. state_root,
  117. num_accounts,
  118. exit_root,
  119. forge_l1_txs_num,
  120. slot_num,
  121. total_fees_usd
  122. ) VALUES %s;`,
  123. batches[:],
  124. )
  125. }
  126. // GetBatches retrieve batches from the DB, given a range of batch numbers defined by from and to
  127. func (hdb *HistoryDB) GetBatches(from, to common.BatchNum) ([]*common.Batch, error) {
  128. var batches []*common.Batch
  129. err := meddler.QueryAll(
  130. hdb.db, &batches,
  131. "SELECT * FROM batch WHERE $1 <= batch_num AND batch_num < $2;",
  132. from, to,
  133. )
  134. return batches, err
  135. }
  136. // GetLastBatchNum returns the BatchNum of the latest forged batch
  137. func (hdb *HistoryDB) GetLastBatchNum() (common.BatchNum, error) {
  138. row := hdb.db.QueryRow("SELECT batch_num FROM batch ORDER BY batch_num DESC LIMIT 1;")
  139. var batchNum common.BatchNum
  140. return batchNum, row.Scan(&batchNum)
  141. }
  142. // GetLastL1TxsNum returns the greatest ForgeL1TxsNum in the DB. If there's no
  143. // batch in the DB (nil, nil) is returned.
  144. func (hdb *HistoryDB) GetLastL1TxsNum() (*int64, error) {
  145. row := hdb.db.QueryRow("SELECT MAX(forge_l1_txs_num) FROM batch;")
  146. lastL1TxsNum := new(int64)
  147. return lastL1TxsNum, row.Scan(&lastL1TxsNum)
  148. }
  149. // Reorg deletes all the information that was added into the DB after the
  150. // lastValidBlock. If lastValidBlock is negative, all block information is
  151. // deleted.
  152. func (hdb *HistoryDB) Reorg(lastValidBlock int64) error {
  153. var err error
  154. if lastValidBlock < 0 {
  155. _, err = hdb.db.Exec("DELETE FROM block;")
  156. } else {
  157. _, err = hdb.db.Exec("DELETE FROM block WHERE eth_block_num > $1;", lastValidBlock)
  158. }
  159. return err
  160. }
  161. // SyncPoD stores all the data that can be changed / added on a block in the PoD SC
  162. func (hdb *HistoryDB) SyncPoD(
  163. blockNum uint64,
  164. bids []common.Bid,
  165. coordinators []common.Coordinator,
  166. vars *common.AuctionVars,
  167. ) error {
  168. return nil
  169. }
  170. // AddBids insert Bids into the DB
  171. func (hdb *HistoryDB) AddBids(bids []common.Bid) error { return hdb.addBids(hdb.db, bids) }
  172. func (hdb *HistoryDB) addBids(d meddler.DB, bids []common.Bid) error {
  173. // TODO: check the coordinator info
  174. return db.BulkInsert(
  175. d,
  176. "INSERT INTO bid (slot_num, forger_addr, bid_value, eth_block_num) VALUES %s;",
  177. bids[:],
  178. )
  179. }
  180. // GetBids return the bids
  181. func (hdb *HistoryDB) GetBids() ([]*common.Bid, error) {
  182. var bids []*common.Bid
  183. err := meddler.QueryAll(
  184. hdb.db, &bids,
  185. "SELECT * FROM bid;",
  186. )
  187. return bids, err
  188. }
  189. // AddCoordinators insert Coordinators into the DB
  190. func (hdb *HistoryDB) AddCoordinators(coordinators []common.Coordinator) error {
  191. return hdb.addCoordinators(hdb.db, coordinators)
  192. }
  193. func (hdb *HistoryDB) addCoordinators(d meddler.DB, coordinators []common.Coordinator) error {
  194. return db.BulkInsert(
  195. d,
  196. "INSERT INTO coordinator (forger_addr, eth_block_num, withdraw_addr, url) VALUES %s;",
  197. coordinators[:],
  198. )
  199. }
  200. // AddExitTree insert Exit tree into the DB
  201. func (hdb *HistoryDB) AddExitTree(exitTree []common.ExitInfo) error {
  202. return hdb.addExitTree(hdb.db, exitTree)
  203. }
  204. func (hdb *HistoryDB) addExitTree(d meddler.DB, exitTree []common.ExitInfo) error {
  205. return db.BulkInsert(
  206. d,
  207. "INSERT INTO exit_tree (batch_num, account_idx, merkle_proof, balance, "+
  208. "instant_withdrawn, delayed_withdraw_request, delayed_withdrawn) VALUES %s;",
  209. exitTree[:],
  210. )
  211. }
  212. // AddToken insert a token into the DB
  213. func (hdb *HistoryDB) AddToken(token *common.Token) error {
  214. return meddler.Insert(hdb.db, "token", token)
  215. }
  216. // AddTokens insert tokens into the DB
  217. func (hdb *HistoryDB) AddTokens(tokens []common.Token) error { return hdb.addTokens(hdb.db, tokens) }
  218. func (hdb *HistoryDB) addTokens(d meddler.DB, tokens []common.Token) error {
  219. return db.BulkInsert(
  220. d,
  221. `INSERT INTO token (
  222. token_id,
  223. eth_block_num,
  224. eth_addr,
  225. name,
  226. symbol,
  227. decimals,
  228. usd,
  229. usd_update
  230. ) VALUES %s;`,
  231. tokens[:],
  232. )
  233. }
  234. // UpdateTokenValue updates the USD value of a token
  235. func (hdb *HistoryDB) UpdateTokenValue(tokenSymbol string, value float64) error {
  236. _, err := hdb.db.Exec(
  237. "UPDATE token SET usd = $1 WHERE symbol = $2;",
  238. value, tokenSymbol,
  239. )
  240. return err
  241. }
  242. // GetTokens returns a list of tokens from the DB
  243. func (hdb *HistoryDB) GetTokens() ([]*common.Token, error) {
  244. var tokens []*common.Token
  245. err := meddler.QueryAll(
  246. hdb.db, &tokens,
  247. "SELECT * FROM token ORDER BY token_id;",
  248. )
  249. return tokens, err
  250. }
  251. // GetTokenSymbols returns all the token symbols from the DB
  252. func (hdb *HistoryDB) GetTokenSymbols() ([]string, error) {
  253. var tokenSymbols []string
  254. rows, err := hdb.db.Query("SELECT symbol FROM token;")
  255. if err != nil {
  256. return nil, err
  257. }
  258. sym := new(string)
  259. for rows.Next() {
  260. err = rows.Scan(sym)
  261. if err != nil {
  262. return nil, err
  263. }
  264. tokenSymbols = append(tokenSymbols, *sym)
  265. }
  266. return tokenSymbols, nil
  267. }
  268. // AddAccounts insert accounts into the DB
  269. func (hdb *HistoryDB) AddAccounts(accounts []common.Account) error {
  270. return hdb.addAccounts(hdb.db, accounts)
  271. }
  272. func (hdb *HistoryDB) addAccounts(d meddler.DB, accounts []common.Account) error {
  273. return db.BulkInsert(
  274. d,
  275. `INSERT INTO account (
  276. idx,
  277. token_id,
  278. batch_num,
  279. bjj,
  280. eth_addr
  281. ) VALUES %s;`,
  282. accounts[:],
  283. )
  284. }
  285. // GetAccounts returns a list of accounts from the DB
  286. func (hdb *HistoryDB) GetAccounts() ([]*common.Account, error) {
  287. var accs []*common.Account
  288. err := meddler.QueryAll(
  289. hdb.db, &accs,
  290. "SELECT * FROM account ORDER BY idx;",
  291. )
  292. return accs, err
  293. }
  294. // AddL1Txs inserts L1 txs to the DB. USD and LoadAmountUSD will be set automatically before storing the tx.
  295. // If the tx is originated by a coordinator, BatchNum must be provided. If it's originated by a user,
  296. // BatchNum should be null, and the value will be setted by a trigger when a batch forges the tx.
  297. func (hdb *HistoryDB) AddL1Txs(l1txs []common.L1Tx) error { return hdb.addL1Txs(hdb.db, l1txs) }
  298. // addL1Txs inserts L1 txs to the DB. USD and LoadAmountUSD will be set automatically before storing the tx.
  299. // If the tx is originated by a coordinator, BatchNum must be provided. If it's originated by a user,
  300. // BatchNum should be null, and the value will be setted by a trigger when a batch forges the tx.
  301. func (hdb *HistoryDB) addL1Txs(d meddler.DB, l1txs []common.L1Tx) error {
  302. txs := []common.Tx{}
  303. for _, tx := range l1txs {
  304. txs = append(txs, *(tx.Tx()))
  305. }
  306. return hdb.addTxs(d, txs)
  307. }
  308. // AddL2Txs inserts L2 txs to the DB. USD and FeeUSD will be set automatically before storing the tx.
  309. func (hdb *HistoryDB) AddL2Txs(l2txs []common.L2Tx) error { return hdb.addL2Txs(hdb.db, l2txs) }
  310. // addL2Txs inserts L2 txs to the DB. USD and FeeUSD will be set automatically before storing the tx.
  311. func (hdb *HistoryDB) addL2Txs(d meddler.DB, l2txs []common.L2Tx) error {
  312. txs := []common.Tx{}
  313. for _, tx := range l2txs {
  314. txs = append(txs, *(tx.Tx()))
  315. }
  316. return hdb.addTxs(d, txs)
  317. }
  318. func (hdb *HistoryDB) addTxs(d meddler.DB, txs []common.Tx) error {
  319. return db.BulkInsert(
  320. d,
  321. `INSERT INTO tx (
  322. is_l1,
  323. id,
  324. type,
  325. position,
  326. from_idx,
  327. to_idx,
  328. amount,
  329. amount_f,
  330. token_id,
  331. amount_usd,
  332. batch_num,
  333. eth_block_num,
  334. to_forge_l1_txs_num,
  335. user_origin,
  336. from_eth_addr,
  337. from_bjj,
  338. load_amount,
  339. load_amount_f,
  340. load_amount_usd,
  341. fee,
  342. fee_usd,
  343. nonce
  344. ) VALUES %s;`,
  345. txs[:],
  346. )
  347. }
  348. // GetTxs returns a list of txs from the DB
  349. func (hdb *HistoryDB) GetTxs() ([]*common.Tx, error) {
  350. var txs []*common.Tx
  351. err := meddler.QueryAll(
  352. hdb.db, &txs,
  353. `SELECT * FROM tx
  354. ORDER BY (batch_num, position) ASC`,
  355. )
  356. return txs, err
  357. }
  358. // GetHistoryTxs returns a list of txs from the DB using the HistoryTx struct
  359. func (hdb *HistoryDB) GetHistoryTxs(
  360. ethAddr *ethCommon.Address, bjj *babyjub.PublicKey,
  361. tokenID, idx, batchNum *uint, txType *common.TxType,
  362. offset, limit *uint, last bool,
  363. ) ([]*HistoryTx, int, error) {
  364. if ethAddr != nil && bjj != nil {
  365. return nil, 0, errors.New("ethAddr and bjj are incompatible")
  366. }
  367. var query string
  368. var args []interface{}
  369. queryStr := `SELECT tx.*, token.token_id, token.eth_block_num AS token_block,
  370. token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
  371. token.usd_update, block.timestamp, count(*) OVER() AS total_items
  372. FROM tx
  373. INNER JOIN token ON tx.token_id = token.token_id
  374. INNER JOIN block ON tx.eth_block_num = block.eth_block_num `
  375. // Apply filters
  376. nextIsAnd := false
  377. // ethAddr filter
  378. if ethAddr != nil {
  379. queryStr = `WITH acc AS
  380. (select idx from account where eth_addr = ?) ` + queryStr
  381. queryStr += ", acc WHERE (tx.from_idx IN(acc.idx) OR tx.to_idx IN(acc.idx)) "
  382. nextIsAnd = true
  383. args = append(args, ethAddr)
  384. } else if bjj != nil { // bjj filter
  385. queryStr = `WITH acc AS
  386. (select idx from account where bjj = ?) ` + queryStr
  387. queryStr += ", acc WHERE (tx.from_idx IN(acc.idx) OR tx.to_idx IN(acc.idx)) "
  388. nextIsAnd = true
  389. args = append(args, bjj)
  390. }
  391. // tokenID filter
  392. if tokenID != nil {
  393. if nextIsAnd {
  394. queryStr += "AND "
  395. } else {
  396. queryStr += "WHERE "
  397. }
  398. queryStr += "tx.token_id = ? "
  399. args = append(args, tokenID)
  400. nextIsAnd = true
  401. }
  402. // idx filter
  403. if idx != nil {
  404. if nextIsAnd {
  405. queryStr += "AND "
  406. } else {
  407. queryStr += "WHERE "
  408. }
  409. queryStr += "(tx.from_idx = ? OR tx.to_idx = ?) "
  410. args = append(args, idx, idx)
  411. nextIsAnd = true
  412. }
  413. // batchNum filter
  414. if batchNum != nil {
  415. if nextIsAnd {
  416. queryStr += "AND "
  417. } else {
  418. queryStr += "WHERE "
  419. }
  420. queryStr += "tx.batch_num = ? "
  421. args = append(args, batchNum)
  422. nextIsAnd = true
  423. }
  424. // txType filter
  425. if txType != nil {
  426. if nextIsAnd {
  427. queryStr += "AND "
  428. } else {
  429. queryStr += "WHERE "
  430. }
  431. queryStr += "tx.type = ? "
  432. args = append(args, txType)
  433. // nextIsAnd = true
  434. }
  435. // pagination
  436. if last {
  437. queryStr += "ORDER BY (batch_num, position) DESC NULLS FIRST "
  438. } else {
  439. queryStr += "ORDER BY (batch_num, position) ASC NULLS LAST "
  440. queryStr += fmt.Sprintf("OFFSET %d ", *offset)
  441. }
  442. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  443. query = hdb.db.Rebind(queryStr)
  444. // log.Debug(query)
  445. txs := []*HistoryTx{}
  446. if err := meddler.QueryAll(hdb.db, &txs, query, args...); err != nil {
  447. return nil, 0, err
  448. }
  449. if len(txs) == 0 {
  450. return nil, 0, sql.ErrNoRows
  451. } else if last {
  452. tmp := []*HistoryTx{}
  453. for i := len(txs) - 1; i >= 0; i-- {
  454. tmp = append(tmp, txs[i])
  455. }
  456. txs = tmp
  457. }
  458. return txs, txs[0].TotalItems, nil
  459. }
  460. // GetTx returns a tx from the DB
  461. func (hdb *HistoryDB) GetTx(txID common.TxID) (*common.Tx, error) {
  462. tx := new(common.Tx)
  463. return tx, meddler.QueryRow(
  464. hdb.db, tx,
  465. "SELECT * FROM tx WHERE id = $1;",
  466. txID,
  467. )
  468. }
  469. // // GetL1UserTxs gets L1 User Txs to be forged in a batch that will create an account
  470. // // TODO: This is currently not used. Figure out if it should be used somewhere or removed.
  471. // func (hdb *HistoryDB) GetL1UserTxs(toForgeL1TxsNum int64) ([]*common.Tx, error) {
  472. // var txs []*common.Tx
  473. // err := meddler.QueryAll(
  474. // hdb.db, &txs,
  475. // "SELECT * FROM tx WHERE to_forge_l1_txs_num = $1 AND is_l1 = TRUE AND user_origin = TRUE;",
  476. // toForgeL1TxsNum,
  477. // )
  478. // return txs, err
  479. // }
  480. // TODO: Think about chaning all the queries that return a last value, to queries that return the next valid value.
  481. // GetLastTxsPosition for a given to_forge_l1_txs_num
  482. func (hdb *HistoryDB) GetLastTxsPosition(toForgeL1TxsNum int64) (int, error) {
  483. row := hdb.db.QueryRow("SELECT MAX(position) FROM tx WHERE to_forge_l1_txs_num = $1;", toForgeL1TxsNum)
  484. var lastL1TxsPosition int
  485. return lastL1TxsPosition, row.Scan(&lastL1TxsPosition)
  486. }
  487. // AddBlockSCData stores all the information of a block retrieved by the Synchronizer
  488. func (hdb *HistoryDB) AddBlockSCData(blockData *BlockData) (err error) {
  489. txn, err := hdb.db.Begin()
  490. if err != nil {
  491. return err
  492. }
  493. defer func() {
  494. if err != nil {
  495. err = txn.Rollback()
  496. }
  497. }()
  498. // Add block
  499. err = hdb.addBlock(txn, blockData.block)
  500. if err != nil {
  501. return err
  502. }
  503. // Add l1 Txs
  504. if len(blockData.L1UserTxs) > 0 {
  505. err = hdb.addL1Txs(txn, blockData.L1UserTxs)
  506. if err != nil {
  507. return err
  508. }
  509. }
  510. // Add Tokens
  511. if len(blockData.RegisteredTokens) > 0 {
  512. err = hdb.addTokens(txn, blockData.RegisteredTokens)
  513. if err != nil {
  514. return err
  515. }
  516. }
  517. // Add Bids
  518. if len(blockData.Bids) > 0 {
  519. err = hdb.addBids(txn, blockData.Bids)
  520. if err != nil {
  521. return err
  522. }
  523. }
  524. // Add Coordinators
  525. if len(blockData.Coordinators) > 0 {
  526. err = hdb.addCoordinators(txn, blockData.Coordinators)
  527. if err != nil {
  528. return err
  529. }
  530. }
  531. // Add Batches
  532. for _, batch := range blockData.Batches {
  533. // Add Batch: this will trigger an update on the DB
  534. // that will set the batch num of forged L1 txs in this batch
  535. err = hdb.addBatch(txn, batch.Batch)
  536. if err != nil {
  537. return err
  538. }
  539. // Add unforged l1 Txs
  540. if batch.L1Batch {
  541. if len(batch.L1CoordinatorTxs) > 0 {
  542. err = hdb.addL1Txs(txn, batch.L1CoordinatorTxs)
  543. if err != nil {
  544. return err
  545. }
  546. }
  547. }
  548. // Add l2 Txs
  549. if len(batch.L2Txs) > 0 {
  550. err = hdb.addL2Txs(txn, batch.L2Txs)
  551. if err != nil {
  552. return err
  553. }
  554. }
  555. // Add accounts
  556. if len(batch.CreatedAccounts) > 0 {
  557. err = hdb.addAccounts(txn, batch.CreatedAccounts)
  558. if err != nil {
  559. return err
  560. }
  561. }
  562. // Add exit tree
  563. if len(batch.ExitTree) > 0 {
  564. err = hdb.addExitTree(txn, batch.ExitTree)
  565. if err != nil {
  566. return err
  567. }
  568. }
  569. // TODO: INSERT CONTRACTS VARS
  570. }
  571. return txn.Commit()
  572. }