github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/consensus/istanbul/core/preprepare.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 "time" 21 22 "github.com/electroneum/electroneum-sc/common/hexutil" 23 "github.com/electroneum/electroneum-sc/consensus" 24 qbfttypes "github.com/electroneum/electroneum-sc/consensus/istanbul/types" 25 "github.com/electroneum/electroneum-sc/rlp" 26 ) 27 28 // sendPreprepareMsg is called either 29 // - when we are proposer after calling `miner.Seal(...)` 30 // - roundChange happens and we are the proposer 31 32 // It 33 // - creates and sign PRE-PREPARE message with block proposed on `miner.Seal()` 34 // - extends PRE-PREPARE message with ROUND-CHANGE and PREPARE justification 35 // - broadcast PRE-PREPARE message to other validators 36 func (c *core) sendPreprepareMsg(request *Request) { 37 logger := c.currentLogger(true, nil) 38 39 // If I'm the proposer and I have the same sequence with the proposal 40 if c.current.Sequence().Cmp(request.Proposal.Number()) == 0 && c.IsProposer() { 41 // Creates PRE-PREPARE message 42 curView := c.currentView() 43 preprepare := qbfttypes.NewPreprepare(curView.Sequence, curView.Round, request.Proposal) 44 preprepare.SetSource(c.Address()) 45 46 // Sign payload 47 encodedPayload, err := preprepare.EncodePayloadForSigning() 48 if err != nil { 49 withMsg(logger, preprepare).Error("IBFT: failed to encode payload of PRE-PREPARE message", "err", err) 50 return 51 } 52 signature, err := c.backend.Sign(encodedPayload) 53 if err != nil { 54 withMsg(logger, preprepare).Error("IBFT: failed to sign PRE-PREPARE message", "err", err) 55 return 56 } 57 preprepare.SetSignature(signature) 58 59 // Extend PRE-PREPARE message with ROUND-CHANGE justification 60 if request.RCMessages != nil { 61 preprepare.JustificationRoundChanges = make([]*qbfttypes.SignedRoundChangePayload, 0) 62 for _, m := range request.RCMessages.Values() { 63 preprepare.JustificationRoundChanges = append(preprepare.JustificationRoundChanges, &m.(*qbfttypes.RoundChange).SignedRoundChangePayload) 64 withMsg(logger, preprepare).Trace("IBFT: add ROUND-CHANGE justification", "rc", m.(*qbfttypes.RoundChange).SignedRoundChangePayload) 65 } 66 withMsg(logger, preprepare).Trace("IBFT: extended PRE-PREPARE message with ROUND-CHANGE justifications", "justifications", preprepare.JustificationRoundChanges) 67 } 68 69 // Extend PRE-PREPARE message with PREPARE justification 70 if request.PrepareMessages != nil { 71 preprepare.JustificationPrepares = request.PrepareMessages 72 withMsg(logger, preprepare).Trace("IBFT: extended PRE-PREPARE message with PREPARE justification", "justification", preprepare.JustificationPrepares) 73 } 74 75 // RLP-encode message 76 payload, err := rlp.EncodeToBytes(&preprepare) 77 if err != nil { 78 withMsg(logger, preprepare).Error("IBFT: failed to encode PRE-PREPARE message", "err", err) 79 return 80 } 81 82 logger = withMsg(logger, preprepare).New("block.number", preprepare.Proposal.Number().Uint64(), "block.hash", preprepare.Proposal.Hash().String()) 83 84 logger.Info("IBFT: broadcast PRE-PREPARE message", "payload", hexutil.Encode(payload)) 85 86 // Broadcast RLP-encoded message 87 if err = c.backend.Broadcast(c.valSet, preprepare.Code(), payload); err != nil { 88 logger.Error("IBFT: failed to broadcast PRE-PREPARE message", "err", err) 89 return 90 } 91 92 // Set the preprepareSent to the current round 93 c.current.preprepareSent = curView.Round 94 } 95 } 96 97 // handlePreprepareMsg is called when receiving a PRE-PREPARE message from the proposer 98 99 // It 100 // - validates PRE-PREPARE message was created by the right proposer node 101 // - validates PRE-PREPARE message justification 102 // - validates PRE-PREPARE message block proposal 103 func (c *core) handlePreprepareMsg(preprepare *qbfttypes.Preprepare) error { 104 logger := c.currentLogger(true, preprepare) 105 106 logger = logger.New("proposal.number", preprepare.Proposal.Number().Uint64(), "proposal.hash", preprepare.Proposal.Hash().String()) 107 108 c.logger.Info("IBFT: handle PRE-PREPARE message") 109 110 // Validates PRE-PREPARE message comes from current proposer 111 if !c.valSet.IsProposer(preprepare.Source()) { 112 logger.Warn("IBFT: ignore PRE-PREPARE message from non proposer", "proposer", c.valSet.GetProposer().Address()) 113 return errNotFromProposer 114 } 115 116 // Validates PRE-PREPARE message justification 117 if preprepare.Round.Uint64() > 0 { 118 if err := isJustified(preprepare.Proposal, preprepare.JustificationRoundChanges, preprepare.JustificationPrepares, c.QuorumSize()); err != nil { 119 logger.Warn("IBFT: invalid PRE-PREPARE message justification", "err", err) 120 return errInvalidPreparedBlock 121 } 122 } 123 124 // Validates PRE-PREPARE block proposal we received 125 if duration, err := c.backend.Verify(preprepare.Proposal); err != nil { 126 // if it's a future block, we will handle it again after the duration 127 if err == consensus.ErrFutureBlock { 128 logger.Info("IBFT: PRE-PREPARE block proposal is in the future (will be treated again later)", "duration", duration) 129 130 // start a timer to re-input PRE-PREPARE message as a backlog event 131 c.stopFuturePreprepareTimer() 132 c.futurePreprepareTimer = time.AfterFunc(duration, func() { 133 _, validator := c.valSet.GetByAddress(preprepare.Source()) 134 c.sendEvent(backlogEvent{ 135 src: validator, 136 msg: preprepare, 137 }) 138 }) 139 } else { 140 logger.Warn("IBFT: invalid PRE-PREPARE block proposal", "err", err) 141 } 142 143 return err 144 } 145 146 // Here is about to accept the PRE-PREPARE 147 if c.state == StateAcceptRequest { 148 c.logger.Info("IBFT: accepted PRE-PREPARE message") 149 150 // Re-initialize ROUND-CHANGE timer 151 c.newRoundChangeTimer() 152 c.consensusTimestamp = time.Now() 153 154 // Update current state 155 c.current.SetPreprepare(preprepare) 156 c.setState(StatePreprepared) 157 158 // Broadcast prepare message to other validators 159 c.broadcastPrepare() 160 } 161 162 return nil 163 }