From 88202c656f73b921744d5064d5aeff888c7e4b61 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sat, 27 Jan 2018 12:29:52 +0100 Subject: [PATCH 1/5] 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() From 373f600c7b94cd515d7af8691986f192211a6be1 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sat, 27 Jan 2018 12:30:28 +0100 Subject: [PATCH 2/5] core, downloader, handler, sync: make use of mutex-free stats --- common/chainstats/chainstats.go | 4 ++++ core/blockchain.go | 18 ++++++++++++++++++ eth/downloader/downloader.go | 28 ++++++++++++++++++---------- eth/handler.go | 8 ++++---- eth/sync.go | 10 +++++----- 5 files changed, 49 insertions(+), 19 deletions(-) diff --git a/common/chainstats/chainstats.go b/common/chainstats/chainstats.go index 35397eff66..7df0a3f884 100644 --- a/common/chainstats/chainstats.go +++ b/common/chainstats/chainstats.go @@ -47,6 +47,10 @@ func (stats *Chainstats) SetNumber(number *big.Int) { func (stats *Chainstats) GetFastNumber() uint64 { return stats.currentFastBlockNumber.Load().(*big.Int).Uint64() } +func (stats *Chainstats) GetNumbers() (uint64, uint64) { + return stats.currentBlockNumber.Load().(*big.Int).Uint64(), + stats.currentFastBlockNumber.Load().(*big.Int).Uint64() +} func (stats *Chainstats) SetFastNumber(number *big.Int) { stats.currentFastBlockNumber.Store(number) } diff --git a/core/blockchain.go b/core/blockchain.go index 9adecef7a9..c7ce127368 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -714,6 +714,24 @@ func (bc *BlockChain) procFutureBlocks() { } } +// Stats returns the chainstats which can be queried non-blocking for info about difficulty and numbers +// These are provided on a best-effort, and it's theoretically possible that two consecutive calls to +// number and difficulty return number for X and difficulty for Y, if the stats is updated between the calls +func (bc *BlockChain) Stats() *chainstats.Chainstats { + return bc.chainStats +} +func (bc *BlockChain) CurrentNumber() uint64 { + return bc.chainStats.GetNumber() +} + +func (bc *BlockChain) CurrentFastNumber() uint64 { + return bc.chainStats.GetFastNumber() +} + +func (bc *BlockChain) CurrentTD() *big.Int { + return bc.chainStats.GetTotalDifficulty() +} + // WriteStatus status of write type WriteStatus byte diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 7ede530a94..32cbca6051 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -193,6 +193,15 @@ type BlockChain interface { // InsertReceiptChain inserts a batch of receipts into the local chain. InsertReceiptChain(types.Blocks, []types.Receipts) (int, error) + + // CurrentNumber retrieves number of the current head block + CurrentNumber() uint64 + + // CurrentNumber retrieves number of the current head fast block + CurrentFastNumber() uint64 + + // CurrentTD retrives the total difficulty of the current head block + CurrentTD() *big.Int } // New creates a new downloader to fetch hashes and blocks from remote peers. @@ -583,9 +592,9 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err floor, ceil := int64(-1), d.lightchain.CurrentHeader().Number.Uint64() if d.mode == FullSync { - ceil = d.blockchain.CurrentBlock().NumberU64() + ceil = d.blockchain.CurrentNumber() } else if d.mode == FastSync { - ceil = d.blockchain.CurrentFastBlock().NumberU64() + ceil = d.blockchain.CurrentFastNumber() } if ceil >= MaxForkAncestry { floor = int64(ceil - MaxForkAncestry) @@ -1156,16 +1165,16 @@ func (d *Downloader) processHeaders(origin uint64, pivot uint64, td *big.Int) er for i, header := range rollback { hashes[i] = header.Hash() } - lastHeader, lastFastBlock, lastBlock := d.lightchain.CurrentHeader().Number, common.Big0, common.Big0 + lastHeader, lastFastBlock, lastBlock := d.lightchain.CurrentHeader().Number, uint64(0), uint64(0) if d.mode != LightSync { - lastFastBlock = d.blockchain.CurrentFastBlock().Number() - lastBlock = d.blockchain.CurrentBlock().Number() + lastFastBlock = d.blockchain.CurrentFastNumber() + lastBlock = d.blockchain.CurrentNumber() } d.lightchain.Rollback(hashes) - curFastBlock, curBlock := common.Big0, common.Big0 + curFastBlock, curBlock := uint64(0), uint64(0) if d.mode != LightSync { - curFastBlock = d.blockchain.CurrentFastBlock().Number() - curBlock = d.blockchain.CurrentBlock().Number() + curFastBlock = d.blockchain.CurrentFastNumber() + curBlock = d.blockchain.CurrentNumber() } log.Warn("Rolled back headers", "count", len(hashes), "header", fmt.Sprintf("%d->%d", lastHeader, d.lightchain.CurrentHeader().Number), @@ -1205,8 +1214,7 @@ func (d *Downloader) processHeaders(origin uint64, pivot uint64, td *big.Int) er // L: Request new headers up from 11 (R's TD was higher, it must have something) // R: Nothing to give if d.mode != LightSync { - head := d.blockchain.CurrentBlock() - if !gotHeaders && td.Cmp(d.blockchain.GetTd(head.Hash(), head.NumberU64())) > 0 { + if !gotHeaders && td.Cmp(d.blockchain.CurrentTD()) > 0 { return errStallingPeer } } diff --git a/eth/handler.go b/eth/handler.go index c2426544f6..71a0ee36ee 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -113,7 +113,7 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne quitSync: make(chan struct{}), } // Figure out whether to allow fast sync or not - if mode == downloader.FastSync && blockchain.CurrentBlock().NumberU64() > 0 { + if mode == downloader.FastSync && blockchain.Stats().GetNumber() > 0 { log.Warn("Blockchain not empty, fast sync disabled") mode = downloader.FullSync } @@ -165,7 +165,7 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne return engine.VerifyHeader(blockchain, header, true) } heighter := func() uint64 { - return blockchain.CurrentBlock().NumberU64() + return blockchain.Stats().GetNumber() } inserter := func(blocks types.Blocks) (int, error) { // If fast sync is running, deny importing weird blocks @@ -647,8 +647,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { // Schedule a sync if above ours. Note, this will not fire a sync for a gap of // a singe block (as the true TD is below the propagated block), however this // scenario should easily be covered by the fetcher. - currentBlock := pm.blockchain.CurrentBlock() - if trueTD.Cmp(pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64())) > 0 { + currentTd := pm.blockchain.Stats().GetTotalDifficulty() + if trueTD.Cmp(currentTd) > 0 { go pm.synchronise(p) } } diff --git a/eth/sync.go b/eth/sync.go index 2da1464bc5..f20fbe55c4 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -167,8 +167,8 @@ func (pm *ProtocolManager) synchronise(peer *peer) { return } // Make sure the peer's TD is higher than our own - currentBlock := pm.blockchain.CurrentBlock() - td := pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64()) + currentNumber, currentFastNumber := pm.blockchain.Stats().GetNumbers() + td := pm.blockchain.Stats().GetTotalDifficulty() pHead, pTd := peer.Head() if pTd.Cmp(td) <= 0 { @@ -179,7 +179,7 @@ func (pm *ProtocolManager) synchronise(peer *peer) { if atomic.LoadUint32(&pm.fastSync) == 1 { // Fast sync was explicitly requested, and explicitly granted mode = downloader.FastSync - } else if currentBlock.NumberU64() == 0 && pm.blockchain.CurrentFastBlock().NumberU64() > 0 { + } else if currentNumber == 0 && currentFastNumber > 0 { // The database seems empty as the current block is the genesis. Yet the fast // block is ahead, so fast sync was enabled for this node at a certain point. // The only scenario where this can happen is if the user manually (or via a @@ -197,13 +197,13 @@ func (pm *ProtocolManager) synchronise(peer *peer) { atomic.StoreUint32(&pm.fastSync, 0) } atomic.StoreUint32(&pm.acceptTxs, 1) // Mark initial sync done - if head := pm.blockchain.CurrentBlock(); head.NumberU64() > 0 { + if pm.blockchain.Stats().GetNumber() > 0 { // We've completed a sync cycle, notify all peers of new state. This path is // essential in star-topology networks where a gateway node needs to notify // all its out-of-date peers of the availability of a new block. This failure // scenario will most often crop up in private and hackathon networks with // degenerate connectivity, but it should be healthy for the mainnet too to // more reliably update peers or the local TD state. - go pm.BroadcastBlock(head, false) + go pm.BroadcastBlock(pm.blockchain.CurrentBlock(), false) } } From 5e6dc9fc06e8902906985243c1f9f6960584aae8 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sat, 27 Jan 2018 15:45:41 +0100 Subject: [PATCH 3/5] core, chainstats: remove unnecessary code, add docs --- common/chainstats/chainstats.go | 29 +++++++++++++++++++++++------ core/blockchain.go | 6 ------ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/common/chainstats/chainstats.go b/common/chainstats/chainstats.go index 7df0a3f884..e0aba99711 100644 --- a/common/chainstats/chainstats.go +++ b/common/chainstats/chainstats.go @@ -19,47 +19,64 @@ package chainstats import ( - "github.com/ethereum/go-ethereum/core/types" "math/big" "sync/atomic" + + "github.com/ethereum/go-ethereum/core/types" ) type Chainstats struct { currentBlockNumber atomic.Value currentFastBlockNumber atomic.Value currentTd atomic.Value - currentFastTd atomic.Value } func NewChainstats() *Chainstats { - return &Chainstats{} + stats := &Chainstats{} + stats.currentBlockNumber.Store(big.NewInt(0)) + stats.currentFastBlockNumber.Store(big.NewInt(0)) + stats.currentTd.Store(big.NewInt(0)) + return stats } + +// GetNumber returns the latest block number func (stats *Chainstats) GetNumber() uint64 { return stats.currentBlockNumber.Load().(*big.Int).Uint64() } + +// UpdateNumbers is a convenience method to set both latest number and fast number func (stats *Chainstats) UpdateNumbers(currentBlock, currentFastBlock *types.Block) { stats.currentBlockNumber.Store(currentBlock.Number()) stats.currentFastBlockNumber.Store(currentFastBlock.Number()) } + +// SetNumber stores latest block number func (stats *Chainstats) SetNumber(number *big.Int) { stats.currentBlockNumber.Store(number) } + +// GetFastNumber return latest fast block number func (stats *Chainstats) GetFastNumber() uint64 { return stats.currentFastBlockNumber.Load().(*big.Int).Uint64() } + +// GetNumbers convenience-method to get both last number and last fast number func (stats *Chainstats) GetNumbers() (uint64, uint64) { return stats.currentBlockNumber.Load().(*big.Int).Uint64(), stats.currentFastBlockNumber.Load().(*big.Int).Uint64() } + +// SetFastNumber stores latest fast block number func (stats *Chainstats) SetFastNumber(number *big.Int) { stats.currentFastBlockNumber.Store(number) } + +// GetTotalDifficulty return latest total difficulty func (stats *Chainstats) GetTotalDifficulty() *big.Int { return new(big.Int).Set(stats.currentTd.Load().(*big.Int)) } + +// SetTotalDifficulty sets latest total difficulty 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 c7ce127368..1fbba38ae0 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -252,7 +252,6 @@ func (bc *BlockChain) loadLastState() error { 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) @@ -315,7 +314,6 @@ func (bc *BlockChain) SetHead(head uint64) error { 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() } @@ -437,7 +435,6 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error { bc.chainStats.UpdateNumbers(bc.currentBlock, bc.currentFastBlock) bc.chainStats.SetTotalDifficulty(bc.genesisBlock.Difficulty()) - bc.chainStats.SetTotalFastDifficulty(bc.genesisBlock.Difficulty()) return nil } @@ -519,7 +516,6 @@ func (bc *BlockChain) insert(block *types.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. @@ -765,7 +761,6 @@ func (bc *BlockChain) Rollback(chain []common.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 @@ -878,7 +873,6 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ } bc.currentFastBlock = head bc.chainStats.SetFastNumber(bc.currentFastBlock.Number()) - bc.chainStats.SetTotalFastDifficulty(td) } } bc.mu.Unlock() From d90c7c137809dfe03cc71d51892facba4ba4caae Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 2 Feb 2018 13:08:58 +0100 Subject: [PATCH 4/5] chainstats, core: modify chainstats to use uint64, merge setters --- common/chainstats/chainstats.go | 41 +++++++++++++++++---------------- core/blockchain.go | 19 ++++++--------- eth/sync.go | 3 +-- 3 files changed, 29 insertions(+), 34 deletions(-) diff --git a/common/chainstats/chainstats.go b/common/chainstats/chainstats.go index e0aba99711..c562879af5 100644 --- a/common/chainstats/chainstats.go +++ b/common/chainstats/chainstats.go @@ -26,49 +26,50 @@ import ( ) type Chainstats struct { - currentBlockNumber atomic.Value - currentFastBlockNumber atomic.Value + currentBlockNumber uint64 + currentFastBlockNumber uint64 currentTd atomic.Value } func NewChainstats() *Chainstats { stats := &Chainstats{} - stats.currentBlockNumber.Store(big.NewInt(0)) - stats.currentFastBlockNumber.Store(big.NewInt(0)) stats.currentTd.Store(big.NewInt(0)) return stats } // GetNumber returns the latest block number func (stats *Chainstats) GetNumber() uint64 { - return stats.currentBlockNumber.Load().(*big.Int).Uint64() + return stats.currentBlockNumber } -// UpdateNumbers is a convenience method to set both latest number and fast number -func (stats *Chainstats) UpdateNumbers(currentBlock, currentFastBlock *types.Block) { - stats.currentBlockNumber.Store(currentBlock.Number()) - stats.currentFastBlockNumber.Store(currentFastBlock.Number()) +// Update is a convenience method to set all values +func (stats *Chainstats) Update(currentBlock, currentFastBlock *types.Block, totalDifficulty *big.Int) { + stats.SetNumber(currentBlock.NumberU64()) + stats.SetFastNumber(currentFastBlock.NumberU64()) + stats.SetTotalDifficulty(totalDifficulty) + +} + +// GetNumbers convenience-method to get all values +func (stats *Chainstats) Get() (uint64, uint64, *big.Int) { + return stats.currentBlockNumber, + stats.currentFastBlockNumber, + new(big.Int).Set(stats.currentTd.Load().(*big.Int)) } // SetNumber stores latest block number -func (stats *Chainstats) SetNumber(number *big.Int) { - stats.currentBlockNumber.Store(number) +func (stats *Chainstats) SetNumber(number uint64) { + atomic.StoreUint64(&stats.currentBlockNumber, number) } // GetFastNumber return latest fast block number func (stats *Chainstats) GetFastNumber() uint64 { - return stats.currentFastBlockNumber.Load().(*big.Int).Uint64() -} - -// GetNumbers convenience-method to get both last number and last fast number -func (stats *Chainstats) GetNumbers() (uint64, uint64) { - return stats.currentBlockNumber.Load().(*big.Int).Uint64(), - stats.currentFastBlockNumber.Load().(*big.Int).Uint64() + return stats.currentFastBlockNumber } // SetFastNumber stores latest fast block number -func (stats *Chainstats) SetFastNumber(number *big.Int) { - stats.currentFastBlockNumber.Store(number) +func (stats *Chainstats) SetFastNumber(number uint64) { + atomic.StoreUint64(&stats.currentFastBlockNumber, number) } // GetTotalDifficulty return latest total difficulty diff --git a/core/blockchain.go b/core/blockchain.go index 1fbba38ae0..6ec68c8315 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -251,8 +251,7 @@ 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.UpdateNumbers(bc.currentBlock, bc.currentFastBlock) + bc.chainStats.Update(bc.currentBlock, bc.currentFastBlock, blockTd) 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) @@ -312,8 +311,7 @@ func (bc *BlockChain) SetHead(head uint64) error { 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.Update(bc.currentBlock, bc.currentFastBlock, bc.GetTd(bc.currentBlock.Hash(), bc.currentBlock.NumberU64())) return bc.loadLastState() } @@ -332,7 +330,7 @@ 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.SetNumber(block.Number().Uint64()) bc.chainStats.SetTotalDifficulty(bc.GetTd(block.Hash(), block.NumberU64())) bc.mu.Unlock() @@ -433,8 +431,7 @@ 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.Update(bc.currentBlock, bc.currentFastBlock, bc.genesisBlock.Difficulty()) return nil } @@ -514,8 +511,7 @@ 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.Update(bc.currentBlock, bc.currentFastBlock, bc.GetTd(block.Hash(), block.NumberU64())) } // Genesis retrieves the chain's genesis block. @@ -759,8 +755,7 @@ 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.Update(bc.currentBlock, bc.currentFastBlock, bc.GetTd(bc.currentBlock.Hash(), bc.currentBlock.NumberU64())) } // SetReceiptsData computes all the non-consensus fields of the receipts @@ -872,7 +867,7 @@ 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.SetFastNumber(bc.currentFastBlock.NumberU64()) } } bc.mu.Unlock() diff --git a/eth/sync.go b/eth/sync.go index f20fbe55c4..0ca57943b0 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -167,8 +167,7 @@ func (pm *ProtocolManager) synchronise(peer *peer) { return } // Make sure the peer's TD is higher than our own - currentNumber, currentFastNumber := pm.blockchain.Stats().GetNumbers() - td := pm.blockchain.Stats().GetTotalDifficulty() + currentNumber, currentFastNumber, td := pm.blockchain.Stats().Get() pHead, pTd := peer.Head() if pTd.Cmp(td) <= 0 { From f10832685c78024ebf56e5427a64ec7a1088af3a Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 2 Feb 2018 22:27:20 +0100 Subject: [PATCH 5/5] downloader: add missing inteface methods in downloader tests --- eth/downloader/downloader_test.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index cb671a7df4..066d8f8094 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -282,6 +282,18 @@ func (dl *downloadTester) CurrentFastBlock() *types.Block { } return dl.genesis } +func (dl *downloadTester) CurrentNumber() uint64 { + return dl.CurrentBlock().NumberU64() +} + +func (dl *downloadTester) CurrentFastNumber() uint64 { + return dl.CurrentFastBlock().NumberU64() +} + +func (dl *downloadTester) CurrentTD() *big.Int { + cur := dl.CurrentBlock() + return dl.GetTd(cur.Hash(), cur.NumberU64()) +} // FastSyncCommitHead manually sets the head block to a given hash. func (dl *downloadTester) FastSyncCommitHead(hash common.Hash) error {