mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 03:16:45 +01:00
Add Sync stats, and report them in DebugAPI
This commit is contained in:
@@ -5,6 +5,8 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
@@ -39,6 +41,93 @@ var (
|
||||
// Synchronized bool
|
||||
// }
|
||||
|
||||
// Stats of the syncrhonizer
|
||||
type Stats struct {
|
||||
Eth struct {
|
||||
RefreshPeriod time.Duration
|
||||
Updated time.Time
|
||||
FirstBlock int64
|
||||
LastBlock int64
|
||||
LastBatch int64
|
||||
}
|
||||
Sync struct {
|
||||
Updated time.Time
|
||||
LastBlock int64
|
||||
LastBatch int64
|
||||
}
|
||||
}
|
||||
|
||||
// StatsHolder stores stats and that allows reading and writing them
|
||||
// concurrently
|
||||
type StatsHolder struct {
|
||||
stats Stats
|
||||
rw sync.RWMutex
|
||||
}
|
||||
|
||||
// NewStatsHolder creates a new StatsHolder
|
||||
func NewStatsHolder(firstBlock int64, refreshPeriod time.Duration) *StatsHolder {
|
||||
stats := Stats{}
|
||||
stats.Eth.RefreshPeriod = refreshPeriod
|
||||
stats.Eth.FirstBlock = firstBlock
|
||||
return &StatsHolder{stats: stats}
|
||||
}
|
||||
|
||||
// UpdateSync updates the synchronizer stats
|
||||
func (s *StatsHolder) UpdateSync(lastBlock int64, lastBatch *common.BatchNum) {
|
||||
now := time.Now()
|
||||
s.rw.Lock()
|
||||
s.stats.Sync.LastBlock = lastBlock
|
||||
if lastBatch != nil {
|
||||
s.stats.Sync.LastBatch = int64(*lastBatch)
|
||||
}
|
||||
s.stats.Sync.Updated = now
|
||||
s.rw.Unlock()
|
||||
}
|
||||
|
||||
// UpdateEth updates the ethereum stats, only if the previous stats expired
|
||||
func (s *StatsHolder) UpdateEth(ethClient eth.ClientInterface) error {
|
||||
now := time.Now()
|
||||
s.rw.RLock()
|
||||
elapsed := now.Sub(s.stats.Eth.Updated)
|
||||
s.rw.RUnlock()
|
||||
if elapsed < s.stats.Eth.RefreshPeriod {
|
||||
return nil
|
||||
}
|
||||
|
||||
lastBlock, err := ethClient.EthCurrentBlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lastBatch, err := ethClient.RollupLastForgedBatch()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.rw.Lock()
|
||||
s.stats.Eth.Updated = now
|
||||
s.stats.Eth.LastBlock = lastBlock
|
||||
s.stats.Eth.LastBatch = lastBatch
|
||||
s.rw.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// CopyStats returns a copy of the inner Stats
|
||||
func (s *StatsHolder) CopyStats() *Stats {
|
||||
s.rw.RLock()
|
||||
sCopy := s.stats
|
||||
s.rw.RUnlock()
|
||||
return &sCopy
|
||||
}
|
||||
|
||||
func (s *StatsHolder) blocksPerc() float64 {
|
||||
return float64(s.stats.Sync.LastBlock-s.stats.Eth.FirstBlock) * 100.0 /
|
||||
float64(s.stats.Eth.LastBlock-s.stats.Eth.FirstBlock)
|
||||
}
|
||||
|
||||
func (s *StatsHolder) batchesPerc(batchNum int64) float64 {
|
||||
return float64(batchNum) * 100.0 /
|
||||
float64(s.stats.Eth.LastBatch)
|
||||
}
|
||||
|
||||
// ConfigStartBlockNum sets the first block used to start tracking the smart
|
||||
// contracts
|
||||
type ConfigStartBlockNum struct {
|
||||
@@ -56,8 +145,9 @@ type SCVariables struct {
|
||||
|
||||
// Config is the Synchronizer configuration
|
||||
type Config struct {
|
||||
StartBlockNum ConfigStartBlockNum
|
||||
InitialVariables SCVariables
|
||||
StartBlockNum ConfigStartBlockNum
|
||||
InitialVariables SCVariables
|
||||
StatsRefreshPeriod time.Duration
|
||||
}
|
||||
|
||||
// Synchronizer implements the Synchronizer type
|
||||
@@ -71,6 +161,7 @@ type Synchronizer struct {
|
||||
cfg Config
|
||||
startBlockNum int64
|
||||
vars SCVariables
|
||||
stats *StatsHolder
|
||||
// firstSavedBlock *common.Block
|
||||
// mux sync.Mutex
|
||||
}
|
||||
@@ -103,6 +194,7 @@ func NewSynchronizer(ethClient eth.ClientInterface, historyDB *historydb.History
|
||||
if startBlockNum < cfg.StartBlockNum.WDelayer {
|
||||
startBlockNum = cfg.StartBlockNum.WDelayer
|
||||
}
|
||||
stats := NewStatsHolder(startBlockNum, cfg.StatsRefreshPeriod)
|
||||
s := &Synchronizer{
|
||||
ethClient: ethClient,
|
||||
auctionConstants: *auctionConstants,
|
||||
@@ -112,10 +204,16 @@ func NewSynchronizer(ethClient eth.ClientInterface, historyDB *historydb.History
|
||||
stateDB: stateDB,
|
||||
cfg: cfg,
|
||||
startBlockNum: startBlockNum,
|
||||
stats: stats,
|
||||
}
|
||||
return s, s.init()
|
||||
}
|
||||
|
||||
// Stats returns a copy of the Synchronizer Stats
|
||||
func (s *Synchronizer) Stats() *Stats {
|
||||
return s.stats.CopyStats()
|
||||
}
|
||||
|
||||
// AuctionConstants returns the AuctionConstants read from the smart contract
|
||||
func (s *Synchronizer) AuctionConstants() *common.AuctionConstants {
|
||||
return &s.auctionConstants
|
||||
@@ -133,11 +231,13 @@ func (s *Synchronizer) WDelayerConstants() *common.WDelayerConstants {
|
||||
|
||||
func (s *Synchronizer) init() error {
|
||||
rollup, auction, wDelayer, err := s.historyDB.GetSCVars()
|
||||
// If SCVars are not in the HistoryDB, this is probably the first run
|
||||
// of the Synchronizer: store the initial vars taken from config
|
||||
if err == sql.ErrNoRows {
|
||||
rollup = &s.cfg.InitialVariables.Rollup
|
||||
auction = &s.cfg.InitialVariables.Auction
|
||||
wDelayer = &s.cfg.InitialVariables.WDelayer
|
||||
log.Debug("Setting initial SCVars in HistoryDB")
|
||||
log.Info("Setting initial SCVars in HistoryDB")
|
||||
if err = s.historyDB.SetInitialSCVars(rollup, auction, wDelayer); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -145,6 +245,47 @@ func (s *Synchronizer) init() error {
|
||||
s.vars.Rollup = *rollup
|
||||
s.vars.Auction = *auction
|
||||
s.vars.WDelayer = *wDelayer
|
||||
|
||||
// Update stats parameters so that they have valid values before the
|
||||
// first Sync call
|
||||
if err := s.stats.UpdateEth(s.ethClient); err != nil {
|
||||
return err
|
||||
}
|
||||
var lastBlockNum int64
|
||||
lastSavedBlock, err := s.historyDB.GetLastBlock()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
// If there's no block in the DB (or we only have the default block 0),
|
||||
// make sure that the stateDB is clean
|
||||
if err == sql.ErrNoRows || lastSavedBlock.EthBlockNum == 0 {
|
||||
if err := s.stateDB.Reset(0); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
lastBlockNum = lastSavedBlock.EthBlockNum
|
||||
}
|
||||
lastBatchNum, err := s.historyDB.GetLastBatchNum()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
if err == sql.ErrNoRows {
|
||||
lastBatchNum = 0
|
||||
}
|
||||
|
||||
s.stats.UpdateSync(lastBlockNum, &lastBatchNum)
|
||||
|
||||
log.Infow("Sync init block",
|
||||
"syncLastBlock", s.stats.stats.Sync.LastBlock,
|
||||
"syncBlocksPerc", s.stats.blocksPerc(),
|
||||
"ethFirstBlock", s.stats.stats.Eth.FirstBlock,
|
||||
"ethLastBlock", s.stats.stats.Eth.LastBlock,
|
||||
)
|
||||
log.Infow("Sync init batch",
|
||||
"syncLastBatch", s.stats.stats.Sync.LastBatch,
|
||||
"syncBatchesPerc", s.stats.batchesPerc(s.stats.stats.Sync.LastBatch),
|
||||
"ethLastBatch", s.stats.stats.Eth.LastBatch,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -182,7 +323,14 @@ func (s *Synchronizer) Sync2(ctx context.Context, lastSavedBlock *common.Block)
|
||||
}
|
||||
log.Debugf("ethBlock: num: %v, parent: %v, hash: %v", ethBlock.EthBlockNum, ethBlock.ParentHash.String(), ethBlock.Hash.String())
|
||||
|
||||
log.Debugw("Syncing...", "block", nextBlockNum)
|
||||
if err := s.stats.UpdateEth(s.ethClient); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
log.Debugw("Syncing...",
|
||||
"block", nextBlockNum,
|
||||
"ethLastBlock", s.stats.stats.Eth.LastBlock,
|
||||
)
|
||||
|
||||
// Check that the obtianed ethBlock.ParentHash == prevEthBlock.Hash; if not, reorg!
|
||||
if lastSavedBlock != nil {
|
||||
@@ -249,6 +397,26 @@ func (s *Synchronizer) Sync2(ctx context.Context, lastSavedBlock *common.Block)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
batchesLen := len(rollupData.Batches)
|
||||
if batchesLen == 0 {
|
||||
s.stats.UpdateSync(ethBlock.EthBlockNum, nil)
|
||||
} else {
|
||||
s.stats.UpdateSync(ethBlock.EthBlockNum,
|
||||
&rollupData.Batches[batchesLen-1].Batch.BatchNum)
|
||||
}
|
||||
log.Debugw("Synced block",
|
||||
"syncLastBlock", s.stats.stats.Sync.LastBlock,
|
||||
"syncBlocksPerc", s.stats.blocksPerc(),
|
||||
"ethLastBlock", s.stats.stats.Eth.LastBlock,
|
||||
)
|
||||
for _, batchData := range rollupData.Batches {
|
||||
log.Debugw("Synced batch",
|
||||
"syncLastBatch", batchData.Batch.BatchNum,
|
||||
"syncBatchesPerc", s.stats.batchesPerc(int64(batchData.Batch.BatchNum)),
|
||||
"ethLastBatch", s.stats.stats.Eth.LastBatch,
|
||||
)
|
||||
}
|
||||
|
||||
return &blockData, nil, nil
|
||||
}
|
||||
|
||||
@@ -566,7 +734,7 @@ func (s *Synchronizer) rollupSync(ethBlock *common.Block) (*common.RollupData, e
|
||||
|
||||
if varsUpdate {
|
||||
s.vars.Rollup.EthBlockNum = blockNum
|
||||
rollupData.Vars = &s.vars.Rollup
|
||||
rollupData.Vars = s.vars.Rollup.Copy()
|
||||
}
|
||||
|
||||
return &rollupData, nil
|
||||
@@ -665,7 +833,7 @@ func (s *Synchronizer) auctionSync(ethBlock *common.Block) (*common.AuctionData,
|
||||
|
||||
if varsUpdate {
|
||||
s.vars.Auction.EthBlockNum = blockNum
|
||||
auctionData.Vars = &s.vars.Auction
|
||||
auctionData.Vars = s.vars.Auction.Copy()
|
||||
}
|
||||
|
||||
return &auctionData, nil
|
||||
@@ -734,7 +902,7 @@ func (s *Synchronizer) wdelayerSync(ethBlock *common.Block) (*common.WDelayerDat
|
||||
|
||||
if varsUpdate {
|
||||
s.vars.WDelayer.EthBlockNum = blockNum
|
||||
wDelayerData.Vars = &s.vars.WDelayer
|
||||
wDelayerData.Vars = s.vars.WDelayer.Copy()
|
||||
}
|
||||
|
||||
return &wDelayerData, nil
|
||||
|
||||
Reference in New Issue
Block a user