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.

235 lines
7.5 KiB

Update coordinator, call all api update functions - Common: - Rename Block.EthBlockNum to Block.Num to avoid unneeded repetition - API: - Add UpdateNetworkInfoBlock to update just block information, to be used when the node is not yet synchronized - Node: - Call API.UpdateMetrics and UpdateRecommendedFee in a loop, with configurable time intervals - Synchronizer: - When mapping events by TxHash, use an array to support the possibility of multiple calls of the same function happening in the same transaction (for example, a smart contract in a single transaction could call withdraw with delay twice, which would generate 2 withdraw events, and 2 deposit events). - In Stats, keep entire LastBlock instead of just the blockNum - In Stats, add lastL1BatchBlock - Test Stats and SCVars - Coordinator: - Enable writing the BatchInfo in every step of the pipeline to disk (with JSON text files) for debugging purposes. - Move the Pipeline functionality from the Coordinator to its own struct (Pipeline) - Implement shouldL1lL2Batch - In TxManager, implement logic to perform several attempts when doing ethereum node RPC calls before considering the error. (Both for calls to forgeBatch and transaction receipt) - In TxManager, reorganize the flow and note the specific points in which actions are made when err != nil - HistoryDB: - Implement GetLastL1BatchBlockNum: returns the blockNum of the latest forged l1Batch, to help the coordinator decide when to forge an L1Batch. - EthereumClient and test.Client: - Update EthBlockByNumber to return the last block when the passed number is -1.
3 years ago
Update coordinator, call all api update functions - Common: - Rename Block.EthBlockNum to Block.Num to avoid unneeded repetition - API: - Add UpdateNetworkInfoBlock to update just block information, to be used when the node is not yet synchronized - Node: - Call API.UpdateMetrics and UpdateRecommendedFee in a loop, with configurable time intervals - Synchronizer: - When mapping events by TxHash, use an array to support the possibility of multiple calls of the same function happening in the same transaction (for example, a smart contract in a single transaction could call withdraw with delay twice, which would generate 2 withdraw events, and 2 deposit events). - In Stats, keep entire LastBlock instead of just the blockNum - In Stats, add lastL1BatchBlock - Test Stats and SCVars - Coordinator: - Enable writing the BatchInfo in every step of the pipeline to disk (with JSON text files) for debugging purposes. - Move the Pipeline functionality from the Coordinator to its own struct (Pipeline) - Implement shouldL1lL2Batch - In TxManager, implement logic to perform several attempts when doing ethereum node RPC calls before considering the error. (Both for calls to forgeBatch and transaction receipt) - In TxManager, reorganize the flow and note the specific points in which actions are made when err != nil - HistoryDB: - Implement GetLastL1BatchBlockNum: returns the blockNum of the latest forged l1Batch, to help the coordinator decide when to forge an L1Batch. - EthereumClient and test.Client: - Update EthBlockByNumber to return the last block when the passed number is -1.
3 years ago
  1. package api
  2. import (
  3. "database/sql"
  4. "math/big"
  5. "net/http"
  6. "time"
  7. ethCommon "github.com/ethereum/go-ethereum/common"
  8. "github.com/gin-gonic/gin"
  9. "github.com/hermeznetwork/hermez-node/common"
  10. "github.com/hermeznetwork/hermez-node/db/historydb"
  11. "github.com/hermeznetwork/tracerr"
  12. )
  13. // Network define status of the network
  14. type Network struct {
  15. LastEthBlock int64 `json:"lastEthereumBlock"`
  16. LastSyncBlock int64 `json:"lastSynchedBlock"`
  17. LastBatch *historydb.BatchAPI `json:"lastBatch"`
  18. CurrentSlot int64 `json:"currentSlot"`
  19. NextForgers []NextForger `json:"nextForgers"`
  20. }
  21. // NextForger is a representation of the information of a coordinator and the period will forge
  22. type NextForger struct {
  23. Coordinator historydb.CoordinatorAPI `json:"coordinator"`
  24. Period Period `json:"period"`
  25. }
  26. // Period is a representation of a period
  27. type Period struct {
  28. SlotNum int64 `json:"slotNum"`
  29. FromBlock int64 `json:"fromBlock"`
  30. ToBlock int64 `json:"toBlock"`
  31. FromTimestamp time.Time `json:"fromTimestamp"`
  32. ToTimestamp time.Time `json:"toTimestamp"`
  33. }
  34. var bootCoordinator historydb.CoordinatorAPI = historydb.CoordinatorAPI{
  35. ItemID: 0,
  36. Bidder: ethCommon.HexToAddress("0x111111111111111111111111111111111111111"),
  37. Forger: ethCommon.HexToAddress("0x111111111111111111111111111111111111111"),
  38. URL: "https://bootCoordinator",
  39. }
  40. func (a *API) getState(c *gin.Context) {
  41. // TODO: There are no events for the buckets information, so now this information will be 0
  42. a.status.RLock()
  43. status := a.status //nolint
  44. a.status.RUnlock()
  45. c.JSON(http.StatusOK, status) //nolint
  46. }
  47. // SC Vars
  48. // SetRollupVariables set Status.Rollup variables
  49. func (a *API) SetRollupVariables(rollupVariables common.RollupVariables) {
  50. a.status.Lock()
  51. a.status.Rollup = rollupVariables
  52. a.status.Unlock()
  53. }
  54. // SetWDelayerVariables set Status.WithdrawalDelayer variables
  55. func (a *API) SetWDelayerVariables(wDelayerVariables common.WDelayerVariables) {
  56. a.status.Lock()
  57. a.status.WithdrawalDelayer = wDelayerVariables
  58. a.status.Unlock()
  59. }
  60. // SetAuctionVariables set Status.Auction variables
  61. func (a *API) SetAuctionVariables(auctionVariables common.AuctionVariables) {
  62. a.status.Lock()
  63. a.status.Auction = auctionVariables
  64. a.status.Unlock()
  65. }
  66. // Network
  67. // UpdateNetworkInfoBlock update Status.Network block related information
  68. func (a *API) UpdateNetworkInfoBlock(
  69. lastEthBlock, lastSyncBlock common.Block,
  70. ) {
  71. a.status.Network.LastSyncBlock = lastSyncBlock.Num
  72. a.status.Network.LastEthBlock = lastEthBlock.Num
  73. }
  74. // UpdateNetworkInfo update Status.Network information
  75. func (a *API) UpdateNetworkInfo(
  76. lastEthBlock, lastSyncBlock common.Block,
  77. lastBatchNum common.BatchNum, currentSlot int64,
  78. ) error {
  79. lastBatch, err := a.h.GetBatchAPI(lastBatchNum)
  80. if tracerr.Unwrap(err) == sql.ErrNoRows {
  81. lastBatch = nil
  82. } else if err != nil {
  83. return tracerr.Wrap(err)
  84. }
  85. lastClosedSlot := currentSlot + int64(a.status.Auction.ClosedAuctionSlots)
  86. nextForgers, err := a.getNextForgers(lastSyncBlock, currentSlot, lastClosedSlot)
  87. if tracerr.Unwrap(err) == sql.ErrNoRows {
  88. nextForgers = nil
  89. } else if err != nil {
  90. return tracerr.Wrap(err)
  91. }
  92. a.status.Lock()
  93. a.status.Network.LastSyncBlock = lastSyncBlock.Num
  94. a.status.Network.LastEthBlock = lastEthBlock.Num
  95. a.status.Network.LastBatch = lastBatch
  96. a.status.Network.CurrentSlot = currentSlot
  97. a.status.Network.NextForgers = nextForgers
  98. a.status.Unlock()
  99. return nil
  100. }
  101. // getNextForgers returns next forgers
  102. func (a *API) getNextForgers(lastBlock common.Block, currentSlot, lastClosedSlot int64) ([]NextForger, error) {
  103. secondsPerBlock := int64(15) //nolint:gomnd
  104. // currentSlot and lastClosedSlot included
  105. limit := uint(lastClosedSlot - currentSlot + 1)
  106. bids, _, err := a.h.GetBestBidsAPI(&currentSlot, &lastClosedSlot, nil, &limit, "ASC")
  107. if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
  108. return nil, tracerr.Wrap(err)
  109. }
  110. nextForgers := []NextForger{}
  111. // Get min bid info
  112. var minBidInfo []historydb.MinBidInfo
  113. if currentSlot >= a.status.Auction.DefaultSlotSetBidSlotNum {
  114. // All min bids can be calculated with the last update of AuctionVariables
  115. minBidInfo = []historydb.MinBidInfo{{
  116. DefaultSlotSetBid: a.status.Auction.DefaultSlotSetBid,
  117. DefaultSlotSetBidSlotNum: a.status.Auction.DefaultSlotSetBidSlotNum,
  118. }}
  119. } else {
  120. // Get all the relevant updates from the DB
  121. minBidInfo, err = a.h.GetAuctionVarsUntilSetSlotNum(lastClosedSlot, int(lastClosedSlot-currentSlot)+1)
  122. if err != nil {
  123. return nil, tracerr.Wrap(err)
  124. }
  125. }
  126. // Create nextForger for each slot
  127. for i := currentSlot; i <= lastClosedSlot; i++ {
  128. fromBlock := i*int64(a.cg.AuctionConstants.BlocksPerSlot) + a.cg.AuctionConstants.GenesisBlockNum
  129. toBlock := (i+1)*int64(a.cg.AuctionConstants.BlocksPerSlot) + a.cg.AuctionConstants.GenesisBlockNum - 1
  130. nextForger := NextForger{
  131. Period: Period{
  132. SlotNum: i,
  133. FromBlock: fromBlock,
  134. ToBlock: toBlock,
  135. FromTimestamp: lastBlock.Timestamp.Add(time.Second * time.Duration(secondsPerBlock*(fromBlock-lastBlock.Num))),
  136. ToTimestamp: lastBlock.Timestamp.Add(time.Second * time.Duration(secondsPerBlock*(toBlock-lastBlock.Num))),
  137. },
  138. }
  139. foundForger := false
  140. // If there is a bid for a slot, get forger (coordinator)
  141. for j := range bids {
  142. slotNum := bids[j].SlotNum
  143. if slotNum == i {
  144. // There's a bid for the slot
  145. // Check if the bid is greater than the minimum required
  146. for i := 0; i < len(minBidInfo); i++ {
  147. // Find the most recent update
  148. if slotNum >= minBidInfo[i].DefaultSlotSetBidSlotNum {
  149. // Get min bid
  150. minBidSelector := slotNum % int64(len(a.status.Auction.DefaultSlotSetBid))
  151. minBid := minBidInfo[i].DefaultSlotSetBid[minBidSelector]
  152. // Check if the bid has beaten the minimum
  153. bid, ok := new(big.Int).SetString(string(bids[j].BidValue), 10)
  154. if !ok {
  155. return nil, tracerr.New("Wrong bid value, error parsing it as big.Int")
  156. }
  157. if minBid.Cmp(bid) == 1 {
  158. // Min bid is greater than bid, the slot will be forged by boot coordinator
  159. break
  160. }
  161. foundForger = true
  162. break
  163. }
  164. }
  165. if !foundForger { // There is no bid or it's smaller than the minimum
  166. break
  167. }
  168. coordinator, err := a.h.GetCoordinatorAPI(bids[j].Bidder)
  169. if err != nil {
  170. return nil, tracerr.Wrap(err)
  171. }
  172. nextForger.Coordinator = *coordinator
  173. break
  174. }
  175. }
  176. // If there is no bid, the coordinator that will forge is boot coordinator
  177. if !foundForger {
  178. nextForger.Coordinator = bootCoordinator
  179. }
  180. nextForgers = append(nextForgers, nextForger)
  181. }
  182. return nextForgers, nil
  183. }
  184. // Metrics
  185. // UpdateMetrics update Status.Metrics information
  186. func (a *API) UpdateMetrics() error {
  187. a.status.RLock()
  188. if a.status.Network.LastBatch == nil {
  189. a.status.RUnlock()
  190. return nil
  191. }
  192. batchNum := a.status.Network.LastBatch.BatchNum
  193. a.status.RUnlock()
  194. metrics, err := a.h.GetMetrics(batchNum)
  195. if err != nil {
  196. return tracerr.Wrap(err)
  197. }
  198. a.status.Lock()
  199. a.status.Metrics = *metrics
  200. a.status.Unlock()
  201. return nil
  202. }
  203. // Recommended fee
  204. // UpdateRecommendedFee update Status.RecommendedFee information
  205. func (a *API) UpdateRecommendedFee() error {
  206. feeExistingAccount, err := a.h.GetAvgTxFee()
  207. if err != nil {
  208. return tracerr.Wrap(err)
  209. }
  210. a.status.Lock()
  211. a.status.RecommendedFee.ExistingAccount = feeExistingAccount
  212. a.status.RecommendedFee.CreatesAccount = createAccountExtraFeePercentage * feeExistingAccount
  213. a.status.RecommendedFee.CreatesAccountAndRegister = createAccountInternalExtraFeePercentage * feeExistingAccount
  214. a.status.Unlock()
  215. return nil
  216. }