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 }