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  }