github.com/koko1123/flow-go-1@v0.29.6/network/p2p/middleware/middleware.go (about)

     1  // (c) 2019 Dapper Labs - ALL RIGHTS RESERVED
     2  
     3  package middleware
     4  
     5  import (
     6  	"bufio"
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  	"sync"
    12  	"time"
    13  
    14  	ggio "github.com/gogo/protobuf/io"
    15  	"github.com/ipfs/go-datastore"
    16  	libp2pnetwork "github.com/libp2p/go-libp2p/core/network"
    17  	"github.com/libp2p/go-libp2p/core/peer"
    18  	"github.com/libp2p/go-libp2p/core/peerstore"
    19  	"github.com/libp2p/go-libp2p/core/protocol"
    20  	"github.com/rs/zerolog"
    21  
    22  	"github.com/koko1123/flow-go-1/model/flow"
    23  	"github.com/koko1123/flow-go-1/module"
    24  	"github.com/koko1123/flow-go-1/module/component"
    25  	"github.com/koko1123/flow-go-1/module/irrecoverable"
    26  	"github.com/koko1123/flow-go-1/network"
    27  	"github.com/koko1123/flow-go-1/network/channels"
    28  	"github.com/koko1123/flow-go-1/network/codec"
    29  	"github.com/koko1123/flow-go-1/network/internal/p2putils"
    30  	"github.com/koko1123/flow-go-1/network/message"
    31  	"github.com/koko1123/flow-go-1/network/p2p"
    32  	"github.com/koko1123/flow-go-1/network/p2p/blob"
    33  	"github.com/koko1123/flow-go-1/network/p2p/p2pnode"
    34  	"github.com/koko1123/flow-go-1/network/p2p/ping"
    35  	"github.com/koko1123/flow-go-1/network/p2p/unicast"
    36  	"github.com/koko1123/flow-go-1/network/p2p/unicast/ratelimit"
    37  	"github.com/koko1123/flow-go-1/network/p2p/utils"
    38  	"github.com/koko1123/flow-go-1/network/slashing"
    39  	"github.com/koko1123/flow-go-1/network/validator"
    40  	flowpubsub "github.com/koko1123/flow-go-1/network/validator/pubsub"
    41  	_ "github.com/koko1123/flow-go-1/utils/binstat"
    42  	"github.com/koko1123/flow-go-1/utils/logging"
    43  )
    44  
    45  const (
    46  	_ = iota
    47  	_ = 1 << (10 * iota)
    48  	mb
    49  	gb
    50  )
    51  
    52  const (
    53  	// DefaultMaxUnicastMsgSize defines maximum message size in unicast mode for most messages
    54  	DefaultMaxUnicastMsgSize = 10 * mb // 10 mb
    55  
    56  	// LargeMsgMaxUnicastMsgSize defines maximum message size in unicast mode for large messages
    57  	LargeMsgMaxUnicastMsgSize = gb // 1 gb
    58  
    59  	// DefaultUnicastTimeout is the default maximum time to wait for a default unicast request to complete
    60  	// assuming at least a 1mb/sec connection
    61  	DefaultUnicastTimeout = 5 * time.Second
    62  
    63  	// LargeMsgUnicastTimeout is the maximum time to wait for a unicast request to complete for large message size
    64  	LargeMsgUnicastTimeout = 1000 * time.Second
    65  )
    66  
    67  var (
    68  	_ network.Middleware = (*Middleware)(nil)
    69  
    70  	// ErrUnicastMsgWithoutSub error is provided to the slashing violations consumer in the case where
    71  	// the middleware receives a message via unicast but does not have a corresponding subscription for
    72  	// the channel in that message.
    73  	ErrUnicastMsgWithoutSub = errors.New("middleware does not have subscription for the channel ID indicated in the unicast message received")
    74  )
    75  
    76  // Middleware handles the input & output on the direct connections we have to
    77  // our neighbours on the peer-to-peer network.
    78  type Middleware struct {
    79  	sync.Mutex
    80  	ctx context.Context
    81  	log zerolog.Logger
    82  	ov  network.Overlay
    83  	// TODO: using a waitgroup here doesn't actually guarantee that we'll wait for all
    84  	// goroutines to exit, because new goroutines could be started after we've already
    85  	// returned from wg.Wait(). We need to solve this the right way using ComponentManager
    86  	// and worker routines.
    87  	wg                         sync.WaitGroup
    88  	libP2PNode                 p2p.LibP2PNode
    89  	preferredUnicasts          []unicast.ProtocolName
    90  	me                         flow.Identifier
    91  	bitswapMetrics             module.BitswapMetrics
    92  	rootBlockID                flow.Identifier
    93  	validators                 []network.MessageValidator
    94  	peerManagerFilters         []p2p.PeerFilter
    95  	unicastMessageTimeout      time.Duration
    96  	idTranslator               p2p.IDTranslator
    97  	previousProtocolStatePeers []peer.AddrInfo
    98  	codec                      network.Codec
    99  	slashingViolationsConsumer slashing.ViolationsConsumer
   100  	unicastRateLimiters        *ratelimit.RateLimiters
   101  	authorizedSenderValidator  *validator.AuthorizedSenderValidator
   102  	component.Component
   103  }
   104  
   105  type MiddlewareOption func(*Middleware)
   106  
   107  func WithMessageValidators(validators ...network.MessageValidator) MiddlewareOption {
   108  	return func(mw *Middleware) {
   109  		mw.validators = validators
   110  	}
   111  }
   112  
   113  func WithPreferredUnicastProtocols(unicasts []unicast.ProtocolName) MiddlewareOption {
   114  	return func(mw *Middleware) {
   115  		mw.preferredUnicasts = unicasts
   116  	}
   117  }
   118  
   119  // WithPeerManagerFilters sets a list of p2p.PeerFilter funcs that are used to
   120  // filter out peers provided by the peer manager PeersProvider.
   121  func WithPeerManagerFilters(peerManagerFilters []p2p.PeerFilter) MiddlewareOption {
   122  	return func(mw *Middleware) {
   123  		mw.peerManagerFilters = peerManagerFilters
   124  	}
   125  }
   126  
   127  // WithUnicastRateLimiters sets the unicast rate limiters.
   128  func WithUnicastRateLimiters(rateLimiters *ratelimit.RateLimiters) MiddlewareOption {
   129  	return func(mw *Middleware) {
   130  		mw.unicastRateLimiters = rateLimiters
   131  	}
   132  }
   133  
   134  // NewMiddleware creates a new middleware instance
   135  // libP2PNodeFactory is the factory used to create a LibP2PNode
   136  // flowID is this node's Flow ID
   137  // metrics is the interface to report network related metrics
   138  // unicastMessageTimeout is the timeout used for unicast messages
   139  // connectionGating if set to True, restricts this node to only talk to other nodes which are part of the identity list
   140  // validators are the set of the different message validators that each inbound messages is passed through
   141  // During normal operations any error returned by Middleware.start is considered to be catastrophic
   142  // and will be thrown by the irrecoverable.SignalerContext causing the node to crash.
   143  func NewMiddleware(
   144  	log zerolog.Logger,
   145  	libP2PNode p2p.LibP2PNode,
   146  	flowID flow.Identifier,
   147  	bitswapMet module.BitswapMetrics,
   148  	rootBlockID flow.Identifier,
   149  	unicastMessageTimeout time.Duration,
   150  	idTranslator p2p.IDTranslator,
   151  	codec network.Codec,
   152  	slashingViolationsConsumer slashing.ViolationsConsumer,
   153  	opts ...MiddlewareOption) *Middleware {
   154  
   155  	if unicastMessageTimeout <= 0 {
   156  		unicastMessageTimeout = DefaultUnicastTimeout
   157  	}
   158  
   159  	// create the node entity and inject dependencies & config
   160  	mw := &Middleware{
   161  		log:                        log,
   162  		me:                         flowID,
   163  		libP2PNode:                 libP2PNode,
   164  		bitswapMetrics:             bitswapMet,
   165  		rootBlockID:                rootBlockID,
   166  		validators:                 DefaultValidators(log, flowID),
   167  		unicastMessageTimeout:      unicastMessageTimeout,
   168  		idTranslator:               idTranslator,
   169  		codec:                      codec,
   170  		slashingViolationsConsumer: slashingViolationsConsumer,
   171  		unicastRateLimiters:        ratelimit.NoopRateLimiters(),
   172  	}
   173  
   174  	for _, opt := range opts {
   175  		opt(mw)
   176  	}
   177  
   178  	cm := component.NewComponentManagerBuilder().
   179  		AddWorker(func(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) {
   180  			// TODO: refactor to avoid storing ctx altogether
   181  			mw.ctx = ctx
   182  
   183  			if err := mw.start(ctx); err != nil {
   184  				ctx.Throw(err)
   185  			}
   186  
   187  			ready()
   188  
   189  			<-ctx.Done()
   190  			mw.log.Info().Str("component", "middleware").Msg("stopping subroutines")
   191  
   192  			// wait for the readConnection and readSubscription routines to stop
   193  			mw.wg.Wait()
   194  
   195  			mw.log.Info().Str("component", "middleware").Msg("stopped subroutines")
   196  
   197  			// clean up rate limiter resources
   198  			mw.unicastRateLimiters.Stop()
   199  			mw.log.Info().Str("component", "middleware").Msg("cleaned up unicast rate limiter resources")
   200  
   201  		}).Build()
   202  
   203  	mw.Component = cm
   204  
   205  	return mw
   206  }
   207  
   208  func DefaultValidators(log zerolog.Logger, flowID flow.Identifier) []network.MessageValidator {
   209  	return []network.MessageValidator{
   210  		validator.ValidateNotSender(flowID),   // validator to filter out messages sent by this node itself
   211  		validator.ValidateTarget(log, flowID), // validator to filter out messages not intended for this node
   212  	}
   213  }
   214  
   215  // isProtocolParticipant returns a PeerFilter that returns true if a peer is a staked node.
   216  func (m *Middleware) isProtocolParticipant() p2p.PeerFilter {
   217  	return func(p peer.ID) error {
   218  		if _, ok := m.ov.Identity(p); !ok {
   219  			return fmt.Errorf("failed to get identity of unknown peer with peer id %s", p.String())
   220  		}
   221  		return nil
   222  	}
   223  }
   224  
   225  func (m *Middleware) NewBlobService(channel channels.Channel, ds datastore.Batching, opts ...network.BlobServiceOption) network.BlobService {
   226  	return blob.NewBlobService(m.libP2PNode.Host(), m.libP2PNode.Routing(), channel.String(), ds, m.bitswapMetrics, m.log, opts...)
   227  }
   228  
   229  func (m *Middleware) NewPingService(pingProtocol protocol.ID, provider network.PingInfoProvider) network.PingService {
   230  	return ping.NewPingService(m.libP2PNode.Host(), pingProtocol, m.log, provider)
   231  }
   232  
   233  func (m *Middleware) peerIDs(flowIDs flow.IdentifierList) peer.IDSlice {
   234  	result := make([]peer.ID, 0, len(flowIDs))
   235  
   236  	for _, fid := range flowIDs {
   237  		pid, err := m.idTranslator.GetPeerID(fid)
   238  		if err != nil {
   239  			// We probably don't need to fail the entire function here, since the other
   240  			// translations may still succeed
   241  			m.log.Err(err).Str("flowID", fid.String()).Msg("failed to translate to peer ID")
   242  			continue
   243  		}
   244  
   245  		result = append(result, pid)
   246  	}
   247  
   248  	return result
   249  }
   250  
   251  // Me returns the flow identifier of this middleware
   252  func (m *Middleware) Me() flow.Identifier {
   253  	return m.me
   254  }
   255  
   256  // GetIPPort returns the ip address and port number associated with the middleware
   257  // All errors returned from this function can be considered benign.
   258  func (m *Middleware) GetIPPort() (string, string, error) {
   259  	ipOrHostname, port, err := m.libP2PNode.GetIPPort()
   260  	if err != nil {
   261  		return "", "", fmt.Errorf("failed to get ip and port from libP2P node: %w", err)
   262  	}
   263  
   264  	return ipOrHostname, port, nil
   265  }
   266  
   267  func (m *Middleware) UpdateNodeAddresses() {
   268  	m.log.Info().Msg("Updating protocol state node addresses")
   269  
   270  	ids := m.ov.Identities()
   271  	newInfos, invalid := utils.PeerInfosFromIDs(ids)
   272  
   273  	for id, err := range invalid {
   274  		m.log.Err(err).Str("node_id", id.String()).Msg("failed to extract peer info from identity")
   275  	}
   276  
   277  	m.Lock()
   278  	defer m.Unlock()
   279  
   280  	// set old addresses to expire
   281  	for _, oldInfo := range m.previousProtocolStatePeers {
   282  		m.libP2PNode.Host().Peerstore().SetAddrs(oldInfo.ID, oldInfo.Addrs, peerstore.TempAddrTTL)
   283  	}
   284  
   285  	for _, info := range newInfos {
   286  		m.libP2PNode.Host().Peerstore().SetAddrs(info.ID, info.Addrs, peerstore.PermanentAddrTTL)
   287  	}
   288  
   289  	m.previousProtocolStatePeers = newInfos
   290  }
   291  
   292  func (m *Middleware) SetOverlay(ov network.Overlay) {
   293  	m.ov = ov
   294  }
   295  
   296  // start will start the middleware.
   297  // No errors are expected during normal operation.
   298  func (m *Middleware) start(ctx context.Context) error {
   299  	if m.ov == nil {
   300  		return fmt.Errorf("could not start middleware: overlay must be configured by calling SetOverlay before middleware can be started")
   301  	}
   302  
   303  	m.authorizedSenderValidator = validator.NewAuthorizedSenderValidator(m.log, m.slashingViolationsConsumer, m.ov.Identity)
   304  
   305  	err := m.libP2PNode.WithDefaultUnicastProtocol(m.handleIncomingStream, m.preferredUnicasts)
   306  	if err != nil {
   307  		return fmt.Errorf("could not register preferred unicast protocols on libp2p node: %w", err)
   308  	}
   309  
   310  	m.UpdateNodeAddresses()
   311  
   312  	m.libP2PNode.WithPeersProvider(m.topologyPeers)
   313  
   314  	// starting rate limiters kicks off cleanup loop
   315  	m.unicastRateLimiters.Start()
   316  
   317  	return nil
   318  }
   319  
   320  // topologyPeers callback used by the peer manager to get the list of peer ID's
   321  // which this node should be directly connected to as peers. The peer ID list
   322  // returned will be filtered through any configured m.peerManagerFilters.
   323  func (m *Middleware) topologyPeers() peer.IDSlice {
   324  	peerIDs := make([]peer.ID, 0)
   325  	for _, id := range m.peerIDs(m.ov.Topology().NodeIDs()) {
   326  		peerAllowed := true
   327  		for _, filter := range m.peerManagerFilters {
   328  			if err := filter(id); err != nil {
   329  				m.log.Debug().
   330  					Err(err).
   331  					Str("peer_id", id.String()).
   332  					Msg("filtering topology peer")
   333  
   334  				peerAllowed = false
   335  				break
   336  			}
   337  		}
   338  
   339  		if peerAllowed {
   340  			peerIDs = append(peerIDs, id)
   341  		}
   342  	}
   343  
   344  	return peerIDs
   345  }
   346  
   347  // SendDirect sends msg on a 1-1 direct connection to the target ID. It models a guaranteed delivery asynchronous
   348  // direct one-to-one connection on the underlying network. No intermediate node on the overlay is utilized
   349  // as the router.
   350  //
   351  // Dispatch should be used whenever guaranteed delivery to a specific target is required. Otherwise, Publish is
   352  // a more efficient candidate.
   353  //
   354  // The following benign errors can be returned:
   355  // - the peer ID for the target node ID cannot be found.
   356  // - the msg size was too large.
   357  // - failed to send message to peer.
   358  //
   359  // All errors returned from this function can be considered benign.
   360  func (m *Middleware) SendDirect(msg *network.OutgoingMessageScope) error {
   361  	// since it is a unicast, we only need to get the first peer ID.
   362  	peerID, err := m.idTranslator.GetPeerID(msg.TargetIds()[0])
   363  	if err != nil {
   364  		return fmt.Errorf("could not find peer id for target id: %w", err)
   365  	}
   366  
   367  	maxMsgSize := unicastMaxMsgSize(msg.PayloadType())
   368  	if msg.Size() > maxMsgSize {
   369  		// message size goes beyond maximum size that the serializer can handle.
   370  		// proceeding with this message results in closing the connection by the target side, and
   371  		// delivery failure.
   372  		return fmt.Errorf("message size %d exceeds configured max message size %d", msg.Size(), maxMsgSize)
   373  	}
   374  
   375  	maxTimeout := m.unicastMaxMsgDuration(msg.PayloadType())
   376  
   377  	// pass in a context with timeout to make the unicast call fail fast
   378  	ctx, cancel := context.WithTimeout(m.ctx, maxTimeout)
   379  	defer cancel()
   380  
   381  	// protect the underlying connection from being inadvertently pruned by the peer manager while the stream and
   382  	// connection creation is being attempted, and remove it from protected list once stream created.
   383  	tag := fmt.Sprintf("%v:%v", msg.Channel(), msg.PayloadType())
   384  	m.libP2PNode.Host().ConnManager().Protect(peerID, tag)
   385  	defer m.libP2PNode.Host().ConnManager().Unprotect(peerID, tag)
   386  
   387  	// create new stream
   388  	// streams don't need to be reused and are fairly inexpensive to be created for each send.
   389  	// A stream creation does NOT incur an RTT as stream negotiation happens as part of the first message
   390  	// sent out the receiver
   391  	stream, err := m.libP2PNode.CreateStream(ctx, peerID)
   392  	if err != nil {
   393  		return fmt.Errorf("failed to create stream for %s: %w", msg.TargetIds()[0], err)
   394  	}
   395  
   396  	success := false
   397  
   398  	defer func() {
   399  		if success {
   400  			// close the stream immediately
   401  			err = stream.Close()
   402  			if err != nil {
   403  				err = fmt.Errorf("failed to close the stream for %s: %w", msg.TargetIds()[0], err)
   404  			}
   405  		} else {
   406  			resetErr := stream.Reset()
   407  			if resetErr != nil {
   408  				m.log.Err(resetErr).Msg("failed to reset stream")
   409  			}
   410  		}
   411  	}()
   412  
   413  	deadline, _ := ctx.Deadline()
   414  	err = stream.SetWriteDeadline(deadline)
   415  	if err != nil {
   416  		return fmt.Errorf("failed to set write deadline for stream: %w", err)
   417  	}
   418  
   419  	// create a gogo protobuf writer
   420  	bufw := bufio.NewWriter(stream)
   421  	writer := ggio.NewDelimitedWriter(bufw)
   422  
   423  	err = writer.WriteMsg(msg.Proto())
   424  	if err != nil {
   425  		return fmt.Errorf("failed to send message to %s: %w", msg.TargetIds()[0], err)
   426  	}
   427  
   428  	// flush the stream
   429  	err = bufw.Flush()
   430  	if err != nil {
   431  		return fmt.Errorf("failed to flush stream for %s: %w", msg.TargetIds()[0], err)
   432  	}
   433  
   434  	success = true
   435  
   436  	return nil
   437  }
   438  
   439  // handleIncomingStream handles an incoming stream from a remote peer
   440  // it is a callback that gets called for each incoming stream by libp2p with a new stream object
   441  func (m *Middleware) handleIncomingStream(s libp2pnetwork.Stream) {
   442  	// qualify the logger with local and remote address
   443  	log := p2putils.StreamLogger(m.log, s)
   444  
   445  	log.Info().Msg("incoming stream received")
   446  
   447  	success := false
   448  
   449  	remotePeer := s.Conn().RemotePeer()
   450  
   451  	defer func() {
   452  		if success {
   453  			err := s.Close()
   454  			if err != nil {
   455  				log.Err(err).Msg("failed to close stream")
   456  			}
   457  		} else {
   458  			err := s.Reset()
   459  			if err != nil {
   460  				log.Err(err).Msg("failed to reset stream")
   461  			}
   462  		}
   463  	}()
   464  
   465  	// check if peer is currently rate limited before continuing to process stream.
   466  	if m.unicastRateLimiters.MessageRateLimiter.IsRateLimited(remotePeer) || m.unicastRateLimiters.BandWidthRateLimiter.IsRateLimited(remotePeer) {
   467  		log.Debug().
   468  			Bool(logging.KeySuspicious, true).
   469  			Msg("dropping unicast stream from rate limited peer")
   470  		return
   471  	}
   472  
   473  	// TODO: We need to allow per-topic timeouts and message size limits.
   474  	// This allows us to configure higher limits for topics on which we expect
   475  	// to receive large messages (e.g. Chunk Data Packs), and use the normal
   476  	// limits for other topics. In order to enable this, we will need to register
   477  	// a separate stream handler for each topic.
   478  	ctx, cancel := context.WithTimeout(m.ctx, LargeMsgUnicastTimeout)
   479  	defer cancel()
   480  
   481  	deadline, _ := ctx.Deadline()
   482  
   483  	err := s.SetReadDeadline(deadline)
   484  	if err != nil {
   485  		log.Err(err).Msg("failed to set read deadline for stream")
   486  		return
   487  	}
   488  
   489  	// create the reader
   490  	r := ggio.NewDelimitedReader(s, LargeMsgMaxUnicastMsgSize)
   491  	for {
   492  		if ctx.Err() != nil {
   493  			return
   494  		}
   495  
   496  		// Note: message fields must not be trusted until explicitly validated
   497  		var msg message.Message
   498  		// read the next message (blocking call)
   499  		err = r.ReadMsg(&msg)
   500  		if err != nil {
   501  			if err == io.EOF {
   502  				break
   503  			}
   504  
   505  			m.log.Err(err).Msg("failed to read message")
   506  			return
   507  		}
   508  
   509  		channel := channels.Channel(msg.ChannelID)
   510  		topic := channels.TopicFromChannel(channel, m.rootBlockID)
   511  
   512  		// ignore messages if node does not have subscription to topic
   513  		if !m.libP2PNode.HasSubscription(topic) {
   514  			violation := &slashing.Violation{
   515  				Identity: nil, PeerID: remotePeer.String(), Channel: channel, Protocol: message.ProtocolUnicast,
   516  			}
   517  
   518  			// msg type is not guaranteed to be correct since it is set by the client
   519  			_, what, err := codec.InterfaceFromMessageCode(msg.Payload[0])
   520  			if err != nil {
   521  				violation.Err = err
   522  				m.slashingViolationsConsumer.OnUnknownMsgTypeError(violation)
   523  				return
   524  			}
   525  
   526  			violation.MsgType = what
   527  			violation.Err = ErrUnicastMsgWithoutSub
   528  			m.slashingViolationsConsumer.OnUnauthorizedUnicastOnChannel(violation)
   529  			return
   530  		}
   531  
   532  		// check if unicast messages have reached rate limit before processing next message
   533  		if !m.unicastRateLimiters.MessageAllowed(remotePeer) {
   534  			return
   535  		}
   536  
   537  		// check if we can get a role for logging and metrics label if this is not a public channel
   538  		role := ""
   539  		if !channels.IsPublicChannel(channels.Channel(msg.ChannelID)) {
   540  			if identity, ok := m.ov.Identity(remotePeer); ok {
   541  				role = identity.Role.String()
   542  			}
   543  		}
   544  
   545  		// check unicast bandwidth rate limiter for peer
   546  		if !m.unicastRateLimiters.BandwidthAllowed(
   547  			remotePeer,
   548  			role,
   549  			msg.Size(),
   550  			network.MessageType(msg.Payload),
   551  			channels.Topic(msg.ChannelID)) {
   552  			return
   553  		}
   554  
   555  		m.wg.Add(1)
   556  		go func() {
   557  			defer m.wg.Done()
   558  			m.processUnicastStreamMessage(remotePeer, &msg)
   559  		}()
   560  	}
   561  
   562  	success = true
   563  }
   564  
   565  // Subscribe subscribes the middleware to a channel.
   566  // No errors are expected during normal operation.
   567  func (m *Middleware) Subscribe(channel channels.Channel) error {
   568  
   569  	topic := channels.TopicFromChannel(channel, m.rootBlockID)
   570  
   571  	var peerFilter p2p.PeerFilter
   572  	var validators []validator.PubSubMessageValidator
   573  	if channels.IsPublicChannel(channel) {
   574  		// NOTE: for public channels the callback used to check if a node is staked will
   575  		// return true for every node.
   576  		peerFilter = p2p.AllowAllPeerFilter()
   577  	} else {
   578  		// for channels used by the staked nodes, add the topic validator to filter out messages from non-staked nodes
   579  		validators = append(validators, m.authorizedSenderValidator.PubSubMessageValidator(channel))
   580  
   581  		// NOTE: For non-public channels the libP2P node topic validator will reject
   582  		// messages from unstaked nodes.
   583  		peerFilter = m.isProtocolParticipant()
   584  	}
   585  
   586  	topicValidator := flowpubsub.TopicValidator(m.log, m.codec, m.slashingViolationsConsumer, peerFilter, validators...)
   587  	s, err := m.libP2PNode.Subscribe(topic, topicValidator)
   588  	if err != nil {
   589  		return fmt.Errorf("could not subscribe to topic (%s): %w", topic, err)
   590  	}
   591  
   592  	// create a new readSubscription with the context of the middleware
   593  	rs := newReadSubscription(s, m.processPubSubMessages, m.log)
   594  	m.wg.Add(1)
   595  
   596  	// kick off the receive loop to continuously receive messages
   597  	go func() {
   598  		defer m.wg.Done()
   599  		rs.receiveLoop(m.ctx)
   600  	}()
   601  
   602  	// update peers to add some nodes interested in the same topic as direct peers
   603  	m.libP2PNode.RequestPeerUpdate()
   604  
   605  	return nil
   606  }
   607  
   608  // processPubSubMessages processes messages received from the pubsub subscription.
   609  func (m *Middleware) processPubSubMessages(msg *message.Message, decodedMsgPayload interface{}, peerID peer.ID) {
   610  	m.processAuthenticatedMessage(msg, decodedMsgPayload, peerID, network.ProtocolTypePubSub)
   611  }
   612  
   613  // Unsubscribe unsubscribes the middleware from a channel.
   614  // The following benign errors are expected during normal operations from libP2P:
   615  // - the libP2P node fails to unsubscribe to the topic created from the provided channel.
   616  //
   617  // All errors returned from this function can be considered benign.
   618  func (m *Middleware) Unsubscribe(channel channels.Channel) error {
   619  	topic := channels.TopicFromChannel(channel, m.rootBlockID)
   620  	err := m.libP2PNode.UnSubscribe(topic)
   621  	if err != nil {
   622  		return fmt.Errorf("failed to unsubscribe from channel (%s): %w", channel, err)
   623  	}
   624  
   625  	// update peers to remove nodes subscribed to channel
   626  	m.libP2PNode.RequestPeerUpdate()
   627  
   628  	return nil
   629  }
   630  
   631  // processUnicastStreamMessage will decode, perform authorized sender validation and process a message
   632  // sent via unicast stream. This func should be invoked in a separate goroutine to avoid creating a message decoding bottleneck.
   633  func (m *Middleware) processUnicastStreamMessage(remotePeer peer.ID, msg *message.Message) {
   634  	channel := channels.Channel(msg.ChannelID)
   635  	decodedMsgPayload, err := m.codec.Decode(msg.Payload)
   636  	if codec.IsErrUnknownMsgCode(err) {
   637  		// slash peer if message contains unknown message code byte
   638  		violation := &slashing.Violation{
   639  			PeerID: remotePeer.String(), Channel: channel, Protocol: message.ProtocolUnicast, Err: err,
   640  		}
   641  		m.slashingViolationsConsumer.OnUnknownMsgTypeError(violation)
   642  		return
   643  	}
   644  	if codec.IsErrMsgUnmarshal(err) || codec.IsErrInvalidEncoding(err) {
   645  		// slash if peer sent a message that could not be marshalled into the message type denoted by the message code byte
   646  		violation := &slashing.Violation{
   647  			PeerID: remotePeer.String(), Channel: channel, Protocol: message.ProtocolUnicast, Err: err,
   648  		}
   649  		m.slashingViolationsConsumer.OnInvalidMsgError(violation)
   650  		return
   651  	}
   652  
   653  	// unexpected error condition. this indicates there's a bug
   654  	// don't crash as a result of external inputs since that creates a DoS vector.
   655  	if err != nil {
   656  		m.log.
   657  			Error().
   658  			Err(fmt.Errorf("unexpected error while decoding message: %w", err)).
   659  			Str("peer_id", remotePeer.String()).
   660  			Str("channel", msg.ChannelID).
   661  			Bool(logging.KeySuspicious, true).
   662  			Msg("failed to decode message payload")
   663  		return
   664  	}
   665  
   666  	messageType := network.MessageType(decodedMsgPayload)
   667  
   668  	// TODO: once we've implemented per topic message size limits per the TODO above,
   669  	// we can remove this check
   670  	maxSize := unicastMaxMsgSize(messageType)
   671  	if msg.Size() > maxSize {
   672  		// message size exceeded
   673  		m.log.Error().
   674  			Str("peer_id", remotePeer.String()).
   675  			Str("channel", msg.ChannelID).
   676  			Int("max_size", maxSize).
   677  			Int("size", msg.Size()).
   678  			Bool(logging.KeySuspicious, true).
   679  			Msg("received message exceeded permissible message maxSize")
   680  		return
   681  	}
   682  
   683  	// if message channel is not public perform authorized sender validation
   684  	if !channels.IsPublicChannel(channel) {
   685  		_, err := m.authorizedSenderValidator.Validate(remotePeer, decodedMsgPayload, channel, message.ProtocolUnicast)
   686  		if err != nil {
   687  			m.log.
   688  				Error().
   689  				Err(err).
   690  				Str("peer_id", remotePeer.String()).
   691  				Str("type", messageType).
   692  				Str("channel", msg.ChannelID).
   693  				Msg("unicast authorized sender validation failed")
   694  			return
   695  		}
   696  	}
   697  
   698  	m.processAuthenticatedMessage(msg, decodedMsgPayload, remotePeer, network.ProtocolTypeUnicast)
   699  }
   700  
   701  // processAuthenticatedMessage processes a message and a source (indicated by its peer ID) and eventually passes it to the overlay
   702  // In particular, it populates the `OriginID` field of the message with a Flow ID translated from this source.
   703  // The assumption is that the message has been authenticated at the network level (libp2p) to originate from the peer with ID `peerID`
   704  // this requirement is fulfilled by e.g. the output of readConnection and readSubscription
   705  func (m *Middleware) processAuthenticatedMessage(msg *message.Message, decodedMsgPayload interface{}, peerID peer.ID, protocol network.ProtocolType) {
   706  	originId, err := m.idTranslator.GetFlowID(peerID)
   707  	if err != nil {
   708  		// this error should never happen. by the time the message gets here, the peer should be
   709  		// authenticated which means it must be known
   710  		m.log.Error().
   711  			Err(err).
   712  			Str("peer_id", peerID.String()).
   713  			Bool(logging.KeySuspicious, true).
   714  			Msg("dropped message from unknown peer")
   715  		return
   716  	}
   717  
   718  	scope, err := network.NewIncomingScope(originId, protocol, msg, decodedMsgPayload)
   719  	if err != nil {
   720  		m.log.Error().
   721  			Err(err).
   722  			Str("peer_id", peerID.String()).
   723  			Str("origin_id", originId.String()).
   724  			Msg("could not create incoming message scope")
   725  		return
   726  	}
   727  
   728  	m.processMessage(scope)
   729  }
   730  
   731  // processMessage processes a message and eventually passes it to the overlay
   732  func (m *Middleware) processMessage(scope *network.IncomingMessageScope) {
   733  
   734  	logger := m.log.With().
   735  		Str("channel", scope.Channel().String()).
   736  		Str("type", scope.Protocol().String()).
   737  		Int("msg_size", scope.Size()).
   738  		Hex("origin_id", logging.ID(scope.OriginId())).
   739  		Logger()
   740  
   741  	// run through all the message validators
   742  	for _, v := range m.validators {
   743  		// if any one fails, stop message propagation
   744  		if !v.Validate(*scope) {
   745  			logger.Debug().Msg("new message filtered by message validators")
   746  			return
   747  		}
   748  	}
   749  
   750  	logger.Debug().Msg("processing new message")
   751  
   752  	// if validation passed, send the message to the overlay
   753  	err := m.ov.Receive(scope)
   754  	if err != nil {
   755  		m.log.Error().Err(err).Msg("could not deliver payload")
   756  	}
   757  }
   758  
   759  // Publish publishes a message on the channel. It models a distributed broadcast where the message is meant for all or
   760  // a many nodes subscribing to the channel. It does not guarantee the delivery though, and operates on a best
   761  // effort.
   762  // The following benign errors are expected during normal operations:
   763  // - the msg cannot be marshalled.
   764  // - the msg size exceeds DefaultMaxPubSubMsgSize.
   765  // - the libP2P node fails to publish the message.
   766  //
   767  // All errors returned from this function can be considered benign.
   768  func (m *Middleware) Publish(msg *network.OutgoingMessageScope) error {
   769  	m.log.Debug().
   770  		Str("channel", msg.Channel().String()).
   771  		Interface("msg", msg.Proto()).
   772  		Str("type", msg.PayloadType()).
   773  		Int("msg_size", msg.Size()).
   774  		Msg("publishing new message")
   775  
   776  	// convert the message to bytes to be put on the wire.
   777  	data, err := msg.Proto().Marshal()
   778  	if err != nil {
   779  		return fmt.Errorf("failed to marshal the message: %w", err)
   780  	}
   781  
   782  	msgSize := len(data)
   783  	if msgSize > p2pnode.DefaultMaxPubSubMsgSize {
   784  		// libp2p pubsub will silently drop the message if its size is greater than the configured pubsub max message size
   785  		// hence return an error as this message is undeliverable
   786  		return fmt.Errorf("message size %d exceeds configured max message size %d", msgSize, p2pnode.DefaultMaxPubSubMsgSize)
   787  	}
   788  
   789  	topic := channels.TopicFromChannel(msg.Channel(), m.rootBlockID)
   790  
   791  	// publish the bytes on the topic
   792  	err = m.libP2PNode.Publish(m.ctx, topic, data)
   793  	if err != nil {
   794  		return fmt.Errorf("failed to publish the message: %w", err)
   795  	}
   796  
   797  	return nil
   798  }
   799  
   800  // IsConnected returns true if this node is connected to the node with id nodeID.
   801  // All errors returned from this function can be considered benign.
   802  func (m *Middleware) IsConnected(nodeID flow.Identifier) (bool, error) {
   803  	peerID, err := m.idTranslator.GetPeerID(nodeID)
   804  	if err != nil {
   805  		return false, fmt.Errorf("could not find peer id for target id: %w", err)
   806  	}
   807  	return m.libP2PNode.IsConnected(peerID)
   808  }
   809  
   810  // unicastMaxMsgSize returns the max permissible size for a unicast message
   811  func unicastMaxMsgSize(messageType string) int {
   812  	switch messageType {
   813  	case "messages.ChunkDataResponse":
   814  		return LargeMsgMaxUnicastMsgSize
   815  	default:
   816  		return DefaultMaxUnicastMsgSize
   817  	}
   818  }
   819  
   820  // unicastMaxMsgDuration returns the max duration to allow for a unicast send to complete
   821  func (m *Middleware) unicastMaxMsgDuration(messageType string) time.Duration {
   822  	switch messageType {
   823  	case "messages.ChunkDataResponse":
   824  		if LargeMsgUnicastTimeout > m.unicastMessageTimeout {
   825  			return LargeMsgUnicastTimeout
   826  		}
   827  		return m.unicastMessageTimeout
   828  	default:
   829  		return m.unicastMessageTimeout
   830  	}
   831  }