github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/pbft/core/backlog.go (about)

     1  // Copyright 2020 The go-simplechain Authors
     2  // This file is part of the go-simplechain library.
     3  //
     4  // The go-simplechain 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-simplechain 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-simplechain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package core
    18  
    19  import (
    20  	"github.com/bigzoro/my_simplechain/common/prque"
    21  	"github.com/bigzoro/my_simplechain/consensus/pbft"
    22  )
    23  
    24  var (
    25  	// msgPriority is defined for calculating processing priority to speedup consensus
    26  	// msgPreprepare > msgCommit > msgPrepare
    27  	msgPriority = map[MsgCode]int{
    28  		msgPreprepare: 1,
    29  		msgCommit:     2,
    30  		msgPrepare:    3,
    31  	}
    32  )
    33  
    34  // checkMessage checks the message state
    35  // return errInvalidMessage if the message is invalid
    36  // return errFutureMessage if the message view is larger than current view
    37  // return errOldMessage if the message view is smaller than current view
    38  func (c *core) checkMessage(msgCode MsgCode, view *pbft.View) error {
    39  	if view == nil || view.Sequence == nil || view.Round == nil {
    40  		return errInvalidMessage
    41  	}
    42  
    43  	if msgCode == msgRoundChange {
    44  		if view.Sequence.Cmp(c.currentView().Sequence) > 0 {
    45  			return errFutureMessage
    46  		} else if view.Cmp(c.currentView()) < 0 {
    47  			return errOldMessage
    48  		}
    49  		return nil
    50  	}
    51  
    52  	if view.Cmp(c.currentView()) > 0 {
    53  		return errFutureMessage
    54  	}
    55  
    56  	if view.Cmp(c.currentView()) < 0 {
    57  		return errOldMessage
    58  	}
    59  
    60  	if c.waitingForRoundChange {
    61  		return errFutureMessage
    62  	}
    63  
    64  	if c.state == StateAcceptRequest {
    65  		switch {
    66  		// unsupported light messages node
    67  		case isLightProposalMsg(msgCode) && !c.config.LightMode:
    68  			return errInvalidMessage
    69  		// StateAcceptRequest only accepts msgPreprepare or light proposal messages*
    70  		// other messages are future messages
    71  		case msgCode > msgPreprepare && msgCode <= msgRoundChange:
    72  			return errFutureMessage
    73  		case msgCode == msgGetMissedTxs:
    74  			return errFutureMessage
    75  		}
    76  		return nil
    77  	}
    78  
    79  	// For states(StatePreprepared, StatePrepared, StateCommitted),
    80  	// can accept all message types if processing with same view
    81  	return nil
    82  }
    83  
    84  func (c *core) storeBacklog(msg *message, src pbft.Validator) {
    85  	logger := c.logger.New("from", src, "state", c.state)
    86  
    87  	// dont backlog message from self
    88  	if src.Address() == c.Address() {
    89  		logger.Warn("Backlog from self")
    90  		return
    91  	}
    92  
    93  	logger.Trace("Store future message")
    94  
    95  	c.backlogsMu.Lock()
    96  	defer c.backlogsMu.Unlock()
    97  
    98  	logger.Debug("Retrieving backlog queue", "for", src.Address(), "backlogs_size", len(c.backlogs))
    99  	backlog := c.backlogs[src.Address()]
   100  	if backlog == nil {
   101  		backlog = prque.New(nil)
   102  	}
   103  	switch msg.Code {
   104  	case msgPreprepare:
   105  		var p *pbft.Preprepare
   106  		err := msg.Decode(&p)
   107  		if err == nil {
   108  			backlog.Push(msg, toPriority(msg.Code, p.View))
   109  		}
   110  		// for msgRoundChange, msgPrepare and msgCommit cases
   111  	case msgLightPreprepare:
   112  		var p *pbft.LightPreprepare
   113  		err := msg.Decode(&p)
   114  		if err == nil {
   115  			backlog.Push(msg, toPriority(msg.Code, p.View))
   116  		}
   117  	default:
   118  		var p *pbft.Subject
   119  		err := msg.Decode(&p)
   120  		if err == nil {
   121  			backlog.Push(msg, toPriority(msg.Code, p.View))
   122  		}
   123  	}
   124  	c.backlogs[src.Address()] = backlog
   125  }
   126  
   127  func (c *core) processBacklog() {
   128  	c.backlogsMu.Lock()
   129  	defer c.backlogsMu.Unlock()
   130  
   131  	for srcAddress, backlog := range c.backlogs {
   132  		if backlog == nil {
   133  			continue
   134  		}
   135  		_, src := c.valSet.GetByAddress(srcAddress)
   136  		if src == nil {
   137  			// validator is not available
   138  			delete(c.backlogs, srcAddress)
   139  			continue
   140  		}
   141  		logger := c.logger.New("from", src, "state", c.state)
   142  		isFuture := false
   143  
   144  		// We stop processing if
   145  		//   1. backlog is empty
   146  		//   2. The first message in queue is a future message
   147  		for !(backlog.Empty() || isFuture) {
   148  			m, prio := backlog.Pop()
   149  			msg := m.(*message)
   150  			var view *pbft.View
   151  			switch msg.Code {
   152  			case msgPreprepare:
   153  				var m *pbft.Preprepare
   154  				err := msg.Decode(&m)
   155  				if err == nil {
   156  					view = m.View
   157  				}
   158  			// for msgRoundChange, msgPrepare and msgCommit cases
   159  			case msgLightPreprepare:
   160  				var m *pbft.LightPreprepare
   161  				err := msg.Decode(&m)
   162  				if err == nil {
   163  					view = m.View
   164  				}
   165  			default:
   166  				var sub *pbft.Subject
   167  				err := msg.Decode(&sub)
   168  				if err == nil {
   169  					view = sub.View
   170  				}
   171  			}
   172  			if view == nil {
   173  				logger.Debug("Nil view", "msg", msg)
   174  				continue
   175  			}
   176  			// Push back if it's a future message
   177  			err := c.checkMessage(msg.Code, view)
   178  			if err != nil {
   179  				if err == errFutureMessage {
   180  					logger.Trace("Stop processing backlog", "msg", msg)
   181  					backlog.Push(msg, prio)
   182  					isFuture = true
   183  					break
   184  				}
   185  				logger.Trace("Skip the backlog event", "msg", msg, "err", err)
   186  				continue
   187  			}
   188  			logger.Trace("Post backlog event", "msg", msg)
   189  
   190  			go c.sendEvent(backlogEvent{
   191  				src: src,
   192  				msg: msg,
   193  			})
   194  		}
   195  	}
   196  }
   197  
   198  func toPriority(msgCode MsgCode, view *pbft.View) int64 {
   199  	if msgCode == msgRoundChange {
   200  		// For msgRoundChange, set the message priority based on its sequence
   201  		return -int64(view.Sequence.Uint64() * 1000)
   202  	}
   203  	// FIXME: round will be reset as 0 while new sequence
   204  	// 10 * Round limits the range of message code is from 0 to 9
   205  	// 1000 * Sequence limits the range of round is from 0 to 99
   206  	return -int64(view.Sequence.Uint64()*1000 + view.Round.Uint64()*10 + uint64(msgPriority[msgCode]))
   207  }