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