github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/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  	"github.com/electroneum/electroneum-sc/common/hexutil"
    21  	qbfttypes "github.com/electroneum/electroneum-sc/consensus/istanbul/types"
    22  	"github.com/electroneum/electroneum-sc/rlp"
    23  )
    24  
    25  // broadcastPrepare is called after receiving PRE-PREPARE from proposer node
    26  
    27  // It
    28  // - creates a PREPARE message
    29  // - broadcast PREPARE message to other validators
    30  func (c *core) broadcastPrepare() {
    31  	logger := c.currentLogger(true, nil)
    32  
    33  	// Create PREPARE message from the current proposal
    34  	sub := c.current.Subject()
    35  	prepare := qbfttypes.NewPrepare(sub.View.Sequence, sub.View.Round, sub.Digest)
    36  	prepare.SetSource(c.Address())
    37  
    38  	// Sign Message
    39  	encodedPayload, err := prepare.EncodePayloadForSigning()
    40  	if err != nil {
    41  		withMsg(logger, prepare).Error("IBFT: failed to encode payload of PREPARE message", "err", err)
    42  		return
    43  	}
    44  	signature, err := c.backend.Sign(encodedPayload)
    45  	if err != nil {
    46  		withMsg(logger, prepare).Error("IBFT: failed to sign PREPARE message", "err", err)
    47  		return
    48  	}
    49  	prepare.SetSignature(signature)
    50  
    51  	// RLP-encode message
    52  	payload, err := rlp.EncodeToBytes(&prepare)
    53  	if err != nil {
    54  		withMsg(logger, prepare).Error("IBFT: failed to encode PREPARE message", "err", err)
    55  		return
    56  	}
    57  
    58  	withMsg(logger, prepare).Info("IBFT: broadcast PREPARE message", "payload", hexutil.Encode(payload))
    59  
    60  	// Broadcast RLP-encoded message
    61  	if err = c.backend.Broadcast(c.valSet, prepare.Code(), payload); err != nil {
    62  		withMsg(logger, prepare).Error("IBFT: failed to broadcast PREPARE message", "err", err)
    63  		return
    64  	}
    65  }
    66  
    67  // handlePrepare is called when receiving a PREPARE message
    68  
    69  // It
    70  // - validates PREPARE message digest matches the current block proposal
    71  // - accumulates valid PREPARE message until reaching quorum
    72  // - when quorum is reached update states to "Prepared" and broadcast COMMIT
    73  func (c *core) handlePrepare(prepare *qbfttypes.Prepare) error {
    74  	logger := c.currentLogger(true, prepare).New()
    75  
    76  	logger.Info("IBFT: handle PREPARE message", "prepares.count", c.current.QBFTPrepares.Size(), "quorum", c.QuorumSize())
    77  
    78  	// Check digest
    79  	if prepare.Digest != c.current.Proposal().Hash() {
    80  		logger.Error("IBFT: invalid PREPARE message digest")
    81  		return errInvalidMessage
    82  	}
    83  
    84  	// Save PREPARE messages
    85  	if err := c.current.QBFTPrepares.Add(prepare); err != nil {
    86  		logger.Error("IBFT: failed to save PREPARE message", "err", err)
    87  		return err
    88  	}
    89  
    90  	logger = logger.New("prepares.count", c.current.QBFTPrepares.Size(), "quorum", c.QuorumSize())
    91  
    92  	// Change to "Prepared" state if we've received quorum of PREPARE messages
    93  	// and we are in earlier state than "Prepared"
    94  	if (c.current.QBFTPrepares.Size() >= c.QuorumSize()) && c.state.Cmp(StatePrepared) < 0 {
    95  		logger.Info("IBFT: received quorum of PREPARE messages")
    96  
    97  		// Accumulates PREPARE messages
    98  		c.current.preparedRound = c.currentView().Round
    99  		c.QBFTPreparedPrepares = make([]*qbfttypes.Prepare, 0)
   100  		for _, m := range c.current.QBFTPrepares.Values() {
   101  			c.QBFTPreparedPrepares = append(
   102  				c.QBFTPreparedPrepares,
   103  				qbfttypes.NewPrepareWithSigAndSource(
   104  					m.View().Sequence, m.View().Round, m.(*qbfttypes.Prepare).Digest, m.Signature(), m.Source()))
   105  		}
   106  
   107  		if c.current.Proposal() != nil && c.current.Proposal().Hash() == prepare.Digest {
   108  			logger.Debug("IBFT: PREPARE message matches proposal", "proposal", c.current.Proposal().Hash(), "prepare", prepare.Digest)
   109  			c.current.preparedBlock = c.current.Proposal()
   110  		}
   111  
   112  		c.setState(StatePrepared)
   113  		c.broadcastCommit()
   114  	} else {
   115  		logger.Debug("IBFT: accepted PREPARE messages")
   116  	}
   117  
   118  	return nil
   119  }