diff --git a/consensus/consortium/main.go b/consensus/consortium/main.go index f53db7e8b3..cd2ceb5547 100644 --- a/consensus/consortium/main.go +++ b/consensus/consortium/main.go @@ -198,6 +198,10 @@ func (c *Consortium) IsSystemContract(to *common.Address) bool { return c.v2.IsSystemContract(to) } +func (c *Consortium) GetBestParentBlock(chain *core.BlockChain) (*types.Block, bool) { + return c.v2.GetBestParentBlock(chain) +} + // HandleSubmitBlockReward determines if the transaction is submitBlockReward // transaction with non-zero msg.value and fixes up the statedb. // This function bases on the fact that submitBlockReward is the only system diff --git a/consensus/consortium/v2/consortium.go b/consensus/consortium/v2/consortium.go index 2a5d31ca47..8abc7a0fa5 100644 --- a/consensus/consortium/v2/consortium.go +++ b/consensus/consortium/v2/consortium.go @@ -912,6 +912,47 @@ func (c *Consortium) readSigner() (common.Address, consortiumCommon.SignerFn, co return c.val, c.signFn, c.signTxFn } +// GetBestParentBlock goes backward in the canonical chain to find if the miner can +// create a chain which has more difficulty than current chain. In case the miner +// cannot create a better chain, this function returns the head block of current +// canonical chain. +func (c *Consortium) GetBestParentBlock(chain *core.BlockChain) (*types.Block, bool) { + signer, _, _ := c.readSigner() + + currentBlock := chain.CurrentBlock() + block := currentBlock + prevBlock := chain.GetBlockByHash(block.ParentHash()) + diffculty := block.Difficulty().Int64() + for diffculty < diffInTurn.Int64() { + snap, err := c.snapshot(chain, block.NumberU64()-1, block.ParentHash(), nil) + if err != nil { + return currentBlock, false + } + // Miner can create an inturn block which helps the chain to have + // greater diffculty + if snap.supposeValidator() == signer { + inRecent := false + for seen, recent := range snap.Recents { + if recent == signer { + if limit := uint64(len(snap.Validators)/2 + 1); seen > snap.Number+1-limit { + inRecent = true + break + } + } + } + if !inRecent { + return prevBlock, true + } + } + + block = prevBlock + prevBlock = chain.GetBlockByHash(block.ParentHash()) + diffculty += block.Difficulty().Int64() + } + + return currentBlock, false +} + // ecrecover extracts the Ronin account address from a signed header. func ecrecover(header *types.Header, sigcache *lru.ARCCache, chainId *big.Int) (common.Address, error) { // If the signature's already cached, return that diff --git a/eth/backend.go b/eth/backend.go index cda8d7ece5..46c3672cb4 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -462,6 +462,9 @@ func (s *Ethereum) shouldPreserve(block *types.Block) bool { if _, ok := s.engine.(*clique.Clique); ok { return false } + if _, ok := s.engine.(*consortium.Consortium); ok { + return false + } return s.isLocalBlock(block) } diff --git a/miner/worker.go b/miner/worker.go index 223f47c41e..c175d997ff 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -27,6 +27,7 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/consortium" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" @@ -1013,7 +1014,16 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) defer w.mu.RUnlock() tstart := time.Now() - parent := w.chain.CurrentBlock() + + var ( + parent *types.Block + fastCommit bool + ) + if consortiumEngine, ok := w.engine.(*consortium.Consortium); ok { + parent, fastCommit = consortiumEngine.GetBestParentBlock(w.chain) + } else { + parent = w.chain.CurrentBlock() + } if parent.Time() >= uint64(timestamp) { timestamp = int64(parent.Time() + 1) @@ -1096,6 +1106,14 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) commitUncles(w.localUncles) commitUncles(w.remoteUncles) + // Fast commit an empty block which has block number smaller + // than current block in canonical chain but have greater + // difficulty + if fastCommit { + w.commit(uncles, nil, true, tstart) + return + } + // Create an empty block based on temporary copied state for // sealing in advance without waiting block execution finished. if !noempty && atomic.LoadUint32(&w.noempty) == 0 {