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  }