core, eth: fix dependency cycle (#17720)

This commit is contained in:
gary rong 2018-09-21 01:02:15 +08:00 committed by Péter Szilágyi
parent f55c26ae6d
commit ba0a8b7887
2 changed files with 60 additions and 59 deletions

View File

@ -31,7 +31,6 @@ import (
"github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/common/prque"
"github.com/ethereum/go-ethereum/consensus" "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/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
@ -129,14 +128,14 @@ 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
isLocalFn func(common.Address) bool // Function used to determine whether the block author is a local miner account. shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block.
} }
// NewBlockChain returns a fully initialised block chain using information // NewBlockChain returns a fully initialised block chain using information
// available in the database. It initialises the default Ethereum Validator and // available in the database. It initialises the default Ethereum Validator and
// Processor. // 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 { if cacheConfig == nil {
cacheConfig = &CacheConfig{ cacheConfig = &CacheConfig{
TrieNodeLimit: 256 * 1024 * 1024, TrieNodeLimit: 256 * 1024 * 1024,
@ -150,20 +149,20 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
badBlocks, _ := lru.New(badBlockLimit) badBlocks, _ := lru.New(badBlockLimit)
bc := &BlockChain{ bc := &BlockChain{
chainConfig: chainConfig, chainConfig: chainConfig,
cacheConfig: cacheConfig, cacheConfig: cacheConfig,
db: db, db: db,
triegc: prque.New(nil), triegc: prque.New(nil),
stateCache: state.NewDatabase(db), stateCache: state.NewDatabase(db),
quit: make(chan struct{}), quit: make(chan struct{}),
isLocalFn: isLocalFn, shouldPreserve: shouldPreserve,
bodyCache: bodyCache, bodyCache: bodyCache,
bodyRLPCache: bodyRLPCache, bodyRLPCache: bodyRLPCache,
blockCache: blockCache, blockCache: blockCache,
futureBlocks: futureBlocks, futureBlocks: futureBlocks,
engine: engine, engine: engine,
vmConfig: vmConfig, vmConfig: vmConfig,
badBlocks: badBlocks, badBlocks: badBlocks,
} }
bc.SetValidator(NewBlockValidator(chainConfig, bc, engine)) bc.SetValidator(NewBlockValidator(chainConfig, bc, engine))
bc.SetProcessor(NewStateProcessor(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() { if block.NumberU64() < currentBlock.NumberU64() {
reorg = true reorg = true
} else if block.NumberU64() == currentBlock.NumberU64() { } else if block.NumberU64() == currentBlock.NumberU64() {
if _, ok := bc.engine.(*clique.Clique); ok { var currentPreserve, blockPreserve bool
// The reason we need to disable the self-reorg preserving for clique if bc.shouldPreserve != nil {
// is it can be probable to introduce a deadlock. currentPreserve, blockPreserve = bc.shouldPreserve(currentBlock), bc.shouldPreserve(block)
//
// 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)
} }
reorg = !currentPreserve && (blockPreserve || mrand.Float64() < 0.5)
} }
} }
if reorg { if reorg {

View File

@ -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} 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 { if err != nil {
return nil, err 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") 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 // We regard two types of accounts as local miner account: etherbase
// whether a block is mined by local accounts. We regard two types of // and accounts specified via `txpool.locals` flag.
// accounts as local account: etherbase and accounts specified via func (s *Ethereum) isLocalBlock(block *types.Block) bool {
// `txpool.locals` flag. author, err := s.engine.Author(block.Header())
func (s *Ethereum) isMinerAccount(addr common.Address) bool { 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. // Check whether the given address is etherbase.
s.lock.RLock() s.lock.RLock()
etherbase := s.etherbase etherbase := s.etherbase
s.lock.RUnlock() s.lock.RUnlock()
if addr == etherbase { if author == etherbase {
return true return true
} }
// Check whether the given address is specified by `txpool.local` // Check whether the given address is specified by `txpool.local`
// CLI flag. // CLI flag.
for _, account := range s.config.TxPool.Locals { for _, account := range s.config.TxPool.Locals {
if account == addr { if account == author {
return true return true
} }
} }
return false 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. // SetEtherbase sets the mining reward address.
func (s *Ethereum) SetEtherbase(etherbase common.Address) { func (s *Ethereum) SetEtherbase(etherbase common.Address) {
s.lock.Lock() s.lock.Lock()