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 }