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.

270 lines
8.8 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.
4 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.
4 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/apitypes"
  10. "github.com/hermeznetwork/hermez-node/common"
  11. "github.com/hermeznetwork/hermez-node/db/historydb"
  12. "github.com/hermeznetwork/tracerr"
  13. )
  14. // Network define status of the network
  15. type Network struct {
  16. LastEthBlock int64 `json:"lastEthereumBlock"`
  17. LastSyncBlock int64 `json:"lastSynchedBlock"`
  18. LastBatch *historydb.BatchAPI `json:"lastBatch"`
  19. CurrentSlot int64 `json:"currentSlot"`
  20. NextForgers []NextForger `json:"nextForgers"`
  21. }
  22. // NextForger is a representation of the information of a coordinator and the period will forge
  23. type NextForger struct {
  24. Coordinator historydb.CoordinatorAPI `json:"coordinator"`
  25. Period Period `json:"period"`
  26. }
  27. // Period is a representation of a period
  28. type Period struct {
  29. SlotNum int64 `json:"slotNum"`
  30. FromBlock int64 `json:"fromBlock"`
  31. ToBlock int64 `json:"toBlock"`
  32. FromTimestamp time.Time `json:"fromTimestamp"`
  33. ToTimestamp time.Time `json:"toTimestamp"`
  34. }
  35. var bootCoordinator historydb.CoordinatorAPI = historydb.CoordinatorAPI{
  36. ItemID: 0,
  37. Bidder: ethCommon.HexToAddress("0x111111111111111111111111111111111111111"),
  38. Forger: ethCommon.HexToAddress("0x111111111111111111111111111111111111111"),
  39. URL: "https://bootCoordinator",
  40. }
  41. func (a *API) getState(c *gin.Context) {
  42. // TODO: There are no events for the buckets information, so now this information will be 0
  43. a.status.RLock()
  44. status := a.status //nolint
  45. a.status.RUnlock()
  46. c.JSON(http.StatusOK, status) //nolint
  47. }
  48. // SC Vars
  49. // SetRollupVariables set Status.Rollup variables
  50. func (a *API) SetRollupVariables(rollupVariables common.RollupVariables) {
  51. a.status.Lock()
  52. var rollupVAPI historydb.RollupVariablesAPI
  53. rollupVAPI.EthBlockNum = rollupVariables.EthBlockNum
  54. rollupVAPI.FeeAddToken = apitypes.NewBigIntStr(rollupVariables.FeeAddToken)
  55. rollupVAPI.ForgeL1L2BatchTimeout = rollupVariables.ForgeL1L2BatchTimeout
  56. rollupVAPI.WithdrawalDelay = rollupVariables.WithdrawalDelay
  57. for i, bucket := range rollupVariables.Buckets {
  58. var apiBucket historydb.BucketParamsAPI
  59. apiBucket.CeilUSD = apitypes.NewBigIntStr(bucket.CeilUSD)
  60. apiBucket.Withdrawals = apitypes.NewBigIntStr(bucket.Withdrawals)
  61. apiBucket.BlockWithdrawalRate = apitypes.NewBigIntStr(bucket.BlockWithdrawalRate)
  62. apiBucket.MaxWithdrawals = apitypes.NewBigIntStr(bucket.MaxWithdrawals)
  63. rollupVAPI.Buckets[i] = apiBucket
  64. }
  65. rollupVAPI.SafeMode = rollupVariables.SafeMode
  66. a.status.Rollup = rollupVAPI
  67. a.status.Unlock()
  68. }
  69. // SetWDelayerVariables set Status.WithdrawalDelayer variables
  70. func (a *API) SetWDelayerVariables(wDelayerVariables common.WDelayerVariables) {
  71. a.status.Lock()
  72. a.status.WithdrawalDelayer = wDelayerVariables
  73. a.status.Unlock()
  74. }
  75. // SetAuctionVariables set Status.Auction variables
  76. func (a *API) SetAuctionVariables(auctionVariables common.AuctionVariables) {
  77. a.status.Lock()
  78. a.status.Auction = auctionVariables
  79. a.status.Unlock()
  80. }
  81. // Network
  82. // UpdateNetworkInfoBlock update Status.Network block related information
  83. func (a *API) UpdateNetworkInfoBlock(
  84. lastEthBlock, lastSyncBlock common.Block,
  85. ) {
  86. a.status.Network.LastSyncBlock = lastSyncBlock.Num
  87. a.status.Network.LastEthBlock = lastEthBlock.Num
  88. }
  89. // UpdateNetworkInfo update Status.Network information
  90. func (a *API) UpdateNetworkInfo(
  91. lastEthBlock, lastSyncBlock common.Block,
  92. lastBatchNum common.BatchNum, currentSlot int64,
  93. ) error {
  94. lastBatch, err := a.h.GetBatchAPI(lastBatchNum)
  95. if tracerr.Unwrap(err) == sql.ErrNoRows {
  96. lastBatch = nil
  97. } else if err != nil {
  98. return tracerr.Wrap(err)
  99. }
  100. lastClosedSlot := currentSlot + int64(a.status.Auction.ClosedAuctionSlots)
  101. nextForgers, err := a.getNextForgers(lastSyncBlock, currentSlot, lastClosedSlot)
  102. if tracerr.Unwrap(err) == sql.ErrNoRows {
  103. nextForgers = nil
  104. } else if err != nil {
  105. return tracerr.Wrap(err)
  106. }
  107. a.status.Lock()
  108. a.status.Network.LastSyncBlock = lastSyncBlock.Num
  109. a.status.Network.LastEthBlock = lastEthBlock.Num
  110. a.status.Network.LastBatch = lastBatch
  111. a.status.Network.CurrentSlot = currentSlot
  112. a.status.Network.NextForgers = nextForgers
  113. // Update buckets withdrawals
  114. bucketsUpdate, err := a.h.GetBucketUpdates()
  115. if tracerr.Unwrap(err) == sql.ErrNoRows {
  116. bucketsUpdate = nil
  117. } else if err != nil {
  118. return tracerr.Wrap(err)
  119. }
  120. for i, bucketParams := range a.status.Rollup.Buckets {
  121. for _, bucketUpdate := range bucketsUpdate {
  122. if bucketUpdate.NumBucket == i {
  123. bucketParams.Withdrawals = bucketUpdate.Withdrawals
  124. a.status.Rollup.Buckets[i] = bucketParams
  125. break
  126. }
  127. }
  128. }
  129. a.status.Unlock()
  130. return nil
  131. }
  132. // getNextForgers returns next forgers
  133. func (a *API) getNextForgers(lastBlock common.Block, currentSlot, lastClosedSlot int64) ([]NextForger, error) {
  134. secondsPerBlock := int64(15) //nolint:gomnd
  135. // currentSlot and lastClosedSlot included
  136. limit := uint(lastClosedSlot - currentSlot + 1)
  137. bids, _, err := a.h.GetBestBidsAPI(&currentSlot, &lastClosedSlot, nil, &limit, "ASC")
  138. if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
  139. return nil, tracerr.Wrap(err)
  140. }
  141. nextForgers := []NextForger{}
  142. // Get min bid info
  143. var minBidInfo []historydb.MinBidInfo
  144. if currentSlot >= a.status.Auction.DefaultSlotSetBidSlotNum {
  145. // All min bids can be calculated with the last update of AuctionVariables
  146. minBidInfo = []historydb.MinBidInfo{{
  147. DefaultSlotSetBid: a.status.Auction.DefaultSlotSetBid,
  148. DefaultSlotSetBidSlotNum: a.status.Auction.DefaultSlotSetBidSlotNum,
  149. }}
  150. } else {
  151. // Get all the relevant updates from the DB
  152. minBidInfo, err = a.h.GetAuctionVarsUntilSetSlotNum(lastClosedSlot, int(lastClosedSlot-currentSlot)+1)
  153. if err != nil {
  154. return nil, tracerr.Wrap(err)
  155. }
  156. }
  157. // Create nextForger for each slot
  158. for i := currentSlot; i <= lastClosedSlot; i++ {
  159. fromBlock := i*int64(a.cg.AuctionConstants.BlocksPerSlot) + a.cg.AuctionConstants.GenesisBlockNum
  160. toBlock := (i+1)*int64(a.cg.AuctionConstants.BlocksPerSlot) + a.cg.AuctionConstants.GenesisBlockNum - 1
  161. nextForger := NextForger{
  162. Period: Period{
  163. SlotNum: i,
  164. FromBlock: fromBlock,
  165. ToBlock: toBlock,
  166. FromTimestamp: lastBlock.Timestamp.Add(time.Second * time.Duration(secondsPerBlock*(fromBlock-lastBlock.Num))),
  167. ToTimestamp: lastBlock.Timestamp.Add(time.Second * time.Duration(secondsPerBlock*(toBlock-lastBlock.Num))),
  168. },
  169. }
  170. foundForger := false
  171. // If there is a bid for a slot, get forger (coordinator)
  172. for j := range bids {
  173. slotNum := bids[j].SlotNum
  174. if slotNum == i {
  175. // There's a bid for the slot
  176. // Check if the bid is greater than the minimum required
  177. for i := 0; i < len(minBidInfo); i++ {
  178. // Find the most recent update
  179. if slotNum >= minBidInfo[i].DefaultSlotSetBidSlotNum {
  180. // Get min bid
  181. minBidSelector := slotNum % int64(len(a.status.Auction.DefaultSlotSetBid))
  182. minBid := minBidInfo[i].DefaultSlotSetBid[minBidSelector]
  183. // Check if the bid has beaten the minimum
  184. bid, ok := new(big.Int).SetString(string(bids[j].BidValue), 10)
  185. if !ok {
  186. return nil, tracerr.New("Wrong bid value, error parsing it as big.Int")
  187. }
  188. if minBid.Cmp(bid) == 1 {
  189. // Min bid is greater than bid, the slot will be forged by boot coordinator
  190. break
  191. }
  192. foundForger = true
  193. break
  194. }
  195. }
  196. if !foundForger { // There is no bid or it's smaller than the minimum
  197. break
  198. }
  199. coordinator, err := a.h.GetCoordinatorAPI(bids[j].Bidder)
  200. if err != nil {
  201. return nil, tracerr.Wrap(err)
  202. }
  203. nextForger.Coordinator = *coordinator
  204. break
  205. }
  206. }
  207. // If there is no bid, the coordinator that will forge is boot coordinator
  208. if !foundForger {
  209. nextForger.Coordinator = bootCoordinator
  210. }
  211. nextForgers = append(nextForgers, nextForger)
  212. }
  213. return nextForgers, nil
  214. }
  215. // Metrics
  216. // UpdateMetrics update Status.Metrics information
  217. func (a *API) UpdateMetrics() error {
  218. a.status.RLock()
  219. if a.status.Network.LastBatch == nil {
  220. a.status.RUnlock()
  221. return nil
  222. }
  223. batchNum := a.status.Network.LastBatch.BatchNum
  224. a.status.RUnlock()
  225. metrics, err := a.h.GetMetrics(batchNum)
  226. if err != nil {
  227. return tracerr.Wrap(err)
  228. }
  229. a.status.Lock()
  230. a.status.Metrics = *metrics
  231. a.status.Unlock()
  232. return nil
  233. }
  234. // Recommended fee
  235. // UpdateRecommendedFee update Status.RecommendedFee information
  236. func (a *API) UpdateRecommendedFee() error {
  237. feeExistingAccount, err := a.h.GetAvgTxFee()
  238. if err != nil {
  239. return tracerr.Wrap(err)
  240. }
  241. a.status.Lock()
  242. a.status.RecommendedFee.ExistingAccount = feeExistingAccount
  243. a.status.RecommendedFee.CreatesAccount = createAccountExtraFeePercentage * feeExistingAccount
  244. a.status.RecommendedFee.CreatesAccountAndRegister = createAccountInternalExtraFeePercentage * feeExistingAccount
  245. a.status.Unlock()
  246. return nil
  247. }