github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/network/underlay/network.go (about) 1 package underlay 2 3 import ( 4 "bufio" 5 "context" 6 "errors" 7 "fmt" 8 "io" 9 "sync" 10 "time" 11 12 ggio "github.com/gogo/protobuf/io" 13 "github.com/ipfs/go-datastore" 14 libp2pnet "github.com/libp2p/go-libp2p/core/network" 15 "github.com/libp2p/go-libp2p/core/peer" 16 "github.com/libp2p/go-libp2p/core/peerstore" 17 "github.com/libp2p/go-libp2p/core/protocol" 18 "github.com/rs/zerolog" 19 20 "github.com/onflow/flow-go/model/flow" 21 "github.com/onflow/flow-go/model/flow/filter" 22 "github.com/onflow/flow-go/module" 23 "github.com/onflow/flow-go/module/component" 24 "github.com/onflow/flow-go/module/irrecoverable" 25 "github.com/onflow/flow-go/network" 26 alspmgr "github.com/onflow/flow-go/network/alsp/manager" 27 netcache "github.com/onflow/flow-go/network/cache" 28 "github.com/onflow/flow-go/network/channels" 29 "github.com/onflow/flow-go/network/codec" 30 "github.com/onflow/flow-go/network/internal/p2putils" 31 "github.com/onflow/flow-go/network/message" 32 "github.com/onflow/flow-go/network/p2p" 33 "github.com/onflow/flow-go/network/p2p/blob" 34 p2plogging "github.com/onflow/flow-go/network/p2p/logging" 35 "github.com/onflow/flow-go/network/p2p/ping" 36 "github.com/onflow/flow-go/network/p2p/subscription" 37 "github.com/onflow/flow-go/network/p2p/unicast/protocols" 38 "github.com/onflow/flow-go/network/p2p/unicast/ratelimit" 39 "github.com/onflow/flow-go/network/p2p/utils" 40 "github.com/onflow/flow-go/network/queue" 41 "github.com/onflow/flow-go/network/underlay/internal" 42 "github.com/onflow/flow-go/network/validator" 43 flowpubsub "github.com/onflow/flow-go/network/validator/pubsub" 44 _ "github.com/onflow/flow-go/utils/binstat" 45 "github.com/onflow/flow-go/utils/logging" 46 ) 47 48 const ( 49 _ = iota 50 _ = 1 << (10 * iota) 51 mb 52 gb 53 ) 54 55 const ( 56 // DefaultMaxUnicastMsgSize defines maximum message size in unicast mode for most messages 57 DefaultMaxUnicastMsgSize = 10 * mb // 10 mb 58 59 // LargeMsgMaxUnicastMsgSize defines maximum message size in unicast mode for large messages 60 LargeMsgMaxUnicastMsgSize = gb // 1 gb 61 62 // DefaultUnicastTimeout is the default maximum time to wait for a default unicast request to complete 63 // assuming at least a 1mb/sec connection 64 DefaultUnicastTimeout = 5 * time.Second 65 66 // LargeMsgUnicastTimeout is the maximum time to wait for a unicast request to complete for large message size 67 LargeMsgUnicastTimeout = 1000 * time.Second 68 ) 69 70 var ( 71 // ErrUnicastMsgWithoutSub error is provided to the slashing violations consumer in the case where 72 // the network receives a message via unicast but does not have a corresponding subscription for 73 // the channel in that message. 74 ErrUnicastMsgWithoutSub = errors.New("networking layer does not have subscription for the channel ID indicated in the unicast message received") 75 ) 76 77 // Network serves as the comprehensive networking layer that integrates three interfaces within Flow; Underlay, EngineRegistry, and ConduitAdapter. 78 // It is responsible for creating conduits through which engines can send and receive messages to and from other engines on the network, as well as registering other services 79 // such as BlobService and PingService. It also provides a set of APIs that can be used to send messages to other nodes on the network. 80 // Network is also responsible for managing the topology of the network, i.e., the set of nodes that are connected to each other. 81 // It is also responsible for managing the set of nodes that are connected to each other. 82 type Network struct { 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 *component.ComponentManager 89 ctx context.Context 90 sporkId flow.Identifier 91 identityProvider module.IdentityProvider 92 identityTranslator p2p.IDTranslator 93 logger zerolog.Logger 94 codec network.Codec 95 me module.Local 96 metrics module.NetworkCoreMetrics 97 receiveCache *netcache.ReceiveCache // used to deduplicate incoming messages 98 queue network.MessageQueue 99 subscriptionManager network.SubscriptionManager // used to keep track of subscribed channels 100 conduitFactory network.ConduitFactory 101 topology network.Topology 102 registerEngineRequests chan *registerEngineRequest 103 registerBlobServiceRequests chan *registerBlobServiceRequest 104 misbehaviorReportManager network.MisbehaviorReportManager 105 unicastMessageTimeout time.Duration 106 libP2PNode p2p.LibP2PNode 107 bitswapMetrics module.BitswapMetrics 108 peerUpdateLock sync.Mutex // protects the peer update process 109 previousProtocolStatePeers []peer.AddrInfo 110 slashingViolationsConsumer network.ViolationsConsumer 111 peerManagerFilters []p2p.PeerFilter 112 unicastRateLimiters *ratelimit.RateLimiters 113 validators []network.MessageValidator 114 authorizedSenderValidator *validator.AuthorizedSenderValidator 115 preferredUnicasts []protocols.ProtocolName 116 } 117 118 var _ network.EngineRegistry = &Network{} 119 var _ network.Underlay = &Network{} 120 var _ network.ConduitAdapter = &Network{} 121 122 type registerEngineRequest struct { 123 channel channels.Channel 124 messageProcessor network.MessageProcessor 125 respChan chan *registerEngineResp 126 } 127 128 type registerEngineResp struct { 129 conduit network.Conduit 130 err error 131 } 132 133 type registerBlobServiceRequest struct { 134 channel channels.Channel 135 ds datastore.Batching 136 opts []network.BlobServiceOption 137 respChan chan *registerBlobServiceResp 138 } 139 140 type registerBlobServiceResp struct { 141 blobService network.BlobService 142 err error 143 } 144 145 var ErrNetworkShutdown = errors.New("network has already shutdown") 146 147 // NetworkConfig is a configuration struct for the network. It contains all the 148 // necessary components to create a new network. 149 type NetworkConfig struct { 150 Logger zerolog.Logger 151 Codec network.Codec 152 Me module.Local 153 Topology network.Topology 154 Metrics module.NetworkCoreMetrics 155 IdentityProvider module.IdentityProvider 156 IdentityTranslator p2p.IDTranslator 157 ReceiveCache *netcache.ReceiveCache 158 ConduitFactory network.ConduitFactory 159 AlspCfg *alspmgr.MisbehaviorReportManagerConfig 160 SporkId flow.Identifier 161 UnicastMessageTimeout time.Duration 162 Libp2pNode p2p.LibP2PNode 163 BitSwapMetrics module.BitswapMetrics 164 SlashingViolationConsumerFactory func(network.ConduitAdapter) network.ViolationsConsumer 165 } 166 167 // Validate validates the configuration, and sets default values for any missing fields. 168 func (cfg *NetworkConfig) Validate() { 169 if cfg.UnicastMessageTimeout <= 0 { 170 cfg.UnicastMessageTimeout = DefaultUnicastTimeout 171 } 172 } 173 174 // NetworkConfigOption is a function that can be used to override network config parmeters. 175 type NetworkConfigOption func(*NetworkConfig) 176 177 // WithAlspConfig overrides the default misbehavior report manager config. It is mostly used for testing purposes. 178 // Note: do not override the default misbehavior report manager config in production unless you know what you are doing. 179 // Args: 180 // cfg: misbehavior report manager config 181 // Returns: 182 // NetworkConfigOption: network param option 183 func WithAlspConfig(cfg *alspmgr.MisbehaviorReportManagerConfig) NetworkConfigOption { 184 return func(params *NetworkConfig) { 185 params.AlspCfg = cfg 186 } 187 } 188 189 // WithCodec overrides the default codec (i.e., encoder and decoder). It is mostly used for testing purposes. 190 // Note: do not override the default codec in production unless you know what you are doing. 191 func WithCodec(codec network.Codec) NetworkConfigOption { 192 return func(params *NetworkConfig) { 193 params.Codec = codec 194 } 195 } 196 197 func WithSlashingViolationConsumerFactory(factory func(adapter network.ConduitAdapter) network.ViolationsConsumer) NetworkConfigOption { 198 return func(params *NetworkConfig) { 199 params.SlashingViolationConsumerFactory = factory 200 } 201 } 202 203 // NetworkOption is a function that can be used to override network attributes. 204 // It is mostly used for testing purposes. 205 // Note: do not override network attributes in production unless you know what you are doing. 206 type NetworkOption func(*Network) 207 208 // WithAlspManager sets the misbehavior report manager for the network. It overrides the default 209 // misbehavior report manager that is created from the config. 210 // Note that this option is mostly used for testing purposes, do not use it in production unless you 211 // know what you are doing. 212 // 213 // Args: 214 // 215 // mgr: misbehavior report manager 216 // 217 // Returns: 218 // 219 // NetworkOption: network option 220 func WithAlspManager(mgr network.MisbehaviorReportManager) NetworkOption { 221 return func(n *Network) { 222 n.misbehaviorReportManager = mgr 223 } 224 } 225 226 // WithPeerManagerFilters sets the peer manager filters for the network. It overrides the default 227 // peer manager filters that are created from the config. 228 func WithPeerManagerFilters(filters ...p2p.PeerFilter) NetworkOption { 229 return func(n *Network) { 230 n.peerManagerFilters = filters 231 } 232 } 233 234 // WithUnicastRateLimiters sets the unicast rate limiters for the network. It overrides the default 235 // unicast rate limiters that are created from the config. 236 func WithUnicastRateLimiters(limiters *ratelimit.RateLimiters) NetworkOption { 237 return func(n *Network) { 238 n.unicastRateLimiters = limiters 239 } 240 } 241 242 // WithPreferredUnicastProtocols sets the preferred unicast protocols for the network. It overrides the default 243 // preferred unicast. 244 func WithPreferredUnicastProtocols(protocols ...protocols.ProtocolName) NetworkOption { 245 return func(n *Network) { 246 n.preferredUnicasts = protocols 247 } 248 } 249 250 // WithMessageValidators sets the message validators for the network. It overrides the default 251 // message validators. 252 func WithMessageValidators(validators ...network.MessageValidator) NetworkOption { 253 return func(n *Network) { 254 n.validators = validators 255 } 256 } 257 258 // NewNetwork creates a new network with the given configuration. 259 // Args: 260 // param: network configuration 261 // opts: network options 262 // Returns: 263 // Network: a new network 264 func NewNetwork(param *NetworkConfig, opts ...NetworkOption) (*Network, error) { 265 param.Validate() 266 267 n := &Network{ 268 logger: param.Logger.With().Str("component", "network").Logger(), 269 codec: param.Codec, 270 me: param.Me, 271 receiveCache: param.ReceiveCache, 272 topology: param.Topology, 273 metrics: param.Metrics, 274 bitswapMetrics: param.BitSwapMetrics, 275 identityProvider: param.IdentityProvider, 276 conduitFactory: param.ConduitFactory, 277 registerEngineRequests: make(chan *registerEngineRequest), 278 registerBlobServiceRequests: make(chan *registerBlobServiceRequest), 279 sporkId: param.SporkId, 280 identityTranslator: param.IdentityTranslator, 281 unicastMessageTimeout: param.UnicastMessageTimeout, 282 libP2PNode: param.Libp2pNode, 283 unicastRateLimiters: ratelimit.NoopRateLimiters(), 284 validators: DefaultValidators(param.Logger.With().Str("component", "network-validators").Logger(), param.Me.NodeID()), 285 } 286 287 n.subscriptionManager = subscription.NewChannelSubscriptionManager(n) 288 289 misbehaviorMngr, err := alspmgr.NewMisbehaviorReportManager(param.AlspCfg, n) 290 if err != nil { 291 return nil, fmt.Errorf("could not create misbehavior report manager: %w", err) 292 } 293 n.misbehaviorReportManager = misbehaviorMngr 294 295 for _, opt := range opts { 296 opt(n) 297 } 298 299 if err := n.conduitFactory.RegisterAdapter(n); err != nil { 300 return nil, fmt.Errorf("could not register network adapter: %w", err) 301 } 302 303 builder := component.NewComponentManagerBuilder() 304 builder.AddWorker(func(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) { 305 n.logger.Debug().Msg("starting misbehavior manager") 306 n.misbehaviorReportManager.Start(ctx) 307 308 select { 309 case <-n.misbehaviorReportManager.Ready(): 310 n.logger.Debug().Msg("misbehavior manager is ready") 311 ready() 312 case <-ctx.Done(): 313 // jumps to the end of the select statement to let a graceful shutdown. 314 } 315 316 <-ctx.Done() 317 n.logger.Debug().Msg("stopping misbehavior manager") 318 <-n.misbehaviorReportManager.Done() 319 n.logger.Debug().Msg("misbehavior manager stopped") 320 }) 321 builder.AddWorker(func(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) { 322 n.logger.Debug().Msg("setting up network context") 323 n.ctx = ctx 324 325 ready() 326 327 <-ctx.Done() 328 n.logger.Debug().Msg("network context is done") 329 }) 330 331 for _, limiter := range n.unicastRateLimiters.Limiters() { 332 rateLimiter := limiter 333 builder.AddWorker(func(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) { 334 ready() 335 rateLimiter.Start(ctx) 336 <-rateLimiter.Ready() 337 ready() 338 <-rateLimiter.Done() 339 }) 340 } 341 342 builder.AddWorker(func(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) { 343 // creation of slashing violations consumer should be postponed till here where the network 344 // is start and the overlay is set. 345 n.slashingViolationsConsumer = param.SlashingViolationConsumerFactory(n) 346 347 n.authorizedSenderValidator = validator.NewAuthorizedSenderValidator( 348 n.logger, 349 n.slashingViolationsConsumer, 350 n.Identity) 351 352 err := n.libP2PNode.WithDefaultUnicastProtocol(n.handleIncomingStream, n.preferredUnicasts) 353 if err != nil { 354 ctx.Throw(fmt.Errorf("could not register preferred unicast protocols on libp2p node: %w", err)) 355 } 356 357 n.UpdateNodeAddresses() 358 n.libP2PNode.WithPeersProvider(n.authorizedPeers) 359 360 ready() 361 362 <-ctx.Done() 363 n.logger.Info().Str("component", "network").Msg("stopping subroutines, blocking on read connection loops to end") 364 365 // wait for the readConnection and readSubscription routines to stop 366 n.wg.Wait() 367 n.logger.Info().Str("component", "network").Msg("stopped subroutines") 368 }) 369 370 builder.AddWorker(n.createInboundMessageQueue) 371 builder.AddWorker(n.processRegisterEngineRequests) 372 builder.AddWorker(n.processRegisterBlobServiceRequests) 373 374 n.ComponentManager = builder.Build() 375 return n, nil 376 } 377 378 func (n *Network) processRegisterEngineRequests(parent irrecoverable.SignalerContext, ready component.ReadyFunc) { 379 ready() 380 381 // we need to wait for the libp2p node to be ready before we can register engines 382 n.logger.Debug().Msg("waiting for libp2p node to be ready") 383 <-n.libP2PNode.Ready() 384 n.logger.Debug().Msg("libp2p node is ready") 385 386 for { 387 select { 388 case req := <-n.registerEngineRequests: 389 conduit, err := n.handleRegisterEngineRequest(parent, req.channel, req.messageProcessor) 390 resp := ®isterEngineResp{ 391 conduit: conduit, 392 err: err, 393 } 394 395 select { 396 case <-parent.Done(): 397 return 398 case req.respChan <- resp: 399 } 400 case <-parent.Done(): 401 return 402 } 403 } 404 } 405 406 func (n *Network) processRegisterBlobServiceRequests(parent irrecoverable.SignalerContext, ready component.ReadyFunc) { 407 ready() 408 409 n.logger.Debug().Msg("waiting for libp2p node to be ready") 410 <-n.libP2PNode.Ready() 411 n.logger.Debug().Msg("libp2p node is ready") 412 413 for { 414 select { 415 case req := <-n.registerBlobServiceRequests: 416 blobService, err := n.handleRegisterBlobServiceRequest(parent, req.channel, req.ds, req.opts) 417 resp := ®isterBlobServiceResp{ 418 blobService: blobService, 419 err: err, 420 } 421 422 select { 423 case <-parent.Done(): 424 return 425 case req.respChan <- resp: 426 } 427 case <-parent.Done(): 428 return 429 } 430 } 431 } 432 433 // createInboundMessageQueue creates the queue that will be used to process incoming messages. 434 func (n *Network) createInboundMessageQueue(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) { 435 n.queue = queue.NewMessageQueue(ctx, queue.GetEventPriority, n.metrics) 436 queue.CreateQueueWorkers(ctx, queue.DefaultNumWorkers, n.queue, n.queueSubmitFunc) 437 438 ready() 439 } 440 441 func (n *Network) handleRegisterEngineRequest(parent irrecoverable.SignalerContext, channel channels.Channel, engine network.MessageProcessor) (network.Conduit, error) { 442 if !channels.ChannelExists(channel) { 443 return nil, fmt.Errorf("unknown channel: %s, should be registered in topic map", channel) 444 } 445 446 err := n.subscriptionManager.Register(channel, engine) 447 if err != nil { 448 return nil, fmt.Errorf("failed to register engine for channel %s: %w", channel, err) 449 } 450 451 n.logger.Info(). 452 Str("channel_id", channel.String()). 453 Msg("channel successfully registered") 454 455 // create the conduit 456 newConduit, err := n.conduitFactory.NewConduit(parent, channel) 457 if err != nil { 458 return nil, fmt.Errorf("could not create conduit using factory: %w", err) 459 } 460 461 return newConduit, nil 462 } 463 464 func (n *Network) handleRegisterBlobServiceRequest( 465 parent irrecoverable.SignalerContext, 466 channel channels.Channel, 467 ds datastore.Batching, 468 opts []network.BlobServiceOption, 469 ) (network.BlobService, error) { 470 bs, err := blob.NewBlobService(n.libP2PNode.Host(), n.libP2PNode.Routing(), channel.String(), ds, n.bitswapMetrics, n.logger, opts...) 471 if err != nil { 472 return nil, fmt.Errorf("could not create blob service: %w", err) 473 } 474 475 // start the blob service using the network's context 476 bs.Start(parent) 477 478 return bs, nil 479 } 480 481 // Register will register the given engine with the given unique engine engineID, 482 // returning a conduit to directly submit messages to the message bus of the 483 // engine. 484 func (n *Network) Register(channel channels.Channel, messageProcessor network.MessageProcessor) (network.Conduit, error) { 485 respChan := make(chan *registerEngineResp) 486 487 select { 488 case <-n.ComponentManager.ShutdownSignal(): 489 return nil, ErrNetworkShutdown 490 case n.registerEngineRequests <- ®isterEngineRequest{ 491 channel: channel, 492 messageProcessor: messageProcessor, 493 respChan: respChan, 494 }: 495 select { 496 case <-n.ComponentManager.ShutdownSignal(): 497 return nil, ErrNetworkShutdown 498 case resp := <-respChan: 499 return resp.conduit, resp.err 500 } 501 } 502 } 503 504 func (n *Network) RegisterPingService(pingProtocol protocol.ID, provider network.PingInfoProvider) (network.PingService, error) { 505 select { 506 case <-n.ComponentManager.ShutdownSignal(): 507 return nil, ErrNetworkShutdown 508 default: 509 return ping.NewPingService(n.libP2PNode.Host(), pingProtocol, n.logger, provider), nil 510 } 511 } 512 513 // RegisterBlobService registers a BlobService on the given channel. 514 // The returned BlobService can be used to request blobs from the network. 515 func (n *Network) RegisterBlobService(channel channels.Channel, ds datastore.Batching, opts ...network.BlobServiceOption) (network.BlobService, error) { 516 respChan := make(chan *registerBlobServiceResp) 517 518 select { 519 case <-n.ComponentManager.ShutdownSignal(): 520 return nil, ErrNetworkShutdown 521 case n.registerBlobServiceRequests <- ®isterBlobServiceRequest{ 522 channel: channel, 523 ds: ds, 524 opts: opts, 525 respChan: respChan, 526 }: 527 select { 528 case <-n.ComponentManager.ShutdownSignal(): 529 return nil, ErrNetworkShutdown 530 case resp := <-respChan: 531 return resp.blobService, resp.err 532 } 533 } 534 } 535 536 // UnRegisterChannel unregisters the engine for the specified channel. The engine will no longer be able to send or 537 // receive messages from that channel. 538 func (n *Network) UnRegisterChannel(channel channels.Channel) error { 539 err := n.subscriptionManager.Unregister(channel) 540 if err != nil { 541 return fmt.Errorf("failed to unregister engine for channel %s: %w", channel, err) 542 } 543 return nil 544 } 545 546 func (n *Network) Identities() flow.IdentityList { 547 return n.identityProvider.Identities(filter.NotEjectedFilter) 548 } 549 550 func (n *Network) Identity(pid peer.ID) (*flow.Identity, bool) { 551 return n.identityProvider.ByPeerID(pid) 552 } 553 554 func (n *Network) Receive(msg network.IncomingMessageScope) error { 555 n.metrics.InboundMessageReceived(msg.Size(), msg.Channel().String(), msg.Protocol().String(), msg.PayloadType()) 556 557 err := n.processNetworkMessage(msg) 558 if err != nil { 559 return fmt.Errorf("could not process message: %w", err) 560 } 561 return nil 562 } 563 564 func (n *Network) processNetworkMessage(msg network.IncomingMessageScope) error { 565 // checks the cache for deduplication and adds the message if not already present 566 if !n.receiveCache.Add(msg.EventID()) { 567 // drops duplicate message 568 n.logger.Debug(). 569 Hex("sender_id", logging.ID(msg.OriginId())). 570 Hex("event_id", msg.EventID()). 571 Str("channel", msg.Channel().String()). 572 Msg("dropping message due to duplication") 573 574 n.metrics.DuplicateInboundMessagesDropped(msg.Channel().String(), msg.Protocol().String(), msg.PayloadType()) 575 576 return nil 577 } 578 579 // create queue message 580 qm := queue.QMessage{ 581 Payload: msg.DecodedPayload(), 582 Size: msg.Size(), 583 Target: msg.Channel(), 584 SenderID: msg.OriginId(), 585 } 586 587 // insert the message in the queue 588 err := n.queue.Insert(qm) 589 if err != nil { 590 return fmt.Errorf("failed to insert message in queue: %w", err) 591 } 592 593 return nil 594 } 595 596 // UnicastOnChannel sends the message in a reliable way to the given recipient. 597 // It uses 1-1 direct messaging over the underlying network to deliver the message. 598 // It returns an error if unicasting fails. 599 func (n *Network) UnicastOnChannel(channel channels.Channel, payload interface{}, targetID flow.Identifier) error { 600 if targetID == n.me.NodeID() { 601 n.logger.Debug().Msg("network skips self unicasting") 602 return nil 603 } 604 605 msg, err := message.NewOutgoingScope( 606 flow.IdentifierList{targetID}, 607 channels.TopicFromChannel(channel, n.sporkId), 608 payload, 609 n.codec.Encode, 610 message.ProtocolTypeUnicast) 611 if err != nil { 612 return fmt.Errorf("could not generate outgoing message scope for unicast: %w", err) 613 } 614 615 n.metrics.UnicastMessageSendingStarted(channel.String()) 616 defer n.metrics.UnicastMessageSendingCompleted(channel.String()) 617 618 // since it is a unicast, we only need to get the first peer ID. 619 peerID, err := n.identityTranslator.GetPeerID(msg.TargetIds()[0]) 620 if err != nil { 621 return fmt.Errorf("could not find peer id for target id: %w", err) 622 } 623 624 maxMsgSize := unicastMaxMsgSize(msg.PayloadType()) 625 if msg.Size() > maxMsgSize { 626 // message size goes beyond maximum size that the serializer can handle. 627 // proceeding with this message results in closing the connection by the target side, and 628 // delivery failure. 629 return fmt.Errorf("message size %d exceeds configured max message size %d", msg.Size(), maxMsgSize) 630 } 631 632 maxTimeout := n.unicastMaxMsgDuration(msg.PayloadType()) 633 634 // pass in a context with timeout to make the unicast call fail fast 635 ctx, cancel := context.WithTimeout(n.ctx, maxTimeout) 636 defer cancel() 637 638 // protect the underlying connection from being inadvertently pruned by the peer manager while the stream and 639 // connection creation is being attempted, and remove it from protected list once stream created. 640 channel, ok := channels.ChannelFromTopic(msg.Topic()) 641 if !ok { 642 return fmt.Errorf("could not find channel for topic %s", msg.Topic()) 643 } 644 streamProtectionTag := fmt.Sprintf("%v:%v", channel, msg.PayloadType()) 645 646 err = n.libP2PNode.OpenAndWriteOnStream(ctx, peerID, streamProtectionTag, func(stream libp2pnet.Stream) error { 647 bufw := bufio.NewWriter(stream) 648 writer := ggio.NewDelimitedWriter(bufw) 649 650 err = writer.WriteMsg(msg.Proto()) 651 if err != nil { 652 return fmt.Errorf("failed to send message to target id %x with peer id %s: %w", msg.TargetIds()[0], peerID, err) 653 } 654 655 // flush the stream 656 err = bufw.Flush() 657 if err != nil { 658 return fmt.Errorf("failed to flush stream for target id %x with peer id %s: %w", msg.TargetIds()[0], peerID, err) 659 } 660 661 return nil 662 }) 663 if err != nil { 664 return fmt.Errorf("failed to send message to %x: %w", targetID, err) 665 } 666 667 n.metrics.OutboundMessageSent(msg.Size(), channel.String(), message.ProtocolTypeUnicast.String(), msg.PayloadType()) 668 return nil 669 } 670 671 // PublishOnChannel sends the message in an unreliable way to the given recipients. 672 // In this context, unreliable means that the message is published over a libp2p pub-sub 673 // channel and can be read by any node subscribed to that channel. 674 // The selector could be used to optimize or restrict delivery. 675 func (n *Network) PublishOnChannel(channel channels.Channel, message interface{}, targetIDs ...flow.Identifier) error { 676 filteredIDs := flow.IdentifierList(targetIDs).Filter(n.removeSelfFilter()) 677 678 if len(filteredIDs) == 0 { 679 return network.EmptyTargetList 680 } 681 682 err := n.sendOnChannel(channel, message, filteredIDs) 683 684 if err != nil { 685 return fmt.Errorf("failed to publish on channel %s: %w", channel, err) 686 } 687 688 return nil 689 } 690 691 // MulticastOnChannel unreliably sends the specified event over the channel to randomly selected 'num' number of recipients 692 // selected from the specified targetIDs. 693 func (n *Network) MulticastOnChannel(channel channels.Channel, message interface{}, num uint, targetIDs ...flow.Identifier) error { 694 selectedIDs, err := flow.IdentifierList(targetIDs).Filter(n.removeSelfFilter()).Sample(num) 695 if err != nil { 696 return fmt.Errorf("sampling failed: %w", err) 697 } 698 699 if len(selectedIDs) == 0 { 700 return network.EmptyTargetList 701 } 702 703 err = n.sendOnChannel(channel, message, selectedIDs) 704 705 // publishes the message to the selected targets 706 if err != nil { 707 return fmt.Errorf("failed to multicast on channel %s: %w", channel, err) 708 } 709 710 return nil 711 } 712 713 // removeSelfFilter removes the flow.Identifier of this node if present, from the list of nodes 714 func (n *Network) removeSelfFilter() flow.IdentifierFilter { 715 return func(id flow.Identifier) bool { 716 return id != n.me.NodeID() 717 } 718 } 719 720 // sendOnChannel sends the message on channel to targets. 721 func (n *Network) sendOnChannel(channel channels.Channel, msg interface{}, targetIDs []flow.Identifier) error { 722 n.logger.Debug(). 723 Interface("message", msg). 724 Str("channel", channel.String()). 725 Str("target_ids", fmt.Sprintf("%v", targetIDs)). 726 Msg("sending new message on channel") 727 728 // generate network message (encoding) based on list of recipients 729 scope, err := message.NewOutgoingScope( 730 targetIDs, 731 channels.TopicFromChannel(channel, n.sporkId), 732 msg, 733 n.codec.Encode, 734 message.ProtocolTypePubSub) 735 if err != nil { 736 return fmt.Errorf("failed to generate outgoing message scope %s: %w", channel, err) 737 } 738 739 // publish the message through the channel, however, the message 740 // is only restricted to targetIDs (if they subscribed to channel). 741 err = n.libP2PNode.Publish(n.ctx, scope) 742 if err != nil { 743 return fmt.Errorf("failed to send message on channel %s: %w", channel, err) 744 } 745 746 n.metrics.OutboundMessageSent(scope.Size(), channel.String(), message.ProtocolTypePubSub.String(), scope.PayloadType()) 747 748 return nil 749 } 750 751 // queueSubmitFunc submits the message to the engine synchronously. It is the callback for the queue worker 752 // when it gets a message from the queue 753 func (n *Network) queueSubmitFunc(message interface{}) { 754 qm := message.(queue.QMessage) 755 756 logger := n.logger.With(). 757 Str("channel_id", qm.Target.String()). 758 Str("sender_id", qm.SenderID.String()). 759 Logger() 760 761 eng, err := n.subscriptionManager.GetEngine(qm.Target) 762 if err != nil { 763 // This means the message was received on a channel that the node has not registered an 764 // engine for. This may be because the message was received during startup and the node 765 // hasn't subscribed to the channel yet, or there is a bug. 766 logger.Err(err).Msg("failed to submit message") 767 return 768 } 769 770 logger.Debug().Msg("submitting message to engine") 771 772 n.metrics.MessageProcessingStarted(qm.Target.String()) 773 774 // submits the message to the engine synchronously and 775 // tracks its processing time. 776 startTimestamp := time.Now() 777 778 err = eng.Process(qm.Target, qm.SenderID, qm.Payload) 779 if err != nil { 780 logger.Err(err).Msg("failed to process message") 781 } 782 783 n.metrics.MessageProcessingFinished(qm.Target.String(), time.Since(startTimestamp)) 784 } 785 786 func (n *Network) Topology() flow.IdentityList { 787 return n.topology.Fanout(n.Identities()) 788 } 789 790 // ReportMisbehaviorOnChannel reports the misbehavior of a node on sending a message to the current node that appears 791 // valid based on the networking layer but is considered invalid by the current node based on the Flow protocol. 792 // The misbehavior report is sent to the current node's networking layer on the given channel to be processed. 793 // Args: 794 // - channel: The channel on which the misbehavior report is sent. 795 // - report: The misbehavior report to be sent. 796 // Returns: 797 // none 798 func (n *Network) ReportMisbehaviorOnChannel(channel channels.Channel, report network.MisbehaviorReport) { 799 n.misbehaviorReportManager.HandleMisbehaviorReport(channel, report) 800 } 801 802 func DefaultValidators(log zerolog.Logger, flowID flow.Identifier) []network.MessageValidator { 803 return []network.MessageValidator{ 804 validator.ValidateNotSender(flowID), // validator to filter out messages sent by this node itself 805 validator.ValidateTarget(log, flowID), // validator to filter out messages not intended for this node 806 } 807 } 808 809 // isProtocolParticipant returns a PeerFilter that returns true if a peer is a staked (i.e., authorized) node. 810 func (n *Network) isProtocolParticipant() p2p.PeerFilter { 811 return func(p peer.ID) error { 812 if _, ok := n.Identity(p); !ok { 813 return fmt.Errorf("failed to get identity of unknown peer with peer id %s", p2plogging.PeerId(p)) 814 } 815 return nil 816 } 817 } 818 819 func (n *Network) peerIDs(flowIDs flow.IdentifierList) peer.IDSlice { 820 result := make([]peer.ID, 0, len(flowIDs)) 821 822 for _, fid := range flowIDs { 823 pid, err := n.identityTranslator.GetPeerID(fid) 824 if err != nil { 825 // We probably don't need to fail the entire function here, since the other 826 // translations may still succeed 827 n.logger. 828 Err(err). 829 Str(logging.KeySuspicious, "true"). 830 Hex("node_id", logging.ID(fid)). 831 Msg("failed to translate to peer ID") 832 continue 833 } 834 835 result = append(result, pid) 836 } 837 838 return result 839 } 840 841 func (n *Network) UpdateNodeAddresses() { 842 n.logger.Info().Msg("updating protocol state node addresses") 843 844 ids := n.Identities() 845 newInfos, invalid := utils.PeerInfosFromIDs(ids) 846 847 for id, err := range invalid { 848 n.logger. 849 Err(err). 850 Bool(logging.KeySuspicious, true). 851 Hex("node_id", logging.ID(id)). 852 Msg("failed to extract peer info from identity") 853 } 854 855 n.peerUpdateLock.Lock() 856 defer n.peerUpdateLock.Unlock() 857 858 // set old addresses to expire 859 for _, oldInfo := range n.previousProtocolStatePeers { 860 n.libP2PNode.Host().Peerstore().SetAddrs(oldInfo.ID, oldInfo.Addrs, peerstore.TempAddrTTL) 861 } 862 863 for _, info := range newInfos { 864 n.libP2PNode.Host().Peerstore().SetAddrs(info.ID, info.Addrs, peerstore.PermanentAddrTTL) 865 } 866 867 n.previousProtocolStatePeers = newInfos 868 } 869 870 // authorizedPeers is a peer manager callback used by the underlying libp2p node that updates who can connect to this node (as 871 // well as who this node can connect to). 872 // and who is not allowed to connect to this node. This function is called by the peer manager and connection gater components 873 // of libp2p. 874 // 875 // Args: 876 // none 877 // Returns: 878 // - peer.IDSlice: a list of peer IDs that are allowed to connect to this node (and that this node can connect to). Any peer 879 // not in this list is assumed to be disconnected from this node (if connected) and not allowed to connect to this node. 880 // This is the guarantee that the underlying libp2p node implementation makes. 881 func (n *Network) authorizedPeers() peer.IDSlice { 882 peerIDs := make([]peer.ID, 0) 883 for _, id := range n.peerIDs(n.Topology().NodeIDs()) { 884 peerAllowed := true 885 for _, filter := range n.peerManagerFilters { 886 if err := filter(id); err != nil { 887 n.logger.Debug(). 888 Err(err). 889 Str("peer_id", p2plogging.PeerId(id)). 890 Msg("filtering topology peer") 891 892 peerAllowed = false 893 break 894 } 895 } 896 897 if peerAllowed { 898 peerIDs = append(peerIDs, id) 899 } 900 } 901 902 return peerIDs 903 } 904 905 func (n *Network) OnDisallowListNotification(notification *network.DisallowListingUpdate) { 906 for _, pid := range n.peerIDs(notification.FlowIds) { 907 n.libP2PNode.OnDisallowListNotification(pid, notification.Cause) 908 } 909 } 910 911 func (n *Network) OnAllowListNotification(notification *network.AllowListingUpdate) { 912 for _, pid := range n.peerIDs(notification.FlowIds) { 913 n.libP2PNode.OnAllowListNotification(pid, notification.Cause) 914 } 915 } 916 917 // handleIncomingStream handles an incoming stream from a remote peer 918 // it is a callback that gets called for each incoming stream by libp2p with a new stream object. 919 // TODO: this should be eventually moved to libp2p node. 920 func (n *Network) handleIncomingStream(s libp2pnet.Stream) { 921 // qualify the logger with local and remote address 922 log := p2putils.StreamLogger(n.logger, s) 923 924 log.Info().Msg("incoming stream received") 925 926 success := false 927 928 remotePeer := s.Conn().RemotePeer() 929 930 defer func() { 931 if success { 932 err := s.Close() 933 if err != nil { 934 log.Err(err).Msg("failed to close stream") 935 } 936 } else { 937 err := s.Reset() 938 if err != nil { 939 log.Err(err).Msg("failed to reset stream") 940 } 941 } 942 }() 943 944 // check if peer is currently rate limited before continuing to process stream. 945 if n.unicastRateLimiters.MessageRateLimiter.IsRateLimited(remotePeer) || n.unicastRateLimiters.BandWidthRateLimiter.IsRateLimited(remotePeer) { 946 log.Debug(). 947 Bool(logging.KeySuspicious, true). 948 Msg("dropping unicast stream from rate limited peer") 949 return 950 } 951 952 // TODO: We need to allow per-topic timeouts and message size limits. 953 // This allows us to configure higher limits for topics on which we expect 954 // to receive large messages (e.g. Chunk Data Packs), and use the normal 955 // limits for other topics. In order to enable this, we will need to register 956 // a separate stream handler for each topic. 957 ctx, cancel := context.WithTimeout(n.ctx, LargeMsgUnicastTimeout) 958 defer cancel() 959 960 deadline, _ := ctx.Deadline() 961 962 err := s.SetReadDeadline(deadline) 963 if err != nil { 964 log.Err(err).Msg("failed to set read deadline for stream") 965 return 966 } 967 968 // create the reader 969 r := ggio.NewDelimitedReader(s, LargeMsgMaxUnicastMsgSize) 970 for { 971 if ctx.Err() != nil { 972 return 973 } 974 975 // Note: message fields must not be trusted until explicitly validated 976 var msg message.Message 977 // read the next message (blocking call) 978 err = r.ReadMsg(&msg) 979 if err != nil { 980 if err == io.EOF { 981 break 982 } 983 984 n.logger.Err(err).Msg("failed to read message") 985 return 986 } 987 988 channel := channels.Channel(msg.ChannelID) 989 topic := channels.TopicFromChannel(channel, n.sporkId) 990 991 // ignore messages if node does not have subscription to topic 992 if !n.libP2PNode.HasSubscription(topic) { 993 violation := &network.Violation{ 994 Identity: nil, PeerID: p2plogging.PeerId(remotePeer), Channel: channel, Protocol: message.ProtocolTypeUnicast, 995 } 996 997 msgCode, err := codec.MessageCodeFromPayload(msg.Payload) 998 if err != nil { 999 violation.Err = err 1000 n.slashingViolationsConsumer.OnUnknownMsgTypeError(violation) 1001 return 1002 } 1003 1004 // msg type is not guaranteed to be correct since it is set by the client 1005 _, what, err := codec.InterfaceFromMessageCode(msgCode) 1006 if err != nil { 1007 violation.Err = err 1008 n.slashingViolationsConsumer.OnUnknownMsgTypeError(violation) 1009 return 1010 } 1011 1012 violation.MsgType = what 1013 violation.Err = ErrUnicastMsgWithoutSub 1014 n.slashingViolationsConsumer.OnUnauthorizedUnicastOnChannel(violation) 1015 return 1016 } 1017 1018 // check if unicast messages have reached rate limit before processing next message 1019 if !n.unicastRateLimiters.MessageAllowed(remotePeer) { 1020 return 1021 } 1022 1023 // check if we can get a role for logging and metrics label if this is not a public channel 1024 role := "" 1025 if !channels.IsPublicChannel(channels.Channel(msg.ChannelID)) { 1026 if identity, ok := n.Identity(remotePeer); ok { 1027 role = identity.Role.String() 1028 } 1029 } 1030 1031 // check unicast bandwidth rate limiter for peer 1032 if !n.unicastRateLimiters.BandwidthAllowed( 1033 remotePeer, 1034 role, 1035 msg.Size(), 1036 message.MessageType(msg.Payload), 1037 channels.Topic(msg.ChannelID)) { 1038 return 1039 } 1040 1041 n.wg.Add(1) 1042 go func() { 1043 defer n.wg.Done() 1044 n.processUnicastStreamMessage(remotePeer, &msg) 1045 }() 1046 } 1047 1048 success = true 1049 } 1050 1051 // Subscribe subscribes the network to a channel. 1052 // No errors are expected during normal operation. 1053 func (n *Network) Subscribe(channel channels.Channel) error { 1054 topic := channels.TopicFromChannel(channel, n.sporkId) 1055 1056 var peerFilter p2p.PeerFilter 1057 var validators []validator.PubSubMessageValidator 1058 if channels.IsPublicChannel(channel) { 1059 // NOTE: for public channels the callback used to check if a node is staked will 1060 // return true for every node. 1061 peerFilter = p2p.AllowAllPeerFilter() 1062 } else { 1063 // for channels used by the staked nodes, add the topic validator to filter out messages from non-staked nodes 1064 validators = append(validators, n.authorizedSenderValidator.PubSubMessageValidator(channel)) 1065 1066 // NOTE: For non-public channels the libP2P node topic validator will reject 1067 // messages from unstaked nodes. 1068 peerFilter = n.isProtocolParticipant() 1069 } 1070 1071 topicValidator := flowpubsub.TopicValidator(n.logger, peerFilter, validators...) 1072 s, err := n.libP2PNode.Subscribe(topic, topicValidator) 1073 if err != nil { 1074 return fmt.Errorf("could not subscribe to topic (%s): %w", topic, err) 1075 } 1076 1077 // create a new readSubscription with the context of the network 1078 rs := internal.NewReadSubscription(s, n.processPubSubMessages, n.logger) 1079 n.wg.Add(1) 1080 1081 // kick off the receive loop to continuously receive messages 1082 go func() { 1083 defer n.wg.Done() 1084 rs.ReceiveLoop(n.ctx) 1085 }() 1086 1087 // update peers to add some nodes interested in the same topic as direct peers 1088 n.libP2PNode.RequestPeerUpdate() 1089 1090 return nil 1091 } 1092 1093 // processPubSubMessages processes messages received from the pubsub subscription. 1094 func (n *Network) processPubSubMessages(msg *message.Message, peerID peer.ID) { 1095 n.processAuthenticatedMessage(msg, peerID, message.ProtocolTypePubSub) 1096 } 1097 1098 // Unsubscribe unsubscribes the network from a channel. 1099 // The following benign errors are expected during normal operations from libP2P: 1100 // - the libP2P node fails to unsubscribe to the topic created from the provided channel. 1101 // 1102 // All errors returned from this function can be considered benign. 1103 func (n *Network) Unsubscribe(channel channels.Channel) error { 1104 topic := channels.TopicFromChannel(channel, n.sporkId) 1105 return n.libP2PNode.Unsubscribe(topic) 1106 } 1107 1108 // processUnicastStreamMessage will decode, perform authorized sender validation and process a message 1109 // sent via unicast stream. This func should be invoked in a separate goroutine to avoid creating a message decoding bottleneck. 1110 func (n *Network) processUnicastStreamMessage(remotePeer peer.ID, msg *message.Message) { 1111 channel := channels.Channel(msg.ChannelID) 1112 1113 // TODO: once we've implemented per topic message size limits per the TODO above, 1114 // we can remove this check 1115 maxSize, err := UnicastMaxMsgSizeByCode(msg.Payload) 1116 if err != nil { 1117 n.slashingViolationsConsumer.OnUnknownMsgTypeError(&network.Violation{ 1118 Identity: nil, PeerID: p2plogging.PeerId(remotePeer), MsgType: "", Channel: channel, Protocol: message.ProtocolTypeUnicast, Err: err, 1119 }) 1120 return 1121 } 1122 if msg.Size() > maxSize { 1123 // message size exceeded 1124 n.logger.Error(). 1125 Str("peer_id", p2plogging.PeerId(remotePeer)). 1126 Str("channel", msg.ChannelID). 1127 Int("max_size", maxSize). 1128 Int("size", msg.Size()). 1129 Bool(logging.KeySuspicious, true). 1130 Msg("received message exceeded permissible message maxSize") 1131 return 1132 } 1133 1134 // if message channel is not public perform authorized sender validation 1135 if !channels.IsPublicChannel(channel) { 1136 messageType, err := n.authorizedSenderValidator.Validate(remotePeer, msg.Payload, channel, message.ProtocolTypeUnicast) 1137 if err != nil { 1138 n.logger. 1139 Error(). 1140 Err(err). 1141 Str("peer_id", p2plogging.PeerId(remotePeer)). 1142 Str("type", messageType). 1143 Str("channel", msg.ChannelID). 1144 Msg("unicast authorized sender validation failed") 1145 return 1146 } 1147 } 1148 n.processAuthenticatedMessage(msg, remotePeer, message.ProtocolTypeUnicast) 1149 } 1150 1151 // processAuthenticatedMessage processes a message and a source (indicated by its peer ID) and eventually passes it to the overlay 1152 // In particular, it populates the `OriginID` field of the message with a Flow ID translated from this source. 1153 func (n *Network) processAuthenticatedMessage(msg *message.Message, peerID peer.ID, protocol message.ProtocolType) { 1154 originId, err := n.identityTranslator.GetFlowID(peerID) 1155 if err != nil { 1156 // this error should never happen. by the time the message gets here, the peer should be 1157 // authenticated which means it must be known 1158 n.logger.Error(). 1159 Err(err). 1160 Str("peer_id", p2plogging.PeerId(peerID)). 1161 Bool(logging.KeySuspicious, true). 1162 Msg("dropped message from unknown peer") 1163 return 1164 } 1165 1166 channel := channels.Channel(msg.ChannelID) 1167 decodedMsgPayload, err := n.codec.Decode(msg.Payload) 1168 switch { 1169 case codec.IsErrUnknownMsgCode(err): 1170 // slash peer if message contains unknown message code byte 1171 violation := &network.Violation{ 1172 PeerID: p2plogging.PeerId(peerID), OriginID: originId, Channel: channel, Protocol: protocol, Err: err, 1173 } 1174 n.slashingViolationsConsumer.OnUnknownMsgTypeError(violation) 1175 return 1176 case codec.IsErrMsgUnmarshal(err) || codec.IsErrInvalidEncoding(err): 1177 // slash if peer sent a message that could not be marshalled into the message type denoted by the message code byte 1178 violation := &network.Violation{ 1179 PeerID: p2plogging.PeerId(peerID), OriginID: originId, Channel: channel, Protocol: protocol, Err: err, 1180 } 1181 n.slashingViolationsConsumer.OnInvalidMsgError(violation) 1182 return 1183 case err != nil: 1184 // this condition should never happen and indicates there's a bug 1185 // don't crash as a result of external inputs since that creates a DoS vector 1186 // collect slashing data because this could potentially lead to slashing 1187 err = fmt.Errorf("unexpected error during message validation: %w", err) 1188 violation := &network.Violation{ 1189 PeerID: p2plogging.PeerId(peerID), OriginID: originId, Channel: channel, Protocol: protocol, Err: err, 1190 } 1191 n.slashingViolationsConsumer.OnUnexpectedError(violation) 1192 return 1193 } 1194 1195 scope, err := message.NewIncomingScope(originId, protocol, msg, decodedMsgPayload) 1196 if err != nil { 1197 n.logger.Error(). 1198 Err(err). 1199 Str("peer_id", p2plogging.PeerId(peerID)). 1200 Str("origin_id", originId.String()). 1201 Msg("could not create incoming message scope") 1202 return 1203 } 1204 1205 n.processMessage(scope) 1206 } 1207 1208 // processMessage processes a message and eventually passes it to the overlay 1209 func (n *Network) processMessage(scope network.IncomingMessageScope) { 1210 logger := n.logger.With(). 1211 Str("channel", scope.Channel().String()). 1212 Str("type", scope.Protocol().String()). 1213 Int("msg_size", scope.Size()). 1214 Hex("origin_id", logging.ID(scope.OriginId())). 1215 Logger() 1216 1217 // run through all the message validators 1218 for _, v := range n.validators { 1219 // if any one fails, stop message propagation 1220 if !v.Validate(scope) { 1221 logger.Debug().Msg("new message filtered by message validators") 1222 return 1223 } 1224 } 1225 1226 logger.Debug().Msg("processing new message") 1227 1228 // if validation passed, send the message to the overlay 1229 err := n.Receive(scope) 1230 if err != nil { 1231 n.logger.Error().Err(err).Msg("could not deliver payload") 1232 } 1233 } 1234 1235 // UnicastMaxMsgSizeByCode returns the max permissible size for a unicast message code 1236 func UnicastMaxMsgSizeByCode(payload []byte) (int, error) { 1237 msgCode, err := codec.MessageCodeFromPayload(payload) 1238 if err != nil { 1239 return 0, err 1240 } 1241 _, messageType, err := codec.InterfaceFromMessageCode(msgCode) 1242 if err != nil { 1243 return 0, err 1244 } 1245 1246 maxSize := unicastMaxMsgSize(messageType) 1247 return maxSize, nil 1248 } 1249 1250 // unicastMaxMsgSize returns the max permissible size for a unicast message 1251 func unicastMaxMsgSize(messageType string) int { 1252 switch messageType { 1253 case "*messages.ChunkDataResponse", "messages.ChunkDataResponse": 1254 return LargeMsgMaxUnicastMsgSize 1255 default: 1256 return DefaultMaxUnicastMsgSize 1257 } 1258 } 1259 1260 // unicastMaxMsgDuration returns the max duration to allow for a unicast send to complete 1261 func (n *Network) unicastMaxMsgDuration(messageType string) time.Duration { 1262 switch messageType { 1263 case "*messages.ChunkDataResponse", "messages.ChunkDataResponse": 1264 if LargeMsgUnicastTimeout > n.unicastMessageTimeout { 1265 return LargeMsgUnicastTimeout 1266 } 1267 return n.unicastMessageTimeout 1268 default: 1269 return n.unicastMessageTimeout 1270 } 1271 }