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.

155 lines
4.1 KiB

Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
  1. package stateapiupdater
  2. import (
  3. "database/sql"
  4. "sync"
  5. "github.com/hermeznetwork/hermez-node/common"
  6. "github.com/hermeznetwork/hermez-node/db/historydb"
  7. "github.com/hermeznetwork/tracerr"
  8. )
  9. // Updater is an utility object to facilitate updating the StateAPI
  10. type Updater struct {
  11. hdb *historydb.HistoryDB
  12. state historydb.StateAPI
  13. config historydb.NodeConfig
  14. vars common.SCVariablesPtr
  15. consts historydb.Constants
  16. rw sync.RWMutex
  17. }
  18. // NewUpdater creates a new Updater
  19. func NewUpdater(hdb *historydb.HistoryDB, config *historydb.NodeConfig, vars *common.SCVariables,
  20. consts *historydb.Constants) *Updater {
  21. u := Updater{
  22. hdb: hdb,
  23. config: *config,
  24. consts: *consts,
  25. state: historydb.StateAPI{
  26. NodePublicConfig: historydb.NodePublicConfig{
  27. ForgeDelay: config.ForgeDelay,
  28. },
  29. },
  30. }
  31. u.SetSCVars(vars.AsPtr())
  32. return &u
  33. }
  34. // Store the State in the HistoryDB
  35. func (u *Updater) Store() error {
  36. u.rw.RLock()
  37. defer u.rw.RUnlock()
  38. return tracerr.Wrap(u.hdb.SetStateInternalAPI(&u.state))
  39. }
  40. // SetSCVars sets the smart contract vars (ony updates those that are not nil)
  41. func (u *Updater) SetSCVars(vars *common.SCVariablesPtr) {
  42. u.rw.Lock()
  43. defer u.rw.Unlock()
  44. if vars.Rollup != nil {
  45. u.vars.Rollup = vars.Rollup
  46. rollupVars := historydb.NewRollupVariablesAPI(u.vars.Rollup)
  47. u.state.Rollup = *rollupVars
  48. }
  49. if vars.Auction != nil {
  50. u.vars.Auction = vars.Auction
  51. auctionVars := historydb.NewAuctionVariablesAPI(u.vars.Auction)
  52. u.state.Auction = *auctionVars
  53. }
  54. if vars.WDelayer != nil {
  55. u.vars.WDelayer = vars.WDelayer
  56. u.state.WithdrawalDelayer = *u.vars.WDelayer
  57. }
  58. }
  59. // UpdateRecommendedFee update Status.RecommendedFee information
  60. func (u *Updater) UpdateRecommendedFee() error {
  61. recommendedFee, err := u.hdb.GetRecommendedFee(u.config.MinFeeUSD)
  62. if err != nil {
  63. return tracerr.Wrap(err)
  64. }
  65. u.rw.Lock()
  66. u.state.RecommendedFee = *recommendedFee
  67. u.rw.Unlock()
  68. return nil
  69. }
  70. // UpdateMetrics update Status.Metrics information
  71. func (u *Updater) UpdateMetrics() error {
  72. u.rw.RLock()
  73. lastBatch := u.state.Network.LastBatch
  74. u.rw.RUnlock()
  75. if lastBatch == nil {
  76. return nil
  77. }
  78. lastBatchNum := lastBatch.BatchNum
  79. metrics, err := u.hdb.GetMetricsInternalAPI(lastBatchNum)
  80. if err != nil {
  81. return tracerr.Wrap(err)
  82. }
  83. u.rw.Lock()
  84. u.state.Metrics = *metrics
  85. u.rw.Unlock()
  86. return nil
  87. }
  88. // UpdateNetworkInfoBlock update Status.Network block related information
  89. func (u *Updater) UpdateNetworkInfoBlock(lastEthBlock, lastSyncBlock common.Block) {
  90. u.rw.Lock()
  91. u.state.Network.LastSyncBlock = lastSyncBlock.Num
  92. u.state.Network.LastEthBlock = lastEthBlock.Num
  93. u.rw.Unlock()
  94. }
  95. // UpdateNetworkInfo update Status.Network information
  96. func (u *Updater) UpdateNetworkInfo(
  97. lastEthBlock, lastSyncBlock common.Block,
  98. lastBatchNum common.BatchNum, currentSlot int64,
  99. ) error {
  100. // Get last batch in API format
  101. lastBatch, err := u.hdb.GetBatchInternalAPI(lastBatchNum)
  102. if tracerr.Unwrap(err) == sql.ErrNoRows {
  103. lastBatch = nil
  104. } else if err != nil {
  105. return tracerr.Wrap(err)
  106. }
  107. u.rw.RLock()
  108. auctionVars := u.vars.Auction
  109. u.rw.RUnlock()
  110. // Get next forgers
  111. lastClosedSlot := currentSlot + int64(auctionVars.ClosedAuctionSlots)
  112. nextForgers, err := u.hdb.GetNextForgersInternalAPI(auctionVars, &u.consts.Auction,
  113. lastSyncBlock, currentSlot, lastClosedSlot)
  114. if tracerr.Unwrap(err) == sql.ErrNoRows {
  115. nextForgers = nil
  116. } else if err != nil {
  117. return tracerr.Wrap(err)
  118. }
  119. bucketUpdates, err := u.hdb.GetBucketUpdatesInternalAPI()
  120. if err == sql.ErrNoRows {
  121. bucketUpdates = nil
  122. } else if err != nil {
  123. return tracerr.Wrap(err)
  124. }
  125. u.rw.Lock()
  126. // Update NodeInfo struct
  127. for i, bucketParams := range u.state.Rollup.Buckets {
  128. for _, bucketUpdate := range bucketUpdates {
  129. if bucketUpdate.NumBucket == i {
  130. bucketParams.Withdrawals = bucketUpdate.Withdrawals
  131. u.state.Rollup.Buckets[i] = bucketParams
  132. break
  133. }
  134. }
  135. }
  136. u.state.Network.LastSyncBlock = lastSyncBlock.Num
  137. u.state.Network.LastEthBlock = lastEthBlock.Num
  138. u.state.Network.LastBatch = lastBatch
  139. u.state.Network.CurrentSlot = currentSlot
  140. u.state.Network.NextForgers = nextForgers
  141. u.rw.Unlock()
  142. return nil
  143. }