github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/dbft/core/backlog.go (about)

     1  package core
     2  
     3  import (
     4  	bft "github.com/quickchainproject/quickchain/consensus/dbft"
     5  	"gopkg.in/karalabe/cookiejar.v2/collections/prque"
     6  )
     7  
     8  var (
     9  	// msgPriority is defined for calculating processing priority to speedup consensus
    10  	// msgPreprepare > msgCommit > msgPrepare
    11  	msgPriority = map[uint64]int{
    12  		msgPreprepare: 1,
    13  		msgCommit:     2,
    14  		msgPrepare:    3,
    15  	}
    16  )
    17  
    18  // checkMessage checks the message state
    19  // return errInvalidMessage if the message is invalid
    20  // return errFutureMessage if the message view is larger than current view
    21  // return errOldMessage if the message view is smaller than current view
    22  func (c *core) checkMessage(msgCode uint64, view *bft.View) error {
    23  	if view == nil || view.Sequence == nil || view.Round == nil {
    24  		return errInvalidMessage
    25  	}
    26  
    27  	if msgCode == msgRoundChange {
    28  		if view.Sequence.Cmp(c.currentView().Sequence) > 0 {
    29  			return errFutureMessage
    30  		} else if view.Cmp(c.currentView()) < 0 {
    31  			return errOldMessage
    32  		}
    33  		return nil
    34  	}
    35  
    36  	if view.Cmp(c.currentView()) > 0 {
    37  		return errFutureMessage
    38  	}
    39  
    40  	if view.Cmp(c.currentView()) < 0 {
    41  		return errOldMessage
    42  	}
    43  
    44  	if c.waitingForRoundChange {
    45  		return errFutureMessage
    46  	}
    47  
    48  	// StateAcceptRequest only accepts msgPreprepare
    49  	// other messages are future messages
    50  	if c.state == StateAcceptRequest {
    51  		if msgCode > msgPreprepare {
    52  			return errFutureMessage
    53  		}
    54  		return nil
    55  	}
    56  
    57  	// For states(StatePreprepared, StatePrepared, StateCommitted),
    58  	// can accept all message types if processing with same view
    59  	return nil
    60  }
    61  
    62  func (c *core) storeBacklog(msg *message, src bft.Validator) {
    63  	logger := c.logger.New("from", src, "state", c.state)
    64  
    65  	if src.Address() == c.Address() {
    66  		logger.Warn("Backlog from self")
    67  		return
    68  	}
    69  
    70  	logger.Trace("Store future message")
    71  
    72  	c.backlogsMu.Lock()
    73  	defer c.backlogsMu.Unlock()
    74  
    75  	backlog := c.backlogs[src]
    76  	if backlog == nil {
    77  		backlog = prque.New()
    78  	}
    79  	switch msg.Code {
    80  	case msgPreprepare:
    81  		var p *bft.Preprepare
    82  		err := msg.Decode(&p)
    83  		if err == nil {
    84  			backlog.Push(msg, toPriority(msg.Code, p.View))
    85  		}
    86  		// for msgRoundChange, msgPrepare and msgCommit cases
    87  	default:
    88  		var p *bft.Subject
    89  		err := msg.Decode(&p)
    90  		if err == nil {
    91  			backlog.Push(msg, toPriority(msg.Code, p.View))
    92  		}
    93  	}
    94  	c.backlogs[src] = backlog
    95  }
    96  
    97  func (c *core) processBacklog() {
    98  	c.backlogsMu.Lock()
    99  	defer c.backlogsMu.Unlock()
   100  
   101  	for src, backlog := range c.backlogs {
   102  		if backlog == nil {
   103  			continue
   104  		}
   105  
   106  		logger := c.logger.New("from", src, "state", c.state)
   107  		isFuture := false
   108  
   109  		// We stop processing if
   110  		//   1. backlog is empty
   111  		//   2. The first message in queue is a future message
   112  		for !(backlog.Empty() || isFuture) {
   113  			m, prio := backlog.Pop()
   114  			msg := m.(*message)
   115  			var view *bft.View
   116  			switch msg.Code {
   117  			case msgPreprepare:
   118  				var m *bft.Preprepare
   119  				err := msg.Decode(&m)
   120  				if err == nil {
   121  					view = m.View
   122  				}
   123  				// for msgRoundChange, msgPrepare and msgCommit cases
   124  			default:
   125  				var sub *bft.Subject
   126  				err := msg.Decode(&sub)
   127  				if err == nil {
   128  					view = sub.View
   129  				}
   130  			}
   131  			if view == nil {
   132  				logger.Debug("Nil view", "msg", msg)
   133  				continue
   134  			}
   135  			// Push back if it's a future message
   136  			err := c.checkMessage(msg.Code, view)
   137  			if err != nil {
   138  				if err == errFutureMessage {
   139  					logger.Trace("Stop processing backlog", "msg", msg)
   140  					backlog.Push(msg, prio)
   141  					isFuture = true
   142  					break
   143  				}
   144  				logger.Trace("Skip the backlog event", "msg", msg, "err", err)
   145  				continue
   146  			}
   147  			logger.Trace("Post backlog event", "msg", msg)
   148  
   149  			go c.sendEvent(backlogEvent{
   150  				src: src,
   151  				msg: msg,
   152  			})
   153  		}
   154  	}
   155  }
   156  
   157  func toPriority(msgCode uint64, view *bft.View) float32 {
   158  	if msgCode == msgRoundChange {
   159  		// For msgRoundChange, set the message priority based on its sequence
   160  		return -float32(view.Sequence.Uint64() * 1000)
   161  	}
   162  	// FIXME: round will be reset as 0 while new sequence
   163  	// 10 * Round limits the range of message code is from 0 to 9
   164  	// 1000 * Sequence limits the range of round is from 0 to 99
   165  	return -float32(view.Sequence.Uint64()*1000 + view.Round.Uint64()*10 + uint64(msgPriority[msgCode]))
   166  }