From 88202c656f73b921744d5064d5aeff888c7e4b61 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sat, 27 Jan 2018 12:29:52 +0100 Subject: [PATCH] core,chainstats: implement setting chainstats --- common/chainstats/chainstats.go | 61 +++++++++++++++++++++++++++++++++ core/blockchain.go | 28 ++++++++++++++- 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 common/chainstats/chainstats.go diff --git a/common/chainstats/chainstats.go b/common/chainstats/chainstats.go new file mode 100644 index 0000000000..35397eff66 --- /dev/null +++ b/common/chainstats/chainstats.go @@ -0,0 +1,61 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// Package chainstats implements some chain utilities for sync-free blockchain info lookup + +package chainstats + +import ( + "github.com/ethereum/go-ethereum/core/types" + "math/big" + "sync/atomic" +) + +type Chainstats struct { + currentBlockNumber atomic.Value + currentFastBlockNumber atomic.Value + currentTd atomic.Value + currentFastTd atomic.Value +} + +func NewChainstats() *Chainstats { + return &Chainstats{} +} +func (stats *Chainstats) GetNumber() uint64 { + return stats.currentBlockNumber.Load().(*big.Int).Uint64() +} +func (stats *Chainstats) UpdateNumbers(currentBlock, currentFastBlock *types.Block) { + stats.currentBlockNumber.Store(currentBlock.Number()) + stats.currentFastBlockNumber.Store(currentFastBlock.Number()) +} +func (stats *Chainstats) SetNumber(number *big.Int) { + stats.currentBlockNumber.Store(number) +} +func (stats *Chainstats) GetFastNumber() uint64 { + return stats.currentFastBlockNumber.Load().(*big.Int).Uint64() +} +func (stats *Chainstats) SetFastNumber(number *big.Int) { + stats.currentFastBlockNumber.Store(number) +} +func (stats *Chainstats) GetTotalDifficulty() *big.Int { + return new(big.Int).Set(stats.currentTd.Load().(*big.Int)) +} +func (stats *Chainstats) SetTotalDifficulty(newTd *big.Int) { + stats.currentTd.Store(newTd) +} +func (stats *Chainstats) SetTotalFastDifficulty(newTd *big.Int) { + stats.currentFastTd.Store(newTd) +} diff --git a/core/blockchain.go b/core/blockchain.go index e498dedefc..9adecef7a9 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -28,6 +28,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/chainstats" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/state" @@ -127,7 +128,8 @@ type BlockChain struct { validator Validator // block and state validator interface vmConfig vm.Config - badBlocks *lru.Cache // Bad block cache + badBlocks *lru.Cache // Bad block cache + chainStats *chainstats.Chainstats // Mutex-free lookups of chain stats } // NewBlockChain returns a fully initialised block chain using information @@ -160,6 +162,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par engine: engine, vmConfig: vmConfig, badBlocks: badBlocks, + chainStats: chainstats.NewChainstats(), } bc.SetValidator(NewBlockValidator(chainConfig, bc, engine)) bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine)) @@ -248,6 +251,10 @@ func (bc *BlockChain) loadLastState() error { blockTd := bc.GetTd(bc.currentBlock.Hash(), bc.currentBlock.NumberU64()) fastTd := bc.GetTd(bc.currentFastBlock.Hash(), bc.currentFastBlock.NumberU64()) + bc.chainStats.SetTotalDifficulty(blockTd) + bc.chainStats.SetTotalFastDifficulty(fastTd) + bc.chainStats.UpdateNumbers(bc.currentBlock, bc.currentFastBlock) + log.Info("Loaded most recent local header", "number", currentHeader.Number, "hash", currentHeader.Hash(), "td", headerTd) log.Info("Loaded most recent local full block", "number", bc.currentBlock.Number(), "hash", bc.currentBlock.Hash(), "td", blockTd) log.Info("Loaded most recent local fast block", "number", bc.currentFastBlock.Number(), "hash", bc.currentFastBlock.Hash(), "td", fastTd) @@ -305,6 +312,11 @@ func (bc *BlockChain) SetHead(head uint64) error { if err := WriteHeadFastBlockHash(bc.db, bc.currentFastBlock.Hash()); err != nil { log.Crit("Failed to reset head fast block", "err", err) } + + bc.chainStats.UpdateNumbers(bc.currentBlock, bc.currentFastBlock) + bc.chainStats.SetTotalDifficulty(bc.GetTd(bc.currentBlock.Hash(), bc.currentBlock.NumberU64())) + bc.chainStats.SetTotalFastDifficulty(bc.GetTd(bc.currentFastBlock.Hash(), bc.currentFastBlock.NumberU64())) + return bc.loadLastState() } @@ -322,6 +334,8 @@ func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error { // If all checks out, manually set the head block bc.mu.Lock() bc.currentBlock = block + bc.chainStats.SetNumber(block.Number()) + bc.chainStats.SetTotalDifficulty(bc.GetTd(block.Hash(), block.NumberU64())) bc.mu.Unlock() log.Info("Committed new head block", "number", block.Number(), "hash", hash) @@ -421,6 +435,10 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error { bc.hc.SetCurrentHeader(bc.genesisBlock.Header()) bc.currentFastBlock = bc.genesisBlock + bc.chainStats.UpdateNumbers(bc.currentBlock, bc.currentFastBlock) + bc.chainStats.SetTotalDifficulty(bc.genesisBlock.Difficulty()) + bc.chainStats.SetTotalFastDifficulty(bc.genesisBlock.Difficulty()) + return nil } @@ -499,6 +517,9 @@ func (bc *BlockChain) insert(block *types.Block) { } bc.currentFastBlock = block } + bc.chainStats.UpdateNumbers(bc.currentBlock, bc.currentFastBlock) + bc.chainStats.SetTotalDifficulty(bc.GetTd(block.Hash(), block.NumberU64())) + bc.chainStats.SetTotalFastDifficulty(bc.GetTd(bc.currentFastBlock.Hash(), bc.currentFastBlock.NumberU64())) } // Genesis retrieves the chain's genesis block. @@ -724,6 +745,9 @@ func (bc *BlockChain) Rollback(chain []common.Hash) { WriteHeadBlockHash(bc.db, bc.currentBlock.Hash()) } } + bc.chainStats.UpdateNumbers(bc.currentBlock, bc.currentFastBlock) + bc.chainStats.SetTotalDifficulty(bc.GetTd(bc.currentBlock.Hash(), bc.currentBlock.NumberU64())) + bc.chainStats.SetTotalFastDifficulty(bc.GetTd(bc.currentFastBlock.Hash(), bc.currentFastBlock.NumberU64())) } // SetReceiptsData computes all the non-consensus fields of the receipts @@ -835,6 +859,8 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ log.Crit("Failed to update head fast block hash", "err", err) } bc.currentFastBlock = head + bc.chainStats.SetFastNumber(bc.currentFastBlock.Number()) + bc.chainStats.SetTotalFastDifficulty(td) } } bc.mu.Unlock()