aboutsummaryrefslogtreecommitdiffstats
path: root/core/blockchain.go
diff options
context:
space:
mode:
authorgary rong <garyrong0905@gmail.com>2018-09-20 20:09:30 +0800
committerPéter Szilágyi <peterke@gmail.com>2018-09-20 20:09:30 +0800
commitd6254f827bf493c1471a806b7b8a0e9b86c8c420 (patch)
treee8cd05de67e506ee1b1b12d2b9468952179d1670 /core/blockchain.go
parentf89dce0126f92eb5f3245f6b8e8b1e3ac13641b3 (diff)
downloadgo-tangerine-d6254f827bf493c1471a806b7b8a0e9b86c8c420.tar
go-tangerine-d6254f827bf493c1471a806b7b8a0e9b86c8c420.tar.gz
go-tangerine-d6254f827bf493c1471a806b7b8a0e9b86c8c420.tar.bz2
go-tangerine-d6254f827bf493c1471a806b7b8a0e9b86c8c420.tar.lz
go-tangerine-d6254f827bf493c1471a806b7b8a0e9b86c8c420.tar.xz
go-tangerine-d6254f827bf493c1471a806b7b8a0e9b86c8c420.tar.zst
go-tangerine-d6254f827bf493c1471a806b7b8a0e9b86c8c420.zip
all: protect self-mined block during reorg (#17656)
Diffstat (limited to 'core/blockchain.go')
-rw-r--r--core/blockchain.go48
1 files changed, 44 insertions, 4 deletions
diff --git a/core/blockchain.go b/core/blockchain.go
index 7a3b09705..2f12ca62b 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -31,6 +31,7 @@ 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"
@@ -128,13 +129,14 @@ 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
+ isLocalFn func(common.Address) bool // Function used to determine whether the block author is a local miner account.
}
// 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) (*BlockChain, error) {
+func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, isLocalFn func(common.Address) bool) (*BlockChain, error) {
if cacheConfig == nil {
cacheConfig = &CacheConfig{
TrieNodeLimit: 256 * 1024 * 1024,
@@ -154,6 +156,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
triegc: prque.New(nil),
stateCache: state.NewDatabase(db),
quit: make(chan struct{}),
+ isLocalFn: isLocalFn,
bodyCache: bodyCache,
bodyRLPCache: bodyRLPCache,
blockCache: blockCache,
@@ -967,8 +970,45 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
reorg := externTd.Cmp(localTd) > 0
currentBlock = bc.CurrentBlock()
if !reorg && externTd.Cmp(localTd) == 0 {
- // Split same-difficulty blocks by number, then at random
- reorg = block.NumberU64() < currentBlock.NumberU64() || (block.NumberU64() == currentBlock.NumberU64() && mrand.Float64() < 0.5)
+ // Split same-difficulty blocks by number, then preferentially select
+ // the block generated by the local miner as the canonical block.
+ 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)
+ }
+ }
}
if reorg {
// Reorganise the chain if the parent is not the head block