github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/pbft/core/handler.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"
    21  	"github.com/bigzoro/my_simplechain/consensus/pbft"
    22  )
    23  
    24  // Start implements core.Engine.Start
    25  func (c *core) Start() error {
    26  	// Start a new round from last sequence + 1
    27  	c.startNewRound(common.Big0)
    28  
    29  	// Tests will handle events itself, so we have to make subscribeEvents()
    30  	// be able to call in test.
    31  	c.subscribeEvents()
    32  	go c.handleEvents()
    33  
    34  	return nil
    35  }
    36  
    37  // Stop implements core.Engine.Stop
    38  func (c *core) Stop() error {
    39  	c.stopTimer()
    40  	c.unsubscribeEvents()
    41  
    42  	// Make sure the handler goroutine exits
    43  	c.handlerWg.Wait()
    44  	return nil
    45  }
    46  
    47  // ----------------------------------------------------------------------------
    48  
    49  // Subscribe both internal and external events
    50  func (c *core) subscribeEvents() {
    51  	c.events = c.backend.EventMux().Subscribe(
    52  		// external events
    53  		pbft.RequestEvent{},
    54  		pbft.MessageEvent{},
    55  		// internal events
    56  		backlogEvent{},
    57  	)
    58  	c.timeoutSub = c.backend.EventMux().Subscribe(
    59  		timeoutEvent{},
    60  	)
    61  	c.finalCommittedSub = c.backend.EventMux().Subscribe(
    62  		pbft.FinalCommittedEvent{},
    63  	)
    64  }
    65  
    66  // Unsubscribe all events
    67  func (c *core) unsubscribeEvents() {
    68  	c.events.Unsubscribe()
    69  	c.timeoutSub.Unsubscribe()
    70  	c.finalCommittedSub.Unsubscribe()
    71  }
    72  
    73  func (c *core) handleEvents() {
    74  	// Clear state
    75  	defer func() {
    76  		c.current = nil
    77  		c.handlerWg.Done()
    78  	}()
    79  
    80  	c.handlerWg.Add(1)
    81  
    82  	for {
    83  		select {
    84  		case event, ok := <-c.events.Chan():
    85  			if !ok {
    86  				return
    87  			}
    88  			// A real event arrived, process interesting content
    89  			switch ev := event.Data.(type) {
    90  			case pbft.RequestEvent:
    91  				r := &pbft.Request{
    92  					Proposal: ev.Proposal,
    93  				}
    94  				err := c.handleRequest(r)
    95  				if err == errFutureMessage {
    96  					c.storeRequestMsg(r)
    97  				}
    98  			case pbft.MessageEvent:
    99  				msg, src, forward, err := c.handleMsg(ev.Payload)
   100  				if forward && err == nil {
   101  					c.forward(msg, src)
   102  				}
   103  			case backlogEvent:
   104  				// No need to check signature for internal messages
   105  				if forward, err := c.handleCheckedMsg(ev.msg, ev.src); forward && err == nil {
   106  					p, err := ev.msg.Payload()
   107  					if err != nil {
   108  						c.logger.Warn("Get message payload failed", "err", err)
   109  						continue
   110  					}
   111  					//c.backend.Gossip(c.valSet, p)
   112  					c.backend.Guidance(c.valSet, ev.msg.Address, p)
   113  				}
   114  			}
   115  		case _, ok := <-c.timeoutSub.Chan():
   116  			if !ok {
   117  				return
   118  			}
   119  			c.handleTimeoutMsg()
   120  
   121  		case event, ok := <-c.finalCommittedSub.Chan():
   122  			if !ok {
   123  				return
   124  			}
   125  			switch ev := event.Data.(type) {
   126  			case pbft.FinalCommittedEvent:
   127  				c.handleFinalCommitted(ev.Committed)
   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) (*message, pbft.Validator, bool, error) {
   139  	logger := c.logger.New()
   140  
   141  	// Decode message and check its signature
   142  	msg := new(message)
   143  	if err := msg.FromPayload(payload, c.validateFn); err != nil {
   144  		logger.Error("Failed to decode message from payload", "err", err)
   145  		return nil, nil, false, 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 msg, src, false, pbft.ErrUnauthorizedAddress
   153  	}
   154  
   155  	forward, err := c.handleCheckedMsg(msg, src)
   156  
   157  	return msg, src, forward, err
   158  }
   159  
   160  func (c *core) handleCheckedMsg(msg *message, src pbft.Validator) (bool, error) {
   161  	logger := c.logger.New("address", c.address, "from", src)
   162  
   163  	// Store the message if it's a future message
   164  	testBacklog := func(err error) error {
   165  		if err == errFutureMessage {
   166  			c.storeBacklog(msg, src)
   167  		}
   168  
   169  		return err
   170  	}
   171  	switch msg.Code {
   172  	case msgPreprepare:
   173  		// wouldn't forward preprepare message, if node is in light mode
   174  		return !c.config.LightMode, testBacklog(c.handlePreprepare(msg, src))
   175  
   176  	case msgPrepare:
   177  		return true, testBacklog(c.handlePrepare(msg, src))
   178  
   179  	case msgCommit:
   180  		return true, testBacklog(c.handleCommit(msg, src))
   181  
   182  	case msgRoundChange:
   183  		return true, testBacklog(c.handleRoundChange(msg, src))
   184  
   185  	case msgLightPreprepare:
   186  		if c.config.LightMode {
   187  			return true, testBacklog(c.handleLightPrepare(msg, src))
   188  		}
   189  	case msgGetMissedTxs:
   190  		if c.config.LightMode {
   191  			// wouldn't forward request message
   192  			return false, testBacklog(c.handleGetMissedTxs(msg, src))
   193  		}
   194  	case msgMissedTxs:
   195  		if c.config.LightMode {
   196  			// wouldn't forward response message
   197  			return false, testBacklog(c.handleMissedTxs(msg, src))
   198  		}
   199  
   200  	default:
   201  		logger.Error("Invalid message", "msg", msg)
   202  	}
   203  
   204  	return false, errInvalidMessage
   205  }
   206  
   207  func (c *core) handleTimeoutMsg() {
   208  	// adjust block sealing txs on timeout
   209  	if c.current != nil && c.current.Proposal() != nil && !c.current.Proposal().IsEmpty() {
   210  		c.backend.OnTimeout()
   211  	}
   212  	// If we're not waiting for round change yet, we can try to catch up
   213  	// the max round with F+1 round change message. We only need to catch up
   214  	// if the max round is larger than current round.
   215  	if !c.waitingForRoundChange {
   216  		maxRound := c.roundChangeSet.MaxRound(c.valSet.F() + 1)
   217  		if maxRound != nil && maxRound.Cmp(c.current.Round()) > 0 {
   218  			c.sendRoundChange(maxRound)
   219  			return
   220  		}
   221  	}
   222  
   223  	lastProposal, _, _ := c.backend.LastProposal()
   224  	if lastProposal != nil && lastProposal.Number().Cmp(c.current.Sequence()) >= 0 {
   225  		c.logger.Trace("round change timeout, catch up latest sequence", "number", lastProposal.Number().Uint64())
   226  		//c.logger.Error("[report] round change timeout, catch up latest sequence", "number", lastProposal.Number().Uint64())
   227  		c.startNewRound(common.Big0)
   228  	} else {
   229  		c.sendNextRoundChange()
   230  	}
   231  }