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

     1  package core
     2  
     3  import (
     4  	"github.com/quickchainproject/quickchain/common"
     5  	"github.com/quickchainproject/quickchain/consensus/bft"
     6  )
     7  
     8  // Start implements core.Engine.Start
     9  func (c *core) Start() error {
    10  	// Start a new round from last sequence + 1
    11  	c.startNewRound(common.Big0)
    12  
    13  	// Tests will handle events itself, so we have to make subscribeEvents()
    14  	// be able to call in test.
    15  	c.subscribeEvents()
    16  	go c.handleEvents()
    17  
    18  	return nil
    19  }
    20  
    21  // Stop implements core.Engine.Stop
    22  func (c *core) Stop() error {
    23  	c.stopTimer()
    24  	c.unsubscribeEvents()
    25  
    26  	// Make sure the handler goroutine exits
    27  	c.handlerWg.Wait()
    28  	return nil
    29  }
    30  
    31  // ----------------------------------------------------------------------------
    32  
    33  // Subscribe both internal and external events
    34  func (c *core) subscribeEvents() {
    35  	c.events = c.backend.EventMux().Subscribe(
    36  		// external events
    37  		bft.RequestEvent{},
    38  		bft.MessageEvent{},
    39  		// internal events
    40  		backlogEvent{},
    41  	)
    42  	c.timeoutSub = c.backend.EventMux().Subscribe(
    43  		timeoutEvent{},
    44  	)
    45  	c.finalCommittedSub = c.backend.EventMux().Subscribe(
    46  		bft.FinalCommittedEvent{},
    47  	)
    48  }
    49  
    50  // Unsubscribe all events
    51  func (c *core) unsubscribeEvents() {
    52  	c.events.Unsubscribe()
    53  	c.timeoutSub.Unsubscribe()
    54  	c.finalCommittedSub.Unsubscribe()
    55  }
    56  
    57  func (c *core) handleEvents() {
    58  	// Clear state
    59  	defer func() {
    60  		c.current = nil
    61  		c.handlerWg.Done()
    62  	}()
    63  
    64  	c.handlerWg.Add(1)
    65  
    66  	for {
    67  		select {
    68  		case event, ok := <-c.events.Chan():
    69  			if !ok {
    70  				return
    71  			}
    72  			// A real event arrived, process interesting content
    73  			switch ev := event.Data.(type) {
    74  			case bft.RequestEvent:
    75  				r := &bft.Request{
    76  					Proposal: ev.Proposal,
    77  				}
    78  				err := c.handleRequest(r)
    79  				if err == errFutureMessage {
    80  					c.storeRequestMsg(r)
    81  				}
    82  			case bft.MessageEvent:
    83  				if err := c.handleMsg(ev.Payload); err == nil {
    84  					c.backend.Gossip(c.valSet, ev.Payload)
    85  				}
    86  			case backlogEvent:
    87  				// No need to check signature for internal messages
    88  				if err := c.handleCheckedMsg(ev.msg, ev.src); err == nil {
    89  					p, err := ev.msg.Payload()
    90  					if err != nil {
    91  						c.logger.Warn("Get message payload failed", "err", err)
    92  						continue
    93  					}
    94  					c.backend.Gossip(c.valSet, p)
    95  				}
    96  			}
    97  		case _, ok := <-c.timeoutSub.Chan():
    98  			if !ok {
    99  				return
   100  			}
   101  			c.handleTimeoutMsg()
   102  		case event, ok := <-c.finalCommittedSub.Chan():
   103  			if !ok {
   104  				return
   105  			}
   106  			switch event.Data.(type) {
   107  			case bft.FinalCommittedEvent:
   108  				c.handleFinalCommitted()
   109  			}
   110  		}
   111  	}
   112  }
   113  
   114  // sendEvent sends events to mux
   115  func (c *core) sendEvent(ev interface{}) {
   116  	c.backend.EventMux().Post(ev)
   117  }
   118  
   119  func (c *core) handleMsg(payload []byte) error {
   120  	logger := c.logger.New()
   121  
   122  	// Decode message and check its signature
   123  	msg := new(message)
   124  	if err := msg.FromPayload(payload, c.validateFn); err != nil {
   125  		logger.Error("Failed to decode message from payload", "err", err)
   126  		return err
   127  	}
   128  
   129  	// Only accept message if the address is valid
   130  	_, src := c.valSet.GetByAddress(msg.Address)
   131  	if src == nil {
   132  		logger.Error("Invalid address in message", "msg", msg)
   133  		return bft.ErrUnauthorizedAddress
   134  	}
   135  
   136  	return c.handleCheckedMsg(msg, src)
   137  }
   138  
   139  func (c *core) handleCheckedMsg(msg *message, src bft.Validator) error {
   140  	logger := c.logger.New("address", c.address, "from", src)
   141  
   142  	// Store the message if it's a future message
   143  	testBacklog := func(err error) error {
   144  		if err == errFutureMessage {
   145  			c.storeBacklog(msg, src)
   146  		}
   147  
   148  		return err
   149  	}
   150  
   151  	switch msg.Code {
   152  	case msgPreprepare:
   153  		return testBacklog(c.handlePreprepare(msg, src))
   154  	case msgPrepare:
   155  		return testBacklog(c.handlePrepare(msg, src))
   156  	case msgCommit:
   157  		return testBacklog(c.handleCommit(msg, src))
   158  	case msgRoundChange:
   159  		return testBacklog(c.handleRoundChange(msg, src))
   160  	default:
   161  		logger.Error("Invalid message", "msg", msg)
   162  	}
   163  
   164  	return errInvalidMessage
   165  }
   166  
   167  func (c *core) handleTimeoutMsg() {
   168  	// If we're not waiting for round change yet, we can try to catch up
   169  	// the max round with F+1 round change message. We only need to catch up
   170  	// if the max round is larger than current round.
   171  	if !c.waitingForRoundChange {
   172  		maxRound := c.roundChangeSet.MaxRound(c.valSet.F() + 1)
   173  		if maxRound != nil && maxRound.Cmp(c.current.Round()) > 0 {
   174  			c.sendRoundChange(maxRound)
   175  			return
   176  		}
   177  	}
   178  
   179  	lastProposal, _ := c.backend.LastProposal()
   180  	if lastProposal != nil && lastProposal.Number().Cmp(c.current.Sequence()) >= 0 {
   181  		c.logger.Trace("round change timeout, catch up latest sequence", "number", lastProposal.Number().Uint64())
   182  		c.startNewRound(common.Big0)
   183  	} else {
   184  		c.sendNextRoundChange()
   185  	}
   186  }