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