github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/consensus/istanbul/core/handler.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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-ethereum 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-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "fmt" 21 "math/big" 22 23 "github.com/electroneum/electroneum-sc/common" 24 "github.com/electroneum/electroneum-sc/consensus/istanbul" 25 qbfttypes "github.com/electroneum/electroneum-sc/consensus/istanbul/types" 26 "github.com/electroneum/electroneum-sc/log" 27 "github.com/electroneum/electroneum-sc/rlp" 28 ) 29 30 // Start implements core.Engine.Start 31 func (c *core) Start() error { 32 c.logger.Info("IBFT: start") 33 // Tests will handle events itself, so we have to make subscribeEvents() 34 // be able to call in test. 35 c.subscribeEvents() 36 c.handlerWg.Add(1) 37 go c.handleEvents() 38 39 // Start a new round from last sequence + 1 40 c.startNewRound(common.Big0) 41 42 return nil 43 } 44 45 // Stop implements core.Engine.Stop 46 func (c *core) Stop() error { 47 c.logger.Info("IBFT: stopping...") 48 c.stopTimer() 49 c.unsubscribeEvents() 50 51 // Make sure the handler goroutine exits 52 c.handlerWg.Wait() 53 c.logger.Info("IBFT: stopped") 54 return nil 55 } 56 57 // ---------------------------------------------------------------------------- 58 59 // Subscribe both internal and external events 60 func (c *core) subscribeEvents() { 61 c.events = c.backend.EventMux().Subscribe( 62 // external events 63 istanbul.RequestEvent{}, 64 istanbul.MessageEvent{}, 65 // internal events 66 backlogEvent{}, 67 ) 68 c.timeoutSub = c.backend.EventMux().Subscribe( 69 timeoutEvent{}, 70 ) 71 c.finalCommittedSub = c.backend.EventMux().Subscribe( 72 istanbul.FinalCommittedEvent{}, 73 ) 74 } 75 76 // Unsubscribe all events 77 func (c *core) unsubscribeEvents() { 78 c.events.Unsubscribe() 79 c.timeoutSub.Unsubscribe() 80 c.finalCommittedSub.Unsubscribe() 81 } 82 83 // handleEvents starts main qbft handler loop that processes all incoming messages 84 // sequentially. Each time a message is processed, internal QBFT state is mutated 85 86 // when processing a message it makes sure that the message matches the current state 87 // - in case the message is past, either for an older round or a state that already got acknowledge (e.g. a PREPARE message but we 88 // are already in Prepared state), then message is discarded 89 // - in case the message is future, either for a future round or a state yet to be reached (e.g. a COMMIT message but we are 90 // in PrePrepared state), then message is added to backlog for future processing 91 // - if correct time, message is handled 92 93 // Each time a message is successfully handled it is gossiped to other validators 94 func (c *core) handleEvents() { 95 // Clear state 96 defer func() { 97 c.current = nil 98 c.handlerWg.Done() 99 }() 100 101 for { 102 select { 103 case event, ok := <-c.events.Chan(): 104 if !ok { 105 return 106 } 107 108 // A real event arrived, process interesting content 109 switch ev := event.Data.(type) { 110 case istanbul.RequestEvent: 111 // we are block proposer and look to get our block proposal validated by other validators 112 r := &Request{ 113 Proposal: ev.Proposal, 114 } 115 err := c.handleRequest(r) 116 if err == errFutureMessage { 117 // store request for later treatment 118 c.storeRequestMsg(r) 119 } 120 case istanbul.MessageEvent: 121 // we received a message from another validator 122 if err := c.handleEncodedMsg(ev.Code, ev.Payload); err != nil { 123 continue 124 } 125 126 // if successfully processed, we gossip message to other validators 127 c.backend.Gossip(c.valSet, ev.Code, ev.Payload) 128 case backlogEvent: 129 // we process again a future message that was backlogged 130 // no need to check signature as it was already node when we first received message 131 if err := c.handleDecodedMessage(ev.msg); err != nil { 132 continue 133 } 134 135 data, err := rlp.EncodeToBytes(ev.msg) 136 if err != nil { 137 c.logger.Error("IBFT: can not encode backlog message", "err", err) 138 continue 139 } 140 141 // if successfully processed, we gossip message to other validators 142 c.backend.Gossip(c.valSet, ev.msg.Code(), data) 143 } 144 case _, ok := <-c.timeoutSub.Chan(): 145 // we received a round change timeout 146 if !ok { 147 return 148 } 149 c.handleTimeoutMsg() 150 case event, ok := <-c.finalCommittedSub.Chan(): 151 // our block proposal got committed 152 if !ok { 153 return 154 } 155 switch event.Data.(type) { 156 case istanbul.FinalCommittedEvent: 157 c.handleFinalCommitted() 158 } 159 } 160 } 161 } 162 163 // sendEvent sends events to mux 164 func (c *core) sendEvent(ev interface{}) { 165 c.backend.EventMux().Post(ev) 166 } 167 168 func (c *core) handleEncodedMsg(code uint64, data []byte) error { 169 logger := c.logger.New("code", code, "data", data) 170 171 if _, ok := qbfttypes.MessageCodes()[code]; !ok { 172 logger.Error("IBFT: invalid message event code") 173 return fmt.Errorf("invalid message event code %v", code) 174 } 175 176 // Decode data into a QBFTMessage 177 m, err := qbfttypes.Decode(code, data) 178 if err != nil { 179 logger.Error("IBFT: invalid message", "err", err) 180 return err 181 } 182 183 // Verify signatures and set source address 184 if err = c.verifySignatures(m); err != nil { 185 return err 186 } 187 188 return c.handleDecodedMessage(m) 189 } 190 191 func (c *core) handleDecodedMessage(m qbfttypes.QBFTMessage) error { 192 view := m.View() 193 if err := c.checkMessage(m.Code(), &view); err != nil { 194 // Store in the backlog it it's a future message 195 if err == errFutureMessage { 196 c.addToBacklog(m) 197 } 198 return err 199 } 200 201 return c.deliverMessage(m) 202 } 203 204 // Deliver to specific message handler 205 func (c *core) deliverMessage(m qbfttypes.QBFTMessage) error { 206 var err error 207 208 switch m.Code() { 209 case qbfttypes.PreprepareCode: 210 err = c.handlePreprepareMsg(m.(*qbfttypes.Preprepare)) 211 case qbfttypes.PrepareCode: 212 err = c.handlePrepare(m.(*qbfttypes.Prepare)) 213 case qbfttypes.CommitCode: 214 err = c.handleCommitMsg(m.(*qbfttypes.Commit)) 215 case qbfttypes.RoundChangeCode: 216 err = c.handleRoundChange(m.(*qbfttypes.RoundChange)) 217 default: 218 c.logger.Error("IBFT: invalid message code", "code", m.Code()) 219 return errInvalidMessage 220 } 221 222 return err 223 } 224 225 func (c *core) handleTimeoutMsg() { 226 logger := c.currentLogger(true, nil) 227 // Start the new round 228 round := c.current.Round() 229 nextRound := new(big.Int).Add(round, common.Big1) 230 231 logger.Warn("IBFT: TIMER CHANGING ROUND", "pr", c.current.preparedRound) 232 c.startNewRound(nextRound) 233 logger.Warn("IBFT: TIMER CHANGED ROUND", "pr", c.current.preparedRound) 234 235 // Send Round Change 236 c.broadcastRoundChange(nextRound) 237 } 238 239 // Verifies the signature of the message m and of any justification payloads 240 // piggybacked in m, if any. It also sets the source address on the messages 241 // and justification payloads. 242 func (c *core) verifySignatures(m qbfttypes.QBFTMessage) error { 243 logger := c.currentLogger(true, m) 244 245 // Anonymous function to verify the signature of a single message or payload 246 verify := func(m qbfttypes.QBFTMessage) error { 247 payload, err := m.EncodePayloadForSigning() 248 if err != nil { 249 logger.Error("IBFT: invalid message payload", "err", err) 250 return err 251 } 252 source, err := c.validateFn(payload, m.Signature()) 253 if err != nil { 254 logger.Error("IBFT: invalid message signature", "err", err) 255 return errInvalidSigner 256 } 257 m.SetSource(source) 258 return nil 259 } 260 261 // Verifies the signature of the message 262 if err := verify(m); err != nil { 263 return err 264 } 265 266 // Verifies the signature of piggybacked justification payloads. 267 switch msgType := m.(type) { 268 case *qbfttypes.RoundChange: 269 signedPreparePayloads := msgType.Justification 270 for _, p := range signedPreparePayloads { 271 if err := verify(p); err != nil { 272 return err 273 } 274 } 275 case *qbfttypes.Preprepare: 276 signedRoundChangePayloads := msgType.JustificationRoundChanges 277 for _, p := range signedRoundChangePayloads { 278 if err := verify(p); err != nil { 279 return err 280 } 281 } 282 } 283 284 return nil 285 } 286 287 func (c *core) currentLogger(state bool, msg qbfttypes.QBFTMessage) log.Logger { 288 logCtx := []interface{}{ 289 "current.round", c.current.Round().Uint64(), 290 "current.sequence", c.current.Sequence().Uint64(), 291 } 292 293 if state { 294 logCtx = append(logCtx, "state", c.state) 295 } 296 297 if msg != nil { 298 logCtx = append( 299 logCtx, 300 "msg.code", msg.Code(), 301 "msg.source", msg.Source().String(), 302 "msg.round", msg.View().Round.Uint64(), 303 "msg.sequence", msg.View().Sequence.Uint64(), 304 ) 305 } 306 307 return c.logger.New(logCtx...) 308 } 309 310 func withMsg(logger log.Logger, msg qbfttypes.QBFTMessage) log.Logger { 311 return logger.New( 312 "msg.code", msg.Code(), 313 "msg.source", msg.Source().String(), 314 "msg.round", msg.View().Round.Uint64(), 315 "msg.sequence", msg.View().Sequence.Uint64(), 316 ) 317 }