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