core/eth: Add mutex-free lookup of total difficulty

This commit is contained in:
Martin Holst Swende 2017-09-06 11:19:09 +02:00
parent 1e67378df8
commit 77c5188219
2 changed files with 43 additions and 15 deletions

View file

@ -114,7 +114,8 @@ type BlockChain struct {
validator Validator // block and state validator interface validator Validator // block and state validator interface
vmConfig vm.Config 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 // 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, vmConfig: vmConfig,
badBlocks: badBlocks, badBlocks: badBlocks,
} }
bc.SetValidator(NewBlockValidator(config, bc, engine)) bc.SetValidator(NewBlockValidator(config, bc, engine))
bc.SetProcessor(NewStateProcessor(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 // Take ownership of this particular state
go bc.update() go bc.update()
return bc, nil return bc, nil
@ -330,6 +339,13 @@ func (bc *BlockChain) CurrentBlock() *types.Block {
return bc.currentBlock 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 // CurrentFastBlock retrieves the current fast-sync head block of the canonical
// chain. The block is retrieved from the blockchain's internal cache. // chain. The block is retrieved from the blockchain's internal cache.
func (bc *BlockChain) CurrentFastBlock() *types.Block { func (bc *BlockChain) CurrentFastBlock() *types.Block {
@ -864,9 +880,13 @@ func (bc *BlockChain) WriteBlock(block *types.Block) (status WriteStatus, err er
} else { } else {
status = SideStatTy 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()) bc.futureBlocks.Remove(block.Hash())
return return
} }

View file

@ -167,44 +167,52 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
return return
} }
// Make sure the peer's TD is higher than our own // Make sure the peer's TD is higher than our own
currentBlock := pm.blockchain.CurrentBlock() td := pm.blockchain.CurrentTd()
td := pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
pHead, pTd := peer.Head() pHead, pTd := peer.Head()
if pTd.Cmp(td) <= 0 { if pTd.Cmp(td) <= 0 {
return return
} }
var currentBlock *types.Block
// Otherwise try to sync with the downloader // Otherwise try to sync with the downloader
mode := downloader.FullSync mode := downloader.FullSync
if atomic.LoadUint32(&pm.fastSync) == 1 { if atomic.LoadUint32(&pm.fastSync) == 1 {
// Fast sync was explicitly requested, and explicitly granted // Fast sync was explicitly requested, and explicitly granted
mode = downloader.FastSync mode = downloader.FastSync
} else if currentBlock.NumberU64() == 0 && pm.blockchain.CurrentFastBlock().NumberU64() > 0 { } else{
// The database seems empty as the current block is the genesis. Yet the fast currentBlock = pm.blockchain.CurrentBlock()
// block is ahead, so fast sync was enabled for this node at a certain point. if currentBlock.NumberU64() == 0 && pm.blockchain.CurrentFastBlock().NumberU64() > 0 {
// The only scenario where this can happen is if the user manually (or via a // The database seems empty as the current block is the genesis. Yet the fast
// bad block) rolled back a fast sync node below the sync point. In this case // block is ahead, so fast sync was enabled for this node at a certain point.
// however it's safe to reenable fast sync. // The only scenario where this can happen is if the user manually (or via a
atomic.StoreUint32(&pm.fastSync, 1) // bad block) rolled back a fast sync node below the sync point. In this case
mode = downloader.FastSync // 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 { if err := pm.downloader.Synchronise(peer.id, pHead, pTd, mode); err != nil {
return return
} }
atomic.StoreUint32(&pm.acceptTxs, 1) // Mark initial sync done 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 // 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 // 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 // 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 // scenario will most often crop up in private and hackathon networks with
// degenerate connectivity, but it should be healthy for the mainnet too to // degenerate connectivity, but it should be healthy for the mainnet too to
// more reliably update peers or the local TD state. // 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 fast sync was enabled, and we synced up, disable it
if atomic.LoadUint32(&pm.fastSync) == 1 { if atomic.LoadUint32(&pm.fastSync) == 1 {
// Disable fast sync if we indeed have something in our chain // 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") log.Info("Fast sync complete, auto disabling")
atomic.StoreUint32(&pm.fastSync, 0) atomic.StoreUint32(&pm.fastSync, 0)
} }