github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/consensus/istanbul/core/request.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/consensus/istanbul"
    21  )
    22  
    23  // handleRequest is called by proposer in reaction to `miner.Seal()`
    24  // (this is the starting of the QBFT validation process)
    25  
    26  // It
    27  // - validates block proposal is not empty and number correspond to the current sequence
    28  // - creates and send PRE-PREPARE message to other validators
    29  func (c *core) handleRequest(request *Request) error {
    30  	logger := c.currentLogger(true, nil)
    31  
    32  	logger.Info("IBFT: handle block proposal request")
    33  
    34  	if err := c.checkRequestMsg(request); err != nil {
    35  		if err == errInvalidMessage {
    36  			logger.Error("IBFT: invalid request")
    37  			return err
    38  		}
    39  		logger.Error("IBFT: unexpected request", "err", err, "number", request.Proposal.Number(), "hash", request.Proposal.Hash())
    40  		return err
    41  	}
    42  
    43  	c.current.pendingRequest = request
    44  	if c.state == StateAcceptRequest {
    45  		// Start ROUND-CHANGE timer
    46  		c.newRoundChangeTimer()
    47  
    48  		// Send PRE-PREPARE message to other validators
    49  		c.sendPreprepareMsg(request)
    50  	}
    51  
    52  	return nil
    53  }
    54  
    55  // check request state
    56  // return errInvalidMessage if the message is invalid
    57  // return errFutureMessage if the sequence of proposal is larger than current sequence
    58  // return errOldMessage if the sequence of proposal is smaller than current sequence
    59  func (c *core) checkRequestMsg(request *Request) error {
    60  	if request == nil || request.Proposal == nil {
    61  		return errInvalidMessage
    62  	}
    63  
    64  	if c := c.current.sequence.Cmp(request.Proposal.Number()); c > 0 {
    65  		return errOldMessage
    66  	} else if c < 0 {
    67  		return errFutureMessage
    68  	} else {
    69  		return nil
    70  	}
    71  }
    72  
    73  func (c *core) storeRequestMsg(request *Request) {
    74  	logger := c.currentLogger(true, nil).New("proposal.number", request.Proposal.Number(), "proposal.hash", request.Proposal.Hash())
    75  
    76  	logger.Trace("IBFT: store block proposal request for future treatment")
    77  
    78  	c.pendingRequestsMu.Lock()
    79  	defer c.pendingRequestsMu.Unlock()
    80  
    81  	c.pendingRequests.Push(request, float32(-request.Proposal.Number().Int64()))
    82  }
    83  
    84  // processPendingRequests is called each time QBFT state is re-initialized
    85  // it lookup over pending requests and re-input its so they can be treated
    86  func (c *core) processPendingRequests() {
    87  	c.pendingRequestsMu.Lock()
    88  	defer c.pendingRequestsMu.Unlock()
    89  
    90  	logger := c.currentLogger(true, nil)
    91  	logger.Debug("IBFT: lookup for pending block proposal requests")
    92  
    93  	for !(c.pendingRequests.Empty()) {
    94  		m, prio := c.pendingRequests.Pop()
    95  		r, ok := m.(*Request)
    96  		if !ok {
    97  			logger.Error("IBFT: malformed pending block proposal request, skip", "msg", m)
    98  			continue
    99  		}
   100  		// Push back if it's a future message
   101  		err := c.checkRequestMsg(r)
   102  		if err != nil {
   103  			if err == errFutureMessage {
   104  				logger.Trace("IBFT: stop looking up for pending block proposal request")
   105  				c.pendingRequests.Push(m, prio)
   106  				break
   107  			}
   108  			logger.Trace("IBFT: skip pending invalid block proposal request", "number", r.Proposal.Number(), "hash", r.Proposal.Hash(), "err", err)
   109  			continue
   110  		}
   111  		logger.Debug("IBFT: found pending block proposal request", "proposal.number", r.Proposal.Number(), "proposal.hash", r.Proposal.Hash())
   112  
   113  		go c.sendEvent(istanbul.RequestEvent{
   114  			Proposal: r.Proposal,
   115  		})
   116  	}
   117  }