github.com/ConsenSys/Quorum@v20.10.0+incompatible/consensus/istanbul/core/commit.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) sendCommit() {
    27  	sub := c.current.Subject()
    28  	c.broadcastCommit(sub)
    29  }
    30  
    31  func (c *core) sendCommitForOldBlock(view *istanbul.View, digest common.Hash) {
    32  	sub := &istanbul.Subject{
    33  		View:   view,
    34  		Digest: digest,
    35  	}
    36  	c.broadcastCommit(sub)
    37  }
    38  
    39  func (c *core) broadcastCommit(sub *istanbul.Subject) {
    40  	logger := c.logger.New("state", c.state)
    41  
    42  	encodedSubject, err := Encode(sub)
    43  	if err != nil {
    44  		logger.Error("Failed to encode", "subject", sub)
    45  		return
    46  	}
    47  	c.broadcast(&message{
    48  		Code: msgCommit,
    49  		Msg:  encodedSubject,
    50  	})
    51  }
    52  
    53  func (c *core) handleCommit(msg *message, src istanbul.Validator) error {
    54  	// Decode COMMIT message
    55  	var commit *istanbul.Subject
    56  	err := msg.Decode(&commit)
    57  	if err != nil {
    58  		return errFailedDecodeCommit
    59  	}
    60  
    61  	if err := c.checkMessage(msgCommit, commit.View); err != nil {
    62  		return err
    63  	}
    64  
    65  	if err := c.verifyCommit(commit, src); err != nil {
    66  		return err
    67  	}
    68  
    69  	c.acceptCommit(msg, src)
    70  
    71  	// Commit the proposal once we have enough COMMIT messages and we are not in the Committed state.
    72  	//
    73  	// If we already have a proposal, we may have chance to speed up the consensus process
    74  	// by committing the proposal without PREPARE messages.
    75  	if c.current.Commits.Size() >= c.QuorumSize() && c.state.Cmp(StateCommitted) < 0 {
    76  		// Still need to call LockHash here since state can skip Prepared state and jump directly to the Committed state.
    77  		c.current.LockHash()
    78  		c.commit()
    79  	}
    80  
    81  	return nil
    82  }
    83  
    84  // verifyCommit verifies if the received COMMIT message is equivalent to our subject
    85  func (c *core) verifyCommit(commit *istanbul.Subject, src istanbul.Validator) error {
    86  	logger := c.logger.New("from", src, "state", c.state)
    87  
    88  	sub := c.current.Subject()
    89  	if !reflect.DeepEqual(commit, sub) {
    90  		logger.Warn("Inconsistent subjects between commit and proposal", "expected", sub, "got", commit)
    91  		return errInconsistentSubject
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  func (c *core) acceptCommit(msg *message, src istanbul.Validator) error {
    98  	logger := c.logger.New("from", src, "state", c.state)
    99  
   100  	// Add the COMMIT message to current round state
   101  	if err := c.current.Commits.Add(msg); err != nil {
   102  		logger.Error("Failed to record commit message", "msg", msg, "err", err)
   103  		return err
   104  	}
   105  
   106  	return nil
   107  }