diff --git a/core/blockchain.go b/core/blockchain.go index d74b3520b1..85707eb9a5 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -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 { @@ -858,9 +874,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 } diff --git a/eth/sync.go b/eth/sync.go index 7442f912c7..d638ed2126 100644 --- a/eth/sync.go +++ b/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) }