github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/pbft/core/preprepare.go (about)

     1  // Copyright 2020 The go-simplechain Authors
     2  // This file is part of the go-simplechain library.
     3  //
     4  // The go-simplechain 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-simplechain 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-simplechain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package core
    18  
    19  import (
    20  	"time"
    21  
    22  	"github.com/bigzoro/my_simplechain/consensus"
    23  	"github.com/bigzoro/my_simplechain/consensus/pbft"
    24  	"github.com/bigzoro/my_simplechain/log"
    25  )
    26  
    27  func (c *core) sendPreprepare(request *pbft.Request) {
    28  	logger := c.logger.New("state", c.state)
    29  	defer func(start time.Time) {
    30  		log.Report("send pre-prepare", "cost", time.Since(start))
    31  	}(time.Now())
    32  
    33  	// If I'm the proposer and I have the same sequence with the proposal
    34  	if c.current.Sequence().Cmp(request.Proposal.Number()) == 0 && c.IsProposer() {
    35  		curView := c.currentView()
    36  
    37  		if c.config.LightMode {
    38  			c.sendLightPrepare(request, curView)
    39  			return
    40  		}
    41  
    42  		preprepare := pbft.Preprepare{
    43  			View:     curView,
    44  			Proposal: request.Proposal,
    45  		}
    46  		preprepareMsg, err := Encode(&preprepare)
    47  		if err != nil {
    48  			logger.Error("Failed to encode", "view", curView)
    49  			return
    50  		}
    51  
    52  		c.broadcast(&message{
    53  			Code: msgPreprepare,
    54  			Msg:  preprepareMsg,
    55  		}, false)
    56  		c.handlePrepare2(&preprepare, nil, nil)
    57  	}
    58  }
    59  
    60  // Handle common Pre-prepare message
    61  func (c *core) handlePreprepare(msg *message, src pbft.Validator) error {
    62  	logger := c.logger.New("from", src, "state", c.state)
    63  	c.prepareTimestamp = time.Now()
    64  
    65  	//record := time.Now()
    66  	var preprepare *pbft.Preprepare
    67  	err := msg.Decode(&preprepare)
    68  	if err != nil {
    69  		logger.Warn("Failed decode preprepare", "err", err)
    70  		return errFailedDecodePreprepare
    71  	}
    72  
    73  	//log.Report("handlePreprepare -> decode", "cost", time.Since(record), "from", src)
    74  
    75  	err = c.checkPreprepareMsg(msg, src, preprepare.View, preprepare.Proposal)
    76  	if err != nil {
    77  		return err
    78  	}
    79  	return c.handlePrepare2(preprepare, msg, src)
    80  }
    81  
    82  func (c *core) handlePrepare2(preprepare *pbft.Preprepare, msg *message, src pbft.Validator) error {
    83  	logger := c.logger.New("state", c.state)
    84  	// Verify the proposal we received ()
    85  	if duration, err := c.backend.Verify(preprepare.Proposal, true, true); err != nil {
    86  		// if it's a future block, we will handle it again after the duration
    87  		if err == consensus.ErrFutureBlock {
    88  			if duration > time.Second*time.Duration(c.config.BlockPeriod) && msg != nil {
    89  				logger.Warn("Proposed block will be committed in the future", "err", err, "duration", duration)
    90  				// wait until block timestamp at commit stage
    91  				c.stopFuturePreprepareTimer()
    92  				c.futurePreprepareTimer = time.AfterFunc(duration, func() {
    93  					c.sendEvent(backlogEvent{
    94  						src: src,
    95  						msg: msg,
    96  					})
    97  				})
    98  			}
    99  		} else {
   100  			logger.Warn("Failed to verify proposal", "err", err, "duration", duration)
   101  			c.sendNextRoundChange()
   102  			return err
   103  		}
   104  	}
   105  	return c.checkAndAcceptPreprepare(preprepare)
   106  }
   107  
   108  func (c *core) checkPreprepareMsg(msg *message, src pbft.Validator, view *pbft.View, proposal pbft.Proposal) error {
   109  	logger := c.logger.New("from", src, "state", c.state, "view", view)
   110  
   111  	// Ensure we have the same view with the PRE-PREPARE message
   112  	// If it is old message, see if we need to broadcast COMMIT
   113  	if err := c.checkMessage(msg.Code, view); err != nil {
   114  		switch err {
   115  		case errOldMessage:
   116  			// Get validator set for the given proposal
   117  			valSet := c.backend.ParentValidators(proposal).Copy()
   118  			previousProposer := c.backend.GetProposer(proposal.Number().Uint64() - 1)
   119  			valSet.CalcProposer(previousProposer, view.Round.Uint64())
   120  			// Broadcast COMMIT if it is an existing block
   121  			// 1. The proposer needs to be a proposer matches the given (Sequence + Round)
   122  			// 2. The given block must exist
   123  			if valSet.IsProposer(src.Address()) {
   124  				commitHash, has := c.backend.HasProposal(proposal.PendingHash(), proposal.Number())
   125  				if has {
   126  					c.sendCommitForOldBlock(view, proposal.PendingHash(), commitHash)
   127  					return nil
   128  				}
   129  			}
   130  		}
   131  		logger.Trace("checkMessage failed", "code", msg.Code, "view", view)
   132  		//logger.Error("[report] ## checkMessage failed", "code", msg.Code, "err", err)
   133  		return err
   134  	}
   135  
   136  	// Check if the message comes from current proposer
   137  	if !c.valSet.IsProposer(src.Address()) {
   138  		logger.Warn("Ignore preprepare messages from non-proposer")
   139  		return errNotFromProposer
   140  	}
   141  
   142  	return nil
   143  }
   144  
   145  func (c *core) checkAndAcceptPreprepare(preprepare *pbft.Preprepare) error {
   146  	// only accept pre-prepare at StateAcceptRequest
   147  	if c.state != StateAcceptRequest {
   148  		return nil
   149  	}
   150  
   151  	// Send ROUND CHANGE if the locked proposal and the received proposal are different
   152  	if c.current.IsHashLocked() {
   153  		if preprepare.Proposal.PendingHash() == c.current.GetLockedHash() {
   154  			// Broadcast COMMIT and enters Prepared state directly
   155  			c.acceptPreprepare(preprepare)
   156  			c.setState(StatePrepared)
   157  			c.sendCommit()
   158  
   159  		} else {
   160  			// Send round change
   161  			c.sendNextRoundChange()
   162  		}
   163  		return nil
   164  	}
   165  
   166  	// Either
   167  	//   1. the locked proposal and the received proposal match
   168  	//   2. we have no locked proposal
   169  	c.acceptPreprepare(preprepare)
   170  
   171  	// execute proposal and broadcast it
   172  	if err := c.executePreprepare(preprepare); err != nil {
   173  		// Verify proposal failed
   174  		// Send round change
   175  		c.sendNextRoundChange()
   176  		return err
   177  	}
   178  
   179  	c.setState(StatePreprepared)
   180  	c.sendPrepare()
   181  	return nil
   182  }
   183  
   184  func (c *core) acceptPreprepare(preprepare *pbft.Preprepare) {
   185  	c.consensusTimestamp = time.Now()
   186  	c.current.SetPreprepare(preprepare)
   187  }
   188  
   189  func (c *core) executePreprepare(preprepare *pbft.Preprepare) error {
   190  	logger := c.logger.New("state", c.state)
   191  
   192  	block, err := c.backend.Execute(preprepare.Proposal)
   193  	if err != nil {
   194  		logger.Warn("Failed execute pre-prepare", "view", preprepare.View, "err", err)
   195  		return err
   196  	}
   197  	c.current.SetPrepare(block)
   198  	return nil
   199  }