github.com/elastos/Elastos.ELA.SideChain.ETH@v0.2.2/consensus/pbft/pbft.go (about)

     1  // Copyright (c) 2017-2019 The Elastos Foundation
     2  // Use of this source code is governed by an MIT
     3  // license that can be found in the LICENSE file.
     4  //
     5  
     6  package pbft
     7  
     8  import (
     9  	"bytes"
    10  	"errors"
    11  	"fmt"
    12  	"github.com/elastos/Elastos.ELA.SideChain.ESC/chainbridge-core/crypto"
    13  	"io"
    14  	"math/big"
    15  	"path/filepath"
    16  	"strings"
    17  	"time"
    18  
    19  	"github.com/elastos/Elastos.ELA.SideChain.ESC/common"
    20  	"github.com/elastos/Elastos.ELA.SideChain.ESC/consensus"
    21  	"github.com/elastos/Elastos.ELA.SideChain.ESC/core"
    22  	"github.com/elastos/Elastos.ELA.SideChain.ESC/core/state"
    23  	"github.com/elastos/Elastos.ELA.SideChain.ESC/core/types"
    24  	"github.com/elastos/Elastos.ELA.SideChain.ESC/dpos"
    25  	dmsg "github.com/elastos/Elastos.ELA.SideChain.ESC/dpos/msg"
    26  	"github.com/elastos/Elastos.ELA.SideChain.ESC/log"
    27  	"github.com/elastos/Elastos.ELA.SideChain.ESC/params"
    28  	"github.com/elastos/Elastos.ELA.SideChain.ESC/rlp"
    29  	"github.com/elastos/Elastos.ELA.SideChain.ESC/rpc"
    30  	"github.com/elastos/Elastos.ELA.SideChain.ESC/smallcrosstx"
    31  	"github.com/elastos/Elastos.ELA.SideChain.ESC/spv"
    32  	"github.com/elastos/Elastos.ELA.SideChain.ESC/withdrawfailedtx"
    33  	"github.com/elastos/Elastos.ELA/core/types/payload"
    34  
    35  	ecom "github.com/elastos/Elastos.ELA/common"
    36  	daccount "github.com/elastos/Elastos.ELA/dpos/account"
    37  	"github.com/elastos/Elastos.ELA/dpos/dtime"
    38  	"github.com/elastos/Elastos.ELA/dpos/p2p/peer"
    39  	"github.com/elastos/Elastos.ELA/events"
    40  	"github.com/elastos/Elastos.ELA/p2p/msg"
    41  
    42  	"golang.org/x/crypto/sha3"
    43  )
    44  
    45  var (
    46  	extraVanity = 32            // Fixed number of extra-data prefix bytes
    47  	extraSeal   = 65            // Fixed number of extra-data suffix bytes reserved for signer seal
    48  	diffInTurn  = big.NewInt(2) // Block difficulty for in-turn signatures
    49  	diffNoTurn  = big.NewInt(1) // Block difficulty for in-turn signatures
    50  )
    51  
    52  const (
    53  	// maxRequestedBlocks is the maximum number of requested block
    54  	// hashes to store in memory.
    55  	maxRequestedBlocks = msg.MaxInvPerMsg
    56  )
    57  
    58  var (
    59  	// errUnknownBlock is returned when the list of signers is requested for a block
    60  	// that is not part of the local blockchain.
    61  	errUnknownBlock = errors.New("unknown block")
    62  
    63  	// errInvalidMixDigest is returned if a block's mix digest is non-zero.
    64  	errInvalidMixDigest = errors.New("non-zero mix digest")
    65  	// errInvalidUncleHash is returned if a block contains an non-empty uncle list.
    66  	errInvalidUncleHash = errors.New("non empty uncle hash")
    67  	// to contain a 64 byte secp256k1 signature.
    68  	errMissingSignature = errors.New("extra-data 64 byte signature suffix missing")
    69  	// errUnauthorizedSigner is returned if a header is signed by a non-authorized entity.
    70  	errUnauthorizedSigner = errors.New("unauthorized signer")
    71  	// ErrInvalidTimestamp is returned if the timestamp of a block is lower than
    72  	// the previous block's timestamp + the minimum block period.
    73  	ErrInvalidTimestamp = errors.New("invalid timestamp")
    74  
    75  	ErrAlreadyConfirmedBlock = errors.New("already confirmed block")
    76  
    77  	ErrWaitSyncBlock = errors.New("has confirmed, wait sync block")
    78  
    79  	ErrInvalidConfirm = errors.New("invalid confirm")
    80  
    81  	ErrSignerNotOnduty = errors.New("singer is not on duty")
    82  
    83  	ErrConsensusIsRunning = errors.New("current consensus is running")
    84  
    85  	ErrWaitRecoverStatus = errors.New("wait for recoved states")
    86  
    87  	// errInvalidDifficulty is returned if the difficulty of a block neither 2.
    88  	errInvalidDifficulty = errors.New("invalid difficulty")
    89  
    90  	errChainForkBlock = errors.New("chain fork block")
    91  
    92  	errDoubleSignBlock = errors.New("double sign block")
    93  )
    94  
    95  // Pbft is a consensus engine based on Byzantine fault-tolerant algorithm
    96  type Pbft struct {
    97  	datadir       string
    98  	cfg           params.PbftConfig
    99  	dispatcher    *dpos.Dispatcher
   100  	confirmCh     chan *payload.Confirm
   101  	unConfirmCh   chan *payload.Confirm
   102  	account       daccount.Account
   103  	bridgeAccount crypto.Keypair
   104  	network       *dpos.Network
   105  	blockPool     *dpos.BlockPool
   106  	chain         *core.BlockChain
   107  	timeSource    dtime.MedianTimeSource
   108  
   109  	// IsCurrent returns whether BlockChain synced to best height.
   110  	IsCurrent          func() bool
   111  	StartMine          func()
   112  	OnDuty             func()
   113  	OnInsertChainError func(id peer.PID, block *types.Block, err error)
   114  
   115  	requestedBlocks    map[common.Hash]struct{}
   116  	requestedProposals map[ecom.Uint256]struct{}
   117  	statusMap          map[uint32]map[string]*dmsg.ConsensusStatus
   118  	notHandledProposal map[string]struct{}
   119  
   120  	enableViewLoop bool
   121  	recoverStarted bool
   122  	isRecoved      bool
   123  	period         uint64
   124  	isSealOver     bool
   125  	isRecovering   bool
   126  }
   127  
   128  func New(chainConfig *params.ChainConfig, dataDir string) *Pbft {
   129  	logpath := filepath.Join(dataDir, "/logs/dpos")
   130  	dposPath := filepath.Join(dataDir, "/network/dpos")
   131  	if strings.LastIndex(dataDir, "/") == len(dataDir)-1 {
   132  		dposPath = filepath.Join(dataDir, "network/dpos")
   133  		logpath = filepath.Join(dataDir, "logs/dpos")
   134  	}
   135  	cfg := chainConfig.Pbft
   136  	if cfg == nil {
   137  		dpos.InitLog(0, 0, 0, logpath)
   138  		return &Pbft{}
   139  	}
   140  	pbftKeystore := chainConfig.PbftKeyStore
   141  	password := []byte(chainConfig.PbftKeyStorePassWord)
   142  	dpos.InitLog(cfg.PrintLevel, cfg.MaxPerLogSize, cfg.MaxLogsSize, logpath)
   143  	producers := make([][]byte, len(cfg.Producers))
   144  	for i, v := range cfg.Producers {
   145  		producers[i] = common.Hex2Bytes(v)
   146  	}
   147  	account, err := dpos.GetDposAccount(pbftKeystore, password)
   148  	var bridgeAccount crypto.Keypair
   149  	if err != nil {
   150  		if string(password) == "" {
   151  			fmt.Println("create dpos account error:", err.Error(), "pbftKeystore:", pbftKeystore, "password")
   152  		} else {
   153  			fmt.Println("create dpos account error:", err.Error(), "pbftKeystore:", pbftKeystore, "password", string(password))
   154  		}
   155  		//can't return, because common node need verify use this engine
   156  	} else {
   157  		bridgeAccount, err = dpos.GetBridgeAccount(pbftKeystore, password)
   158  		if err != nil {
   159  			if string(password) == "" {
   160  				fmt.Println("create GetArbiterAccount error:", err.Error(), "pbftKeystore:", pbftKeystore, "password")
   161  			} else {
   162  				fmt.Println("create GetArbiterAccount error:", err.Error(), "pbftKeystore:", pbftKeystore, "password", string(password))
   163  			}
   164  		}
   165  	}
   166  	medianTimeSouce := dtime.NewMedianTime()
   167  
   168  	pbft := &Pbft{
   169  		datadir:            dataDir,
   170  		cfg:                *cfg,
   171  		confirmCh:          make(chan *payload.Confirm),
   172  		unConfirmCh:        make(chan *payload.Confirm),
   173  		account:            account,
   174  		bridgeAccount:      bridgeAccount,
   175  		requestedBlocks:    make(map[common.Hash]struct{}),
   176  		requestedProposals: make(map[ecom.Uint256]struct{}),
   177  		statusMap:          make(map[uint32]map[string]*dmsg.ConsensusStatus),
   178  		notHandledProposal: make(map[string]struct{}),
   179  		period:             5,
   180  		timeSource:         medianTimeSouce,
   181  	}
   182  	blockPool := dpos.NewBlockPool(pbft.verifyConfirm, pbft.verifyBlock, DBlockSealHash)
   183  	pbft.blockPool = blockPool
   184  	var accpubkey []byte
   185  
   186  	if account != nil {
   187  		accpubkey = account.PublicKeyBytes()
   188  		network, err := dpos.NewNetwork(&dpos.NetworkConfig{
   189  			IPAddress:        cfg.IPAddress,
   190  			Magic:            cfg.Magic,
   191  			DefaultPort:      cfg.DPoSPort,
   192  			Account:          account,
   193  			MedianTime:       medianTimeSouce,
   194  			MaxNodePerHost:   cfg.MaxNodePerHost,
   195  			Listener:         pbft,
   196  			DataPath:         dposPath,
   197  			PublicKey:        accpubkey,
   198  			GetCurrentHeight: pbft.GetMainChainHeight,
   199  			AnnounceAddr: func() {
   200  				events.Notify(dpos.ETAnnounceAddr, nil)
   201  			},
   202  		})
   203  		if err != nil {
   204  			dpos.Error("New dpos network error:", err.Error())
   205  			return nil
   206  		}
   207  		pbft.network = network
   208  		pbft.subscribeEvent()
   209  	}
   210  	pbft.dispatcher = dpos.NewDispatcher(producers, pbft.onConfirm, pbft.onUnConfirm,
   211  		10*time.Second, accpubkey, medianTimeSouce, pbft, chainConfig.GetPbftBlock())
   212  	return pbft
   213  }
   214  
   215  func (p *Pbft) GetMainChainHeight(pid peer.PID) uint64 {
   216  	return spv.GetSpvHeight()
   217  }
   218  
   219  func (p *Pbft) subscribeEvent() {
   220  	events.Subscribe(func(e *events.Event) {
   221  		switch e.Type {
   222  		case events.ETDirectPeersChanged:
   223  			peersInfo := e.Data.(*peer.PeersInfo)
   224  			go p.network.UpdatePeers(peersInfo.CurrentPeers, peersInfo.NextPeers)
   225  		case dpos.ETNewPeer:
   226  			count := len(p.network.GetActivePeers())
   227  			log.Info("new peer accept", "active peer count", count)
   228  			height := p.chain.CurrentHeader().Number.Uint64()
   229  			cfg := p.chain.Config()
   230  			if cfg.PBFTBlock != nil && height >= cfg.PBFTBlock.Uint64()-cfg.PreConnectOffset && height < cfg.PBFTBlock.Uint64() {
   231  				log.Info("before change engine AnnounceDAddr")
   232  				go p.AnnounceDAddr()
   233  			}
   234  
   235  			if p.chain.Engine() == p && !p.dispatcher.GetConsensusView().HasProducerMajorityCount(count) {
   236  				log.Info("end change engine AnnounceDAddr")
   237  				go p.AnnounceDAddr()
   238  			}
   239  		case dpos.ETNextProducers:
   240  			producers := e.Data.([]peer.PID)
   241  			log.Info("update next producers", "totalCount", spv.GetTotalProducersCount())
   242  			p.dispatcher.GetConsensusView().UpdateNextProducers(producers, spv.GetTotalProducersCount())
   243  		case dpos.ETOnSPVHeight:
   244  			height := e.Data.(uint32)
   245  			if spv.GetWorkingHeight() >= height {
   246  				if uint64(spv.GetWorkingHeight()-height) <= p.chain.Config().PreConnectOffset {
   247  					curProducers := p.dispatcher.GetConsensusView().GetProducers()
   248  					isSame := p.dispatcher.GetConsensusView().IsSameProducers(curProducers)
   249  					if !isSame {
   250  						go p.AnnounceDAddr()
   251  					} else {
   252  						log.Info("For the same batch of aribters, no need to re-connect direct net")
   253  					}
   254  				}
   255  			}
   256  		case dpos.ETSmallCroTx:
   257  			if croTx, ok := e.Data.(*smallcrosstx.ETSmallCrossTx); ok {
   258  				msg := dmsg.NewSmallCroTx(croTx.Signature, croTx.RawTx)
   259  				p.BroadMessage(msg)
   260  			}
   261  
   262  		case dpos.ETFailedWithdrawTx:
   263  			if failEvt, ok := e.Data.(*withdrawfailedtx.FailedWithdrawEvent); ok {
   264  				msg := dmsg.NewFailedWithdrawTx(failEvt.Signature, failEvt.Txid)
   265  				p.BroadMessage(msg)
   266  			}
   267  		}
   268  	})
   269  }
   270  
   271  func (p *Pbft) IsSameProducers(curProducers [][]byte) bool {
   272  	return p.dispatcher.GetConsensusView().IsSameProducers(curProducers)
   273  }
   274  
   275  func (p *Pbft) IsCurrentProducers(curProducers [][]byte) bool {
   276  	return p.dispatcher.GetConsensusView().IsCurrentProducers(curProducers)
   277  }
   278  
   279  func (p *Pbft) GetDataDir() string {
   280  	return p.datadir
   281  }
   282  
   283  func (p *Pbft) GetPbftConfig() params.PbftConfig {
   284  	return p.cfg
   285  }
   286  
   287  func (p *Pbft) CurrentBlock() *types.Block {
   288  	if p.chain == nil {
   289  		return nil
   290  	}
   291  	return p.chain.CurrentBlock()
   292  }
   293  
   294  func (p *Pbft) GetBlockByHeight(height uint64) *types.Block {
   295  	if p.chain == nil {
   296  		return nil
   297  	}
   298  	return p.chain.GetBlockByNumber(height)
   299  }
   300  
   301  func (p *Pbft) Author(header *types.Header) (common.Address, error) {
   302  	return header.Coinbase, nil
   303  }
   304  
   305  func (p *Pbft) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error {
   306  	dpos.Info("Pbft VerifyHeader")
   307  	return p.verifyHeader(chain, header, nil, seal)
   308  }
   309  
   310  func (p *Pbft) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) {
   311  	dpos.Info("Pbft VerifyHeaders")
   312  	abort := make(chan struct{})
   313  	results := make(chan error, len(headers))
   314  
   315  	go func() {
   316  		for i, header := range headers {
   317  			var err error
   318  			//Check header is verified
   319  			if seals[i] {
   320  				// Don't waste time checking blocks from the future
   321  				if header.Time > uint64(time.Now().Unix()) {
   322  					err = consensus.ErrFutureBlock
   323  				}
   324  			}
   325  			if err == nil && !p.IsInBlockPool(p.SealHash(header)) {
   326  				err = p.verifyHeader(chain, header, headers[:i], seals[i])
   327  			} else if err == nil {
   328  				err = p.verifySeal(chain, header, headers[:i])
   329  			}
   330  
   331  			select {
   332  			case <-abort:
   333  				return
   334  			case results <- err:
   335  			}
   336  		}
   337  	}()
   338  	return abort, results
   339  }
   340  
   341  func (p *Pbft) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header, seal bool) error {
   342  
   343  	if header.Number == nil || header.Number.Uint64() == 0 {
   344  		return errUnknownBlock
   345  	}
   346  	// Don't waste time checking blocks from the future
   347  	if seal && header.Time > uint64(time.Now().Unix()) {
   348  		return consensus.ErrFutureBlock
   349  	}
   350  
   351  	// Verify that the gas limit is <= 2^63-1
   352  	cap := uint64(0x7fffffffffffffff)
   353  	if header.GasLimit > cap {
   354  		return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap)
   355  	}
   356  	// Verify that the gasUsed is <= gasLimit
   357  	if header.GasUsed > header.GasLimit {
   358  		return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
   359  	}
   360  	// Ensure that the mix digest is zero as we don't have fork protection currently
   361  	if header.MixDigest != (common.Hash{}) {
   362  		return errInvalidMixDigest
   363  	}
   364  	// Ensure that the block doesn't contain any uncles which are meaningless in Pbft
   365  	if header.UncleHash != types.CalcUncleHash(nil) {
   366  		return errInvalidUncleHash
   367  	}
   368  
   369  	number := header.Number.Uint64()
   370  	var parent *types.Header
   371  	if len(parents) > 0 {
   372  		parent = parents[len(parents)-1]
   373  	} else {
   374  		parent = chain.GetHeader(header.ParentHash, number-1)
   375  	}
   376  	if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash {
   377  		return consensus.ErrUnknownAncestor
   378  	}
   379  	log.Info("verify header HasConfirmed", "seal:", seal, "height", header.Number)
   380  	if !seal && p.dispatcher.GetFinishedHeight() == number {
   381  		log.Warn("verify header already confirm block")
   382  		return ErrAlreadyConfirmedBlock
   383  	}
   384  
   385  	if parent.Time+p.period > header.Time {
   386  		return ErrInvalidTimestamp
   387  	}
   388  
   389  	if number > 0 {
   390  		if header.Difficulty == nil || (header.Difficulty.Cmp(diffInTurn) != 0) {
   391  			return errInvalidDifficulty
   392  		}
   393  	}
   394  
   395  	if seal {
   396  		return p.verifySeal(chain, header, parents)
   397  	}
   398  
   399  	return nil
   400  }
   401  
   402  func (p *Pbft) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
   403  	dpos.Info("Pbft VerifyUncles")
   404  	if len(block.Uncles()) > 0 {
   405  		return errors.New("uncles not allowed")
   406  	}
   407  	return nil
   408  }
   409  
   410  func (p *Pbft) VerifySeal(chain consensus.ChainReader, header *types.Header) error {
   411  	dpos.Info("Pbft VerifySeal")
   412  	return p.verifySeal(chain, header, nil)
   413  }
   414  
   415  func (p *Pbft) verifySeal(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error {
   416  	// Verifying the genesis block is not supported
   417  	number := header.Number.Uint64()
   418  	if number == 0 {
   419  		return errUnknownBlock
   420  	}
   421  
   422  	// Retrieve the confirm from the header extra-data
   423  	var confirm payload.Confirm
   424  	err := confirm.Deserialize(bytes.NewReader(header.Extra))
   425  	if err != nil {
   426  		return err
   427  	}
   428  	err = p.verifyConfirm(&confirm, header.Nonce.Uint64())
   429  	if err != nil {
   430  		return err
   431  	}
   432  
   433  	if oldHeader := chain.GetHeaderByNumber(number); oldHeader != nil {
   434  		var oldConfirm payload.Confirm
   435  		err := oldConfirm.Deserialize(bytes.NewReader(oldHeader.Extra))
   436  		if err != nil {
   437  			return nil
   438  		}
   439  
   440  		if confirm.Proposal.ViewOffset < oldConfirm.Proposal.ViewOffset && number < chain.CurrentHeader().Number.Uint64() {
   441  			log.Warn("verify seal chain fork", "oldViewOffset", oldConfirm.Proposal.ViewOffset, "newViewOffset", confirm.Proposal.ViewOffset, "height", number)
   442  			//return errChainForkBlock
   443  		}
   444  		if confirm.Proposal.ViewOffset == oldConfirm.Proposal.ViewOffset && oldHeader.Hash() != header.Hash() {
   445  			return errDoubleSignBlock
   446  		}
   447  	}
   448  
   449  	return nil
   450  }
   451  
   452  func (p *Pbft) Prepare(chain consensus.ChainReader, header *types.Header) error {
   453  	log.Info("Pbft Prepare:", "height:", header.Number.Uint64(), "parent", header.ParentHash.String())
   454  	p.isSealOver = false
   455  	nowTime := uint64(time.Now().Unix())
   456  	if p.dispatcher != nil {
   457  		nowTime = uint64(p.dispatcher.GetNowTime().Unix())
   458  	}
   459  	header.Difficulty = p.CalcDifficulty(chain, nowTime, nil)
   460  	if p.dispatcher != nil {
   461  		header.Nonce = types.EncodeNonce(p.dispatcher.GetConsensusView().GetSpvHeight())
   462  	}
   463  	parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
   464  	if parent == nil {
   465  		return consensus.ErrUnknownAncestor
   466  	}
   467  	if !p.isRecoved {
   468  		return ErrWaitRecoverStatus
   469  	}
   470  	if p.dispatcher.GetConsensusView().IsRunning() && p.enableViewLoop {
   471  		return ErrConsensusIsRunning
   472  	}
   473  	p.Start(parent.Time)
   474  	header.Time = parent.Time + p.period
   475  	if header.Time < nowTime {
   476  		header.Time = nowTime
   477  		p.dispatcher.ResetView(nowTime)
   478  	}
   479  	if !p.IsOnduty() {
   480  		return ErrSignerNotOnduty
   481  	}
   482  	if header.Number.Uint64() <= p.dispatcher.GetFinishedHeight() {
   483  		return ErrAlreadyConfirmedBlock
   484  	}
   485  	return nil
   486  }
   487  
   488  func (p *Pbft) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
   489  	uncles []*types.Header) {
   490  	dpos.Info("Pbft Finalize:", "height:", header.Number.Uint64())
   491  	sealHash := p.SealHash(header)
   492  	hash, _ := ecom.Uint256FromBytes(sealHash.Bytes())
   493  	p.dispatcher.FinishedProposal(header.Number.Uint64(), *hash, header.Time)
   494  	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
   495  	header.UncleHash = types.CalcUncleHash(nil)
   496  	p.CleanFinalConfirmedBlock(header.Number.Uint64())
   497  }
   498  
   499  func (p *Pbft) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
   500  	uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
   501  	dpos.Info("Pbft FinalizeAndAssemble")
   502  	// No block rewards in DPoS, so the state remains as is and uncles are dropped
   503  	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
   504  	header.UncleHash = types.CalcUncleHash(nil)
   505  
   506  	// Assemble and return the final block for sealing
   507  	return types.NewBlock(header, txs, nil, receipts), nil
   508  }
   509  
   510  func (p *Pbft) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
   511  	dpos.Info("Pbft Seal:", block.NumberU64())
   512  	if p.account == nil {
   513  		return errors.New("no signer inited")
   514  	}
   515  
   516  	if !p.isRecoved {
   517  		return ErrWaitRecoverStatus
   518  	}
   519  
   520  	parent := chain.GetHeader(block.ParentHash(), block.NumberU64()-1)
   521  	if parent == nil {
   522  		return consensus.ErrUnknownAncestor
   523  	}
   524  
   525  	if block.NumberU64() <= p.dispatcher.GetFinishedHeight() {
   526  		return ErrAlreadyConfirmedBlock
   527  	}
   528  	if !p.IsProducer() {
   529  		return errUnauthorizedSigner
   530  	}
   531  	if !p.IsOnduty() {
   532  		return ErrSignerNotOnduty
   533  	}
   534  	p.BroadBlockMsg(block)
   535  
   536  	if err := p.StartProposal(block); err != nil {
   537  		return err
   538  	}
   539  	p.isSealOver = false
   540  	header := block.Header()
   541  	//Waiting for statistics of voting results
   542  	delay := time.Unix(int64(header.Time), 0).Sub(p.dispatcher.GetNowTime())
   543  	log.Info("wait seal time", "delay", delay)
   544  	time.Sleep(delay)
   545  	changeViewTime := p.dispatcher.GetConsensusView().GetChangeViewTime()
   546  	toleranceDelay := changeViewTime.Sub(p.dispatcher.GetNowTime())
   547  	log.Info("changeViewLeftTime", "toleranceDelay", toleranceDelay)
   548  	select {
   549  	case confirm := <-p.confirmCh:
   550  		log.Info("Received confirmCh", "proposal", confirm.Proposal.Hash().String(), "block:", block.NumberU64())
   551  		p.addConfirmToBlock(header, confirm)
   552  		p.isSealOver = true
   553  		break
   554  	case <-p.unConfirmCh:
   555  		log.Warn("proposal is rejected")
   556  		p.isSealOver = true
   557  		return nil
   558  	case <-time.After(toleranceDelay):
   559  		log.Warn("seal time out stop mine")
   560  		p.isSealOver = true
   561  		return nil
   562  	case <-stop:
   563  		log.Warn("pbft seal is stop")
   564  		p.isSealOver = true
   565  		return nil
   566  	}
   567  	finalBlock := block.WithSeal(header)
   568  	go func() {
   569  		select {
   570  		case results <- finalBlock:
   571  			p.BroadBlockMsg(finalBlock)
   572  			p.CleanFinalConfirmedBlock(block.NumberU64())
   573  		default:
   574  			dpos.Warn("Sealing result is not read by miner", "sealhash", SealHash(header))
   575  		}
   576  	}()
   577  
   578  	return nil
   579  }
   580  
   581  func (p *Pbft) addConfirmToBlock(header *types.Header, confirm *payload.Confirm) error {
   582  	sealBuf := new(bytes.Buffer)
   583  	if err := confirm.Serialize(sealBuf); err != nil {
   584  		log.Error("confirm serialize error", "error", err)
   585  		return err
   586  	}
   587  	header.Extra = make([]byte, sealBuf.Len())
   588  	copy(header.Extra[:], sealBuf.Bytes()[:])
   589  	sealHash := SealHash(header)
   590  	hash, _ := ecom.Uint256FromBytes(sealHash.Bytes())
   591  	p.dispatcher.FinishedProposal(header.Number.Uint64(), *hash, header.Time)
   592  	return nil
   593  }
   594  
   595  func (p *Pbft) onConfirm(confirm *payload.Confirm) error {
   596  	log.Info("--------[onConfirm]------", "proposal:", confirm.Proposal.Hash())
   597  	if p.isSealOver && p.IsOnduty() {
   598  		log.Warn("seal block is over, can't confirm")
   599  		return errors.New("seal block is over, can't confirm")
   600  	}
   601  	err := p.blockPool.AppendConfirm(confirm)
   602  	if err != nil {
   603  		log.Error("Received confirm", "proposal", confirm.Proposal.Hash().String(), "err:", err)
   604  		return err
   605  	}
   606  	if p.IsOnduty() {
   607  		log.Info("on duty, set confirm block")
   608  		p.confirmCh <- confirm
   609  	} else {
   610  		log.Info("not on duty, not broad confirm block")
   611  	}
   612  
   613  	return err
   614  }
   615  
   616  func (p *Pbft) onUnConfirm(unconfirm *payload.Confirm) error {
   617  	log.Info("--------[onUnConfirm]------", "proposal:", unconfirm.Proposal.Hash())
   618  	if p.isSealOver {
   619  		return errors.New("seal block is over, can't unconfirm")
   620  	}
   621  	if p.IsOnduty() {
   622  		p.unConfirmCh <- unconfirm
   623  	}
   624  	return nil
   625  }
   626  
   627  func (p *Pbft) SealHash(header *types.Header) common.Hash {
   628  	return SealHash(header)
   629  }
   630  
   631  func (p *Pbft) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int {
   632  	dpos.Info("Pbft CalcDifficulty")
   633  	if p.IsOnduty() {
   634  		return diffInTurn
   635  	}
   636  	return diffNoTurn
   637  }
   638  
   639  func (p *Pbft) APIs(chain consensus.ChainReader) []rpc.API {
   640  	return []rpc.API{{
   641  		Namespace: "pbft",
   642  		Version:   "1.0",
   643  		Service:   &API{chain: chain, pbft: p},
   644  		Public:    false,
   645  	}}
   646  }
   647  
   648  func (p *Pbft) Close() error {
   649  	dpos.Info("Pbft Close")
   650  	p.enableViewLoop = false
   651  	return nil
   652  }
   653  
   654  func (p *Pbft) SignersCount() int {
   655  	dpos.Info("Pbft SignersCount")
   656  	count := p.dispatcher.GetConsensusView().GetTotalProducersCount()
   657  	return count
   658  }
   659  
   660  // SealHash returns the hash of a block prior to it being sealed.
   661  func SealHash(header *types.Header) (hash common.Hash) {
   662  	hasher := sha3.NewLegacyKeccak256()
   663  	encodeSigHeader(hasher, header)
   664  	hasher.Sum(hash[:0])
   665  	return hash
   666  }
   667  
   668  func DBlockSealHash(block dpos.DBlock) (hash ecom.Uint256, err error) {
   669  	if b, ok := block.(*types.Block); ok {
   670  		hasher := sha3.NewLegacyKeccak256()
   671  		encodeSigHeader(hasher, b.Header())
   672  		hasher.Sum(hash[:0])
   673  		return hash, nil
   674  	} else {
   675  		return ecom.EmptyHash, errors.New("verifyBlock errror, block is not ethereum block")
   676  	}
   677  }
   678  
   679  func encodeSigHeader(w io.Writer, header *types.Header) {
   680  	err := rlp.Encode(w, []interface{}{
   681  		header.ParentHash,
   682  		header.UncleHash,
   683  		header.Coinbase,
   684  		header.Root,
   685  		header.TxHash,
   686  		header.ReceiptHash,
   687  		header.Bloom,
   688  		header.Difficulty,
   689  		header.Number,
   690  		header.GasLimit,
   691  		header.GasUsed,
   692  		header.Time,
   693  		//header.Extra[:len(header.Extra)-crypto.SignatureLength], // Yes, this will panic if extra is too short
   694  		header.MixDigest,
   695  		header.Nonce,
   696  	})
   697  	if err != nil {
   698  		panic("can't encode: " + err.Error())
   699  	}
   700  }
   701  
   702  func (p *Pbft) AddDirectLinkPeer(pid peer.PID, addr string) {
   703  	if p.network != nil {
   704  		p.network.AddDirectLinkAddr(pid, addr)
   705  	}
   706  }
   707  
   708  func (p *Pbft) GetActivePeersCount() int {
   709  	if p.network != nil {
   710  		return len(p.network.GetActivePeers())
   711  	}
   712  	return 0
   713  }
   714  
   715  func (p *Pbft) StartServer() {
   716  	if p.network != nil {
   717  		p.network.Start()
   718  		p.Recover()
   719  	}
   720  }
   721  
   722  func (p *Pbft) StopServer() {
   723  	if p.network != nil {
   724  		p.network.Stop()
   725  	}
   726  	p.enableViewLoop = false
   727  }
   728  
   729  func (p *Pbft) Start(headerTime uint64) {
   730  	if p.account == nil {
   731  		return
   732  	}
   733  	if !p.enableViewLoop {
   734  		p.enableViewLoop = true
   735  		p.dispatcher.GetConsensusView().SetChangViewTime(headerTime)
   736  		p.dispatcher.GetConsensusView().UpdateDutyIndex(p.chain.CurrentBlock().NumberU64())
   737  		go p.changeViewLoop()
   738  	} else {
   739  		p.dispatcher.ResetView(headerTime)
   740  	}
   741  	p.dispatcher.GetConsensusView().SetRunning()
   742  }
   743  
   744  func (p *Pbft) changeViewLoop() {
   745  	for p.enableViewLoop {
   746  		p.network.PostChangeViewTask()
   747  		time.Sleep(1 * time.Second)
   748  	}
   749  }
   750  
   751  func (p *Pbft) Recover() {
   752  	if p.IsCurrent == nil || p.account == nil || p.isRecovering ||
   753  		!p.dispatcher.IsProducer(p.account.PublicKeyBytes()) {
   754  		log.Info(" Recover Error")
   755  		p.dispatcher.GetConsensusView().DumpInfo()
   756  		return
   757  	}
   758  	p.isRecovering = true
   759  	for {
   760  		if p.IsCurrent() && len(p.network.GetActivePeers()) > 0 &&
   761  			p.dispatcher.GetConsensusView().HasProducerMajorityCount(len(p.network.GetActivePeers())) {
   762  			log.Info("----- PostRecoverTask --------", "GetActivePeers", len(p.network.GetActivePeers()), "total", len(p.dispatcher.GetConsensusView().GetProducers()))
   763  			p.network.PostRecoverTask()
   764  			p.isRecovering = false
   765  			return
   766  		}
   767  		time.Sleep(time.Second)
   768  	}
   769  }
   770  
   771  func (p *Pbft) IsOnduty() bool {
   772  	if p.account == nil {
   773  		return false
   774  	}
   775  	return p.dispatcher.ProducerIsOnDuty()
   776  }
   777  
   778  func (p *Pbft) IsProducer() bool {
   779  	if p.account == nil {
   780  		return false
   781  	}
   782  	return p.dispatcher.IsProducer(p.account.PublicKeyBytes())
   783  }
   784  
   785  func (p *Pbft) SetBlockChain(chain *core.BlockChain) {
   786  	p.chain = chain
   787  }
   788  
   789  func (p *Pbft) GetBlockChain() *core.BlockChain {
   790  	return p.chain
   791  }
   792  
   793  func (p *Pbft) broadConfirmMsg(confirm *payload.Confirm, height uint64) {
   794  	msg := dmsg.NewConfirmMsg(confirm, height)
   795  	p.BroadMessage(msg)
   796  }
   797  
   798  func (p *Pbft) verifyConfirm(confirm *payload.Confirm, elaHeight uint64) error {
   799  	minSignCount := 0
   800  	if elaHeight == 0 {
   801  		minSignCount = p.dispatcher.GetConsensusView().GetCRMajorityCount()
   802  	} else {
   803  		_, count, err := spv.GetProducers(elaHeight)
   804  		if err != nil {
   805  			return err
   806  		}
   807  		minSignCount = p.dispatcher.GetConsensusView().GetMajorityCountByTotalSigners(count)
   808  	}
   809  	err := dpos.CheckConfirm(confirm, minSignCount)
   810  	return err
   811  }
   812  
   813  func (p *Pbft) verifyBlock(block dpos.DBlock) error {
   814  	if p.chain == nil {
   815  		return errors.New("pbft chain is nil")
   816  	}
   817  	if b, ok := block.(*types.Block); ok {
   818  		err := p.VerifyHeader(p.chain, b.Header(), false)
   819  		if err != nil {
   820  			return err
   821  		}
   822  		err = p.chain.Validator().ValidateBody(b)
   823  		if err != nil {
   824  			log.Error("validateBody error", "height:", b.GetHeight())
   825  			return err
   826  		}
   827  	} else {
   828  		return errors.New("verifyBlock errror, block is not ethereum block")
   829  	}
   830  
   831  	return nil
   832  }
   833  
   834  func (p *Pbft) IsInBlockPool(hash common.Hash) bool {
   835  	if u256, err := ecom.Uint256FromBytes(hash.Bytes()); err == nil {
   836  		_, suc := p.blockPool.GetBlock(*u256)
   837  		return suc
   838  	}
   839  	return false
   840  }
   841  
   842  func (p *Pbft) CleanFinalConfirmedBlock(height uint64) {
   843  	p.blockPool.CleanFinalConfirmedBlock(height)
   844  }
   845  
   846  func (p *Pbft) OnViewChanged(isOnDuty bool, force bool) {
   847  	if isOnDuty && p.OnDuty != nil {
   848  		p.OnDuty()
   849  	}
   850  	proposal := p.dispatcher.UpdatePrecociousProposals()
   851  	if proposal != nil {
   852  		log.Info("UpdatePrecociousProposals process proposal")
   853  		p.OnProposalReceived(peer.PID{}, proposal)
   854  	}
   855  
   856  	if !force {
   857  		p.dispatcher.CleanProposals(true)
   858  		if p.IsCurrent() && isOnDuty {
   859  			log.Info("---------startMine()-------")
   860  			p.dispatcher.GetConsensusView().SetReady()
   861  			p.StartMine()
   862  		}
   863  	}
   864  }
   865  
   866  func (p *Pbft) GetTimeSource() dtime.MedianTimeSource {
   867  	return p.timeSource
   868  }
   869  
   870  func (p *Pbft) IsBadBlock(height uint64) bool {
   871  	blocks := p.chain.BadBlocks()
   872  	for _, block := range blocks {
   873  		if block.GetHeight() == height {
   874  			return true
   875  		}
   876  	}
   877  	return false
   878  }
   879  
   880  func (p *Pbft) GetDposAccount() daccount.Account {
   881  	return p.account
   882  }
   883  
   884  func (p *Pbft) IsOnDuty() bool {
   885  	return p.dispatcher.ProducerIsOnDuty()
   886  }