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
20 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. package historydb
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "math"
  6. "math/big"
  7. "time"
  8. ethCommon "github.com/ethereum/go-ethereum/common"
  9. "github.com/hermeznetwork/hermez-node/apitypes"
  10. "github.com/hermeznetwork/hermez-node/common"
  11. "github.com/hermeznetwork/hermez-node/db"
  12. "github.com/hermeznetwork/tracerr"
  13. "github.com/jmoiron/sqlx"
  14. "github.com/russross/meddler"
  15. )
  16. const (
  17. createAccountExtraFeePercentage float64 = 2
  18. createAccountInternalExtraFeePercentage float64 = 2.5
  19. )
  20. type Period struct {
  21. SlotNum int64 `json:"slotNum"`
  22. FromBlock int64 `json:"fromBlock"`
  23. ToBlock int64 `json:"toBlock"`
  24. FromTimestamp time.Time `json:"fromTimestamp"`
  25. ToTimestamp time.Time `json:"toTimestamp"`
  26. }
  27. type NextForger struct {
  28. Coordinator CoordinatorAPI `json:"coordinator"`
  29. Period Period `json:"period"`
  30. }
  31. type Network struct {
  32. LastEthBlock int64 `json:"lastEthereumBlock"`
  33. LastSyncBlock int64 `json:"lastSynchedBlock"`
  34. LastBatch *BatchAPI `json:"lastBatch"`
  35. CurrentSlot int64 `json:"currentSlot"`
  36. NextForgers []NextForger `json:"nextForgers"`
  37. }
  38. // NodePublicConfig is the configuration of the node that is exposed via API
  39. type NodePublicConfig struct {
  40. // ForgeDelay in seconds
  41. ForgeDelay float64 `json:"forgeDelay"`
  42. }
  43. type APIState struct {
  44. // NodePublicConfig is the configuration of the node that is exposed via API
  45. NodePublicConfig NodePublicConfig `json:"nodeConfig"`
  46. Network Network `json:"network"`
  47. Metrics Metrics `json:"metrics"`
  48. Rollup RollupVariablesAPI `json:"rollup"`
  49. Auction AuctionVariablesAPI `json:"auction"`
  50. WithdrawalDelayer common.WDelayerVariables `json:"withdrawalDelayer"`
  51. RecommendedFee common.RecommendedFee `json:"recommendedFee"`
  52. }
  53. type Constants struct {
  54. RollupConstants common.RollupConstants
  55. AuctionConstants common.AuctionConstants
  56. WDelayerConstants common.WDelayerConstants
  57. ChainID uint16
  58. HermezAddress ethCommon.Address
  59. }
  60. type NodeConfig struct {
  61. MaxPoolTxs uint32 `meddler:"max_pool_txs"`
  62. MinFeeUSD float64 `meddler:"min_fee"`
  63. }
  64. type NodeInfo struct {
  65. ItemID int `meddler:"item_id,pk"`
  66. APIState *APIState `meddler:"state,json"`
  67. NodeConfig *NodeConfig `meddler:"config,json"`
  68. Constants *Constants `meddler:"constants,json"`
  69. }
  70. func (hdb *HistoryDB) GetNodeInfo() (*NodeInfo, error) {
  71. ni := &NodeInfo{}
  72. err := meddler.QueryRow(
  73. hdb.dbRead, ni, `SELECT * FROM node_info WHERE item_id = 1;`,
  74. )
  75. return ni, tracerr.Wrap(err)
  76. }
  77. func (hdb *HistoryDB) GetConstants() (*Constants, error) {
  78. var nodeInfo NodeInfo
  79. err := meddler.QueryRow(
  80. hdb.dbRead, &nodeInfo,
  81. "SELECT constants FROM node_info WHERE item_id = 1;",
  82. )
  83. return nodeInfo.Constants, tracerr.Wrap(err)
  84. }
  85. func (hdb *HistoryDB) SetConstants(constants *Constants) error {
  86. _constants := struct {
  87. Constants *Constants `meddler:"constants,json"`
  88. }{constants}
  89. values, err := meddler.Default.Values(&_constants, false)
  90. if err != nil {
  91. return tracerr.Wrap(err)
  92. }
  93. _, err = hdb.dbWrite.Exec(
  94. "UPDATE node_info SET constants = $1 WHERE item_id = 1;",
  95. values[0],
  96. )
  97. return tracerr.Wrap(err)
  98. }
  99. func (hdb *HistoryDB) GetAPIState() (*APIState, error) {
  100. var nodeInfo NodeInfo
  101. err := meddler.QueryRow(
  102. hdb.dbRead, &nodeInfo,
  103. "SELECT state FROM node_info WHERE item_id = 1;",
  104. )
  105. return nodeInfo.APIState, tracerr.Wrap(err)
  106. }
  107. func (hdb *HistoryDB) SetAPIState(apiState *APIState) error {
  108. _apiState := struct {
  109. APIState *APIState `meddler:"state,json"`
  110. }{apiState}
  111. values, err := meddler.Default.Values(&_apiState, false)
  112. if err != nil {
  113. return tracerr.Wrap(err)
  114. }
  115. _, err = hdb.dbWrite.Exec(
  116. "UPDATE node_info SET state = $1 WHERE item_id = 1;",
  117. values[0],
  118. )
  119. return tracerr.Wrap(err)
  120. }
  121. func (hdb *HistoryDB) GetNodeConfig() (*NodeConfig, error) {
  122. var nodeInfo NodeInfo
  123. err := meddler.QueryRow(
  124. hdb.dbRead, &nodeInfo,
  125. "SELECT config FROM node_info WHERE item_id = 1;",
  126. )
  127. return nodeInfo.NodeConfig, tracerr.Wrap(err)
  128. }
  129. func (hdb *HistoryDB) SetNodeConfig(nodeConfig *NodeConfig) error {
  130. _nodeConfig := struct {
  131. NodeConfig *NodeConfig `meddler:"config,json"`
  132. }{nodeConfig}
  133. values, err := meddler.Default.Values(&_nodeConfig, false)
  134. if err != nil {
  135. return tracerr.Wrap(err)
  136. }
  137. _, err = hdb.dbWrite.Exec(
  138. "UPDATE config SET state = $1 WHERE item_id = 1;",
  139. values[0],
  140. )
  141. return tracerr.Wrap(err)
  142. }
  143. // func (hdb *HistoryDB) SetInitialNodeInfo(maxPoolTxs uint32, minFeeUSD float64, constants *Constants) error {
  144. // ni := &NodeInfo{
  145. // MaxPoolTxs: &maxPoolTxs,
  146. // MinFeeUSD: &minFeeUSD,
  147. // Constants: constants,
  148. // }
  149. // return tracerr.Wrap(meddler.Insert(hdb.dbWrite, "node_info", ni))
  150. // }
  151. type APIStateUpdater struct {
  152. hdb *HistoryDB
  153. state APIState
  154. config NodeConfig
  155. constants Constants
  156. }
  157. func (u *APIStateUpdater) SetSCVars(rollupVariables *common.RollupVariables,
  158. auctionVariables *common.AuctionVariables,
  159. wDelayerVariables *common.WDelayerVariables) {
  160. if rollupVariables != nil {
  161. rollupVars := NewRollupVariablesAPI(rollupVariables)
  162. u.state.Rollup = *rollupVars
  163. }
  164. if auctionVariables != nil {
  165. auctionVars := NewAuctionVariablesAPI(auctionVariables)
  166. u.state.Auction = *auctionVars
  167. }
  168. if wDelayerVariables != nil {
  169. u.state.WithdrawalDelayer = *wDelayerVariables
  170. }
  171. }
  172. func (u *APIStateUpdater) UpdateNetworkInfoBlock(lastEthBlock, lastSyncBlock common.Block) {
  173. u.state.Network.LastSyncBlock = lastSyncBlock.Num
  174. u.state.Network.LastEthBlock = lastEthBlock.Num
  175. }
  176. func (u *APIStateUpdater) UpdateNetworkInfo(
  177. txn *sqlx.Tx,
  178. lastEthBlock, lastSyncBlock common.Block,
  179. lastBatchNum common.BatchNum, currentSlot int64,
  180. ) error {
  181. // Get last batch in API format
  182. lastBatch, err := u.hdb.getBatchAPI(txn, lastBatchNum)
  183. if tracerr.Unwrap(err) == sql.ErrNoRows {
  184. lastBatch = nil
  185. } else if err != nil {
  186. return tracerr.Wrap(err)
  187. }
  188. // Get next forrgers
  189. lastClosedSlot := currentSlot + int64(u.state.Auction.ClosedAuctionSlots)
  190. nextForgers, err := u.getNextForgers(txn, lastSyncBlock, currentSlot, lastClosedSlot)
  191. if tracerr.Unwrap(err) == sql.ErrNoRows {
  192. nextForgers = nil
  193. } else if err != nil {
  194. return tracerr.Wrap(err)
  195. }
  196. bucketUpdates, err := u.hdb.getBucketUpdatesAPI(txn)
  197. if err == sql.ErrNoRows {
  198. bucketUpdates = nil
  199. } else if err != nil {
  200. return tracerr.Wrap(err)
  201. }
  202. // Update NodeInfo struct
  203. for i, bucketParams := range u.state.Rollup.Buckets {
  204. for _, bucketUpdate := range bucketUpdates {
  205. if bucketUpdate.NumBucket == i {
  206. bucketParams.Withdrawals = bucketUpdate.Withdrawals
  207. u.state.Rollup.Buckets[i] = bucketParams
  208. break
  209. }
  210. }
  211. }
  212. u.state.Network.LastSyncBlock = lastSyncBlock.Num
  213. u.state.Network.LastEthBlock = lastEthBlock.Num
  214. u.state.Network.LastBatch = lastBatch
  215. u.state.Network.CurrentSlot = currentSlot
  216. u.state.Network.NextForgers = nextForgers
  217. return nil
  218. }
  219. // TODO: Remove
  220. // SetRollupVariables set Status.Rollup variables
  221. func (hdb *HistoryDB) SetRollupVariables(rollupVariables *common.RollupVariables) error {
  222. setUpdatedNodeInfo := func(txn *sqlx.Tx, ni *NodeInfo) error {
  223. rollupVars := NewRollupVariablesAPI(rollupVariables)
  224. ni.APIState.Rollup = *rollupVars
  225. return nil
  226. }
  227. return hdb.updateNodeInfo(setUpdatedNodeInfo)
  228. }
  229. // TODO: Remove
  230. // SetWDelayerVariables set Status.WithdrawalDelayer variables
  231. func (hdb *HistoryDB) SetWDelayerVariables(wDelayerVariables *common.WDelayerVariables) error {
  232. setUpdatedNodeInfo := func(txn *sqlx.Tx, ni *NodeInfo) error {
  233. ni.APIState.WithdrawalDelayer = *wDelayerVariables
  234. return nil
  235. }
  236. return hdb.updateNodeInfo(setUpdatedNodeInfo)
  237. }
  238. // TODO: Remove
  239. // SetAuctionVariables set Status.Auction variables
  240. func (hdb *HistoryDB) SetAuctionVariables(auctionVariables *common.AuctionVariables) error {
  241. setUpdatedNodeInfo := func(txn *sqlx.Tx, ni *NodeInfo) error {
  242. auctionVars := NewAuctionVariablesAPI(auctionVariables)
  243. ni.APIState.Auction = *auctionVars
  244. return nil
  245. }
  246. return hdb.updateNodeInfo(setUpdatedNodeInfo)
  247. }
  248. // TODO: Remove
  249. // UpdateNetworkInfoBlock update Status.Network block related information
  250. func (hdb *HistoryDB) UpdateNetworkInfoBlock(
  251. lastEthBlock, lastSyncBlock common.Block,
  252. ) error {
  253. setUpdatedNodeInfo := func(txn *sqlx.Tx, ni *NodeInfo) error {
  254. ni.APIState.Network.LastSyncBlock = lastSyncBlock.Num
  255. ni.APIState.Network.LastEthBlock = lastEthBlock.Num
  256. return nil
  257. }
  258. return hdb.updateNodeInfo(setUpdatedNodeInfo)
  259. }
  260. // UpdateNetworkInfo update Status.Network information
  261. func (hdb *HistoryDB) UpdateNetworkInfo(
  262. lastEthBlock, lastSyncBlock common.Block,
  263. lastBatchNum common.BatchNum, currentSlot int64,
  264. ) error {
  265. setUpdatedNodeInfo := func(txn *sqlx.Tx, ni *NodeInfo) error {
  266. // Get last batch in API format
  267. lastBatch, err := hdb.getBatchAPI(txn, lastBatchNum)
  268. if tracerr.Unwrap(err) == sql.ErrNoRows {
  269. lastBatch = nil
  270. } else if err != nil {
  271. return tracerr.Wrap(err)
  272. }
  273. // Get next forrgers
  274. lastClosedSlot := currentSlot + int64(ni.APIState.Auction.ClosedAuctionSlots)
  275. nextForgers, err := hdb.getNextForgers(txn, ni, lastSyncBlock, currentSlot, lastClosedSlot)
  276. if tracerr.Unwrap(err) == sql.ErrNoRows {
  277. nextForgers = nil
  278. } else if err != nil {
  279. return tracerr.Wrap(err)
  280. }
  281. // Get buckets withdrawals
  282. var bucketUpdatesPtrs []*BucketUpdateAPI
  283. var bucketUpdates []BucketUpdateAPI
  284. err = meddler.QueryAll(
  285. txn, &bucketUpdatesPtrs,
  286. `SELECT num_bucket, withdrawals FROM bucket_update
  287. WHERE item_id in(SELECT max(item_id) FROM bucket_update
  288. group by num_bucket)
  289. ORDER BY num_bucket ASC;`,
  290. )
  291. if err == sql.ErrNoRows {
  292. bucketUpdates = nil
  293. } else if err != nil {
  294. return tracerr.Wrap(err)
  295. } else {
  296. bucketUpdates = db.SlicePtrsToSlice(bucketUpdatesPtrs).([]BucketUpdateAPI)
  297. }
  298. // Update NodeInfo struct
  299. for i, bucketParams := range ni.APIState.Rollup.Buckets {
  300. for _, bucketUpdate := range bucketUpdates {
  301. if bucketUpdate.NumBucket == i {
  302. bucketParams.Withdrawals = bucketUpdate.Withdrawals
  303. ni.APIState.Rollup.Buckets[i] = bucketParams
  304. break
  305. }
  306. }
  307. }
  308. ni.APIState.Network.LastSyncBlock = lastSyncBlock.Num
  309. ni.APIState.Network.LastEthBlock = lastEthBlock.Num
  310. ni.APIState.Network.LastBatch = lastBatch
  311. ni.APIState.Network.CurrentSlot = currentSlot
  312. ni.APIState.Network.NextForgers = nextForgers
  313. return nil
  314. }
  315. return hdb.updateNodeInfo(setUpdatedNodeInfo)
  316. }
  317. // apiSlotToBigInts converts from [6]*apitypes.BigIntStr to [6]*big.Int
  318. func apiSlotToBigInts(defaultSlotSetBid [6]*apitypes.BigIntStr) ([6]*big.Int, error) {
  319. var slots [6]*big.Int
  320. for i, slot := range defaultSlotSetBid {
  321. bigInt, ok := new(big.Int).SetString(string(*slot), 10)
  322. if !ok {
  323. return slots, tracerr.Wrap(fmt.Errorf("can't convert %T into big.Int", slot))
  324. }
  325. slots[i] = bigInt
  326. }
  327. return slots, nil
  328. }
  329. // getNextForgers returns next forgers
  330. func (u *APIStateUpdater) getNextForgers(txn *sqlx.Tx,
  331. lastBlock common.Block, currentSlot, lastClosedSlot int64) ([]NextForger, error) {
  332. secondsPerBlock := int64(15) //nolint:gomnd
  333. // currentSlot and lastClosedSlot included
  334. limit := uint(lastClosedSlot - currentSlot + 1)
  335. bids, _, err := u.hdb.getBestBidsAPI(txn, &currentSlot, &lastClosedSlot, nil, &limit, "ASC")
  336. if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
  337. return nil, tracerr.Wrap(err)
  338. }
  339. nextForgers := []NextForger{}
  340. // Get min bid info
  341. var minBidInfo []MinBidInfo
  342. if currentSlot >= u.state.Auction.DefaultSlotSetBidSlotNum {
  343. // All min bids can be calculated with the last update of AuctionVariables
  344. bigIntSlots, err := apiSlotToBigInts(u.state.Auction.DefaultSlotSetBid)
  345. if err != nil {
  346. return nil, tracerr.Wrap(err)
  347. }
  348. minBidInfo = []MinBidInfo{{
  349. DefaultSlotSetBid: bigIntSlots,
  350. DefaultSlotSetBidSlotNum: u.state.Auction.DefaultSlotSetBidSlotNum,
  351. }}
  352. } else {
  353. // Get all the relevant updates from the DB
  354. minBidInfo, err = u.hdb.getMinBidInfo(txn, currentSlot, lastClosedSlot)
  355. if err != nil {
  356. return nil, tracerr.Wrap(err)
  357. }
  358. }
  359. // Create nextForger for each slot
  360. for i := currentSlot; i <= lastClosedSlot; i++ {
  361. fromBlock := i*int64(u.constants.AuctionConstants.BlocksPerSlot) +
  362. u.constants.AuctionConstants.GenesisBlockNum
  363. toBlock := (i+1)*int64(u.constants.AuctionConstants.BlocksPerSlot) +
  364. u.constants.AuctionConstants.GenesisBlockNum - 1
  365. nextForger := NextForger{
  366. Period: Period{
  367. SlotNum: i,
  368. FromBlock: fromBlock,
  369. ToBlock: toBlock,
  370. FromTimestamp: lastBlock.Timestamp.Add(time.Second *
  371. time.Duration(secondsPerBlock*(fromBlock-lastBlock.Num))),
  372. ToTimestamp: lastBlock.Timestamp.Add(time.Second *
  373. time.Duration(secondsPerBlock*(toBlock-lastBlock.Num))),
  374. },
  375. }
  376. foundForger := false
  377. // If there is a bid for a slot, get forger (coordinator)
  378. for j := range bids {
  379. slotNum := bids[j].SlotNum
  380. if slotNum == i {
  381. // There's a bid for the slot
  382. // Check if the bid is greater than the minimum required
  383. for i := 0; i < len(minBidInfo); i++ {
  384. // Find the most recent update
  385. if slotNum >= minBidInfo[i].DefaultSlotSetBidSlotNum {
  386. // Get min bid
  387. minBidSelector := slotNum % int64(len(u.state.Auction.DefaultSlotSetBid))
  388. minBid := minBidInfo[i].DefaultSlotSetBid[minBidSelector]
  389. // Check if the bid has beaten the minimum
  390. bid, ok := new(big.Int).SetString(string(bids[j].BidValue), 10)
  391. if !ok {
  392. return nil, tracerr.New("Wrong bid value, error parsing it as big.Int")
  393. }
  394. if minBid.Cmp(bid) == 1 {
  395. // Min bid is greater than bid, the slot will be forged by boot coordinator
  396. break
  397. }
  398. foundForger = true
  399. break
  400. }
  401. }
  402. if !foundForger { // There is no bid or it's smaller than the minimum
  403. break
  404. }
  405. coordinator, err := u.hdb.GetCoordinatorAPI(bids[j].Bidder)
  406. if err != nil {
  407. return nil, tracerr.Wrap(err)
  408. }
  409. nextForger.Coordinator = *coordinator
  410. break
  411. }
  412. }
  413. // If there is no bid, the coordinator that will forge is boot coordinator
  414. if !foundForger {
  415. nextForger.Coordinator = CoordinatorAPI{
  416. Forger: u.state.Auction.BootCoordinator,
  417. URL: u.state.Auction.BootCoordinatorURL,
  418. }
  419. }
  420. nextForgers = append(nextForgers, nextForger)
  421. }
  422. return nextForgers, nil
  423. }
  424. // TODO: Rename to getMetrics and don't write anything
  425. // UpdateMetrics update Status.Metrics information
  426. func (hdb *HistoryDB) UpdateMetrics() error {
  427. setUpdatedNodeInfo := func(txn *sqlx.Tx, ni *NodeInfo) error {
  428. // Get the first and last batch of the last 24h and their timestamps
  429. if ni.APIState.Network.LastBatch == nil {
  430. return nil
  431. }
  432. type period struct {
  433. FromBatchNum common.BatchNum `meddler:"from_batch_num"`
  434. FromTimestamp time.Time `meddler:"from_timestamp"`
  435. ToBatchNum common.BatchNum `meddler:"-"`
  436. ToTimestamp time.Time `meddler:"to_timestamp"`
  437. }
  438. p := &period{
  439. ToBatchNum: ni.APIState.Network.LastBatch.BatchNum,
  440. }
  441. if err := meddler.QueryRow(
  442. txn, p, `SELECT
  443. COALESCE (MIN(batch.batch_num), 0) as from_batch_num,
  444. COALESCE (MIN(block.timestamp), NOW()) AS from_timestamp,
  445. COALESCE (MAX(block.timestamp), NOW()) AS to_timestamp
  446. FROM batch INNER JOIN block ON batch.eth_block_num = block.eth_block_num
  447. WHERE block.timestamp >= NOW() - INTERVAL '24 HOURS';`,
  448. ); err != nil {
  449. return tracerr.Wrap(err)
  450. }
  451. // Get the amount of txs of that period
  452. row := txn.QueryRow(
  453. `SELECT COUNT(*) as total_txs FROM tx WHERE tx.batch_num between $1 AND $2;`,
  454. p.FromBatchNum, p.ToBatchNum,
  455. )
  456. var nTxs int
  457. if err := row.Scan(&nTxs); err != nil {
  458. return tracerr.Wrap(err)
  459. }
  460. // Set txs/s
  461. seconds := p.ToTimestamp.Sub(p.FromTimestamp).Seconds()
  462. if seconds == 0 { // Avoid dividing by 0
  463. seconds++
  464. }
  465. ni.APIState.Metrics.TransactionsPerSecond = float64(nTxs) / seconds
  466. // Set txs/batch
  467. nBatches := p.ToBatchNum - p.FromBatchNum
  468. if nBatches == 0 { // Avoid dividing by 0
  469. nBatches++
  470. }
  471. if (p.ToBatchNum - p.FromBatchNum) > 0 {
  472. ni.APIState.Metrics.TransactionsPerBatch = float64(nTxs) /
  473. float64(nBatches)
  474. } else {
  475. ni.APIState.Metrics.TransactionsPerBatch = 0
  476. }
  477. // Get total fee of that period
  478. row = txn.QueryRow(
  479. `SELECT COALESCE (SUM(total_fees_usd), 0) FROM batch WHERE batch_num between $1 AND $2;`,
  480. p.FromBatchNum, p.ToBatchNum,
  481. )
  482. var totalFee float64
  483. if err := row.Scan(&totalFee); err != nil {
  484. return tracerr.Wrap(err)
  485. }
  486. // Set batch frequency
  487. ni.APIState.Metrics.BatchFrequency = seconds / float64(nBatches)
  488. if nTxs > 0 {
  489. ni.APIState.Metrics.AvgTransactionFee = totalFee / float64(nTxs)
  490. } else {
  491. ni.APIState.Metrics.AvgTransactionFee = 0
  492. }
  493. // Get and set amount of registered accounts
  494. type registeredAccounts struct {
  495. TotalIdx int64 `meddler:"total_idx"`
  496. TotalBJJ int64 `meddler:"total_bjj"`
  497. }
  498. ra := &registeredAccounts{}
  499. if err := meddler.QueryRow(
  500. txn, ra,
  501. `SELECT COUNT(*) AS total_bjj, COUNT(DISTINCT(bjj)) AS total_idx FROM account;`,
  502. ); err != nil {
  503. return tracerr.Wrap(err)
  504. }
  505. ni.APIState.Metrics.TotalAccounts = ra.TotalIdx
  506. ni.APIState.Metrics.TotalBJJs = ra.TotalBJJ
  507. // Get and set estimated time to forge L1 tx
  508. row = txn.QueryRow(
  509. `SELECT COALESCE (AVG(EXTRACT(EPOCH FROM (forged.timestamp - added.timestamp))), 0) FROM tx
  510. INNER JOIN block AS added ON tx.eth_block_num = added.eth_block_num
  511. INNER JOIN batch AS forged_batch ON tx.batch_num = forged_batch.batch_num
  512. INNER JOIN block AS forged ON forged_batch.eth_block_num = forged.eth_block_num
  513. WHERE tx.batch_num between $1 and $2 AND tx.is_l1 AND tx.user_origin;`,
  514. p.FromBatchNum, p.ToBatchNum,
  515. )
  516. var timeToForgeL1 float64
  517. if err := row.Scan(&timeToForgeL1); err != nil {
  518. return tracerr.Wrap(err)
  519. }
  520. ni.APIState.Metrics.EstimatedTimeToForgeL1 = timeToForgeL1
  521. return nil
  522. }
  523. return hdb.updateNodeInfo(setUpdatedNodeInfo)
  524. }
  525. // UpdateRecommendedFee update Status.RecommendedFee information
  526. func (hdb *HistoryDB) UpdateRecommendedFee() error {
  527. setUpdatedNodeInfo := func(txn *sqlx.Tx, ni *NodeInfo) error {
  528. // Get total txs and the batch of the first selected tx of the last hour
  529. type totalTxsSinceBatchNum struct {
  530. TotalTxs int `meddler:"total_txs"`
  531. FirstBatchNum common.BatchNum `meddler:"batch_num"`
  532. }
  533. ttsbn := &totalTxsSinceBatchNum{}
  534. if err := meddler.QueryRow(
  535. txn, ttsbn, `SELECT COUNT(tx.*) as total_txs,
  536. COALESCE (MIN(tx.batch_num), 0) as batch_num
  537. FROM tx INNER JOIN block ON tx.eth_block_num = block.eth_block_num
  538. WHERE block.timestamp >= NOW() - INTERVAL '1 HOURS';`,
  539. ); err != nil {
  540. return tracerr.Wrap(err)
  541. }
  542. // Get the amount of batches and acumulated fees for the last hour
  543. type totalBatchesAndFee struct {
  544. TotalBatches int `meddler:"total_batches"`
  545. TotalFees float64 `meddler:"total_fees"`
  546. }
  547. tbf := &totalBatchesAndFee{}
  548. if err := meddler.QueryRow(
  549. txn, tbf, `SELECT COUNT(*) AS total_batches,
  550. COALESCE (SUM(total_fees_usd), 0) AS total_fees FROM batch
  551. WHERE batch_num > $1;`, ttsbn.FirstBatchNum,
  552. ); err != nil {
  553. return tracerr.Wrap(err)
  554. }
  555. // Update NodeInfo struct
  556. var avgTransactionFee float64
  557. if ttsbn.TotalTxs > 0 {
  558. avgTransactionFee = tbf.TotalFees / float64(ttsbn.TotalTxs)
  559. } else {
  560. avgTransactionFee = 0
  561. }
  562. ni.APIState.RecommendedFee.ExistingAccount =
  563. math.Max(avgTransactionFee, *ni.MinFeeUSD)
  564. ni.APIState.RecommendedFee.CreatesAccount =
  565. math.Max(createAccountExtraFeePercentage*avgTransactionFee, *ni.MinFeeUSD)
  566. ni.APIState.RecommendedFee.CreatesAccountAndRegister =
  567. math.Max(createAccountInternalExtraFeePercentage*avgTransactionFee, *ni.MinFeeUSD)
  568. return nil
  569. }
  570. return hdb.updateNodeInfo(setUpdatedNodeInfo)
  571. }
  572. func (hdb *HistoryDB) updateNodeInfo(setUpdatedNodeInfo func(*sqlx.Tx, *NodeInfo) error) error {
  573. // Create a SQL transaction or read and update atomicaly
  574. txn, err := hdb.dbWrite.Beginx()
  575. if err != nil {
  576. return tracerr.Wrap(err)
  577. }
  578. defer func() {
  579. if err != nil {
  580. db.Rollback(txn)
  581. }
  582. }()
  583. // Read current node info
  584. ni := &NodeInfo{}
  585. if err := meddler.QueryRow(
  586. txn, ni, "SELECT * FROM node_info;",
  587. ); err != nil {
  588. return tracerr.Wrap(err)
  589. }
  590. // Update NodeInfo struct
  591. if err := setUpdatedNodeInfo(txn, ni); err != nil {
  592. return tracerr.Wrap(err)
  593. }
  594. // Update NodeInfo at DB
  595. if _, err := txn.Exec("DELETE FROM node_info;"); err != nil {
  596. return tracerr.Wrap(err)
  597. }
  598. if err := meddler.Insert(txn, "node_info", ni); err != nil {
  599. return tracerr.Wrap(err)
  600. }
  601. // Commit NodeInfo update
  602. return tracerr.Wrap(txn.Commit())
  603. }