github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/consensus/istanbul/core/roundchange.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 "sort" 23 "strings" 24 "sync" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/consensus/istanbul" 28 ) 29 30 // sendRoundChange broadcasts a ROUND CHANGE message with the current desired round. 31 func (c *core) sendRoundChange() { 32 logger := c.newLogger("func", "sendRoundChange") 33 34 msg, err := c.buildRoundChangeMsg(c.current.DesiredRound()) 35 if err != nil { 36 logger.Error("Could not build round change message", "err", msg) 37 return 38 } 39 40 c.broadcast(msg) 41 } 42 43 // sendRoundChange sends a ROUND CHANGE message for the current desired round back to a single address 44 func (c *core) sendRoundChangeAgain(addr common.Address) { 45 logger := c.newLogger("func", "sendRoundChangeAgain", "to", addr) 46 47 msg, err := c.buildRoundChangeMsg(c.current.DesiredRound()) 48 if err != nil { 49 logger.Error("Could not build round change message", "err", err) 50 return 51 } 52 53 c.unicast(msg, addr) 54 } 55 56 // buildRoundChangeMsg creates a round change msg for the given round 57 func (c *core) buildRoundChangeMsg(round *big.Int) (*istanbul.Message, error) { 58 nextView := &istanbul.View{ 59 Round: new(big.Int).Set(round), 60 Sequence: new(big.Int).Set(c.current.View().Sequence), 61 } 62 63 rc := &istanbul.RoundChange{ 64 View: nextView, 65 PreparedCertificate: c.current.PreparedCertificate(), 66 } 67 68 payload, err := Encode(rc) 69 if err != nil { 70 return nil, err 71 } 72 73 return &istanbul.Message{ 74 Code: istanbul.MsgRoundChange, 75 Msg: payload, 76 }, nil 77 } 78 79 func (c *core) handleRoundChangeCertificate(proposal istanbul.Subject, roundChangeCertificate istanbul.RoundChangeCertificate) error { 80 logger := c.newLogger("func", "handleRoundChangeCertificate", "proposal_round", proposal.View.Round, "proposal_seq", proposal.View.Sequence, "proposal_digest", proposal.Digest.String()) 81 82 if len(roundChangeCertificate.RoundChangeMessages) > c.current.ValidatorSet().Size() || len(roundChangeCertificate.RoundChangeMessages) < c.current.ValidatorSet().MinQuorumSize() { 83 return errInvalidRoundChangeCertificateNumMsgs 84 } 85 86 maxRound := big.NewInt(-1) 87 preferredDigest := common.Hash{} 88 seen := make(map[common.Address]bool) 89 decodedMessages := make([]istanbul.RoundChange, len(roundChangeCertificate.RoundChangeMessages)) 90 for i := range roundChangeCertificate.RoundChangeMessages { 91 // use a different variable each time since we'll store a pointer to the variable 92 message := roundChangeCertificate.RoundChangeMessages[i] 93 94 // Verify message signed by a validator 95 data, err := message.PayloadNoSig() 96 if err != nil { 97 return err 98 } 99 100 signer, err := c.validateFn(data, message.Signature) 101 if err != nil { 102 return err 103 } 104 105 if signer != message.Address { 106 return errInvalidRoundChangeCertificateMsgSignature 107 } 108 109 // Check for duplicate ROUND CHANGE messages 110 if seen[signer] { 111 return errInvalidRoundChangeCertificateDuplicate 112 } 113 seen[signer] = true 114 115 // Check that the message is a ROUND CHANGE message 116 if istanbul.MsgRoundChange != message.Code { 117 return errInvalidRoundChangeCertificateMsgCode 118 } 119 120 var roundChange *istanbul.RoundChange 121 if err := message.Decode(&roundChange); err != nil { 122 logger.Warn("Failed to decode ROUND CHANGE in certificate", "err", err) 123 return err 124 } else if roundChange.View == nil || roundChange.View.Sequence == nil || roundChange.View.Round == nil { 125 return errInvalidRoundChangeCertificateMsgView 126 } 127 128 msgLogger := logger.New("msg_round", roundChange.View.Round, "msg_seq", roundChange.View.Sequence) 129 130 // Verify ROUND CHANGE message is for the same sequence AND an equal or subsequent round as the proposal. 131 // We have already called checkMessage by this point and checked the proposal's and PREPREPARE's sequence match. 132 if roundChange.View.Sequence.Cmp(proposal.View.Sequence) != 0 || roundChange.View.Round.Cmp(proposal.View.Round) < 0 { 133 msgLogger.Error("Round change in certificate for a different sequence or an earlier round", "err", err) 134 return errInvalidRoundChangeCertificateMsgView 135 } 136 137 if roundChange.HasPreparedCertificate() { 138 msgLogger.Trace("Round change message has prepared certificate") 139 preparedView, err := c.verifyPreparedCertificate(roundChange.PreparedCertificate) 140 if err != nil { 141 return err 142 } 143 // We must use the proposal in the prepared certificate with the highest round number. (See OSDI 99, Section 4.4) 144 // Older prepared certificates may be generated, but if no node committed, there is no guarantee that 145 // it will be the next pre-prepare. If one node committed, that block is guaranteed (by quorum intersection) 146 // to be the next pre-prepare. That (higher view) prepared cert should override older perpared certs for 147 // blocks that were not committed. 148 // Also reject round change messages where the prepared view is greater than the round change view. 149 msgLogger = msgLogger.New("prepared_round", preparedView.Round, "prepared_seq", preparedView.Sequence) 150 if preparedView == nil || preparedView.Round.Cmp(proposal.View.Round) > 0 { 151 return errInvalidRoundChangeViewMismatch 152 } else if preparedView.Round.Cmp(maxRound) > 0 { 153 msgLogger.Trace("Prepared certificate is latest in round change certificate") 154 maxRound = preparedView.Round 155 preferredDigest = roundChange.PreparedCertificate.Proposal.Hash() 156 } 157 } 158 159 decodedMessages[i] = *roundChange 160 // TODO(joshua): startNewRound needs these round change messages to generate a 161 // round change certificate even if this node is not the next proposer 162 c.roundChangeSet.Add(roundChange.View.Round, &message) 163 } 164 165 if maxRound.Cmp(big.NewInt(-1)) > 0 && proposal.Digest != preferredDigest { 166 return errInvalidPreparedCertificateDigestMismatch 167 } 168 169 // May have already moved to this round based on quorum round change messages. 170 logger.Trace("Trying to move to round change certificate's round", "target round", proposal.View.Round) 171 172 return c.startNewRound(proposal.View.Round) 173 } 174 175 func (c *core) handleRoundChange(msg *istanbul.Message) error { 176 logger := c.newLogger("func", "handleRoundChange", "tag", "handleMsg", "from", msg.Address) 177 178 // Decode ROUND CHANGE message 179 var rc *istanbul.RoundChange 180 if err := msg.Decode(&rc); err != nil { 181 logger.Info("Failed to decode ROUND CHANGE", "err", err) 182 return errInvalidMessage 183 } 184 logger = logger.New("msg_round", rc.View.Round, "msg_seq", rc.View.Sequence) 185 186 // Must be same sequence and future round. 187 err := c.checkMessage(istanbul.MsgRoundChange, rc.View) 188 189 // If the RC message is for the current sequence but a prior round, help the sender fast forward 190 // by sending back to it (not broadcasting) a round change message for our desired round. 191 if err == errOldMessage && rc.View.Sequence.Cmp(c.current.Sequence()) == 0 { 192 logger.Trace("Sending round change for desired round to node with a previous desired round", "msg_round", rc.View.Round) 193 c.sendRoundChangeAgain(msg.Address) 194 return nil 195 } else if err != nil { 196 logger.Debug("Check round change message failed", "err", err) 197 return err 198 } 199 200 // Verify the PREPARED certificate if present. 201 if rc.HasPreparedCertificate() { 202 preparedView, err := c.verifyPreparedCertificate(rc.PreparedCertificate) 203 if err != nil { 204 return err 205 } else if preparedView == nil || preparedView.Round.Cmp(rc.View.Round) > 0 { 206 return errInvalidRoundChangeViewMismatch 207 } 208 } 209 210 roundView := rc.View 211 212 // Add the ROUND CHANGE message to its message set. 213 if err := c.roundChangeSet.Add(roundView.Round, msg); err != nil { 214 logger.Warn("Failed to add round change message", "roundView", roundView, "err", err) 215 return err 216 } 217 218 // Skip to the highest round we know F+1 (one honest validator) is at, but 219 // don't start a round until we have a quorum who want to start a given round. 220 ffRound := c.roundChangeSet.MaxRound(c.current.ValidatorSet().F() + 1) 221 quorumRound := c.roundChangeSet.MaxOnOneRound(c.current.ValidatorSet().MinQuorumSize()) 222 logger = logger.New("ffRound", ffRound, "quorumRound", quorumRound) 223 logger.Trace("Got round change message", "rcs", c.roundChangeSet.String()) 224 // On f+1 round changes we send a round change and wait for the next round if we haven't done so already 225 // On quorum round change messages we go to the next round immediately. 226 if quorumRound != nil && quorumRound.Cmp(c.current.DesiredRound()) >= 0 { 227 logger.Debug("Got quorum round change messages, starting new round.") 228 return c.startNewRound(quorumRound) 229 } else if ffRound != nil { 230 logger.Debug("Got f+1 round change messages, sending own round change message and waiting for next round.") 231 c.waitForDesiredRound(ffRound) 232 } 233 234 return nil 235 } 236 237 // ---------------------------------------------------------------------------- 238 239 func newRoundChangeSet(valSet istanbul.ValidatorSet) *roundChangeSet { 240 return &roundChangeSet{ 241 validatorSet: valSet, 242 msgsForRound: make(map[uint64]MessageSet), 243 latestRoundForVal: make(map[common.Address]uint64), 244 mu: new(sync.Mutex), 245 } 246 } 247 248 type roundChangeSet struct { 249 validatorSet istanbul.ValidatorSet 250 msgsForRound map[uint64]MessageSet 251 latestRoundForVal map[common.Address]uint64 252 mu *sync.Mutex 253 } 254 255 // Add adds the round and message into round change set 256 func (rcs *roundChangeSet) Add(r *big.Int, msg *istanbul.Message) error { 257 rcs.mu.Lock() 258 defer rcs.mu.Unlock() 259 260 src := msg.Address 261 round := r.Uint64() 262 263 if prevLatestRound, ok := rcs.latestRoundForVal[src]; ok { 264 if prevLatestRound > round { 265 // Reject as we have an RC for a later round from this validator. 266 return errOldMessage 267 } else if prevLatestRound < round { 268 // Already got an RC for an earlier round from this validator. 269 // Forget that and remember this. 270 if rcs.msgsForRound[prevLatestRound] != nil { 271 rcs.msgsForRound[prevLatestRound].Remove(src) 272 if rcs.msgsForRound[prevLatestRound].Size() == 0 { 273 delete(rcs.msgsForRound, prevLatestRound) 274 } 275 } 276 } 277 } 278 279 rcs.latestRoundForVal[src] = round 280 281 if rcs.msgsForRound[round] == nil { 282 rcs.msgsForRound[round] = newMessageSet(rcs.validatorSet) 283 } 284 return rcs.msgsForRound[round].Add(msg) 285 } 286 287 // Clear deletes the messages with smaller round 288 func (rcs *roundChangeSet) Clear(round *big.Int) { 289 rcs.mu.Lock() 290 defer rcs.mu.Unlock() 291 292 for k, rms := range rcs.msgsForRound { 293 if rms.Size() == 0 || k < round.Uint64() { 294 for _, msg := range rms.Values() { 295 if _, ok := rcs.latestRoundForVal[msg.Address]; ok { 296 delete(rcs.latestRoundForVal, msg.Address) 297 } 298 } 299 delete(rcs.msgsForRound, k) 300 } 301 } 302 } 303 304 // MaxRound returns the max round which the number of messages is equal or larger than num 305 func (rcs *roundChangeSet) MaxRound(num int) *big.Int { 306 rcs.mu.Lock() 307 defer rcs.mu.Unlock() 308 309 // Sort rounds descending 310 var sortedRounds []uint64 311 for r := range rcs.msgsForRound { 312 sortedRounds = append(sortedRounds, r) 313 } 314 sort.Slice(sortedRounds, func(i, j int) bool { return sortedRounds[i] > sortedRounds[j] }) 315 316 acc := 0 317 for _, r := range sortedRounds { 318 rms := rcs.msgsForRound[r] 319 acc += rms.Size() 320 if acc >= num { 321 return new(big.Int).SetUint64(r) 322 } 323 } 324 325 return nil 326 } 327 328 // MaxOnOneRound returns the max round which the number of messages is >= num 329 func (rcs *roundChangeSet) MaxOnOneRound(num int) *big.Int { 330 rcs.mu.Lock() 331 defer rcs.mu.Unlock() 332 333 // Sort rounds descending 334 var sortedRounds []uint64 335 for r := range rcs.msgsForRound { 336 sortedRounds = append(sortedRounds, r) 337 } 338 sort.Slice(sortedRounds, func(i, j int) bool { return sortedRounds[i] > sortedRounds[j] }) 339 340 for _, r := range sortedRounds { 341 rms := rcs.msgsForRound[r] 342 if rms.Size() >= num { 343 return new(big.Int).SetUint64(r) 344 } 345 } 346 return nil 347 } 348 349 func (rcs *roundChangeSet) String() string { 350 rcs.mu.Lock() 351 defer rcs.mu.Unlock() 352 353 // Sort rounds descending 354 var sortedRounds []uint64 355 for r := range rcs.msgsForRound { 356 sortedRounds = append(sortedRounds, r) 357 } 358 sort.Slice(sortedRounds, func(i, j int) bool { return sortedRounds[i] > sortedRounds[j] }) 359 360 modeRound := uint64(0) 361 modeRoundSize := 0 362 msgsForRoundStr := make([]string, 0, len(sortedRounds)) 363 for _, r := range sortedRounds { 364 rms := rcs.msgsForRound[r] 365 if rms.Size() > modeRoundSize { 366 modeRound = r 367 modeRoundSize = rms.Size() 368 } 369 msgsForRoundStr = append(msgsForRoundStr, fmt.Sprintf("%v: %v", r, rms.String())) 370 } 371 372 latestRoundForValStr := make([]string, 0, len(rcs.latestRoundForVal)) 373 for addr, r := range rcs.latestRoundForVal { 374 latestRoundForValStr = append(latestRoundForValStr, fmt.Sprintf("%v: %v", addr.String(), r)) 375 } 376 377 return fmt.Sprintf("RCS len=%v mode_round=%v mode_round_len=%v unique_rounds=%v %v", 378 len(rcs.latestRoundForVal), 379 modeRound, 380 modeRoundSize, 381 len(rcs.msgsForRound), 382 strings.Join(msgsForRoundStr, ", ")) 383 } 384 385 // Gets a round change certificate for a specific round. Includes quorumSize messages of that round or later. 386 // If the total is less than quorumSize, returns an empty cert and errFailedCreateRoundChangeCertificate. 387 func (rcs *roundChangeSet) getCertificate(minRound *big.Int, quorumSize int) (istanbul.RoundChangeCertificate, error) { 388 rcs.mu.Lock() 389 defer rcs.mu.Unlock() 390 391 // Sort rounds descending 392 var sortedRounds []uint64 393 for r := range rcs.msgsForRound { 394 sortedRounds = append(sortedRounds, r) 395 } 396 sort.Slice(sortedRounds, func(i, j int) bool { return sortedRounds[i] > sortedRounds[j] }) 397 398 var messages []istanbul.Message 399 for _, r := range sortedRounds { 400 if r < minRound.Uint64() { 401 break 402 } 403 for _, message := range rcs.msgsForRound[r].Values() { 404 messages = append(messages, *message) 405 406 // Stop when we've added a quorum of the highest-round messages. 407 if len(messages) >= quorumSize { 408 return istanbul.RoundChangeCertificate{ 409 RoundChangeMessages: messages, 410 }, nil 411 } 412 } 413 } 414 415 // Didn't find a quorum of messages. Return an empty certificate with error. 416 return istanbul.RoundChangeCertificate{}, errFailedCreateRoundChangeCertificate 417 }