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.

641 lines
17 KiB

4 years ago
  1. package historydb
  2. import (
  3. "database/sql"
  4. "errors"
  5. "fmt"
  6. ethCommon "github.com/ethereum/go-ethereum/common"
  7. "github.com/gobuffalo/packr/v2"
  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. migrate "github.com/rubenv/sql-migrate"
  16. "github.com/russross/meddler"
  17. )
  18. // TODO(Edu): Document here how HistoryDB is kept consistent
  19. // HistoryDB persist the historic of the rollup
  20. type HistoryDB struct {
  21. db *sqlx.DB
  22. }
  23. // BlockData contains the information of a Block
  24. type BlockData struct {
  25. block *common.Block
  26. // Rollup
  27. // L1UserTxs that were submitted in the block
  28. L1UserTxs []common.L1Tx
  29. Batches []BatchData
  30. RegisteredTokens []common.Token
  31. RollupVars *common.RollupVars
  32. // Auction
  33. Bids []common.Bid
  34. Coordinators []common.Coordinator
  35. AuctionVars *common.AuctionVars
  36. // WithdrawalDelayer
  37. // TODO: enable when common.WithdrawalDelayerVars is Merged from Synchronizer PR
  38. // WithdrawalDelayerVars *common.WithdrawalDelayerVars
  39. }
  40. // BatchData contains the information of a Batch
  41. type BatchData struct {
  42. // L1UserTxs that were forged in the batch
  43. L1Batch bool // TODO: Remove once Batch.ForgeL1TxsNum is a pointer
  44. L1UserTxs []common.L1Tx
  45. L1CoordinatorTxs []common.L1Tx
  46. L2Txs []common.L2Tx
  47. CreatedAccounts []common.Account
  48. ExitTree []common.ExitInfo
  49. Batch *common.Batch
  50. }
  51. // NewHistoryDB initialize the DB
  52. func NewHistoryDB(port int, host, user, password, dbname string) (*HistoryDB, error) {
  53. // Connect to DB
  54. psqlconn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbname)
  55. hdb, err := sqlx.Connect("postgres", psqlconn)
  56. if err != nil {
  57. return nil, err
  58. }
  59. // Init meddler
  60. db.InitMeddler()
  61. meddler.Default = meddler.PostgreSQL
  62. // Run DB migrations
  63. migrations := &migrate.PackrMigrationSource{
  64. Box: packr.New("history-migrations", "./migrations"),
  65. }
  66. nMigrations, err := migrate.Exec(hdb.DB, "postgres", migrations, migrate.Up)
  67. if err != nil {
  68. return nil, err
  69. }
  70. log.Debug("HistoryDB applied ", nMigrations, " migrations for ", dbname, " database")
  71. return &HistoryDB{hdb}, nil
  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 blocks, 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. return meddler.Insert(d, "batch", batch)
  124. }
  125. // AddBatches insert Bids into the DB
  126. func (hdb *HistoryDB) AddBatches(batches []common.Batch) error {
  127. return hdb.addBatches(hdb.db, batches)
  128. }
  129. func (hdb *HistoryDB) addBatches(d meddler.DB, batches []common.Batch) error {
  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 batches, 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, forger_addr, bid_value, eth_block_num) 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 bids, 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 (forger_addr, eth_block_num, withdraw_addr, 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. usd,
  249. usd_update
  250. ) VALUES %s;`,
  251. tokens[:],
  252. )
  253. }
  254. // UpdateTokenValue updates the USD value of a token
  255. func (hdb *HistoryDB) UpdateTokenValue(tokenID common.TokenID, value float64) error {
  256. _, err := hdb.db.Exec(
  257. "UPDATE token SET usd = $1 WHERE token_id = $2;",
  258. value, tokenID,
  259. )
  260. return err
  261. }
  262. // GetTokens returns a list of tokens from the DB
  263. func (hdb *HistoryDB) GetTokens() ([]*common.Token, error) {
  264. var tokens []*common.Token
  265. err := meddler.QueryAll(
  266. hdb.db, &tokens,
  267. "SELECT * FROM token ORDER BY token_id;",
  268. )
  269. return tokens, err
  270. }
  271. // AddAccounts insert accounts into the DB
  272. func (hdb *HistoryDB) AddAccounts(accounts []common.Account) error {
  273. return hdb.addAccounts(hdb.db, accounts)
  274. }
  275. func (hdb *HistoryDB) addAccounts(d meddler.DB, accounts []common.Account) error {
  276. return db.BulkInsert(
  277. d,
  278. `INSERT INTO account (
  279. idx,
  280. token_id,
  281. batch_num,
  282. bjj,
  283. eth_addr
  284. ) VALUES %s;`,
  285. accounts[:],
  286. )
  287. }
  288. // GetAccounts returns a list of accounts from the DB
  289. func (hdb *HistoryDB) GetAccounts() ([]*common.Account, error) {
  290. var accs []*common.Account
  291. err := meddler.QueryAll(
  292. hdb.db, &accs,
  293. "SELECT * FROM account ORDER BY idx;",
  294. )
  295. return accs, err
  296. }
  297. // AddL1Txs inserts L1 txs to the DB
  298. func (hdb *HistoryDB) AddL1Txs(l1txs []common.L1Tx) error { return hdb.addL1Txs(hdb.db, l1txs) }
  299. func (hdb *HistoryDB) addL1Txs(d meddler.DB, l1txs []common.L1Tx) error {
  300. txs := []common.Tx{}
  301. for _, tx := range l1txs {
  302. txs = append(txs, *(tx.Tx()))
  303. }
  304. return hdb.addTxs(d, txs)
  305. }
  306. // AddL2Txs inserts L2 txs to the DB
  307. func (hdb *HistoryDB) AddL2Txs(l2txs []common.L2Tx) error { return hdb.addL2Txs(hdb.db, l2txs) }
  308. func (hdb *HistoryDB) addL2Txs(d meddler.DB, l2txs []common.L2Tx) error {
  309. txs := []common.Tx{}
  310. for _, tx := range l2txs {
  311. txs = append(txs, *(tx.Tx()))
  312. }
  313. return hdb.addTxs(d, txs)
  314. }
  315. // AddTxs insert L1 txs into the DB
  316. func (hdb *HistoryDB) AddTxs(txs []common.Tx) error { return hdb.addTxs(hdb.db, txs) }
  317. func (hdb *HistoryDB) addTxs(d meddler.DB, txs []common.Tx) error {
  318. return db.BulkInsert(
  319. d,
  320. `INSERT INTO tx (
  321. is_l1,
  322. id,
  323. type,
  324. position,
  325. from_idx,
  326. to_idx,
  327. amount,
  328. amount_f,
  329. token_id,
  330. amount_usd,
  331. batch_num,
  332. eth_block_num,
  333. to_forge_l1_txs_num,
  334. user_origin,
  335. from_eth_addr,
  336. from_bjj,
  337. load_amount,
  338. load_amount_f,
  339. load_amount_usd,
  340. fee,
  341. fee_usd,
  342. nonce
  343. ) VALUES %s;`,
  344. txs[:],
  345. )
  346. }
  347. // SetBatchNumL1UserTxs sets the batchNum in all the L1UserTxs with toForgeL1TxsNum.
  348. func (hdb *HistoryDB) SetBatchNumL1UserTxs(toForgeL1TxsNum, batchNum int64) error {
  349. return hdb.setBatchNumL1UserTxs(hdb.db, toForgeL1TxsNum, batchNum)
  350. }
  351. func (hdb *HistoryDB) setBatchNumL1UserTxs(d meddler.DB, toForgeL1TxsNum, batchNum int64) error {
  352. _, err := d.Exec("UPDATE tx SET batch_num = $1 WHERE to_forge_l1_txs_num = $2 AND is_l1 = TRUE AND user_origin = TRUE;",
  353. batchNum, toForgeL1TxsNum)
  354. return err
  355. }
  356. // GetTxs returns a list of txs from the DB
  357. func (hdb *HistoryDB) GetTxs() ([]*common.Tx, error) {
  358. var txs []*common.Tx
  359. err := meddler.QueryAll(
  360. hdb.db, &txs,
  361. `SELECT * FROM tx
  362. ORDER BY (batch_num, position) ASC`,
  363. )
  364. return txs, err
  365. }
  366. // GetHistoryTxs returns a list of txs from the DB using the HistoryTx struct
  367. func (hdb *HistoryDB) GetHistoryTxs(
  368. ethAddr *ethCommon.Address, bjj *babyjub.PublicKey,
  369. tokenID, idx, batchNum *uint, txType *common.TxType,
  370. offset, limit *uint, last bool,
  371. ) ([]*HistoryTx, int, error) {
  372. if ethAddr != nil && bjj != nil {
  373. return nil, 0, errors.New("ethAddr and bjj are incompatible")
  374. }
  375. var query string
  376. var args []interface{}
  377. queryStr := `SELECT tx.*, tx.amount_f * token.usd AS current_usd,
  378. token.symbol, token.usd_update, block.timestamp, count(*) OVER() AS total_items FROM tx
  379. INNER JOIN token ON tx.token_id = token.token_id
  380. INNER JOIN block ON tx.eth_block_num = block.eth_block_num `
  381. // Apply filters
  382. nextIsAnd := false
  383. // ethAddr filter
  384. if ethAddr != nil {
  385. queryStr = `WITH acc AS
  386. (select idx from account where eth_addr = ?) ` + 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, ethAddr)
  390. } else if bjj != nil { // bjj filter
  391. queryStr = `WITH acc AS
  392. (select idx from account where bjj = ?) ` + queryStr
  393. queryStr += ", acc WHERE (tx.from_idx IN(acc.idx) OR tx.to_idx IN(acc.idx)) "
  394. nextIsAnd = true
  395. args = append(args, bjj)
  396. }
  397. // tokenID filter
  398. if tokenID != nil {
  399. if nextIsAnd {
  400. queryStr += "AND "
  401. } else {
  402. queryStr += "WHERE "
  403. }
  404. queryStr += "tx.token_id = ? "
  405. args = append(args, tokenID)
  406. nextIsAnd = true
  407. }
  408. // idx filter
  409. if idx != nil {
  410. if nextIsAnd {
  411. queryStr += "AND "
  412. } else {
  413. queryStr += "WHERE "
  414. }
  415. queryStr += "(tx.from_idx = ? OR tx.to_idx = ?) "
  416. args = append(args, idx, idx)
  417. nextIsAnd = true
  418. }
  419. // batchNum filter
  420. if batchNum != nil {
  421. if nextIsAnd {
  422. queryStr += "AND "
  423. } else {
  424. queryStr += "WHERE "
  425. }
  426. queryStr += "tx.batch_num = ? "
  427. args = append(args, batchNum)
  428. nextIsAnd = true
  429. }
  430. // txType filter
  431. if txType != nil {
  432. if nextIsAnd {
  433. queryStr += "AND "
  434. } else {
  435. queryStr += "WHERE "
  436. }
  437. queryStr += "tx.type = ? "
  438. args = append(args, txType)
  439. // nextIsAnd = true
  440. }
  441. // pagination
  442. if last {
  443. queryStr += "ORDER BY (batch_num, position) DESC NULLS FIRST "
  444. } else {
  445. queryStr += "ORDER BY (batch_num, position) ASC NULLS LAST "
  446. queryStr += fmt.Sprintf("OFFSET %d ", *offset)
  447. }
  448. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  449. query = hdb.db.Rebind(queryStr)
  450. // log.Debug(query)
  451. txs := []*HistoryTx{}
  452. if err := meddler.QueryAll(hdb.db, &txs, query, args...); err != nil {
  453. return nil, 0, err
  454. }
  455. if len(txs) == 0 {
  456. return nil, 0, sql.ErrNoRows
  457. } else if last {
  458. tmp := []*HistoryTx{}
  459. for i := len(txs) - 1; i >= 0; i-- {
  460. tmp = append(tmp, txs[i])
  461. }
  462. txs = tmp
  463. }
  464. return txs, txs[0].TotalItems, nil
  465. }
  466. // GetTx returns a tx from the DB
  467. func (hdb *HistoryDB) GetTx(txID common.TxID) (*common.Tx, error) {
  468. tx := new(common.Tx)
  469. return tx, meddler.QueryRow(
  470. hdb.db, tx,
  471. "SELECT * FROM tx WHERE id = $1;",
  472. txID,
  473. )
  474. }
  475. // GetL1UserTxs gets L1 User Txs to be forged in a batch that will create an account
  476. // TODO: This is currently not used. Figure out if it should be used somewhere or removed.
  477. func (hdb *HistoryDB) GetL1UserTxs(toForgeL1TxsNum int64) ([]*common.Tx, error) {
  478. var txs []*common.Tx
  479. err := meddler.QueryAll(
  480. hdb.db, &txs,
  481. "SELECT * FROM tx WHERE to_forge_l1_txs_num = $1 AND is_l1 = TRUE AND user_origin = TRUE;",
  482. toForgeL1TxsNum,
  483. )
  484. return txs, err
  485. }
  486. // TODO: Think about chaning all the queries that return a last value, to queries that return the next valid value.
  487. // GetLastTxsPosition for a given to_forge_l1_txs_num
  488. func (hdb *HistoryDB) GetLastTxsPosition(toForgeL1TxsNum int64) (int, error) {
  489. row := hdb.db.QueryRow("SELECT MAX(position) FROM tx WHERE to_forge_l1_txs_num = $1;", toForgeL1TxsNum)
  490. var lastL1TxsPosition int
  491. return lastL1TxsPosition, row.Scan(&lastL1TxsPosition)
  492. }
  493. // AddBlockSCData stores all the information of a block retrieved by the Synchronizer
  494. func (hdb *HistoryDB) AddBlockSCData(blockData *BlockData) (err error) {
  495. txn, err := hdb.db.Begin()
  496. if err != nil {
  497. return err
  498. }
  499. defer func() {
  500. if err != nil {
  501. err = txn.Rollback()
  502. }
  503. }()
  504. // Add block
  505. err = hdb.addBlock(txn, blockData.block)
  506. if err != nil {
  507. return err
  508. }
  509. // Add l1 Txs
  510. if len(blockData.L1UserTxs) > 0 {
  511. err = hdb.addL1Txs(txn, blockData.L1UserTxs)
  512. if err != nil {
  513. return err
  514. }
  515. }
  516. // Add Tokens
  517. if len(blockData.RegisteredTokens) > 0 {
  518. err = hdb.addTokens(txn, blockData.RegisteredTokens)
  519. if err != nil {
  520. return err
  521. }
  522. }
  523. // Add Bids
  524. if len(blockData.Bids) > 0 {
  525. err = hdb.addBids(txn, blockData.Bids)
  526. if err != nil {
  527. return err
  528. }
  529. }
  530. // Add Coordinators
  531. if len(blockData.Coordinators) > 0 {
  532. err = hdb.addCoordinators(txn, blockData.Coordinators)
  533. if err != nil {
  534. return err
  535. }
  536. }
  537. // Add Batches
  538. for _, batch := range blockData.Batches {
  539. if batch.L1Batch {
  540. err = hdb.setBatchNumL1UserTxs(txn, batch.Batch.ForgeL1TxsNum, int64(batch.Batch.BatchNum))
  541. if err != nil {
  542. return err
  543. }
  544. if len(batch.L1CoordinatorTxs) > 0 {
  545. err = hdb.addL1Txs(txn, batch.L1CoordinatorTxs)
  546. if err != nil {
  547. return err
  548. }
  549. }
  550. }
  551. // Add l2 Txs
  552. if len(batch.L2Txs) > 0 {
  553. err = hdb.addL2Txs(txn, batch.L2Txs)
  554. if err != nil {
  555. return err
  556. }
  557. }
  558. // Add accounts
  559. if len(batch.CreatedAccounts) > 0 {
  560. err = hdb.addAccounts(txn, batch.CreatedAccounts)
  561. if err != nil {
  562. return err
  563. }
  564. }
  565. // Add exit tree
  566. if len(batch.ExitTree) > 0 {
  567. err = hdb.addExitTree(txn, batch.ExitTree)
  568. if err != nil {
  569. return err
  570. }
  571. }
  572. // Add Batch
  573. err = hdb.addBatch(txn, batch.Batch)
  574. if err != nil {
  575. return err
  576. }
  577. // TODO: INSERT CONTRACTS VARS
  578. }
  579. return txn.Commit()
  580. }
  581. // Close frees the resources used by HistoryDB
  582. func (hdb *HistoryDB) Close() error {
  583. return hdb.db.Close()
  584. }