github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/consensus/istanbul/core/preprepare.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  	"time"
    21  
    22  	"github.com/electroneum/electroneum-sc/common/hexutil"
    23  	"github.com/electroneum/electroneum-sc/consensus"
    24  	qbfttypes "github.com/electroneum/electroneum-sc/consensus/istanbul/types"
    25  	"github.com/electroneum/electroneum-sc/rlp"
    26  )
    27  
    28  // sendPreprepareMsg is called either
    29  // - when we are proposer after calling `miner.Seal(...)`
    30  // - roundChange happens and we are the proposer
    31  
    32  // It
    33  // - creates and sign PRE-PREPARE message with block proposed on `miner.Seal()`
    34  // - extends PRE-PREPARE message with ROUND-CHANGE and PREPARE justification
    35  // - broadcast PRE-PREPARE message to other validators
    36  func (c *core) sendPreprepareMsg(request *Request) {
    37  	logger := c.currentLogger(true, nil)
    38  
    39  	// If I'm the proposer and I have the same sequence with the proposal
    40  	if c.current.Sequence().Cmp(request.Proposal.Number()) == 0 && c.IsProposer() {
    41  		// Creates PRE-PREPARE message
    42  		curView := c.currentView()
    43  		preprepare := qbfttypes.NewPreprepare(curView.Sequence, curView.Round, request.Proposal)
    44  		preprepare.SetSource(c.Address())
    45  
    46  		// Sign payload
    47  		encodedPayload, err := preprepare.EncodePayloadForSigning()
    48  		if err != nil {
    49  			withMsg(logger, preprepare).Error("IBFT: failed to encode payload of PRE-PREPARE message", "err", err)
    50  			return
    51  		}
    52  		signature, err := c.backend.Sign(encodedPayload)
    53  		if err != nil {
    54  			withMsg(logger, preprepare).Error("IBFT: failed to sign PRE-PREPARE message", "err", err)
    55  			return
    56  		}
    57  		preprepare.SetSignature(signature)
    58  
    59  		// Extend PRE-PREPARE message with ROUND-CHANGE justification
    60  		if request.RCMessages != nil {
    61  			preprepare.JustificationRoundChanges = make([]*qbfttypes.SignedRoundChangePayload, 0)
    62  			for _, m := range request.RCMessages.Values() {
    63  				preprepare.JustificationRoundChanges = append(preprepare.JustificationRoundChanges, &m.(*qbfttypes.RoundChange).SignedRoundChangePayload)
    64  				withMsg(logger, preprepare).Trace("IBFT: add ROUND-CHANGE justification", "rc", m.(*qbfttypes.RoundChange).SignedRoundChangePayload)
    65  			}
    66  			withMsg(logger, preprepare).Trace("IBFT: extended PRE-PREPARE message with ROUND-CHANGE justifications", "justifications", preprepare.JustificationRoundChanges)
    67  		}
    68  
    69  		// Extend PRE-PREPARE message with PREPARE justification
    70  		if request.PrepareMessages != nil {
    71  			preprepare.JustificationPrepares = request.PrepareMessages
    72  			withMsg(logger, preprepare).Trace("IBFT: extended PRE-PREPARE message with PREPARE justification", "justification", preprepare.JustificationPrepares)
    73  		}
    74  
    75  		// RLP-encode message
    76  		payload, err := rlp.EncodeToBytes(&preprepare)
    77  		if err != nil {
    78  			withMsg(logger, preprepare).Error("IBFT: failed to encode PRE-PREPARE message", "err", err)
    79  			return
    80  		}
    81  
    82  		logger = withMsg(logger, preprepare).New("block.number", preprepare.Proposal.Number().Uint64(), "block.hash", preprepare.Proposal.Hash().String())
    83  
    84  		logger.Info("IBFT: broadcast PRE-PREPARE message", "payload", hexutil.Encode(payload))
    85  
    86  		// Broadcast RLP-encoded message
    87  		if err = c.backend.Broadcast(c.valSet, preprepare.Code(), payload); err != nil {
    88  			logger.Error("IBFT: failed to broadcast PRE-PREPARE message", "err", err)
    89  			return
    90  		}
    91  
    92  		// Set the preprepareSent to the current round
    93  		c.current.preprepareSent = curView.Round
    94  	}
    95  }
    96  
    97  // handlePreprepareMsg is called when receiving a PRE-PREPARE message from the proposer
    98  
    99  // It
   100  // - validates PRE-PREPARE message was created by the right proposer node
   101  // - validates PRE-PREPARE message justification
   102  // - validates PRE-PREPARE message block proposal
   103  func (c *core) handlePreprepareMsg(preprepare *qbfttypes.Preprepare) error {
   104  	logger := c.currentLogger(true, preprepare)
   105  
   106  	logger = logger.New("proposal.number", preprepare.Proposal.Number().Uint64(), "proposal.hash", preprepare.Proposal.Hash().String())
   107  
   108  	c.logger.Info("IBFT: handle PRE-PREPARE message")
   109  
   110  	// Validates PRE-PREPARE message comes from current proposer
   111  	if !c.valSet.IsProposer(preprepare.Source()) {
   112  		logger.Warn("IBFT: ignore PRE-PREPARE message from non proposer", "proposer", c.valSet.GetProposer().Address())
   113  		return errNotFromProposer
   114  	}
   115  
   116  	// Validates PRE-PREPARE message justification
   117  	if preprepare.Round.Uint64() > 0 {
   118  		if err := isJustified(preprepare.Proposal, preprepare.JustificationRoundChanges, preprepare.JustificationPrepares, c.QuorumSize()); err != nil {
   119  			logger.Warn("IBFT: invalid PRE-PREPARE message justification", "err", err)
   120  			return errInvalidPreparedBlock
   121  		}
   122  	}
   123  
   124  	// Validates PRE-PREPARE block proposal we received
   125  	if duration, err := c.backend.Verify(preprepare.Proposal); err != nil {
   126  		// if it's a future block, we will handle it again after the duration
   127  		if err == consensus.ErrFutureBlock {
   128  			logger.Info("IBFT: PRE-PREPARE block proposal is in the future (will be treated again later)", "duration", duration)
   129  
   130  			// start a timer to re-input PRE-PREPARE message as a backlog event
   131  			c.stopFuturePreprepareTimer()
   132  			c.futurePreprepareTimer = time.AfterFunc(duration, func() {
   133  				_, validator := c.valSet.GetByAddress(preprepare.Source())
   134  				c.sendEvent(backlogEvent{
   135  					src: validator,
   136  					msg: preprepare,
   137  				})
   138  			})
   139  		} else {
   140  			logger.Warn("IBFT: invalid PRE-PREPARE block proposal", "err", err)
   141  		}
   142  
   143  		return err
   144  	}
   145  
   146  	// Here is about to accept the PRE-PREPARE
   147  	if c.state == StateAcceptRequest {
   148  		c.logger.Info("IBFT: accepted PRE-PREPARE message")
   149  
   150  		// Re-initialize ROUND-CHANGE timer
   151  		c.newRoundChangeTimer()
   152  		c.consensusTimestamp = time.Now()
   153  
   154  		// Update current state
   155  		c.current.SetPreprepare(preprepare)
   156  		c.setState(StatePreprepared)
   157  
   158  		// Broadcast prepare message to other validators
   159  		c.broadcastPrepare()
   160  	}
   161  
   162  	return nil
   163  }