github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/dbft/core/preprepare.go (about)

     1  package core
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/quickchainproject/quickchain/consensus"
     7  	bft "github.com/quickchainproject/quickchain/consensus/dbft"
     8  )
     9  
    10  func (c *core) sendPreprepare(request *bft.Request) {
    11  	logger := c.logger.New("state", c.state)
    12  
    13  	// If I'm the proposer and I have the same sequence with the proposal
    14  	if c.current.Sequence().Cmp(request.Proposal.Number()) == 0 && c.isProposer() {
    15  		curView := c.currentView()
    16  		preprepare, err := Encode(&bft.Preprepare{
    17  			View:     curView,
    18  			Proposal: request.Proposal,
    19  		})
    20  		if err != nil {
    21  			logger.Error("Failed to encode", "view", curView)
    22  			return
    23  		}
    24  
    25  		c.broadcast(&message{
    26  			Code: msgPreprepare,
    27  			Msg:  preprepare,
    28  		})
    29  	}
    30  }
    31  
    32  func (c *core) handlePreprepare(msg *message, src bft.Validator) error {
    33  	logger := c.logger.New("from", src, "state", c.state)
    34  
    35  	// Decode PRE-PREPARE
    36  	var preprepare *bft.Preprepare
    37  	err := msg.Decode(&preprepare)
    38  	if err != nil {
    39  		return errFailedDecodePreprepare
    40  	}
    41  
    42  	// Ensure we have the same view with the PRE-PREPARE message
    43  	// If it is old message, see if we need to broadcast COMMIT
    44  	if err := c.checkMessage(msgPreprepare, preprepare.View); err != nil {
    45  		if err == errOldMessage {
    46  			// Get validator set for the given proposal
    47  			valSet := c.backend.ParentValidators(preprepare.Proposal).Copy()
    48  			previousProposer := c.backend.GetProposer(preprepare.Proposal.Number().Uint64() - 1)
    49  			valSet.CalcProposer(previousProposer, preprepare.View.Round.Uint64())
    50  			// Broadcast COMMIT if it is an existing block
    51  			// 1. The proposer needs to be a proposer matches the given (Sequence + Round)
    52  			// 2. The given block must exist
    53  			if valSet.IsProposer(src.Address()) && c.backend.HasPropsal(preprepare.Proposal.Hash(), preprepare.Proposal.Number()) {
    54  				c.sendCommitForOldBlock(preprepare.View, preprepare.Proposal.Hash())
    55  				return nil
    56  			}
    57  		}
    58  		return err
    59  	}
    60  
    61  	// Check if the message comes from current proposer
    62  	if !c.valSet.IsProposer(src.Address()) {
    63  		logger.Warn("Ignore preprepare messages from non-proposer")
    64  		return errNotFromProposer
    65  	}
    66  
    67  	// Verify the proposal we received
    68  	if duration, err := c.backend.Verify(preprepare.Proposal); err != nil {
    69  		logger.Warn("Failed to verify proposal", "err", err, "duration", duration)
    70  		// if it's a future block, we will handle it again after the duration
    71  		if err == consensus.ErrFutureBlock {
    72  			c.stopFuturePreprepareTimer()
    73  			c.futurePreprepareTimer = time.AfterFunc(duration, func() {
    74  				c.sendEvent(backlogEvent{
    75  					src: src,
    76  					msg: msg,
    77  				})
    78  			})
    79  		} else {
    80  			c.sendNextRoundChange()
    81  		}
    82  		return err
    83  	}
    84  
    85  	// Here is about to accept the PRE-PREPARE
    86  	if c.state == StateAcceptRequest {
    87  		// Send ROUND CHANGE if the locked proposal and the received proposal are different
    88  		if c.current.IsHashLocked() {
    89  			if preprepare.Proposal.Hash() == c.current.GetLockedHash() {
    90  				// Broadcast COMMIT and enters Prepared state directly
    91  				c.acceptPreprepare(preprepare)
    92  				c.setState(StatePrepared)
    93  				c.sendCommit()
    94  			} else {
    95  				// Send round change
    96  				c.sendNextRoundChange()
    97  			}
    98  		} else {
    99  			// Either
   100  			//   1. the locked proposal and the received proposal match
   101  			//   2. we have no locked proposal
   102  			c.acceptPreprepare(preprepare)
   103  			c.setState(StatePreprepared)
   104  			c.sendPrepare()
   105  		}
   106  	}
   107  
   108  	return nil
   109  }
   110  
   111  func (c *core) acceptPreprepare(preprepare *bft.Preprepare) {
   112  	c.consensusTimestamp = time.Now()
   113  	c.current.SetPreprepare(preprepare)
   114  }