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

     1  package core
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/bigzoro/my_simplechain/consensus"
     7  	"github.com/bigzoro/my_simplechain/consensus/pbft"
     8  	"github.com/bigzoro/my_simplechain/log"
     9  )
    10  
    11  func (c *core) sendLightPrepare(request *pbft.Request, curView *pbft.View) {
    12  	logger := c.logger.New("state", c.state)
    13  
    14  	// encode light proposal
    15  	lightMsg, err := Encode(&pbft.Preprepare{
    16  		View:     curView,
    17  		Proposal: pbft.Proposal2Light(request.Proposal, true),
    18  	})
    19  	if err != nil {
    20  		logger.Error("Failed to encode", "view", curView)
    21  		return
    22  	}
    23  
    24  	// send light pre-prepare msg to others
    25  	c.broadcast(&message{
    26  		Code: msgLightPreprepare,
    27  		Msg:  lightMsg,
    28  	}, false)
    29  
    30  	// handle full proposal by itself
    31  	c.handlePrepare2(&pbft.Preprepare{
    32  		View:     curView,
    33  		Proposal: request.Proposal,
    34  	}, nil, nil)
    35  }
    36  
    37  // The first stage handle light Pre-prepare.
    38  // Check message and verify block header, and try fill proposal with sealer.
    39  // Request missed txs from proposer or enter the second stage for filled proposal.
    40  func (c *core) handleLightPrepare(msg *message, src pbft.Validator) error {
    41  	logger := c.logger.New("from", src, "state", c.state)
    42  	c.prepareTimestamp = time.Now()
    43  
    44  	var preprepare *pbft.LightPreprepare
    45  	err := msg.Decode(&preprepare)
    46  	if err != nil {
    47  		logger.Warn("Failed to decode light preprepare", "err", err)
    48  		return errFailedDecodePreprepare
    49  	}
    50  
    51  	err = c.checkPreprepareMsg(msg, src, preprepare.View, preprepare.Proposal)
    52  	if err != nil {
    53  		return err
    54  	}
    55  
    56  	// Verify the proposal we received, dont check body if we are light
    57  	if duration, err := c.backend.Verify(preprepare.Proposal, true, false); err != nil {
    58  		// if it's a future block, we will handle it again after the duration
    59  		if err == consensus.ErrFutureBlock {
    60  			if duration > time.Second*time.Duration(c.config.BlockPeriod) {
    61  				logger.Warn("Proposed block will be committed in the future", "err", err, "duration", duration)
    62  				// wait until block timestamp at commit stage
    63  				c.stopFuturePreprepareTimer()
    64  				c.futurePreprepareTimer = time.AfterFunc(duration, func() {
    65  					c.sendEvent(backlogEvent{
    66  						src: src,
    67  						msg: msg,
    68  					})
    69  				})
    70  			}
    71  		} else {
    72  			logger.Warn("Failed to verify light proposal header", "err", err, "duration", duration)
    73  			c.sendNextRoundChange()
    74  			return err
    75  		}
    76  	}
    77  
    78  	if c.state != StateAcceptRequest {
    79  		return nil
    80  	}
    81  
    82  	lightProposal, ok := preprepare.Proposal.(pbft.LightProposal)
    83  	if !ok {
    84  		logger.Warn("Failed resolve proposal as a light proposal", "view", preprepare.View)
    85  		return errInvalidLightProposal
    86  	}
    87  
    88  	// empty block, handle immediately
    89  	if len(lightProposal.TxDigests()) == 0 {
    90  		return c.handleLightPrepare2(preprepare.FullPreprepare(), src)
    91  	}
    92  
    93  	// fill light proposal by txpool, return missed transactions
    94  	filled, missedTxs, err := c.backend.FillLightProposal(lightProposal)
    95  	if err != nil {
    96  		logger.Warn("Failed to fill light proposal", "error", err)
    97  		c.sendNextRoundChange()
    98  		return err
    99  	}
   100  
   101  	// cal percent of txs existed in local txpool
   102  	percent := 100.00 - 100.00*float64(len(missedTxs))/float64(len(lightProposal.TxDigests()))
   103  	logger.Trace("light block transaction covered", "percent", percent)
   104  
   105  	// 1.block filled, handle immediately
   106  	// 2.block missed some txs, request them
   107  	if filled {
   108  		// entire the second stage
   109  		return c.handleLightPrepare2(preprepare.FullPreprepare(), src)
   110  
   111  	} else {
   112  		// accept light preprepare
   113  		c.current.SetLightPrepare(preprepare)
   114  		// request missedTxs from proposer
   115  		c.requestMissedTxs(missedTxs, src)
   116  	}
   117  
   118  	return nil
   119  }
   120  
   121  // The second stage handle light Pre-prepare.
   122  func (c *core) handleLightPrepare2(preprepare *pbft.Preprepare, src pbft.Validator) error {
   123  	logger := c.logger.New("from", src, "state", c.state)
   124  	log.Report("> handleLightPrepare2")
   125  	// light proposal was be filled, check body
   126  	if _, err := c.backend.Verify(preprepare.Proposal, false, true); err != nil {
   127  		logger.Warn("Failed to verify light proposal body", "err", err)
   128  		c.sendNextRoundChange()
   129  		return err //TODO
   130  	}
   131  	return c.checkAndAcceptPreprepare(preprepare)
   132  }