mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-16 17:03:46 +00:00
core/eth: Add mutex-free lookup of total difficulty
This commit is contained in:
parent
1e67378df8
commit
77c5188219
2 changed files with 43 additions and 15 deletions
|
|
@ -114,7 +114,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
|
||||
currentTd atomic.Value // The total difficulty
|
||||
}
|
||||
|
||||
// NewBlockChain returns a fully initialised block chain using information
|
||||
|
|
@ -140,6 +141,7 @@ func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, engine co
|
|||
vmConfig: vmConfig,
|
||||
badBlocks: badBlocks,
|
||||
}
|
||||
|
||||
bc.SetValidator(NewBlockValidator(config, bc, engine))
|
||||
bc.SetProcessor(NewStateProcessor(config, bc, engine))
|
||||
|
||||
|
|
@ -168,6 +170,13 @@ func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, engine co
|
|||
}
|
||||
}
|
||||
}
|
||||
currentBlock := bc.CurrentBlock()
|
||||
td := big.NewInt(0)
|
||||
if currentBlock != nil {
|
||||
td.Set(bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64()))
|
||||
}
|
||||
bc.currentTd.Store(td)
|
||||
log.Info("Set initial td", "td", td)
|
||||
// Take ownership of this particular state
|
||||
go bc.update()
|
||||
return bc, nil
|
||||
|
|
@ -330,6 +339,13 @@ func (bc *BlockChain) CurrentBlock() *types.Block {
|
|||
return bc.currentBlock
|
||||
}
|
||||
|
||||
// CurrentTD returns ( a copy of) the current difficulty. This method does not
|
||||
// use any locks, and the information may be mildly stale, since a new block
|
||||
// insertion may be in progress
|
||||
func (bc *BlockChain) CurrentTd() *big.Int {
|
||||
return new(big.Int).Set(bc.currentTd.Load().(*big.Int))
|
||||
}
|
||||
|
||||
// CurrentFastBlock retrieves the current fast-sync head block of the canonical
|
||||
// chain. The block is retrieved from the blockchain's internal cache.
|
||||
func (bc *BlockChain) CurrentFastBlock() *types.Block {
|
||||
|
|
@ -864,9 +880,13 @@ func (bc *BlockChain) WriteBlock(block *types.Block) (status WriteStatus, err er
|
|||
} else {
|
||||
status = SideStatTy
|
||||
}
|
||||
//Creating a new bigint here, to be sure not to violate the rule below:
|
||||
// Once Store has been called, a Value must not be copied.
|
||||
if externTd.Cmp(localTd) > 0 {
|
||||
bc.currentTd.Store(new(big.Int).Set(externTd))
|
||||
}
|
||||
|
||||
bc.futureBlocks.Remove(block.Hash())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
34
eth/sync.go
34
eth/sync.go
|
|
@ -167,44 +167,52 @@ 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())
|
||||
td := pm.blockchain.CurrentTd()
|
||||
|
||||
pHead, pTd := peer.Head()
|
||||
if pTd.Cmp(td) <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var currentBlock *types.Block
|
||||
|
||||
// Otherwise try to sync with the downloader
|
||||
mode := downloader.FullSync
|
||||
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 {
|
||||
// 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
|
||||
// bad block) rolled back a fast sync node below the sync point. In this case
|
||||
// however it's safe to reenable fast sync.
|
||||
atomic.StoreUint32(&pm.fastSync, 1)
|
||||
mode = downloader.FastSync
|
||||
} else{
|
||||
currentBlock = pm.blockchain.CurrentBlock()
|
||||
if currentBlock.NumberU64() == 0 && pm.blockchain.CurrentFastBlock().NumberU64() > 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
|
||||
// bad block) rolled back a fast sync node below the sync point. In this case
|
||||
// however it's safe to reenable fast sync.
|
||||
atomic.StoreUint32(&pm.fastSync, 1)
|
||||
mode = downloader.FastSync
|
||||
}
|
||||
}
|
||||
if err := pm.downloader.Synchronise(peer.id, pHead, pTd, mode); err != nil {
|
||||
return
|
||||
}
|
||||
atomic.StoreUint32(&pm.acceptTxs, 1) // Mark initial sync done
|
||||
if head := pm.blockchain.CurrentBlock(); head.NumberU64() > 0 {
|
||||
if currentBlock == nil{
|
||||
currentBlock = pm.blockchain.CurrentBlock()
|
||||
}
|
||||
if currentBlock.NumberU64() > 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(currentBlock, false)
|
||||
}
|
||||
// If fast sync was enabled, and we synced up, disable it
|
||||
if atomic.LoadUint32(&pm.fastSync) == 1 {
|
||||
// Disable fast sync if we indeed have something in our chain
|
||||
if pm.blockchain.CurrentBlock().NumberU64() > 0 {
|
||||
if currentBlock.NumberU64() > 0 {
|
||||
log.Info("Fast sync complete, auto disabling")
|
||||
atomic.StoreUint32(&pm.fastSync, 0)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue