arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
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
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
121	for i, bucketParams := range a.status.Rollup.Buckets {
122		for _, bucketUpdate := range bucketsUpdate {
123			if bucketUpdate.NumBucket == i {
124				bucketParams.Withdrawals = bucketUpdate.Withdrawals
125				a.status.Rollup.Buckets[i] = bucketParams
126				break
127			}
128		}
129	}
130	a.status.Unlock()
131	return nil
132}
133
134// getNextForgers returns next forgers
135func (a *API) getNextForgers(lastBlock common.Block, currentSlot, lastClosedSlot int64) ([]NextForger, error) {
136	secondsPerBlock := int64(15) //nolint:gomnd
137	// currentSlot and lastClosedSlot included
138	limit := uint(lastClosedSlot - currentSlot + 1)
139	bids, _, err := a.h.GetBestBidsAPI(&currentSlot, &lastClosedSlot, nil, &limit, "ASC")
140	if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
141		return nil, tracerr.Wrap(err)
142	}
143	nextForgers := []NextForger{}
144	// Get min bid info
145	var minBidInfo []historydb.MinBidInfo
146	if currentSlot >= a.status.Auction.DefaultSlotSetBidSlotNum {
147		// All min bids can be calculated with the last update of AuctionVariables
148		minBidInfo = []historydb.MinBidInfo{{
149			DefaultSlotSetBid:        a.status.Auction.DefaultSlotSetBid,
150			DefaultSlotSetBidSlotNum: a.status.Auction.DefaultSlotSetBidSlotNum,
151		}}
152	} else {
153		// Get all the relevant updates from the DB
154		minBidInfo, err = a.h.GetAuctionVarsUntilSetSlotNum(lastClosedSlot, int(lastClosedSlot-currentSlot)+1)
155		if err != nil {
156			return nil, tracerr.Wrap(err)
157		}
158	}
159	// Create nextForger for each slot
160	for i := currentSlot; i <= lastClosedSlot; i++ {
161		fromBlock := i*int64(a.cg.AuctionConstants.BlocksPerSlot) + a.cg.AuctionConstants.GenesisBlockNum
162		toBlock := (i+1)*int64(a.cg.AuctionConstants.BlocksPerSlot) + a.cg.AuctionConstants.GenesisBlockNum - 1
163		nextForger := NextForger{
164			Period: Period{
165				SlotNum:       i,
166				FromBlock:     fromBlock,
167				ToBlock:       toBlock,
168				FromTimestamp: lastBlock.Timestamp.Add(time.Second * time.Duration(secondsPerBlock*(fromBlock-lastBlock.Num))),
169				ToTimestamp:   lastBlock.Timestamp.Add(time.Second * time.Duration(secondsPerBlock*(toBlock-lastBlock.Num))),
170			},
171		}
172		foundForger := false
173		// If there is a bid for a slot, get forger (coordinator)
174		for j := range bids {
175			slotNum := bids[j].SlotNum
176			if slotNum == i {
177				// There's a bid for the slot
178				// Check if the bid is greater than the minimum required
179				for i := 0; i < len(minBidInfo); i++ {
180					// Find the most recent update
181					if slotNum >= minBidInfo[i].DefaultSlotSetBidSlotNum {
182						// Get min bid
183						minBidSelector := slotNum % int64(len(a.status.Auction.DefaultSlotSetBid))
184						minBid := minBidInfo[i].DefaultSlotSetBid[minBidSelector]
185						// Check if the bid has beaten the minimum
186						bid, ok := new(big.Int).SetString(string(bids[j].BidValue), 10)
187						if !ok {
188							return nil, tracerr.New("Wrong bid value, error parsing it as big.Int")
189						}
190						if minBid.Cmp(bid) == 1 {
191							// Min bid is greater than bid, the slot will be forged by boot coordinator
192							break
193						}
194						foundForger = true
195						break
196					}
197				}
198				if !foundForger { // There is no bid or it's smaller than the minimum
199					break
200				}
201				coordinator, err := a.h.GetCoordinatorAPI(bids[j].Bidder)
202				if err != nil {
203					return nil, tracerr.Wrap(err)
204				}
205				nextForger.Coordinator = *coordinator
206				break
207			}
208		}
209		// If there is no bid, the coordinator that will forge is boot coordinator
210		if !foundForger {
211			nextForger.Coordinator = bootCoordinator
212		}
213		nextForgers = append(nextForgers, nextForger)
214	}
215	return nextForgers, nil
216}
217
218// Metrics
219
220// UpdateMetrics update Status.Metrics information
221func (a *API) UpdateMetrics() error {
222	a.status.RLock()
223	if a.status.Network.LastBatch == nil {
224		a.status.RUnlock()
225		return nil
226	}
227	batchNum := a.status.Network.LastBatch.BatchNum
228	a.status.RUnlock()
229	metrics, err := a.h.GetMetrics(batchNum)
230	if err != nil {
231		return tracerr.Wrap(err)
232	}
233	a.status.Lock()
234	a.status.Metrics = *metrics
235	a.status.Unlock()
236	return nil
237}
238
239// Recommended fee
240
241// UpdateRecommendedFee update Status.RecommendedFee information
242func (a *API) UpdateRecommendedFee() error {
243	feeExistingAccount, err := a.h.GetAvgTxFee()
244	if err != nil {
245		return tracerr.Wrap(err)
246	}
247	a.status.Lock()
248	a.status.RecommendedFee.ExistingAccount = feeExistingAccount
249	a.status.RecommendedFee.CreatesAccount = createAccountExtraFeePercentage * feeExistingAccount
250	a.status.RecommendedFee.CreatesAccountAndRegister = createAccountInternalExtraFeePercentage * feeExistingAccount
251	a.status.Unlock()
252	return nil
253}