Bläddra i källkod

core, eth: fix dependency cycle (#17720)

gary rong 7 år sedan
förälder
incheckning
ba0a8b7887
2 ändrade filer med 60 tillägg och 59 borttagningar
  1. 21 50
      core/blockchain.go
  2. 39 9
      eth/backend.go

+ 21 - 50
core/blockchain.go

@@ -31,7 +31,6 @@ import (
 	"github.com/ethereum/go-ethereum/common/mclock"
 	"github.com/ethereum/go-ethereum/common/prque"
 	"github.com/ethereum/go-ethereum/consensus"
-	"github.com/ethereum/go-ethereum/consensus/clique"
 	"github.com/ethereum/go-ethereum/core/rawdb"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
@@ -129,14 +128,14 @@ type BlockChain struct {
 	validator Validator // block and state validator interface
 	vmConfig  vm.Config
 
-	badBlocks *lru.Cache                // Bad block cache
-	isLocalFn func(common.Address) bool // Function used to determine whether the block author is a local miner account.
+	badBlocks      *lru.Cache              // Bad block cache
+	shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block.
 }
 
 // NewBlockChain returns a fully initialised block chain using information
 // available in the database. It initialises the default Ethereum Validator and
 // Processor.
-func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, isLocalFn func(common.Address) bool) (*BlockChain, error) {
+func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(block *types.Block) bool) (*BlockChain, error) {
 	if cacheConfig == nil {
 		cacheConfig = &CacheConfig{
 			TrieNodeLimit: 256 * 1024 * 1024,
@@ -150,20 +149,20 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
 	badBlocks, _ := lru.New(badBlockLimit)
 
 	bc := &BlockChain{
-		chainConfig:  chainConfig,
-		cacheConfig:  cacheConfig,
-		db:           db,
-		triegc:       prque.New(nil),
-		stateCache:   state.NewDatabase(db),
-		quit:         make(chan struct{}),
-		isLocalFn:    isLocalFn,
-		bodyCache:    bodyCache,
-		bodyRLPCache: bodyRLPCache,
-		blockCache:   blockCache,
-		futureBlocks: futureBlocks,
-		engine:       engine,
-		vmConfig:     vmConfig,
-		badBlocks:    badBlocks,
+		chainConfig:    chainConfig,
+		cacheConfig:    cacheConfig,
+		db:             db,
+		triegc:         prque.New(nil),
+		stateCache:     state.NewDatabase(db),
+		quit:           make(chan struct{}),
+		shouldPreserve: shouldPreserve,
+		bodyCache:      bodyCache,
+		bodyRLPCache:   bodyRLPCache,
+		blockCache:     blockCache,
+		futureBlocks:   futureBlocks,
+		engine:         engine,
+		vmConfig:       vmConfig,
+		badBlocks:      badBlocks,
 	}
 	bc.SetValidator(NewBlockValidator(chainConfig, bc, engine))
 	bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine))
@@ -975,39 +974,11 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
 		if block.NumberU64() < currentBlock.NumberU64() {
 			reorg = true
 		} else if block.NumberU64() == currentBlock.NumberU64() {
-			if _, ok := bc.engine.(*clique.Clique); ok {
-				// The reason we need to disable the self-reorg preserving for clique
-				// is it can be probable to introduce a deadlock.
-				//
-				// e.g. If there are 7 available signers
-				//
-				// r1   A
-				// r2     B
-				// r3       C
-				// r4         D
-				// r5   A      [X] F G
-				// r6    [X]
-				//
-				// In the round5, the inturn signer E is offline, so the worst case
-				// is A, F and G sign the block of round5 and reject the block of opponents
-				// and in the round6, the last available signer B is offline, the whole
-				// network is stuck.
-				reorg = mrand.Float64() < 0.5
-			} else {
-				currentAuthor, err := bc.engine.Author(currentBlock.Header())
-				if err != nil {
-					return NonStatTy, err
-				}
-				blockAuthor, err := bc.engine.Author(block.Header())
-				if err != nil {
-					return NonStatTy, err
-				}
-				var currentLocal, blockLocal bool
-				if bc.isLocalFn != nil {
-					currentLocal, blockLocal = bc.isLocalFn(currentAuthor), bc.isLocalFn(blockAuthor)
-				}
-				reorg = !currentLocal && (blockLocal || mrand.Float64() < 0.5)
+			var currentPreserve, blockPreserve bool
+			if bc.shouldPreserve != nil {
+				currentPreserve, blockPreserve = bc.shouldPreserve(currentBlock), bc.shouldPreserve(block)
 			}
+			reorg = !currentPreserve && (blockPreserve || mrand.Float64() < 0.5)
 		}
 	}
 	if reorg {

+ 39 - 9
eth/backend.go

@@ -156,7 +156,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
 		}
 		cacheConfig = &core.CacheConfig{Disabled: config.NoPruning, TrieNodeLimit: config.TrieCache, TrieTimeLimit: config.TrieTimeout}
 	)
-	eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, eth.chainConfig, eth.engine, vmConfig, eth.isMinerAccount)
+	eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, eth.chainConfig, eth.engine, vmConfig, eth.shouldPreserve)
 	if err != nil {
 		return nil, err
 	}
@@ -334,30 +334,60 @@ func (s *Ethereum) Etherbase() (eb common.Address, err error) {
 	return common.Address{}, fmt.Errorf("etherbase must be explicitly specified")
 }
 
-// isMinerAccount checks whether the specified address is a miner account.
+// isLocalBlock checks whether the specified block is mined
+// by local miner accounts.
 //
-// This function is used during block chain reorg checking to determine
-// whether a block is mined by local accounts. We regard two types of
-// accounts as local account: etherbase and accounts specified via
-// `txpool.locals` flag.
-func (s *Ethereum) isMinerAccount(addr common.Address) bool {
+// We regard two types of accounts as local miner account: etherbase
+// and accounts specified via `txpool.locals` flag.
+func (s *Ethereum) isLocalBlock(block *types.Block) bool {
+	author, err := s.engine.Author(block.Header())
+	if err != nil {
+		log.Warn("Failed to retrieve block author", "number", block.NumberU64(), "hash", block.Hash(), "err", err)
+		return false
+	}
 	// Check whether the given address is etherbase.
 	s.lock.RLock()
 	etherbase := s.etherbase
 	s.lock.RUnlock()
-	if addr == etherbase {
+	if author == etherbase {
 		return true
 	}
 	// Check whether the given address is specified by `txpool.local`
 	// CLI flag.
 	for _, account := range s.config.TxPool.Locals {
-		if account == addr {
+		if account == author {
 			return true
 		}
 	}
 	return false
 }
 
+// shouldPreserve checks whether we should preserve the given block
+// during the chain reorg depending on whether the author of block
+// is a local account.
+func (s *Ethereum) shouldPreserve(block *types.Block) bool {
+	// The reason we need to disable the self-reorg preserving for clique
+	// is it can be probable to introduce a deadlock.
+	//
+	// e.g. If there are 7 available signers
+	//
+	// r1   A
+	// r2     B
+	// r3       C
+	// r4         D
+	// r5   A      [X] F G
+	// r6    [X]
+	//
+	// In the round5, the inturn signer E is offline, so the worst case
+	// is A, F and G sign the block of round5 and reject the block of opponents
+	// and in the round6, the last available signer B is offline, the whole
+	// network is stuck.
+	if _, ok := s.engine.(*clique.Clique); ok {
+		return false
+	}
+	return s.isLocalBlock(block)
+}
+
 // SetEtherbase sets the mining reward address.
 func (s *Ethereum) SetEtherbase(etherbase common.Address) {
 	s.lock.Lock()