github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/consensus/istanbul/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  	"fmt"
    21  	"math/big"
    22  
    23  	"github.com/electroneum/electroneum-sc/common"
    24  	"github.com/electroneum/electroneum-sc/consensus/istanbul"
    25  	qbfttypes "github.com/electroneum/electroneum-sc/consensus/istanbul/types"
    26  	"github.com/electroneum/electroneum-sc/log"
    27  	"github.com/electroneum/electroneum-sc/rlp"
    28  )
    29  
    30  // Start implements core.Engine.Start
    31  func (c *core) Start() error {
    32  	c.logger.Info("IBFT: start")
    33  	// Tests will handle events itself, so we have to make subscribeEvents()
    34  	// be able to call in test.
    35  	c.subscribeEvents()
    36  	c.handlerWg.Add(1)
    37  	go c.handleEvents()
    38  
    39  	// Start a new round from last sequence + 1
    40  	c.startNewRound(common.Big0)
    41  
    42  	return nil
    43  }
    44  
    45  // Stop implements core.Engine.Stop
    46  func (c *core) Stop() error {
    47  	c.logger.Info("IBFT: stopping...")
    48  	c.stopTimer()
    49  	c.unsubscribeEvents()
    50  
    51  	// Make sure the handler goroutine exits
    52  	c.handlerWg.Wait()
    53  	c.logger.Info("IBFT: stopped")
    54  	return nil
    55  }
    56  
    57  // ----------------------------------------------------------------------------
    58  
    59  // Subscribe both internal and external events
    60  func (c *core) subscribeEvents() {
    61  	c.events = c.backend.EventMux().Subscribe(
    62  		// external events
    63  		istanbul.RequestEvent{},
    64  		istanbul.MessageEvent{},
    65  		// internal events
    66  		backlogEvent{},
    67  	)
    68  	c.timeoutSub = c.backend.EventMux().Subscribe(
    69  		timeoutEvent{},
    70  	)
    71  	c.finalCommittedSub = c.backend.EventMux().Subscribe(
    72  		istanbul.FinalCommittedEvent{},
    73  	)
    74  }
    75  
    76  // Unsubscribe all events
    77  func (c *core) unsubscribeEvents() {
    78  	c.events.Unsubscribe()
    79  	c.timeoutSub.Unsubscribe()
    80  	c.finalCommittedSub.Unsubscribe()
    81  }
    82  
    83  // handleEvents starts main qbft handler loop that processes all incoming messages
    84  // sequentially. Each time a message is processed, internal QBFT state is mutated
    85  
    86  // when processing a message it makes sure that the message matches the current state
    87  // - in case the message is past, either for an older round or a state that already got acknowledge (e.g. a PREPARE message but we
    88  // are already in Prepared state), then message is discarded
    89  // - in case the message is future, either for a future round or a state yet to be reached (e.g. a COMMIT message but we are
    90  // in PrePrepared state), then message is added to backlog for future processing
    91  // - if correct time, message is handled
    92  
    93  // Each time a message is successfully handled it is gossiped to other validators
    94  func (c *core) handleEvents() {
    95  	// Clear state
    96  	defer func() {
    97  		c.current = nil
    98  		c.handlerWg.Done()
    99  	}()
   100  
   101  	for {
   102  		select {
   103  		case event, ok := <-c.events.Chan():
   104  			if !ok {
   105  				return
   106  			}
   107  
   108  			// A real event arrived, process interesting content
   109  			switch ev := event.Data.(type) {
   110  			case istanbul.RequestEvent:
   111  				// we are block proposer and look to get our block proposal validated by other validators
   112  				r := &Request{
   113  					Proposal: ev.Proposal,
   114  				}
   115  				err := c.handleRequest(r)
   116  				if err == errFutureMessage {
   117  					// store request for later treatment
   118  					c.storeRequestMsg(r)
   119  				}
   120  			case istanbul.MessageEvent:
   121  				// we received a message from another validator
   122  				if err := c.handleEncodedMsg(ev.Code, ev.Payload); err != nil {
   123  					continue
   124  				}
   125  
   126  				// if successfully processed, we gossip message to other validators
   127  				c.backend.Gossip(c.valSet, ev.Code, ev.Payload)
   128  			case backlogEvent:
   129  				// we process again a future message that was backlogged
   130  				// no need to check signature as it was already node when we first received message
   131  				if err := c.handleDecodedMessage(ev.msg); err != nil {
   132  					continue
   133  				}
   134  
   135  				data, err := rlp.EncodeToBytes(ev.msg)
   136  				if err != nil {
   137  					c.logger.Error("IBFT: can not encode backlog message", "err", err)
   138  					continue
   139  				}
   140  
   141  				// if successfully processed, we gossip message to other validators
   142  				c.backend.Gossip(c.valSet, ev.msg.Code(), data)
   143  			}
   144  		case _, ok := <-c.timeoutSub.Chan():
   145  			// we received a round change timeout
   146  			if !ok {
   147  				return
   148  			}
   149  			c.handleTimeoutMsg()
   150  		case event, ok := <-c.finalCommittedSub.Chan():
   151  			// our block proposal got committed
   152  			if !ok {
   153  				return
   154  			}
   155  			switch event.Data.(type) {
   156  			case istanbul.FinalCommittedEvent:
   157  				c.handleFinalCommitted()
   158  			}
   159  		}
   160  	}
   161  }
   162  
   163  // sendEvent sends events to mux
   164  func (c *core) sendEvent(ev interface{}) {
   165  	c.backend.EventMux().Post(ev)
   166  }
   167  
   168  func (c *core) handleEncodedMsg(code uint64, data []byte) error {
   169  	logger := c.logger.New("code", code, "data", data)
   170  
   171  	if _, ok := qbfttypes.MessageCodes()[code]; !ok {
   172  		logger.Error("IBFT: invalid message event code")
   173  		return fmt.Errorf("invalid message event code %v", code)
   174  	}
   175  
   176  	// Decode data into a QBFTMessage
   177  	m, err := qbfttypes.Decode(code, data)
   178  	if err != nil {
   179  		logger.Error("IBFT: invalid message", "err", err)
   180  		return err
   181  	}
   182  
   183  	// Verify signatures and set source address
   184  	if err = c.verifySignatures(m); err != nil {
   185  		return err
   186  	}
   187  
   188  	return c.handleDecodedMessage(m)
   189  }
   190  
   191  func (c *core) handleDecodedMessage(m qbfttypes.QBFTMessage) error {
   192  	view := m.View()
   193  	if err := c.checkMessage(m.Code(), &view); err != nil {
   194  		// Store in the backlog it it's a future message
   195  		if err == errFutureMessage {
   196  			c.addToBacklog(m)
   197  		}
   198  		return err
   199  	}
   200  
   201  	return c.deliverMessage(m)
   202  }
   203  
   204  // Deliver to specific message handler
   205  func (c *core) deliverMessage(m qbfttypes.QBFTMessage) error {
   206  	var err error
   207  
   208  	switch m.Code() {
   209  	case qbfttypes.PreprepareCode:
   210  		err = c.handlePreprepareMsg(m.(*qbfttypes.Preprepare))
   211  	case qbfttypes.PrepareCode:
   212  		err = c.handlePrepare(m.(*qbfttypes.Prepare))
   213  	case qbfttypes.CommitCode:
   214  		err = c.handleCommitMsg(m.(*qbfttypes.Commit))
   215  	case qbfttypes.RoundChangeCode:
   216  		err = c.handleRoundChange(m.(*qbfttypes.RoundChange))
   217  	default:
   218  		c.logger.Error("IBFT: invalid message code", "code", m.Code())
   219  		return errInvalidMessage
   220  	}
   221  
   222  	return err
   223  }
   224  
   225  func (c *core) handleTimeoutMsg() {
   226  	logger := c.currentLogger(true, nil)
   227  	// Start the new round
   228  	round := c.current.Round()
   229  	nextRound := new(big.Int).Add(round, common.Big1)
   230  
   231  	logger.Warn("IBFT: TIMER CHANGING ROUND", "pr", c.current.preparedRound)
   232  	c.startNewRound(nextRound)
   233  	logger.Warn("IBFT: TIMER CHANGED ROUND", "pr", c.current.preparedRound)
   234  
   235  	// Send Round Change
   236  	c.broadcastRoundChange(nextRound)
   237  }
   238  
   239  // Verifies the signature of the message m and of any justification payloads
   240  // piggybacked in m, if any. It also sets the source address on the messages
   241  // and justification payloads.
   242  func (c *core) verifySignatures(m qbfttypes.QBFTMessage) error {
   243  	logger := c.currentLogger(true, m)
   244  
   245  	// Anonymous function to verify the signature of a single message or payload
   246  	verify := func(m qbfttypes.QBFTMessage) error {
   247  		payload, err := m.EncodePayloadForSigning()
   248  		if err != nil {
   249  			logger.Error("IBFT: invalid message payload", "err", err)
   250  			return err
   251  		}
   252  		source, err := c.validateFn(payload, m.Signature())
   253  		if err != nil {
   254  			logger.Error("IBFT: invalid message signature", "err", err)
   255  			return errInvalidSigner
   256  		}
   257  		m.SetSource(source)
   258  		return nil
   259  	}
   260  
   261  	// Verifies the signature of the message
   262  	if err := verify(m); err != nil {
   263  		return err
   264  	}
   265  
   266  	// Verifies the signature of piggybacked justification payloads.
   267  	switch msgType := m.(type) {
   268  	case *qbfttypes.RoundChange:
   269  		signedPreparePayloads := msgType.Justification
   270  		for _, p := range signedPreparePayloads {
   271  			if err := verify(p); err != nil {
   272  				return err
   273  			}
   274  		}
   275  	case *qbfttypes.Preprepare:
   276  		signedRoundChangePayloads := msgType.JustificationRoundChanges
   277  		for _, p := range signedRoundChangePayloads {
   278  			if err := verify(p); err != nil {
   279  				return err
   280  			}
   281  		}
   282  	}
   283  
   284  	return nil
   285  }
   286  
   287  func (c *core) currentLogger(state bool, msg qbfttypes.QBFTMessage) log.Logger {
   288  	logCtx := []interface{}{
   289  		"current.round", c.current.Round().Uint64(),
   290  		"current.sequence", c.current.Sequence().Uint64(),
   291  	}
   292  
   293  	if state {
   294  		logCtx = append(logCtx, "state", c.state)
   295  	}
   296  
   297  	if msg != nil {
   298  		logCtx = append(
   299  			logCtx,
   300  			"msg.code", msg.Code(),
   301  			"msg.source", msg.Source().String(),
   302  			"msg.round", msg.View().Round.Uint64(),
   303  			"msg.sequence", msg.View().Sequence.Uint64(),
   304  		)
   305  	}
   306  
   307  	return c.logger.New(logCtx...)
   308  }
   309  
   310  func withMsg(logger log.Logger, msg qbfttypes.QBFTMessage) log.Logger {
   311  	return logger.New(
   312  		"msg.code", msg.Code(),
   313  		"msg.source", msg.Source().String(),
   314  		"msg.round", msg.View().Round.Uint64(),
   315  		"msg.sequence", msg.View().Sequence.Uint64(),
   316  	)
   317  }