arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/api/stateapiupdater/stateapiupdater.go
api/stateapiupdater/stateapiupdater.goRaw
  1/*
  2Package stateapiupdater is responsible for generating and storing the object response of the GET /state endpoint exposed through the api package.
  3This object is extensively defined at the OpenAPI spec located at api/swagger.yml.
  4
  5Deployment considerations: in a setup where multiple processes are used (dedicated api process, separated coord / sync, ...), only one process should care
  6of using this package.
  7*/
  8package stateapiupdater
  9
 10import (
 11	"database/sql"
 12	"fmt"
 13	"sync"
 14
 15	"github.com/hermeznetwork/hermez-node/common"
 16	"github.com/hermeznetwork/hermez-node/db/historydb"
 17	"github.com/hermeznetwork/hermez-node/log"
 18	"github.com/hermeznetwork/tracerr"
 19)
 20
 21// Updater is an utility object to facilitate updating the StateAPI
 22type Updater struct {
 23	hdb    *historydb.HistoryDB
 24	state  historydb.StateAPI
 25	config historydb.NodeConfig
 26	vars   common.SCVariablesPtr
 27	consts historydb.Constants
 28	rw     sync.RWMutex
 29	rfp    *RecommendedFeePolicy
 30}
 31
 32// RecommendedFeePolicy describes how the recommended fee is calculated
 33type RecommendedFeePolicy struct {
 34	PolicyType  RecommendedFeePolicyType `validate:"required"`
 35	StaticValue float64
 36}
 37
 38// RecommendedFeePolicyType describes the different available recommended fee strategies
 39type RecommendedFeePolicyType string
 40
 41const (
 42	// RecommendedFeePolicyTypeStatic always give the same StaticValue as recommended fee
 43	RecommendedFeePolicyTypeStatic RecommendedFeePolicyType = "Static"
 44	// RecommendedFeePolicyTypeAvgLastHour set the recommended fee using the average fee of the last hour
 45	RecommendedFeePolicyTypeAvgLastHour RecommendedFeePolicyType = "AvgLastHour"
 46)
 47
 48func (rfp *RecommendedFeePolicy) valid() bool {
 49	switch rfp.PolicyType {
 50	case RecommendedFeePolicyTypeStatic:
 51		if rfp.StaticValue == 0 {
 52			log.Warn("RcommendedFee is set to 0 USD, and the policy is static")
 53		}
 54		return true
 55	case RecommendedFeePolicyTypeAvgLastHour:
 56		return true
 57	default:
 58		return false
 59	}
 60}
 61
 62// NewUpdater creates a new Updater
 63func NewUpdater(hdb *historydb.HistoryDB, config *historydb.NodeConfig, vars *common.SCVariables,
 64	consts *historydb.Constants, rfp *RecommendedFeePolicy) (*Updater, error) {
 65	if ok := rfp.valid(); !ok {
 66		return nil, tracerr.Wrap(fmt.Errorf("Invalid recommended fee policy: %v", rfp.PolicyType))
 67	}
 68	u := Updater{
 69		hdb:    hdb,
 70		config: *config,
 71		consts: *consts,
 72		state: historydb.StateAPI{
 73			NodePublicInfo: historydb.NodePublicInfo{
 74				ForgeDelay: config.ForgeDelay,
 75			},
 76		},
 77		rfp: rfp,
 78	}
 79	u.SetSCVars(vars.AsPtr())
 80	return &u, nil
 81}
 82
 83// Store the State in the HistoryDB
 84func (u *Updater) Store() error {
 85	u.rw.RLock()
 86	defer u.rw.RUnlock()
 87	return tracerr.Wrap(u.hdb.SetStateInternalAPI(&u.state))
 88}
 89
 90// SetSCVars sets the smart contract vars (ony updates those that are not nil)
 91func (u *Updater) SetSCVars(vars *common.SCVariablesPtr) {
 92	u.rw.Lock()
 93	defer u.rw.Unlock()
 94	if vars.Rollup != nil {
 95		u.vars.Rollup = vars.Rollup
 96		rollupVars := historydb.NewRollupVariablesAPI(u.vars.Rollup)
 97		u.state.Rollup = *rollupVars
 98	}
 99	if vars.Auction != nil {
100		u.vars.Auction = vars.Auction
101		auctionVars := historydb.NewAuctionVariablesAPI(u.vars.Auction)
102		u.state.Auction = *auctionVars
103	}
104	if vars.WDelayer != nil {
105		u.vars.WDelayer = vars.WDelayer
106		u.state.WithdrawalDelayer = *u.vars.WDelayer
107	}
108}
109
110// UpdateRecommendedFee update Status.RecommendedFee information
111func (u *Updater) UpdateRecommendedFee() error {
112	switch u.rfp.PolicyType {
113	case RecommendedFeePolicyTypeStatic:
114		u.rw.Lock()
115		u.state.RecommendedFee = common.RecommendedFee{
116			ExistingAccount:        u.rfp.StaticValue,
117			CreatesAccount:         u.rfp.StaticValue,
118			CreatesAccountInternal: u.rfp.StaticValue,
119		}
120		u.rw.Unlock()
121	case RecommendedFeePolicyTypeAvgLastHour:
122		recommendedFee, err := u.hdb.GetRecommendedFee(u.config.MinFeeUSD, u.config.MaxFeeUSD)
123		if err != nil {
124			return tracerr.Wrap(err)
125		}
126		u.rw.Lock()
127		u.state.RecommendedFee = *recommendedFee
128		u.rw.Unlock()
129	default:
130		return tracerr.New("Invalid recommende fee policy")
131	}
132
133	return nil
134}
135
136// UpdateMetrics update Status.Metrics information
137func (u *Updater) UpdateMetrics() error {
138	u.rw.RLock()
139	lastBatch := u.state.Network.LastBatch
140	u.rw.RUnlock()
141	if lastBatch == nil {
142		return nil
143	}
144	lastBatchNum := lastBatch.BatchNum
145	metrics, poolLoad, err := u.hdb.GetMetricsInternalAPI(lastBatchNum)
146	if err != nil {
147		return tracerr.Wrap(err)
148	}
149	u.rw.Lock()
150	u.state.Metrics = *metrics
151	u.state.NodePublicInfo.PoolLoad = poolLoad
152	u.rw.Unlock()
153	return nil
154}
155
156// UpdateNetworkInfoBlock update Status.Network block related information
157func (u *Updater) UpdateNetworkInfoBlock(lastEthBlock, lastSyncBlock common.Block) {
158	u.rw.Lock()
159	u.state.Network.LastSyncBlock = lastSyncBlock.Num
160	u.state.Network.LastEthBlock = lastEthBlock.Num
161	u.rw.Unlock()
162}
163
164// UpdateNetworkInfo update Status.Network information
165func (u *Updater) UpdateNetworkInfo(
166	lastEthBlock, lastSyncBlock common.Block,
167	lastBatchNum common.BatchNum, currentSlot int64,
168) error {
169	// Get last batch in API format
170	lastBatch, err := u.hdb.GetBatchInternalAPI(lastBatchNum)
171	if tracerr.Unwrap(err) == sql.ErrNoRows {
172		lastBatch = nil
173	} else if err != nil {
174		return tracerr.Wrap(err)
175	}
176	u.rw.RLock()
177	auctionVars := u.vars.Auction
178	u.rw.RUnlock()
179	// Get next forgers
180	lastClosedSlot := currentSlot + int64(auctionVars.ClosedAuctionSlots)
181	nextForgers, err := u.hdb.GetNextForgersInternalAPI(auctionVars, &u.consts.Auction,
182		lastSyncBlock, currentSlot, lastClosedSlot)
183	if tracerr.Unwrap(err) == sql.ErrNoRows {
184		nextForgers = nil
185	} else if err != nil {
186		return tracerr.Wrap(err)
187	}
188
189	bucketUpdates, err := u.hdb.GetBucketUpdatesInternalAPI()
190	if err == sql.ErrNoRows {
191		bucketUpdates = nil
192	} else if err != nil {
193		return tracerr.Wrap(err)
194	}
195
196	u.rw.Lock()
197	// Update NodeInfo struct
198	for i, bucketParams := range u.state.Rollup.Buckets {
199		for _, bucketUpdate := range bucketUpdates {
200			if bucketUpdate.NumBucket == i {
201				bucketParams.Withdrawals = bucketUpdate.Withdrawals
202				u.state.Rollup.Buckets[i] = bucketParams
203				break
204			}
205		}
206	}
207	// Update pending L1s
208	pendingL1s, err := u.hdb.GetUnforgedL1UserTxsCount()
209	if err != nil {
210		return tracerr.Wrap(err)
211	}
212	u.state.Network.LastSyncBlock = lastSyncBlock.Num
213	u.state.Network.LastEthBlock = lastEthBlock.Num
214	u.state.Network.LastBatch = lastBatch
215	u.state.Network.CurrentSlot = currentSlot
216	u.state.Network.NextForgers = nextForgers
217	u.state.Network.PendingL1Txs = pendingL1s
218	u.rw.Unlock()
219	return nil
220}