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