github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/consensus/dpos/bft.go (about)

     1  // Copyright 2019 The go-vnt Authors
     2  // This file is part of the go-vnt library.
     3  //
     4  // The go-vnt library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-vnt library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-vnt library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package dpos
    18  
    19  import (
    20  	"fmt"
    21  	"math/big"
    22  	"sync"
    23  	"sync/atomic"
    24  	"time"
    25  
    26  	"github.com/vntchain/go-vnt/common"
    27  	"github.com/vntchain/go-vnt/core/types"
    28  	"github.com/vntchain/go-vnt/log"
    29  )
    30  
    31  // BFT step
    32  const (
    33  	newRound    = uint32(0)
    34  	prePrePared = uint32(1)
    35  	preparing   = uint32(2)
    36  	prepared    = uint32(3)
    37  	committing  = uint32(4)
    38  	committed   = uint32(5)
    39  	done        = uint32(6)
    40  )
    41  
    42  type BftManager struct {
    43  	dp       *Dpos // DPoS object
    44  	quorum   int   // 2f+1
    45  	coinBase common.Address
    46  
    47  	mp      *msgPool // message pool of all future round bft messages, and not verified
    48  	roundMp *msgPool // message pool of current round, and been verified
    49  
    50  	// BFT state
    51  	h           *big.Int                    // local block chain height, protect by newRoundRWLock
    52  	r           uint32                      // local BFT round, protect by newRoundRWLock
    53  	step        uint32                      // local BFT round, protect by atomic operation
    54  	witnessList map[common.Address]struct{} // current witness list, rely on producing
    55  
    56  	newRoundRWLock sync.RWMutex // RW lock for switch to new round
    57  
    58  	blockRound uint32 // round of sealing block, no need lock
    59  	producing  uint32 // producing or not, atomic read and write
    60  
    61  	// callbacks
    62  	sendBftMsg  func(types.ConsensusMsg)
    63  	verifyBlock func(*types.Block) (types.Receipts, []*types.Log, uint64, error)
    64  	writeBlock  func(*types.Block) error
    65  }
    66  
    67  func newBftManager(dp *Dpos) *BftManager {
    68  	n := dp.config.WitnessesNum
    69  	q := n - (n-1)/3 // N-f
    70  	return &BftManager{
    71  		dp:          dp,
    72  		quorum:      q,
    73  		mp:          newMsgPool(q, "msg pool"),
    74  		roundMp:     newMsgPool(q, "round msg pool"),
    75  		h:           big.NewInt(0),
    76  		r:           0,
    77  		step:        newRound,
    78  		witnessList: make(map[common.Address]struct{}, dp.config.WitnessesNum),
    79  		producing:   0,
    80  	}
    81  }
    82  
    83  // startPrePrepare will send pre-prepare msg and prepare msg
    84  func (b *BftManager) startPrePrepare(block *types.Block) {
    85  	log.Trace("Start PrePrepare")
    86  
    87  	prePreMsg := b.makePrePrepareMsg(block, b.blockRound)
    88  
    89  	// This node is a witness, which can seal block, no need check again
    90  	b.sendBftMsg(prePreMsg)
    91  
    92  	// startPrePrepare may be execute before newRound, so calling handleBftMsg
    93  	// to check round
    94  	go b.handleBftMsg(prePreMsg)
    95  }
    96  
    97  func (b *BftManager) handleBftMsg(msg types.ConsensusMsg) error {
    98  	msgBlkNum, msgHash, msgType, msgRound := msg.GetBlockNum(), msg.Hash(), msg.Type(), msg.GetRound()
    99  	if msgBlkNum == nil {
   100  		return fmt.Errorf("bft msg's height is empty")
   101  	}
   102  
   103  	log.Trace("Handle bft msg", "type", msgType.String(),
   104  		"number", msgBlkNum.Uint64(), "round", msgRound, "hash", msgHash)
   105  
   106  	// Read lock for critical section
   107  	b.newRoundRWLock.RLock()
   108  	defer func() {
   109  		b.newRoundRWLock.RUnlock()
   110  		log.Trace("handle msg end", "hash", msgHash)
   111  	}()
   112  
   113  	// If not producing, no need deal with these bft msg right now,
   114  	// save to msg pool, if you are witness and producing after sync,
   115  	// you will fast deal with these msg.
   116  	if atomic.LoadUint32(&b.producing) == 0 {
   117  		_ = b.mp.addMsg(msg)
   118  		log.Debug("HandleBftMsg: return for not producing")
   119  		return nil
   120  	}
   121  
   122  	// 比较高度
   123  	blkNumCmp := msgBlkNum.Cmp(b.h)
   124  	if blkNumCmp > 0 {
   125  		if err := b.mp.addMsg(msg); err != nil {
   126  			log.Error("add prepare msg to msg pool error", "err", err)
   127  			return err
   128  		}
   129  		if prePrepareMsg, ok := msg.(*types.PreprepareMsg); ok {
   130  			go b.startSync(prePrepareMsg.Block)
   131  		}
   132  		return nil
   133  	} else if blkNumCmp < 0 {
   134  		// 比当前高度消息的msg,暂时先直接舍弃掉
   135  		return fmt.Errorf("the height of msg is lower than current height, msg height :%d, current height : %d", msgBlkNum, b.h)
   136  	}
   137  
   138  	// 高度一致比较轮次
   139  	if msgRound < b.r {
   140  		return fmt.Errorf("the round of msg is lower than current round, msg round :%d, current round : %d", msgRound, b.r)
   141  	} else if msgRound > b.r {
   142  		if err := b.mp.addMsg(msg); err != nil {
   143  			log.Error("add msg to msg pool error", "err", err)
   144  			return err
   145  		}
   146  		return nil
   147  	}
   148  
   149  	switch msgType {
   150  	case types.BftPreprepareMessage:
   151  		return b.handlePrePrepareMsg(msg.(*types.PreprepareMsg))
   152  	case types.BftPrepareMessage:
   153  		return b.handlePrepareMsg(msg.(*types.PrepareMsg))
   154  	case types.BftCommitMessage:
   155  		return b.handleCommitMsg(msg.(*types.CommitMsg))
   156  	default:
   157  		log.Error("unknown bft message", "type", msgType.String())
   158  		return fmt.Errorf("unknown bft message type: %s", msgType.String())
   159  	}
   160  }
   161  
   162  // handlePrePrepareMsg
   163  // WARN: msg pool has only one pre-prepare msg position, only the first correct one can be
   164  // saved to msg pool. No need to care about you will vote for two pre-prepare msg. You only
   165  // vote for the pre-prepare msg in msg pool.
   166  func (b *BftManager) handlePrePrepareMsg(msg *types.PreprepareMsg) error {
   167  	log.Trace("HandlePrePrepareMsg")
   168  	defer log.Trace("HandlePrePrepareMsg exit")
   169  
   170  	// check bft step, should be at newRound
   171  	stp := atomic.LoadUint32(&b.step)
   172  	if stp != newRound {
   173  		log.Debug("Pre-prepare msg bft step not match", "local round", stp)
   174  		return nil
   175  	}
   176  
   177  	// Verify msg
   178  	if err := b.verifyPrePrepareMsg(msg); err != nil {
   179  		log.Debug("Pre-prepare msg is invalid", "error", err)
   180  		return err
   181  	}
   182  	if _, _, _, err := b.verifyBlock(msg.Block); err != nil {
   183  		log.Debug("Pre-prepare's block is invalid", "error", err)
   184  		return nil
   185  	} else {
   186  		log.Debug("Pre-prepare block is valid")
   187  	}
   188  
   189  	log.Trace("HandlePrePrepareMsg verified block")
   190  
   191  	// Add msg to round msg pool, instead of msg pool
   192  	if err := b.roundMp.addMsg(msg); err != nil {
   193  		log.Warn("Add pre-prepare msg failed", "error", err)
   194  		return err
   195  	}
   196  
   197  	log.Trace("HandlePrePrepareMsg msg has been add to round msg pool")
   198  
   199  	// Go to next step
   200  	if ok := atomic.CompareAndSwapUint32(&b.step, newRound, prePrePared); ok {
   201  		return b.startPrepare()
   202  	}
   203  	return nil
   204  }
   205  
   206  // startPrepare enter prepare step, whether
   207  func (b *BftManager) startPrepare() error {
   208  	log.Trace("StartPrepare")
   209  	defer log.Trace("StartPrepare exit")
   210  
   211  	// check our state and make a prepare msg
   212  	if atomic.LoadUint32(&b.step) != prePrePared {
   213  		return nil
   214  	}
   215  	prePreMsg, err := b.roundMp.getPrePrepareMsg(b.h, b.r)
   216  	if err != nil {
   217  		log.Error("Get pre-prepare msg from msg pool in prepare", "error", err)
   218  		return fmt.Errorf("get pre-prepare msg from msg pool, error: %s", err)
   219  	}
   220  	preMsg, err := b.makePrepareMsg(prePreMsg)
   221  	if err != nil {
   222  		return err
   223  	}
   224  	if err := b.roundMp.addMsg(preMsg); err != nil {
   225  		return err
   226  	}
   227  
   228  	// The one of first changing step, send the msg
   229  	if ok := atomic.CompareAndSwapUint32(&b.step, prePrePared, preparing); ok {
   230  		b.sendMsg(preMsg)
   231  	}
   232  
   233  	// Maybe have enough prepare msg to enter commit, when pre-prepare msg comes after prepare msg
   234  	return b.tryCommitStep()
   235  }
   236  
   237  // tryCommitStep check whether can enter commit step
   238  func (b *BftManager) tryCommitStep() error {
   239  	log.Trace("tryCommitStep")
   240  	defer log.Trace("tryCommitStep exit")
   241  
   242  	stp := atomic.LoadUint32(&b.step)
   243  	if stp < preparing || stp > prepared {
   244  		log.Debug("tryCommitStep step not match", "step", stp)
   245  		return nil
   246  	}
   247  
   248  	var (
   249  		prePreMsg   *types.PreprepareMsg
   250  		prepareMsgs []*types.PrepareMsg
   251  		err         error
   252  	)
   253  	if prepareMsgs, err = b.roundMp.getTwoThirdMajorityPrepareMsg(b.h, b.r); err != nil {
   254  		return nil
   255  	}
   256  	if prePreMsg, err = b.roundMp.getPrePrepareMsg(b.h, b.r); err != nil {
   257  		log.Error("Get pre-prepare msg from msg pool in try commit", "error", err)
   258  		return fmt.Errorf("get pre-prepare msg from msg pool, error: %s", err)
   259  	}
   260  	if prePreMsg.Block.Hash() != prepareMsgs[0].BlockHash {
   261  		log.Error("Majority prepare msg is not match with pre-prepare msg", "block in prepare",
   262  			prepareMsgs[0].BlockHash, "block in pre-prepare", prePreMsg.Block.Hash())
   263  		return fmt.Errorf("majority prepare msg is not match with pre-prepare msg")
   264  	}
   265  	atomic.CompareAndSwapUint32(&b.step, preparing, prepared)
   266  	return b.startCommit(prePreMsg)
   267  }
   268  
   269  // startCommit build commit message and send it
   270  func (b *BftManager) startCommit(prePreMsg *types.PreprepareMsg) error {
   271  	log.Trace("StartCommit")
   272  	defer log.Trace("StartCommit exit")
   273  
   274  	if atomic.LoadUint32(&b.step) != prepared {
   275  		return nil
   276  	}
   277  
   278  	commitMsg, err := b.makeCommitMsg(prePreMsg)
   279  	if err != nil {
   280  		return err
   281  	}
   282  	if err := b.roundMp.addMsg(commitMsg); err != nil {
   283  		return err
   284  	}
   285  
   286  	// The one of first changing step, send the msg
   287  	if ok := atomic.CompareAndSwapUint32(&b.step, prepared, committing); ok {
   288  		b.sendMsg(commitMsg)
   289  	}
   290  
   291  	return b.tryWriteBlockStep()
   292  }
   293  
   294  // sendMsg only witness send bft message.
   295  // Caller make sure has the newRoundRWLock.
   296  func (b *BftManager) sendMsg(msg types.ConsensusMsg) {
   297  	log.Trace("bft sendMsg start")
   298  	if _, ok := b.witnessList[b.coinBase]; ok {
   299  		b.sendBftMsg(msg)
   300  	}
   301  	log.Trace("bft sendMsg success")
   302  }
   303  
   304  func (b *BftManager) tryWriteBlockStep() error {
   305  	log.Trace("TryWriteBlockStep")
   306  	defer log.Trace("TryWriteBlockStep exit")
   307  
   308  	if atomic.LoadUint32(&b.step) != committing {
   309  		return nil
   310  	}
   311  	// commit消息满足数量要求后写区块
   312  	if commitMsgs, err := b.roundMp.getTwoThirdMajorityCommitMsg(b.h, b.r); err != nil {
   313  		return nil
   314  	} else if ok := atomic.CompareAndSwapUint32(&b.step, committing, committed); ok {
   315  		if prePrepareMsg, err := b.roundMp.getPrePrepareMsg(b.h, b.r); err != nil {
   316  			log.Error("Get pre-prepare msg from msg pool in try write block", "err", err)
   317  			return fmt.Errorf("get pre-prepare msg from msg pool, error: %s", err)
   318  		} else {
   319  			if err := b.writeBlockWithSig(prePrepareMsg, commitMsgs); err != nil {
   320  				log.Error("Write block to chain", "err", err)
   321  				return fmt.Errorf("write block to chain error: %s", err)
   322  			}
   323  			atomic.CompareAndSwapUint32(&b.step, committed, done)
   324  		}
   325  	}
   326  	return nil
   327  }
   328  
   329  func (b *BftManager) handlePrepareMsg(msg *types.PrepareMsg) error {
   330  	stp := atomic.LoadUint32(&b.step)
   331  	// 当前阶段大于preparing,则prepare消息已经没用了,直接舍弃
   332  	if stp > preparing {
   333  		log.Debug("prepare msg bft step not match", "local step", stp)
   334  		return nil
   335  	}
   336  
   337  	if err := b.verifyPrepareMsg(msg); err != nil {
   338  		log.Error("failed to verify prepare msg", "err", err)
   339  		return err
   340  	}
   341  	if err := b.roundMp.addMsg(msg); err != nil {
   342  		log.Error("failed to add prepare msg", "height", b.h, "round", b.r, "err", err)
   343  		return err
   344  	}
   345  
   346  	return b.tryCommitStep()
   347  }
   348  
   349  func (b *BftManager) handleCommitMsg(msg *types.CommitMsg) error {
   350  	stp := atomic.LoadUint32(&b.step)
   351  	// 当前阶段大于committing,则commit消息已经没用了,直接舍弃
   352  	if stp > committing {
   353  		log.Debug("commit msg bft step not match", "local step", stp)
   354  		return nil
   355  	}
   356  	if err := b.verifyCommitMsg(msg); err != nil {
   357  		log.Error("failed to verify commit msg", "err", err)
   358  		return err
   359  	}
   360  	if err := b.roundMp.addMsg(msg); err != nil {
   361  		log.Error("failed to add commit msg", "height", b.h, "round", b.r, "err", err)
   362  		return err
   363  	}
   364  
   365  	return b.tryWriteBlockStep()
   366  }
   367  
   368  // writeBlock to block chain
   369  func (b *BftManager) writeBlockWithSig(msg *types.PreprepareMsg, cmtMsg []*types.CommitMsg) error {
   370  	block := msg.Block
   371  	// Match pre-prepare msg and commit msg
   372  	if block.Hash() != cmtMsg[0].BlockHash {
   373  		return fmt.Errorf("writeBlockWithSig error, commit msg for block: %s, not for block: %s", cmtMsg[0].BlockHash.String(), block.Hash().String())
   374  	}
   375  
   376  	block.FillBftMsg(cmtMsg)
   377  	log.Trace("writeBlockWithSig", "h", b.h.String(), "r", b.r, "hash", block.Hash().Hex())
   378  	return b.writeBlock(block)
   379  }
   380  
   381  // newRound has lock, it maybe time consuming at sometime, call it by routine
   382  func (b *BftManager) newRound(h *big.Int, r uint32, witList []common.Address) {
   383  	log.Trace("New round switch start")
   384  	b.newRoundRWLock.Lock()
   385  
   386  	// Update witness list
   387  	if b.h.Cmp(h) != 0 {
   388  		b.witnessList = make(map[common.Address]struct{})
   389  		for _, wit := range witList {
   390  			b.witnessList[wit] = struct{}{}
   391  		}
   392  	}
   393  
   394  	// Reset state and round msg pool
   395  	b.h = h
   396  	b.r = r
   397  	b.step = newRound
   398  
   399  	// Reset round msg pool
   400  	b.roundMp.cleanAllMessage()
   401  
   402  	// Switch to new round finished
   403  	b.newRoundRWLock.Unlock()
   404  
   405  	log.Trace("New round switch finish", "h", b.h.String(), "r", b.r, "time", time.Now().Unix())
   406  
   407  	// New round switch finished, must return right now
   408  	go b.importCurRoundMsg()
   409  }
   410  
   411  // importCurRoundMsg import consensus messages, but can not directly import to round msg pool
   412  func (b *BftManager) importCurRoundMsg() {
   413  	b.newRoundRWLock.RLock()
   414  	msg := b.mp.getAllMsgOf(b.h, b.r)
   415  	b.newRoundRWLock.RUnlock()
   416  	for _, m := range msg {
   417  		log.Trace("Import Msg", "type", m.Type(), "hash", m.Hash())
   418  		go b.handleBftMsg(m)
   419  	}
   420  }
   421  
   422  func (b *BftManager) startSync(block *types.Block) {
   423  	// 	TODO Not emergency, sync will be triggered by block hash msg
   424  	log.Debug("Bft manager startPrePrepare sync")
   425  }
   426  
   427  func (b *BftManager) producingStop() {
   428  	atomic.StoreUint32(&b.producing, 0)
   429  	log.Debug("BFT stop producing")
   430  }
   431  
   432  func (b *BftManager) producingStart() {
   433  	atomic.StoreUint32(&b.producing, 1)
   434  	log.Debug("BFT start producing")
   435  }
   436  
   437  func (b *BftManager) validWitness(wit common.Address) bool {
   438  	_, ok := b.witnessList[wit]
   439  	return ok
   440  }
   441  
   442  // cleanOldMsg clean msg pool and keep future message. cleaning only
   443  // on height % 100 == 0.
   444  func (b *BftManager) cleanOldMsg(h *big.Int) {
   445  	b.mp.cleanOldMessage(h)
   446  }