github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/consensus/istanbul/core/request.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 "github.com/electroneum/electroneum-sc/consensus/istanbul" 21 ) 22 23 // handleRequest is called by proposer in reaction to `miner.Seal()` 24 // (this is the starting of the QBFT validation process) 25 26 // It 27 // - validates block proposal is not empty and number correspond to the current sequence 28 // - creates and send PRE-PREPARE message to other validators 29 func (c *core) handleRequest(request *Request) error { 30 logger := c.currentLogger(true, nil) 31 32 logger.Info("IBFT: handle block proposal request") 33 34 if err := c.checkRequestMsg(request); err != nil { 35 if err == errInvalidMessage { 36 logger.Error("IBFT: invalid request") 37 return err 38 } 39 logger.Error("IBFT: unexpected request", "err", err, "number", request.Proposal.Number(), "hash", request.Proposal.Hash()) 40 return err 41 } 42 43 c.current.pendingRequest = request 44 if c.state == StateAcceptRequest { 45 // Start ROUND-CHANGE timer 46 c.newRoundChangeTimer() 47 48 // Send PRE-PREPARE message to other validators 49 c.sendPreprepareMsg(request) 50 } 51 52 return nil 53 } 54 55 // check request state 56 // return errInvalidMessage if the message is invalid 57 // return errFutureMessage if the sequence of proposal is larger than current sequence 58 // return errOldMessage if the sequence of proposal is smaller than current sequence 59 func (c *core) checkRequestMsg(request *Request) error { 60 if request == nil || request.Proposal == nil { 61 return errInvalidMessage 62 } 63 64 if c := c.current.sequence.Cmp(request.Proposal.Number()); c > 0 { 65 return errOldMessage 66 } else if c < 0 { 67 return errFutureMessage 68 } else { 69 return nil 70 } 71 } 72 73 func (c *core) storeRequestMsg(request *Request) { 74 logger := c.currentLogger(true, nil).New("proposal.number", request.Proposal.Number(), "proposal.hash", request.Proposal.Hash()) 75 76 logger.Trace("IBFT: store block proposal request for future treatment") 77 78 c.pendingRequestsMu.Lock() 79 defer c.pendingRequestsMu.Unlock() 80 81 c.pendingRequests.Push(request, float32(-request.Proposal.Number().Int64())) 82 } 83 84 // processPendingRequests is called each time QBFT state is re-initialized 85 // it lookup over pending requests and re-input its so they can be treated 86 func (c *core) processPendingRequests() { 87 c.pendingRequestsMu.Lock() 88 defer c.pendingRequestsMu.Unlock() 89 90 logger := c.currentLogger(true, nil) 91 logger.Debug("IBFT: lookup for pending block proposal requests") 92 93 for !(c.pendingRequests.Empty()) { 94 m, prio := c.pendingRequests.Pop() 95 r, ok := m.(*Request) 96 if !ok { 97 logger.Error("IBFT: malformed pending block proposal request, skip", "msg", m) 98 continue 99 } 100 // Push back if it's a future message 101 err := c.checkRequestMsg(r) 102 if err != nil { 103 if err == errFutureMessage { 104 logger.Trace("IBFT: stop looking up for pending block proposal request") 105 c.pendingRequests.Push(m, prio) 106 break 107 } 108 logger.Trace("IBFT: skip pending invalid block proposal request", "number", r.Proposal.Number(), "hash", r.Proposal.Hash(), "err", err) 109 continue 110 } 111 logger.Debug("IBFT: found pending block proposal request", "proposal.number", r.Proposal.Number(), "proposal.hash", r.Proposal.Hash()) 112 113 go c.sendEvent(istanbul.RequestEvent{ 114 Proposal: r.Proposal, 115 }) 116 } 117 }