aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/blockchain.go71
-rw-r--r--eth/backend.go48
2 files changed, 60 insertions, 59 deletions
diff --git a/core/blockchain.go b/core/blockchain.go
index 2f12ca62b..fe961e0c4 100644
--- a/core/blockchain.go
+++ b/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 {
diff --git a/eth/backend.go b/eth/backend.go
index 90d185ed4..ca0b13eed 100644
--- a/eth/backend.go
+++ b/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()