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 }