github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/pbft/core/handler.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 "github.com/bigzoro/my_simplechain/common" 21 "github.com/bigzoro/my_simplechain/consensus/pbft" 22 ) 23 24 // Start implements core.Engine.Start 25 func (c *core) Start() error { 26 // Start a new round from last sequence + 1 27 c.startNewRound(common.Big0) 28 29 // Tests will handle events itself, so we have to make subscribeEvents() 30 // be able to call in test. 31 c.subscribeEvents() 32 go c.handleEvents() 33 34 return nil 35 } 36 37 // Stop implements core.Engine.Stop 38 func (c *core) Stop() error { 39 c.stopTimer() 40 c.unsubscribeEvents() 41 42 // Make sure the handler goroutine exits 43 c.handlerWg.Wait() 44 return nil 45 } 46 47 // ---------------------------------------------------------------------------- 48 49 // Subscribe both internal and external events 50 func (c *core) subscribeEvents() { 51 c.events = c.backend.EventMux().Subscribe( 52 // external events 53 pbft.RequestEvent{}, 54 pbft.MessageEvent{}, 55 // internal events 56 backlogEvent{}, 57 ) 58 c.timeoutSub = c.backend.EventMux().Subscribe( 59 timeoutEvent{}, 60 ) 61 c.finalCommittedSub = c.backend.EventMux().Subscribe( 62 pbft.FinalCommittedEvent{}, 63 ) 64 } 65 66 // Unsubscribe all events 67 func (c *core) unsubscribeEvents() { 68 c.events.Unsubscribe() 69 c.timeoutSub.Unsubscribe() 70 c.finalCommittedSub.Unsubscribe() 71 } 72 73 func (c *core) handleEvents() { 74 // Clear state 75 defer func() { 76 c.current = nil 77 c.handlerWg.Done() 78 }() 79 80 c.handlerWg.Add(1) 81 82 for { 83 select { 84 case event, ok := <-c.events.Chan(): 85 if !ok { 86 return 87 } 88 // A real event arrived, process interesting content 89 switch ev := event.Data.(type) { 90 case pbft.RequestEvent: 91 r := &pbft.Request{ 92 Proposal: ev.Proposal, 93 } 94 err := c.handleRequest(r) 95 if err == errFutureMessage { 96 c.storeRequestMsg(r) 97 } 98 case pbft.MessageEvent: 99 msg, src, forward, err := c.handleMsg(ev.Payload) 100 if forward && err == nil { 101 c.forward(msg, src) 102 } 103 case backlogEvent: 104 // No need to check signature for internal messages 105 if forward, err := c.handleCheckedMsg(ev.msg, ev.src); forward && err == nil { 106 p, err := ev.msg.Payload() 107 if err != nil { 108 c.logger.Warn("Get message payload failed", "err", err) 109 continue 110 } 111 //c.backend.Gossip(c.valSet, p) 112 c.backend.Guidance(c.valSet, ev.msg.Address, p) 113 } 114 } 115 case _, ok := <-c.timeoutSub.Chan(): 116 if !ok { 117 return 118 } 119 c.handleTimeoutMsg() 120 121 case event, ok := <-c.finalCommittedSub.Chan(): 122 if !ok { 123 return 124 } 125 switch ev := event.Data.(type) { 126 case pbft.FinalCommittedEvent: 127 c.handleFinalCommitted(ev.Committed) 128 } 129 } 130 } 131 } 132 133 // sendEvent sends events to mux 134 func (c *core) sendEvent(ev interface{}) { 135 c.backend.EventMux().Post(ev) 136 } 137 138 func (c *core) handleMsg(payload []byte) (*message, pbft.Validator, bool, error) { 139 logger := c.logger.New() 140 141 // Decode message and check its signature 142 msg := new(message) 143 if err := msg.FromPayload(payload, c.validateFn); err != nil { 144 logger.Error("Failed to decode message from payload", "err", err) 145 return nil, nil, false, err 146 } 147 148 // Only accept message if the address is valid 149 _, src := c.valSet.GetByAddress(msg.Address) 150 if src == nil { 151 logger.Error("Invalid address in message", "msg", msg) 152 return msg, src, false, pbft.ErrUnauthorizedAddress 153 } 154 155 forward, err := c.handleCheckedMsg(msg, src) 156 157 return msg, src, forward, err 158 } 159 160 func (c *core) handleCheckedMsg(msg *message, src pbft.Validator) (bool, error) { 161 logger := c.logger.New("address", c.address, "from", src) 162 163 // Store the message if it's a future message 164 testBacklog := func(err error) error { 165 if err == errFutureMessage { 166 c.storeBacklog(msg, src) 167 } 168 169 return err 170 } 171 switch msg.Code { 172 case msgPreprepare: 173 // wouldn't forward preprepare message, if node is in light mode 174 return !c.config.LightMode, testBacklog(c.handlePreprepare(msg, src)) 175 176 case msgPrepare: 177 return true, testBacklog(c.handlePrepare(msg, src)) 178 179 case msgCommit: 180 return true, testBacklog(c.handleCommit(msg, src)) 181 182 case msgRoundChange: 183 return true, testBacklog(c.handleRoundChange(msg, src)) 184 185 case msgLightPreprepare: 186 if c.config.LightMode { 187 return true, testBacklog(c.handleLightPrepare(msg, src)) 188 } 189 case msgGetMissedTxs: 190 if c.config.LightMode { 191 // wouldn't forward request message 192 return false, testBacklog(c.handleGetMissedTxs(msg, src)) 193 } 194 case msgMissedTxs: 195 if c.config.LightMode { 196 // wouldn't forward response message 197 return false, testBacklog(c.handleMissedTxs(msg, src)) 198 } 199 200 default: 201 logger.Error("Invalid message", "msg", msg) 202 } 203 204 return false, errInvalidMessage 205 } 206 207 func (c *core) handleTimeoutMsg() { 208 // adjust block sealing txs on timeout 209 if c.current != nil && c.current.Proposal() != nil && !c.current.Proposal().IsEmpty() { 210 c.backend.OnTimeout() 211 } 212 // If we're not waiting for round change yet, we can try to catch up 213 // the max round with F+1 round change message. We only need to catch up 214 // if the max round is larger than current round. 215 if !c.waitingForRoundChange { 216 maxRound := c.roundChangeSet.MaxRound(c.valSet.F() + 1) 217 if maxRound != nil && maxRound.Cmp(c.current.Round()) > 0 { 218 c.sendRoundChange(maxRound) 219 return 220 } 221 } 222 223 lastProposal, _, _ := c.backend.LastProposal() 224 if lastProposal != nil && lastProposal.Number().Cmp(c.current.Sequence()) >= 0 { 225 c.logger.Trace("round change timeout, catch up latest sequence", "number", lastProposal.Number().Uint64()) 226 //c.logger.Error("[report] round change timeout, catch up latest sequence", "number", lastProposal.Number().Uint64()) 227 c.startNewRound(common.Big0) 228 } else { 229 c.sendNextRoundChange() 230 } 231 }