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