github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/consensus/istanbul/core/prepare.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 "reflect" 21 22 "github.com/ethereum/go-ethereum/common" 23 "github.com/ethereum/go-ethereum/consensus/istanbul" 24 ) 25 26 func (c *core) sendPrepare() { 27 logger := c.newLogger("func", "sendPrepare") 28 29 sub := c.current.Subject() 30 encodedSubject, err := Encode(sub) 31 if err != nil { 32 logger.Error("Failed to encode", "subject", sub) 33 return 34 } 35 logger.Debug("Sending prepare") 36 c.broadcast(&istanbul.Message{ 37 Code: istanbul.MsgPrepare, 38 Msg: encodedSubject, 39 }) 40 } 41 42 // Verify a prepared certificate and return the view that all of its messages pertain to. 43 func (c *core) verifyPreparedCertificate(preparedCertificate istanbul.PreparedCertificate) (*istanbul.View, error) { 44 logger := c.newLogger("func", "verifyPreparedCertificate", "proposal_number", preparedCertificate.Proposal.Number(), "proposal_hash", preparedCertificate.Proposal.Hash().String()) 45 46 // Validate the attached proposal 47 if _, err := c.verifyProposal(preparedCertificate.Proposal); err != nil { 48 return nil, errInvalidPreparedCertificateProposal 49 } 50 51 if len(preparedCertificate.PrepareOrCommitMessages) > c.current.ValidatorSet().Size() || len(preparedCertificate.PrepareOrCommitMessages) < c.current.ValidatorSet().MinQuorumSize() { 52 return nil, errInvalidPreparedCertificateNumMsgs 53 } 54 55 seen := make(map[common.Address]bool) 56 57 var view *istanbul.View 58 for _, message := range preparedCertificate.PrepareOrCommitMessages { 59 data, err := message.PayloadNoSig() 60 if err != nil { 61 return nil, err 62 } 63 64 // Verify message signed by a validator 65 signer, err := c.validateFn(data, message.Signature) 66 if err != nil { 67 return nil, err 68 } 69 70 if signer != message.Address { 71 return nil, errInvalidPreparedCertificateMsgSignature 72 } 73 74 // Check for duplicate messages 75 if seen[signer] { 76 return nil, errInvalidPreparedCertificateDuplicate 77 } 78 seen[signer] = true 79 80 // Check that the message is a PREPARE or COMMIT message 81 if message.Code != istanbul.MsgPrepare && message.Code != istanbul.MsgCommit { 82 return nil, errInvalidPreparedCertificateMsgCode 83 } 84 85 var subject *istanbul.Subject 86 87 if message.Code == istanbul.MsgCommit { 88 var committedSubject *istanbul.CommittedSubject 89 err := message.Decode(&committedSubject) 90 if err != nil { 91 logger.Error("Failed to decode committedSubject in PREPARED certificate", "err", err) 92 return nil, err 93 } 94 95 // Verify the committedSeal 96 src := c.current.GetValidatorByAddress(signer) 97 err = c.verifyCommittedSeal(committedSubject, src) 98 if err != nil { 99 logger.Error("Commit seal did not contain signature from message signer.", "err", err) 100 return nil, err 101 } 102 103 newValSet, err := c.backend.NextBlockValidators(preparedCertificate.Proposal) 104 if err != nil { 105 return nil, err 106 } 107 err = c.verifyEpochValidatorSetSeal(committedSubject, preparedCertificate.Proposal.Number().Uint64(), newValSet, src) 108 if err != nil { 109 logger.Error("Epoch validator set seal seal did not contain signature from message signer.", "err", err) 110 return nil, err 111 } 112 113 subject = committedSubject.Subject 114 } else { 115 if err := message.Decode(&subject); err != nil { 116 logger.Error("Failed to decode message in PREPARED certificate", "err", err) 117 return nil, err 118 } 119 } 120 121 msgLogger := logger.New("msg_round", subject.View.Round, "msg_seq", subject.View.Sequence, "msg_digest", subject.Digest.String()) 122 msgLogger.Trace("Decoded message in prepared certificate", "code", message.Code) 123 124 // Verify message for the proper sequence. 125 if subject.View.Sequence.Cmp(c.current.Sequence()) != 0 { 126 return nil, errInvalidPreparedCertificateMsgView 127 } 128 129 // Verify message for the proper proposal. 130 if subject.Digest != preparedCertificate.Proposal.Hash() { 131 return nil, errInvalidPreparedCertificateDigestMismatch 132 } 133 134 // Verify that the view is the same for all of the messages 135 if view == nil { 136 view = subject.View 137 } else { 138 if view.Cmp(subject.View) != 0 { 139 return nil, errInvalidPreparedCertificateInconsistentViews 140 } 141 } 142 } 143 return view, nil 144 } 145 146 // Extract the view from a PreparedCertificate that has already been verified. 147 func (c *core) getViewFromVerifiedPreparedCertificate(preparedCertificate istanbul.PreparedCertificate) (*istanbul.View, error) { 148 logger := c.newLogger("func", "getViewFromVerifiedPreparedCertificate", "proposal_number", preparedCertificate.Proposal.Number(), "proposal_hash", preparedCertificate.Proposal.Hash().String()) 149 150 if len(preparedCertificate.PrepareOrCommitMessages) < c.current.ValidatorSet().MinQuorumSize() { 151 return nil, errInvalidPreparedCertificateNumMsgs 152 } 153 154 message := preparedCertificate.PrepareOrCommitMessages[0] 155 156 var subject *istanbul.Subject 157 158 if message.Code == istanbul.MsgCommit { 159 var committedSubject *istanbul.CommittedSubject 160 err := message.Decode(&committedSubject) 161 if err != nil { 162 logger.Error("Failed to decode committedSubject in PREPARED certificate", "err", err) 163 return nil, err 164 } 165 subject = committedSubject.Subject 166 } else { 167 if err := message.Decode(&subject); err != nil { 168 logger.Error("Failed to decode message in PREPARED certificate", "err", err) 169 return nil, err 170 } 171 } 172 173 return subject.View, nil 174 } 175 176 func (c *core) handlePrepare(msg *istanbul.Message) error { 177 // Decode PREPARE message 178 var prepare *istanbul.Subject 179 err := msg.Decode(&prepare) 180 if err != nil { 181 return errFailedDecodePrepare 182 } 183 logger := c.newLogger("func", "handlePrepare", "tag", "handleMsg", "msg_round", prepare.View.Round, "msg_seq", prepare.View.Sequence, "msg_digest", prepare.Digest.String()) 184 185 if err := c.checkMessage(istanbul.MsgPrepare, prepare.View); err != nil { 186 return err 187 } 188 189 if err := c.verifyPrepare(prepare); err != nil { 190 return err 191 } 192 193 // Add the PREPARE message to current round state 194 if err := c.current.AddPrepare(msg); err != nil { 195 logger.Error("Failed to add PREPARE message to round state", "err", err) 196 return err 197 } 198 199 preparesAndCommits := c.current.GetPrepareOrCommitSize() 200 minQuorumSize := c.current.ValidatorSet().MinQuorumSize() 201 logger.Trace("Accepted prepare", "Number of prepares or commits", preparesAndCommits) 202 203 // Change to Prepared state if we've received enough PREPARE messages and we are in earlier state 204 // before Prepared state. 205 // TODO(joshua): Remove state comparisons (or change the cmp function) 206 if (preparesAndCommits >= minQuorumSize) && c.current.State().Cmp(StatePrepared) < 0 { 207 208 err := c.current.TransitionToPrepared(minQuorumSize) 209 if err != nil { 210 logger.Error("Failed to create and set preprared certificate", "err", err) 211 return err 212 } 213 logger.Trace("Got quorum prepares or commits", "tag", "stateTransition", "commits", c.current.Commits, "prepares", c.current.Prepares) 214 215 // Process Backlog Messages 216 c.backlog.updateState(c.current.View(), c.current.State()) 217 218 c.sendCommit() 219 220 } 221 222 return nil 223 } 224 225 // verifyPrepare verifies if the received PREPARE message is equivalent to our subject 226 func (c *core) verifyPrepare(prepare *istanbul.Subject) error { 227 logger := c.newLogger("func", "verifyPrepare", "prepare_round", prepare.View.Round, "prepare_seq", prepare.View.Sequence, "prepare_digest", prepare.Digest.String()) 228 229 sub := c.current.Subject() 230 if !reflect.DeepEqual(prepare, sub) { 231 logger.Warn("Inconsistent subjects between PREPARE and proposal", "expected", sub, "got", prepare) 232 return errInconsistentSubject 233 } 234 235 return nil 236 }