From 916b16de713b48bb86213bbe4c0c79f35a75bf83 Mon Sep 17 00:00:00 2001 From: AnilChinchawale Date: Mon, 18 Jan 2021 10:57:22 +0530 Subject: [PATCH] fix masternode stop block production. --- consensus/XDPoS/XDPoS.go | 29 +++++++++++++++++------------ consensus/XDPoS/snapshot.go | 18 ++++++++++++------ core/blockchain.go | 8 +++++--- miner/worker.go | 20 ++++++++------------ 4 files changed, 42 insertions(+), 33 deletions(-) diff --git a/consensus/XDPoS/XDPoS.go b/consensus/XDPoS/XDPoS.go index 6e5d21f071..72649d536d 100644 --- a/consensus/XDPoS/XDPoS.go +++ b/consensus/XDPoS/XDPoS.go @@ -114,6 +114,11 @@ var ( // ones). errInvalidCheckpointSigners = errors.New("invalid signer list on checkpoint block") + // errMismatchingCheckpointSigners is returned if a checkpoint block contains a + // list of signers different than the one the local node calculated. + errMismatchingCheckpointSigners = errors.New("mismatching signer list on checkpoint block") + + errInvalidCheckpointPenalties = errors.New("invalid penalty list on checkpoint block") // errInvalidMixDigest is returned if a block's mix digest is non-zero. @@ -134,16 +139,15 @@ var ( // be modified via out-of-range or non-contiguous headers. errInvalidVotingChain = errors.New("invalid voting chain") - // errUnauthorized is returned if a header is signed by a non-authorized entity. - errUnauthorized = errors.New("unauthorized") + // errUnauthorizedSigner is returned if a header is signed by a non-authorized entity. + errUnauthorizedSigner = errors.New("unauthorized signer") + + // errRecentlySigned is returned if a header is signed by an authorized entity + // that already signed a header recently, thus is temporarily not allowed to. + errRecentlySigned = errors.New("recently signed") errFailedDoubleValidation = errors.New("wrong pair of creator-validator in double validation") - // errWaitTransactions is returned if an empty block is attempted to be sealed - // on an instant chain (0 second period). It's important to refuse these as the - // block reward is zero, so an empty block just bloats the chain... fast. - errWaitTransactions = errors.New("waiting for transactions") - ErrInvalidCheckpointValidators = errors.New("invalid validators list on checkpoint block") ) @@ -431,7 +435,7 @@ func (c *XDPoS) verifyCascadingFields(chain consensus.ChainReader, header *types validSigners := compareSignersLists(masternodesFromCheckpointHeader, signers) if !validSigners { log.Error("Masternodes lists are different in checkpoint header and snapshot", "number", number, "masternodes_from_checkpoint_header", masternodesFromCheckpointHeader, "masternodes_in_snapshot", signers, "penList", penPenalties) - return errInvalidCheckpointSigners + return errMismatchingCheckpointSigners } if c.HookVerifyMNs != nil { err := c.HookVerifyMNs(header, signers) @@ -702,7 +706,7 @@ func (c *XDPoS) verifySeal(chain consensus.ChainReader, header *types.Header, pa } if !valid { log.Debug("Unauthorized creator found", "block number", number, "creator", creator.String(), "masternodes", mstring, "snapshot from parent block", nstring) - return errUnauthorized + return errUnauthorizedSigner } } if len(masternodes) > 1 { @@ -713,7 +717,7 @@ func (c *XDPoS) verifySeal(chain consensus.ChainReader, header *types.Header, pa if limit := uint64(2); seen > number-limit { // Only take into account the non-epoch blocks if number%c.config.Epoch != 0 { - return errUnauthorized + return errRecentlySigned } } } @@ -943,7 +947,8 @@ func (c *XDPoS) Seal(chain consensus.ChainReader, block *types.Block, results ch // For 0-period chains, refuse to seal empty blocks (no reward but would spin sealing) // checkpoint blocks have no tx if c.config.Period == 0 && len(block.Transactions()) == 0 && number%c.config.Epoch != 0 { - return errWaitTransactions + log.Info("Sealing paused, waiting for transactions") + return nil } // Don't hold the signer fields for the entire sealing procedure c.lock.RLock() @@ -965,7 +970,7 @@ func (c *XDPoS) Seal(chain consensus.ChainReader, block *types.Block, results ch } } if !valid { - return errUnauthorized + return errUnauthorizedSigner } } // If we're amongst the recent signers, wait for the next block diff --git a/consensus/XDPoS/snapshot.go b/consensus/XDPoS/snapshot.go index f3fc61a77a..f4f6bbf304 100644 --- a/consensus/XDPoS/snapshot.go +++ b/consensus/XDPoS/snapshot.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" lru "github.com/hashicorp/golang-lru" ) @@ -47,7 +48,7 @@ import ( // Snapshot is the state of the authorization voting at a given point in time. type Snapshot struct { config *params.XDPoSConfig // Consensus engine parameters to fine tune behavior - sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover + sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover Number uint64 `json:"number"` // Block number where the snapshot was created Hash common.Hash `json:"hash"` // Block hash where the snapshot was created @@ -217,11 +218,16 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { //if _, ok := snap.Signers[signer]; !ok { // return nil, errUnauthorizedSigner //} - //for _, recent := range snap.Recents { - // if recent == signer { - // return nil, errRecentlySigned - // } - //} + for seen, recent := range snap.Recents { + if recent == signer { + if limit := uint64(2); number < limit || seen > number-limit { + if number%s.config.Epoch != 0 { + log.Error("errRecentlySigned") + return nil, errRecentlySigned + } + } + } + } snap.Recents[number] = signer // Header authorized, discard any previous votes from the signer diff --git a/core/blockchain.go b/core/blockchain.go index e851c0927a..858fed3c90 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1406,9 +1406,11 @@ func (bc *BlockChain) getResultBlock(block *types.Block, verifiedM2 bool) (*Resu } log.Debug("Number block need calculated again", "number", block.NumberU64(), "hash", block.Hash().Hex(), "winners", len(winner)) // Import all the pruned blocks to make the state available - _, _, _, err := bc.insertChain(winner, false) - if err != nil { - return nil, err + if len(winner) > 0 { + _, _, _, err := bc.insertChain(winner, false) + if err != nil { + return nil, err + } } case err != nil: bc.reportBlock(block, nil, err) diff --git a/miner/worker.go b/miner/worker.go index f35cad1fe4..cb471e9d6b 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -29,8 +29,8 @@ 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/misc" "github.com/ethereum/go-ethereum/consensus/XDPoS" + "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/contracts" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" @@ -174,8 +174,8 @@ type worker struct { snapshotState *state.StateDB // atomic status counters - running int32 // The indicator whether the consensus engine is running or not. - newTxs int32 // New arrival transaction count since last sealing work submitting. + running int32 // The indicator whether the consensus engine is running or not. + newTxs int32 // New arrival transaction count since last sealing work submitting. announceTxs bool lastParentBlockCommit string @@ -213,7 +213,7 @@ func newWorker(config *params.ChainConfig, engine consensus.Engine, eth Backend, startCh: make(chan struct{}, 1), resubmitIntervalCh: make(chan time.Duration), resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize), - announceTxs: announceTxs, + announceTxs: announceTxs, } if worker.announceTxs { // Subscribe NewTxsEvent for tx pool @@ -374,13 +374,8 @@ func (w *worker) newWorkLoop(recommit time.Duration) { case <-timer.C: // If mining is running resubmit a new work cycle periodically to pull in // higher priced transactions. Disable this overhead for pending blocks. - if w.isRunning() && (w.config.Clique == nil || w.config.Clique.Period > 0) { - // Short circuit if no new transaction arrives. - if atomic.LoadInt32(&w.newTxs) == 0 { - timer.Reset(recommit) - continue - } - commit(true, commitInterruptResubmit) + if w.isRunning() && (w.config.XDPoS == nil || w.config.XDPoS.Period > 0) { + commit(false, commitInterruptResubmit) } case interval := <-w.resubmitIntervalCh: @@ -984,7 +979,7 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) return } if !ok { - log.Info("Not my turn to commit block. Waiting...") + log.Info("Not my turn to commit block. Waiting...", "coinbase", w.coinbase, "parent", parent.Header().Number) // in case some nodes are down if preIndex == -1 { // first block @@ -1150,6 +1145,7 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st receipts[i] = new(types.Receipt) *receipts[i] = *l } + log.Info("commit", "root", w.current.state.IntermediateRoot(true).String()) s := w.current.state.Copy() block, err := w.engine.Finalize(w.chain, w.current.header, s, w.current.txs, uncles, w.current.receipts) if err != nil {