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	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(&currentSlot, &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}