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}