github.com/MetalBlockchain/metalgo@v1.11.9/snow/networking/sender/sender.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package sender 5 6 import ( 7 "context" 8 9 "github.com/prometheus/client_golang/prometheus" 10 "go.uber.org/zap" 11 12 "github.com/MetalBlockchain/metalgo/ids" 13 "github.com/MetalBlockchain/metalgo/message" 14 "github.com/MetalBlockchain/metalgo/proto/pb/p2p" 15 "github.com/MetalBlockchain/metalgo/snow" 16 "github.com/MetalBlockchain/metalgo/snow/engine/common" 17 "github.com/MetalBlockchain/metalgo/snow/networking/router" 18 "github.com/MetalBlockchain/metalgo/snow/networking/timeout" 19 "github.com/MetalBlockchain/metalgo/subnets" 20 "github.com/MetalBlockchain/metalgo/utils/logging" 21 "github.com/MetalBlockchain/metalgo/utils/set" 22 ) 23 24 const opLabel = "op" 25 26 var ( 27 _ common.Sender = (*sender)(nil) 28 29 opLabels = []string{opLabel} 30 ) 31 32 // sender is a wrapper around an ExternalSender. 33 // Messages to this node are put directly into [router] rather than 34 // being sent over the network via the wrapped ExternalSender. 35 // sender registers outbound requests with [router] so that [router] 36 // fires a timeout if we don't get a response to the request. 37 type sender struct { 38 ctx *snow.ConsensusContext 39 msgCreator message.OutboundMsgBuilder 40 41 sender ExternalSender // Actually does the sending over the network 42 router router.Router 43 timeouts timeout.Manager 44 45 // Counts how many request have failed because the node was benched 46 failedDueToBench *prometheus.CounterVec // op 47 48 engineType p2p.EngineType 49 subnet subnets.Subnet 50 } 51 52 func New( 53 ctx *snow.ConsensusContext, 54 msgCreator message.OutboundMsgBuilder, 55 externalSender ExternalSender, 56 router router.Router, 57 timeouts timeout.Manager, 58 engineType p2p.EngineType, 59 subnet subnets.Subnet, 60 reg prometheus.Registerer, 61 ) (common.Sender, error) { 62 s := &sender{ 63 ctx: ctx, 64 msgCreator: msgCreator, 65 sender: externalSender, 66 router: router, 67 timeouts: timeouts, 68 failedDueToBench: prometheus.NewCounterVec( 69 prometheus.CounterOpts{ 70 Name: "failed_benched", 71 Help: "requests dropped because a node was benched", 72 }, 73 opLabels, 74 ), 75 engineType: engineType, 76 subnet: subnet, 77 } 78 return s, reg.Register(s.failedDueToBench) 79 } 80 81 func (s *sender) SendGetStateSummaryFrontier(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32) { 82 ctx = context.WithoutCancel(ctx) 83 84 // Note that this timeout duration won't exactly match the one that gets 85 // registered. That's OK. 86 deadline := s.timeouts.TimeoutDuration() 87 88 // Tell the router to expect a response message or a message notifying 89 // that we won't get a response from each of these nodes. 90 // We register timeouts for all nodes, regardless of whether we fail 91 // to send them a message, to avoid busy looping when disconnected from 92 // the internet. 93 for nodeID := range nodeIDs { 94 inMsg := message.InternalGetStateSummaryFrontierFailed( 95 nodeID, 96 s.ctx.ChainID, 97 requestID, 98 ) 99 s.router.RegisterRequest( 100 ctx, 101 nodeID, 102 s.ctx.ChainID, 103 s.ctx.ChainID, 104 requestID, 105 message.StateSummaryFrontierOp, 106 inMsg, 107 p2p.EngineType_ENGINE_TYPE_UNSPECIFIED, 108 ) 109 } 110 111 // Sending a message to myself. No need to send it over the network. 112 // Just put it right into the router. Asynchronously to avoid deadlock. 113 if nodeIDs.Contains(s.ctx.NodeID) { 114 nodeIDs.Remove(s.ctx.NodeID) 115 inMsg := message.InboundGetStateSummaryFrontier( 116 s.ctx.ChainID, 117 requestID, 118 deadline, 119 s.ctx.NodeID, 120 ) 121 go s.router.HandleInbound(ctx, inMsg) 122 } 123 124 // Create the outbound message. 125 outMsg, err := s.msgCreator.GetStateSummaryFrontier( 126 s.ctx.ChainID, 127 requestID, 128 deadline, 129 ) 130 131 // Send the message over the network. 132 var sentTo set.Set[ids.NodeID] 133 if err == nil { 134 sentTo = s.sender.Send( 135 outMsg, 136 common.SendConfig{ 137 NodeIDs: nodeIDs, 138 }, 139 s.ctx.SubnetID, 140 s.subnet, 141 ) 142 } else { 143 s.ctx.Log.Error("failed to build message", 144 zap.Stringer("messageOp", message.GetStateSummaryFrontierOp), 145 zap.Stringer("chainID", s.ctx.ChainID), 146 zap.Uint32("requestID", requestID), 147 zap.Duration("deadline", deadline), 148 zap.Error(err), 149 ) 150 } 151 152 for nodeID := range nodeIDs { 153 if !sentTo.Contains(nodeID) { 154 s.ctx.Log.Debug("failed to send message", 155 zap.Stringer("messageOp", message.GetStateSummaryFrontierOp), 156 zap.Stringer("nodeID", nodeID), 157 zap.Stringer("chainID", s.ctx.ChainID), 158 zap.Uint32("requestID", requestID), 159 ) 160 } 161 } 162 } 163 164 func (s *sender) SendStateSummaryFrontier(ctx context.Context, nodeID ids.NodeID, requestID uint32, summary []byte) { 165 ctx = context.WithoutCancel(ctx) 166 167 // Sending this message to myself. 168 if nodeID == s.ctx.NodeID { 169 inMsg := message.InboundStateSummaryFrontier( 170 s.ctx.ChainID, 171 requestID, 172 summary, 173 nodeID, 174 ) 175 go s.router.HandleInbound(ctx, inMsg) 176 return 177 } 178 179 // Create the outbound message. 180 outMsg, err := s.msgCreator.StateSummaryFrontier( 181 s.ctx.ChainID, 182 requestID, 183 summary, 184 ) 185 if err != nil { 186 s.ctx.Log.Error("failed to build message", 187 zap.Stringer("messageOp", message.StateSummaryFrontierOp), 188 zap.Stringer("chainID", s.ctx.ChainID), 189 zap.Uint32("requestID", requestID), 190 zap.Binary("summaryBytes", summary), 191 zap.Error(err), 192 ) 193 return 194 } 195 196 // Send the message over the network. 197 nodeIDs := set.Of(nodeID) 198 sentTo := s.sender.Send( 199 outMsg, 200 common.SendConfig{ 201 NodeIDs: nodeIDs, 202 }, 203 s.ctx.SubnetID, 204 s.subnet, 205 ) 206 if sentTo.Len() == 0 { 207 if s.ctx.Log.Enabled(logging.Verbo) { 208 s.ctx.Log.Verbo("failed to send message", 209 zap.Stringer("messageOp", message.StateSummaryFrontierOp), 210 zap.Stringer("nodeID", nodeID), 211 zap.Stringer("chainID", s.ctx.ChainID), 212 zap.Uint32("requestID", requestID), 213 zap.Binary("summary", summary), 214 ) 215 } else { 216 s.ctx.Log.Debug("failed to send message", 217 zap.Stringer("messageOp", message.StateSummaryFrontierOp), 218 zap.Stringer("nodeID", nodeID), 219 zap.Stringer("chainID", s.ctx.ChainID), 220 zap.Uint32("requestID", requestID), 221 ) 222 } 223 } 224 } 225 226 func (s *sender) SendGetAcceptedStateSummary(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, heights []uint64) { 227 ctx = context.WithoutCancel(ctx) 228 229 // Note that this timeout duration won't exactly match the one that gets 230 // registered. That's OK. 231 deadline := s.timeouts.TimeoutDuration() 232 233 // Tell the router to expect a response message or a message notifying 234 // that we won't get a response from each of these nodes. 235 // We register timeouts for all nodes, regardless of whether we fail 236 // to send them a message, to avoid busy looping when disconnected from 237 // the internet. 238 for nodeID := range nodeIDs { 239 inMsg := message.InternalGetAcceptedStateSummaryFailed( 240 nodeID, 241 s.ctx.ChainID, 242 requestID, 243 ) 244 s.router.RegisterRequest( 245 ctx, 246 nodeID, 247 s.ctx.ChainID, 248 s.ctx.ChainID, 249 requestID, 250 message.AcceptedStateSummaryOp, 251 inMsg, 252 p2p.EngineType_ENGINE_TYPE_UNSPECIFIED, 253 ) 254 } 255 256 // Sending a message to myself. No need to send it over the network. 257 // Just put it right into the router. Asynchronously to avoid deadlock. 258 if nodeIDs.Contains(s.ctx.NodeID) { 259 nodeIDs.Remove(s.ctx.NodeID) 260 inMsg := message.InboundGetAcceptedStateSummary( 261 s.ctx.ChainID, 262 requestID, 263 heights, 264 deadline, 265 s.ctx.NodeID, 266 ) 267 go s.router.HandleInbound(ctx, inMsg) 268 } 269 270 // Create the outbound message. 271 outMsg, err := s.msgCreator.GetAcceptedStateSummary( 272 s.ctx.ChainID, 273 requestID, 274 deadline, 275 heights, 276 ) 277 278 // Send the message over the network. 279 var sentTo set.Set[ids.NodeID] 280 if err == nil { 281 sentTo = s.sender.Send( 282 outMsg, 283 common.SendConfig{ 284 NodeIDs: nodeIDs, 285 }, 286 s.ctx.SubnetID, 287 s.subnet, 288 ) 289 } else { 290 s.ctx.Log.Error("failed to build message", 291 zap.Stringer("messageOp", message.GetAcceptedStateSummaryOp), 292 zap.Stringer("chainID", s.ctx.ChainID), 293 zap.Uint32("requestID", requestID), 294 zap.Uint64s("heights", heights), 295 zap.Error(err), 296 ) 297 } 298 299 for nodeID := range nodeIDs { 300 if !sentTo.Contains(nodeID) { 301 s.ctx.Log.Debug("failed to send message", 302 zap.Stringer("messageOp", message.GetAcceptedStateSummaryOp), 303 zap.Stringer("nodeID", nodeID), 304 zap.Stringer("chainID", s.ctx.ChainID), 305 zap.Uint32("requestID", requestID), 306 zap.Uint64s("heights", heights), 307 ) 308 } 309 } 310 } 311 312 func (s *sender) SendAcceptedStateSummary(ctx context.Context, nodeID ids.NodeID, requestID uint32, summaryIDs []ids.ID) { 313 ctx = context.WithoutCancel(ctx) 314 315 if nodeID == s.ctx.NodeID { 316 inMsg := message.InboundAcceptedStateSummary( 317 s.ctx.ChainID, 318 requestID, 319 summaryIDs, 320 nodeID, 321 ) 322 go s.router.HandleInbound(ctx, inMsg) 323 return 324 } 325 326 // Create the outbound message. 327 outMsg, err := s.msgCreator.AcceptedStateSummary( 328 s.ctx.ChainID, 329 requestID, 330 summaryIDs, 331 ) 332 if err != nil { 333 s.ctx.Log.Error("failed to build message", 334 zap.Stringer("messageOp", message.AcceptedStateSummaryOp), 335 zap.Stringer("chainID", s.ctx.ChainID), 336 zap.Uint32("requestID", requestID), 337 zap.Stringers("summaryIDs", summaryIDs), 338 zap.Error(err), 339 ) 340 return 341 } 342 343 // Send the message over the network. 344 nodeIDs := set.Of(nodeID) 345 sentTo := s.sender.Send( 346 outMsg, 347 common.SendConfig{ 348 NodeIDs: nodeIDs, 349 }, 350 s.ctx.SubnetID, 351 s.subnet, 352 ) 353 if sentTo.Len() == 0 { 354 s.ctx.Log.Debug("failed to send message", 355 zap.Stringer("messageOp", message.AcceptedStateSummaryOp), 356 zap.Stringer("nodeID", nodeID), 357 zap.Stringer("chainID", s.ctx.ChainID), 358 zap.Uint32("requestID", requestID), 359 zap.Stringers("summaryIDs", summaryIDs), 360 ) 361 } 362 } 363 364 func (s *sender) SendGetAcceptedFrontier(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32) { 365 ctx = context.WithoutCancel(ctx) 366 367 // Note that this timeout duration won't exactly match the one that gets 368 // registered. That's OK. 369 deadline := s.timeouts.TimeoutDuration() 370 371 // Tell the router to expect a response message or a message notifying 372 // that we won't get a response from each of these nodes. 373 // We register timeouts for all nodes, regardless of whether we fail 374 // to send them a message, to avoid busy looping when disconnected from 375 // the internet. 376 for nodeID := range nodeIDs { 377 inMsg := message.InternalGetAcceptedFrontierFailed( 378 nodeID, 379 s.ctx.ChainID, 380 requestID, 381 ) 382 s.router.RegisterRequest( 383 ctx, 384 nodeID, 385 s.ctx.ChainID, 386 s.ctx.ChainID, 387 requestID, 388 message.AcceptedFrontierOp, 389 inMsg, 390 p2p.EngineType_ENGINE_TYPE_UNSPECIFIED, 391 ) 392 } 393 394 // Sending a message to myself. No need to send it over the network. 395 // Just put it right into the router. Asynchronously to avoid deadlock. 396 if nodeIDs.Contains(s.ctx.NodeID) { 397 nodeIDs.Remove(s.ctx.NodeID) 398 inMsg := message.InboundGetAcceptedFrontier( 399 s.ctx.ChainID, 400 requestID, 401 deadline, 402 s.ctx.NodeID, 403 ) 404 go s.router.HandleInbound(ctx, inMsg) 405 } 406 407 // Create the outbound message. 408 outMsg, err := s.msgCreator.GetAcceptedFrontier( 409 s.ctx.ChainID, 410 requestID, 411 deadline, 412 ) 413 414 // Send the message over the network. 415 var sentTo set.Set[ids.NodeID] 416 if err == nil { 417 sentTo = s.sender.Send( 418 outMsg, 419 common.SendConfig{ 420 NodeIDs: nodeIDs, 421 }, 422 s.ctx.SubnetID, 423 s.subnet, 424 ) 425 } else { 426 s.ctx.Log.Error("failed to build message", 427 zap.Stringer("messageOp", message.GetAcceptedFrontierOp), 428 zap.Stringer("chainID", s.ctx.ChainID), 429 zap.Uint32("requestID", requestID), 430 zap.Duration("deadline", deadline), 431 zap.Error(err), 432 ) 433 } 434 435 for nodeID := range nodeIDs { 436 if !sentTo.Contains(nodeID) { 437 s.ctx.Log.Debug("failed to send message", 438 zap.Stringer("messageOp", message.GetAcceptedFrontierOp), 439 zap.Stringer("nodeID", nodeID), 440 zap.Stringer("chainID", s.ctx.ChainID), 441 zap.Uint32("requestID", requestID), 442 ) 443 } 444 } 445 } 446 447 func (s *sender) SendAcceptedFrontier(ctx context.Context, nodeID ids.NodeID, requestID uint32, containerID ids.ID) { 448 ctx = context.WithoutCancel(ctx) 449 450 // Sending this message to myself. 451 if nodeID == s.ctx.NodeID { 452 inMsg := message.InboundAcceptedFrontier( 453 s.ctx.ChainID, 454 requestID, 455 containerID, 456 nodeID, 457 ) 458 go s.router.HandleInbound(ctx, inMsg) 459 return 460 } 461 462 // Create the outbound message. 463 outMsg, err := s.msgCreator.AcceptedFrontier( 464 s.ctx.ChainID, 465 requestID, 466 containerID, 467 ) 468 if err != nil { 469 s.ctx.Log.Error("failed to build message", 470 zap.Stringer("messageOp", message.AcceptedFrontierOp), 471 zap.Stringer("chainID", s.ctx.ChainID), 472 zap.Uint32("requestID", requestID), 473 zap.Stringer("containerID", containerID), 474 zap.Error(err), 475 ) 476 return 477 } 478 479 // Send the message over the network. 480 nodeIDs := set.Of(nodeID) 481 sentTo := s.sender.Send( 482 outMsg, 483 common.SendConfig{ 484 NodeIDs: nodeIDs, 485 }, 486 s.ctx.SubnetID, 487 s.subnet, 488 ) 489 if sentTo.Len() == 0 { 490 s.ctx.Log.Debug("failed to send message", 491 zap.Stringer("messageOp", message.AcceptedFrontierOp), 492 zap.Stringer("nodeID", nodeID), 493 zap.Stringer("chainID", s.ctx.ChainID), 494 zap.Uint32("requestID", requestID), 495 zap.Stringer("containerID", containerID), 496 ) 497 } 498 } 499 500 func (s *sender) SendGetAccepted(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, containerIDs []ids.ID) { 501 ctx = context.WithoutCancel(ctx) 502 503 // Note that this timeout duration won't exactly match the one that gets 504 // registered. That's OK. 505 deadline := s.timeouts.TimeoutDuration() 506 507 // Tell the router to expect a response message or a message notifying 508 // that we won't get a response from each of these nodes. 509 // We register timeouts for all nodes, regardless of whether we fail 510 // to send them a message, to avoid busy looping when disconnected from 511 // the internet. 512 for nodeID := range nodeIDs { 513 inMsg := message.InternalGetAcceptedFailed( 514 nodeID, 515 s.ctx.ChainID, 516 requestID, 517 ) 518 s.router.RegisterRequest( 519 ctx, 520 nodeID, 521 s.ctx.ChainID, 522 s.ctx.ChainID, 523 requestID, 524 message.AcceptedOp, 525 inMsg, 526 p2p.EngineType_ENGINE_TYPE_UNSPECIFIED, 527 ) 528 } 529 530 // Sending a message to myself. No need to send it over the network. 531 // Just put it right into the router. Asynchronously to avoid deadlock. 532 if nodeIDs.Contains(s.ctx.NodeID) { 533 nodeIDs.Remove(s.ctx.NodeID) 534 inMsg := message.InboundGetAccepted( 535 s.ctx.ChainID, 536 requestID, 537 deadline, 538 containerIDs, 539 s.ctx.NodeID, 540 ) 541 go s.router.HandleInbound(ctx, inMsg) 542 } 543 544 // Create the outbound message. 545 outMsg, err := s.msgCreator.GetAccepted( 546 s.ctx.ChainID, 547 requestID, 548 deadline, 549 containerIDs, 550 ) 551 552 // Send the message over the network. 553 var sentTo set.Set[ids.NodeID] 554 if err == nil { 555 sentTo = s.sender.Send( 556 outMsg, 557 common.SendConfig{ 558 NodeIDs: nodeIDs, 559 }, 560 s.ctx.SubnetID, 561 s.subnet, 562 ) 563 } else { 564 s.ctx.Log.Error("failed to build message", 565 zap.Stringer("messageOp", message.GetAcceptedOp), 566 zap.Stringer("chainID", s.ctx.ChainID), 567 zap.Uint32("requestID", requestID), 568 zap.Stringers("containerIDs", containerIDs), 569 zap.Error(err), 570 ) 571 } 572 573 for nodeID := range nodeIDs { 574 if !sentTo.Contains(nodeID) { 575 s.ctx.Log.Debug("failed to send message", 576 zap.Stringer("messageOp", message.GetAcceptedOp), 577 zap.Stringer("nodeID", nodeID), 578 zap.Stringer("chainID", s.ctx.ChainID), 579 zap.Uint32("requestID", requestID), 580 zap.Stringers("containerIDs", containerIDs), 581 ) 582 } 583 } 584 } 585 586 func (s *sender) SendAccepted(ctx context.Context, nodeID ids.NodeID, requestID uint32, containerIDs []ids.ID) { 587 ctx = context.WithoutCancel(ctx) 588 589 if nodeID == s.ctx.NodeID { 590 inMsg := message.InboundAccepted( 591 s.ctx.ChainID, 592 requestID, 593 containerIDs, 594 nodeID, 595 ) 596 go s.router.HandleInbound(ctx, inMsg) 597 return 598 } 599 600 // Create the outbound message. 601 outMsg, err := s.msgCreator.Accepted(s.ctx.ChainID, requestID, containerIDs) 602 if err != nil { 603 s.ctx.Log.Error("failed to build message", 604 zap.Stringer("messageOp", message.AcceptedOp), 605 zap.Stringer("chainID", s.ctx.ChainID), 606 zap.Uint32("requestID", requestID), 607 zap.Stringers("containerIDs", containerIDs), 608 zap.Error(err), 609 ) 610 return 611 } 612 613 // Send the message over the network. 614 nodeIDs := set.Of(nodeID) 615 sentTo := s.sender.Send( 616 outMsg, 617 common.SendConfig{ 618 NodeIDs: nodeIDs, 619 }, 620 s.ctx.SubnetID, 621 s.subnet, 622 ) 623 if sentTo.Len() == 0 { 624 s.ctx.Log.Debug("failed to send message", 625 zap.Stringer("messageOp", message.AcceptedOp), 626 zap.Stringer("nodeID", nodeID), 627 zap.Stringer("chainID", s.ctx.ChainID), 628 zap.Uint32("requestID", requestID), 629 zap.Stringers("containerIDs", containerIDs), 630 ) 631 } 632 } 633 634 func (s *sender) SendGetAncestors(ctx context.Context, nodeID ids.NodeID, requestID uint32, containerID ids.ID) { 635 ctx = context.WithoutCancel(ctx) 636 637 // Tell the router to expect a response message or a message notifying 638 // that we won't get a response from this node. 639 inMsg := message.InternalGetAncestorsFailed( 640 nodeID, 641 s.ctx.ChainID, 642 requestID, 643 s.engineType, 644 ) 645 s.router.RegisterRequest( 646 ctx, 647 nodeID, 648 s.ctx.ChainID, 649 s.ctx.ChainID, 650 requestID, 651 message.AncestorsOp, 652 inMsg, 653 s.engineType, 654 ) 655 656 // Sending a GetAncestors to myself will fail. To avoid constantly sending 657 // myself requests when not connected to any peers, we rely on the timeout 658 // firing to deliver the GetAncestorsFailed message. 659 if nodeID == s.ctx.NodeID { 660 return 661 } 662 663 // [nodeID] may be benched. That is, they've been unresponsive so we don't 664 // even bother sending requests to them. We just have them immediately fail. 665 if s.timeouts.IsBenched(nodeID, s.ctx.ChainID) { 666 s.failedDueToBench.With(prometheus.Labels{ 667 opLabel: message.GetAncestorsOp.String(), 668 }).Inc() 669 s.timeouts.RegisterRequestToUnreachableValidator() 670 go s.router.HandleInbound(ctx, inMsg) 671 return 672 } 673 674 // Note that this timeout duration won't exactly match the one that gets 675 // registered. That's OK. 676 deadline := s.timeouts.TimeoutDuration() 677 // Create the outbound message. 678 outMsg, err := s.msgCreator.GetAncestors( 679 s.ctx.ChainID, 680 requestID, 681 deadline, 682 containerID, 683 s.engineType, 684 ) 685 if err != nil { 686 s.ctx.Log.Error("failed to build message", 687 zap.Stringer("messageOp", message.GetAncestorsOp), 688 zap.Stringer("chainID", s.ctx.ChainID), 689 zap.Uint32("requestID", requestID), 690 zap.Stringer("containerID", containerID), 691 zap.Error(err), 692 ) 693 694 go s.router.HandleInbound(ctx, inMsg) 695 return 696 } 697 698 // Send the message over the network. 699 nodeIDs := set.Of(nodeID) 700 sentTo := s.sender.Send( 701 outMsg, 702 common.SendConfig{ 703 NodeIDs: nodeIDs, 704 }, 705 s.ctx.SubnetID, 706 s.subnet, 707 ) 708 if sentTo.Len() == 0 { 709 s.ctx.Log.Debug("failed to send message", 710 zap.Stringer("messageOp", message.GetAncestorsOp), 711 zap.Stringer("nodeID", nodeID), 712 zap.Stringer("chainID", s.ctx.ChainID), 713 zap.Uint32("requestID", requestID), 714 zap.Stringer("containerID", containerID), 715 ) 716 717 s.timeouts.RegisterRequestToUnreachableValidator() 718 go s.router.HandleInbound(ctx, inMsg) 719 } 720 } 721 722 func (s *sender) SendAncestors(_ context.Context, nodeID ids.NodeID, requestID uint32, containers [][]byte) { 723 // Create the outbound message. 724 outMsg, err := s.msgCreator.Ancestors(s.ctx.ChainID, requestID, containers) 725 if err != nil { 726 s.ctx.Log.Error("failed to build message", 727 zap.Stringer("messageOp", message.AncestorsOp), 728 zap.Stringer("chainID", s.ctx.ChainID), 729 zap.Uint32("requestID", requestID), 730 zap.Int("numContainers", len(containers)), 731 zap.Error(err), 732 ) 733 return 734 } 735 736 // Send the message over the network. 737 nodeIDs := set.Of(nodeID) 738 sentTo := s.sender.Send( 739 outMsg, 740 common.SendConfig{ 741 NodeIDs: nodeIDs, 742 }, 743 s.ctx.SubnetID, 744 s.subnet, 745 ) 746 if sentTo.Len() == 0 { 747 s.ctx.Log.Debug("failed to send message", 748 zap.Stringer("messageOp", message.AncestorsOp), 749 zap.Stringer("nodeID", nodeID), 750 zap.Stringer("chainID", s.ctx.ChainID), 751 zap.Uint32("requestID", requestID), 752 zap.Int("numContainers", len(containers)), 753 ) 754 } 755 } 756 757 func (s *sender) SendGet(ctx context.Context, nodeID ids.NodeID, requestID uint32, containerID ids.ID) { 758 ctx = context.WithoutCancel(ctx) 759 760 // Tell the router to expect a response message or a message notifying 761 // that we won't get a response from this node. 762 inMsg := message.InternalGetFailed( 763 nodeID, 764 s.ctx.ChainID, 765 requestID, 766 ) 767 s.router.RegisterRequest( 768 ctx, 769 nodeID, 770 s.ctx.ChainID, 771 s.ctx.ChainID, 772 requestID, 773 message.PutOp, 774 inMsg, 775 p2p.EngineType_ENGINE_TYPE_UNSPECIFIED, 776 ) 777 778 // Sending a Get to myself always fails. 779 if nodeID == s.ctx.NodeID { 780 go s.router.HandleInbound(ctx, inMsg) 781 return 782 } 783 784 // [nodeID] may be benched. That is, they've been unresponsive so we don't 785 // even bother sending requests to them. We just have them immediately fail. 786 if s.timeouts.IsBenched(nodeID, s.ctx.ChainID) { 787 s.failedDueToBench.With(prometheus.Labels{ 788 opLabel: message.GetOp.String(), 789 }).Inc() 790 s.timeouts.RegisterRequestToUnreachableValidator() 791 go s.router.HandleInbound(ctx, inMsg) 792 return 793 } 794 795 // Note that this timeout duration won't exactly match the one that gets 796 // registered. That's OK. 797 deadline := s.timeouts.TimeoutDuration() 798 // Create the outbound message. 799 outMsg, err := s.msgCreator.Get( 800 s.ctx.ChainID, 801 requestID, 802 deadline, 803 containerID, 804 ) 805 806 // Send the message over the network. 807 var sentTo set.Set[ids.NodeID] 808 if err == nil { 809 nodeIDs := set.Of(nodeID) 810 sentTo = s.sender.Send( 811 outMsg, 812 common.SendConfig{ 813 NodeIDs: nodeIDs, 814 }, 815 s.ctx.SubnetID, 816 s.subnet, 817 ) 818 } else { 819 s.ctx.Log.Error("failed to build message", 820 zap.Stringer("messageOp", message.GetOp), 821 zap.Stringer("chainID", s.ctx.ChainID), 822 zap.Uint32("requestID", requestID), 823 zap.Duration("deadline", deadline), 824 zap.Stringer("containerID", containerID), 825 zap.Error(err), 826 ) 827 } 828 829 if sentTo.Len() == 0 { 830 s.ctx.Log.Debug("failed to send message", 831 zap.Stringer("messageOp", message.GetOp), 832 zap.Stringer("nodeID", nodeID), 833 zap.Stringer("chainID", s.ctx.ChainID), 834 zap.Uint32("requestID", requestID), 835 zap.Stringer("containerID", containerID), 836 ) 837 838 s.timeouts.RegisterRequestToUnreachableValidator() 839 go s.router.HandleInbound(ctx, inMsg) 840 } 841 } 842 843 func (s *sender) SendPut(_ context.Context, nodeID ids.NodeID, requestID uint32, container []byte) { 844 // Create the outbound message. 845 outMsg, err := s.msgCreator.Put(s.ctx.ChainID, requestID, container) 846 if err != nil { 847 s.ctx.Log.Error("failed to build message", 848 zap.Stringer("messageOp", message.PutOp), 849 zap.Stringer("chainID", s.ctx.ChainID), 850 zap.Uint32("requestID", requestID), 851 zap.Binary("container", container), 852 zap.Error(err), 853 ) 854 return 855 } 856 857 // Send the message over the network. 858 nodeIDs := set.Of(nodeID) 859 sentTo := s.sender.Send( 860 outMsg, 861 common.SendConfig{ 862 NodeIDs: nodeIDs, 863 }, 864 s.ctx.SubnetID, 865 s.subnet, 866 ) 867 if sentTo.Len() == 0 { 868 if s.ctx.Log.Enabled(logging.Verbo) { 869 s.ctx.Log.Verbo("failed to send message", 870 zap.Stringer("messageOp", message.PutOp), 871 zap.Stringer("nodeID", nodeID), 872 zap.Stringer("chainID", s.ctx.ChainID), 873 zap.Uint32("requestID", requestID), 874 zap.Binary("container", container), 875 ) 876 } else { 877 s.ctx.Log.Debug("failed to send message", 878 zap.Stringer("messageOp", message.PutOp), 879 zap.Stringer("nodeID", nodeID), 880 zap.Stringer("chainID", s.ctx.ChainID), 881 zap.Uint32("requestID", requestID), 882 ) 883 } 884 } 885 } 886 887 func (s *sender) SendPushQuery( 888 ctx context.Context, 889 nodeIDs set.Set[ids.NodeID], 890 requestID uint32, 891 container []byte, 892 requestedHeight uint64, 893 ) { 894 ctx = context.WithoutCancel(ctx) 895 896 // Tell the router to expect a response message or a message notifying 897 // that we won't get a response from each of these nodes. 898 // We register timeouts for all nodes, regardless of whether we fail 899 // to send them a message, to avoid busy looping when disconnected from 900 // the internet. 901 for nodeID := range nodeIDs { 902 inMsg := message.InternalQueryFailed( 903 nodeID, 904 s.ctx.ChainID, 905 requestID, 906 ) 907 s.router.RegisterRequest( 908 ctx, 909 nodeID, 910 s.ctx.ChainID, 911 s.ctx.ChainID, 912 requestID, 913 message.ChitsOp, 914 inMsg, 915 p2p.EngineType_ENGINE_TYPE_UNSPECIFIED, 916 ) 917 } 918 919 // Note that this timeout duration won't exactly match the one that gets 920 // registered. That's OK. 921 deadline := s.timeouts.TimeoutDuration() 922 923 // Sending a message to myself. No need to send it over the network. Just 924 // put it right into the router. Do so asynchronously to avoid deadlock. 925 if nodeIDs.Contains(s.ctx.NodeID) { 926 nodeIDs.Remove(s.ctx.NodeID) 927 inMsg := message.InboundPushQuery( 928 s.ctx.ChainID, 929 requestID, 930 deadline, 931 container, 932 requestedHeight, 933 s.ctx.NodeID, 934 ) 935 go s.router.HandleInbound(ctx, inMsg) 936 } 937 938 // Some of [nodeIDs] may be benched. That is, they've been unresponsive so 939 // we don't even bother sending messages to them. We just have them 940 // immediately fail. 941 for nodeID := range nodeIDs { 942 if s.timeouts.IsBenched(nodeID, s.ctx.ChainID) { 943 s.failedDueToBench.With(prometheus.Labels{ 944 opLabel: message.PushQueryOp.String(), 945 }).Inc() 946 nodeIDs.Remove(nodeID) 947 s.timeouts.RegisterRequestToUnreachableValidator() 948 949 // Immediately register a failure. Do so asynchronously to avoid 950 // deadlock. 951 inMsg := message.InternalQueryFailed( 952 nodeID, 953 s.ctx.ChainID, 954 requestID, 955 ) 956 go s.router.HandleInbound(ctx, inMsg) 957 } 958 } 959 960 // Create the outbound message. 961 outMsg, err := s.msgCreator.PushQuery( 962 s.ctx.ChainID, 963 requestID, 964 deadline, 965 container, 966 requestedHeight, 967 ) 968 969 // Send the message over the network. 970 // [sentTo] are the IDs of validators who may receive the message. 971 var sentTo set.Set[ids.NodeID] 972 if err == nil { 973 sentTo = s.sender.Send( 974 outMsg, 975 common.SendConfig{ 976 NodeIDs: nodeIDs, 977 }, 978 s.ctx.SubnetID, 979 s.subnet, 980 ) 981 } else { 982 s.ctx.Log.Error("failed to build message", 983 zap.Stringer("messageOp", message.PushQueryOp), 984 zap.Stringer("chainID", s.ctx.ChainID), 985 zap.Uint32("requestID", requestID), 986 zap.Binary("container", container), 987 zap.Uint64("requestedHeight", requestedHeight), 988 zap.Error(err), 989 ) 990 } 991 992 for nodeID := range nodeIDs { 993 if !sentTo.Contains(nodeID) { 994 if s.ctx.Log.Enabled(logging.Verbo) { 995 s.ctx.Log.Verbo("failed to send message", 996 zap.Stringer("messageOp", message.PushQueryOp), 997 zap.Stringer("nodeID", nodeID), 998 zap.Stringer("chainID", s.ctx.ChainID), 999 zap.Uint32("requestID", requestID), 1000 zap.Binary("container", container), 1001 zap.Uint64("requestedHeight", requestedHeight), 1002 ) 1003 } else { 1004 s.ctx.Log.Debug("failed to send message", 1005 zap.Stringer("messageOp", message.PushQueryOp), 1006 zap.Stringer("nodeID", nodeID), 1007 zap.Stringer("chainID", s.ctx.ChainID), 1008 zap.Uint32("requestID", requestID), 1009 zap.Uint64("requestedHeight", requestedHeight), 1010 ) 1011 } 1012 1013 // Register failures for nodes we didn't send a request to. 1014 s.timeouts.RegisterRequestToUnreachableValidator() 1015 inMsg := message.InternalQueryFailed( 1016 nodeID, 1017 s.ctx.ChainID, 1018 requestID, 1019 ) 1020 go s.router.HandleInbound(ctx, inMsg) 1021 } 1022 } 1023 } 1024 1025 func (s *sender) SendPullQuery( 1026 ctx context.Context, 1027 nodeIDs set.Set[ids.NodeID], 1028 requestID uint32, 1029 containerID ids.ID, 1030 requestedHeight uint64, 1031 ) { 1032 ctx = context.WithoutCancel(ctx) 1033 1034 // Tell the router to expect a response message or a message notifying 1035 // that we won't get a response from each of these nodes. 1036 // We register timeouts for all nodes, regardless of whether we fail 1037 // to send them a message, to avoid busy looping when disconnected from 1038 // the internet. 1039 for nodeID := range nodeIDs { 1040 inMsg := message.InternalQueryFailed( 1041 nodeID, 1042 s.ctx.ChainID, 1043 requestID, 1044 ) 1045 s.router.RegisterRequest( 1046 ctx, 1047 nodeID, 1048 s.ctx.ChainID, 1049 s.ctx.ChainID, 1050 requestID, 1051 message.ChitsOp, 1052 inMsg, 1053 p2p.EngineType_ENGINE_TYPE_UNSPECIFIED, 1054 ) 1055 } 1056 1057 // Note that this timeout duration won't exactly match the one that gets 1058 // registered. That's OK. 1059 deadline := s.timeouts.TimeoutDuration() 1060 1061 // Sending a message to myself. No need to send it over the network. Just 1062 // put it right into the router. Do so asynchronously to avoid deadlock. 1063 if nodeIDs.Contains(s.ctx.NodeID) { 1064 nodeIDs.Remove(s.ctx.NodeID) 1065 inMsg := message.InboundPullQuery( 1066 s.ctx.ChainID, 1067 requestID, 1068 deadline, 1069 containerID, 1070 requestedHeight, 1071 s.ctx.NodeID, 1072 ) 1073 go s.router.HandleInbound(ctx, inMsg) 1074 } 1075 1076 // Some of the nodes in [nodeIDs] may be benched. That is, they've been 1077 // unresponsive so we don't even bother sending messages to them. We just 1078 // have them immediately fail. 1079 for nodeID := range nodeIDs { 1080 if s.timeouts.IsBenched(nodeID, s.ctx.ChainID) { 1081 s.failedDueToBench.With(prometheus.Labels{ 1082 opLabel: message.PullQueryOp.String(), 1083 }).Inc() 1084 nodeIDs.Remove(nodeID) 1085 s.timeouts.RegisterRequestToUnreachableValidator() 1086 // Immediately register a failure. Do so asynchronously to avoid 1087 // deadlock. 1088 inMsg := message.InternalQueryFailed( 1089 nodeID, 1090 s.ctx.ChainID, 1091 requestID, 1092 ) 1093 go s.router.HandleInbound(ctx, inMsg) 1094 } 1095 } 1096 1097 // Create the outbound message. 1098 outMsg, err := s.msgCreator.PullQuery( 1099 s.ctx.ChainID, 1100 requestID, 1101 deadline, 1102 containerID, 1103 requestedHeight, 1104 ) 1105 1106 // Send the message over the network. 1107 var sentTo set.Set[ids.NodeID] 1108 if err == nil { 1109 sentTo = s.sender.Send( 1110 outMsg, 1111 common.SendConfig{ 1112 NodeIDs: nodeIDs, 1113 }, 1114 s.ctx.SubnetID, 1115 s.subnet, 1116 ) 1117 } else { 1118 s.ctx.Log.Error("failed to build message", 1119 zap.Stringer("messageOp", message.PullQueryOp), 1120 zap.Stringer("chainID", s.ctx.ChainID), 1121 zap.Uint32("requestID", requestID), 1122 zap.Duration("deadline", deadline), 1123 zap.Stringer("containerID", containerID), 1124 zap.Uint64("requestedHeight", requestedHeight), 1125 zap.Error(err), 1126 ) 1127 } 1128 1129 for nodeID := range nodeIDs { 1130 if !sentTo.Contains(nodeID) { 1131 s.ctx.Log.Debug("failed to send message", 1132 zap.Stringer("messageOp", message.PullQueryOp), 1133 zap.Stringer("nodeID", nodeID), 1134 zap.Stringer("chainID", s.ctx.ChainID), 1135 zap.Uint32("requestID", requestID), 1136 zap.Stringer("containerID", containerID), 1137 zap.Uint64("requestedHeight", requestedHeight), 1138 ) 1139 1140 // Register failures for nodes we didn't send a request to. 1141 s.timeouts.RegisterRequestToUnreachableValidator() 1142 inMsg := message.InternalQueryFailed( 1143 nodeID, 1144 s.ctx.ChainID, 1145 requestID, 1146 ) 1147 go s.router.HandleInbound(ctx, inMsg) 1148 } 1149 } 1150 } 1151 1152 func (s *sender) SendChits( 1153 ctx context.Context, 1154 nodeID ids.NodeID, 1155 requestID uint32, 1156 preferredID ids.ID, 1157 preferredIDAtHeight ids.ID, 1158 acceptedID ids.ID, 1159 ) { 1160 ctx = context.WithoutCancel(ctx) 1161 1162 // If [nodeID] is myself, send this message directly 1163 // to my own router rather than sending it over the network 1164 if nodeID == s.ctx.NodeID { 1165 inMsg := message.InboundChits( 1166 s.ctx.ChainID, 1167 requestID, 1168 preferredID, 1169 preferredIDAtHeight, 1170 acceptedID, 1171 nodeID, 1172 ) 1173 go s.router.HandleInbound(ctx, inMsg) 1174 return 1175 } 1176 1177 // Create the outbound message. 1178 outMsg, err := s.msgCreator.Chits(s.ctx.ChainID, requestID, preferredID, preferredIDAtHeight, acceptedID) 1179 if err != nil { 1180 s.ctx.Log.Error("failed to build message", 1181 zap.Stringer("messageOp", message.ChitsOp), 1182 zap.Stringer("chainID", s.ctx.ChainID), 1183 zap.Uint32("requestID", requestID), 1184 zap.Stringer("preferredID", preferredID), 1185 zap.Stringer("preferredIDAtHeight", preferredIDAtHeight), 1186 zap.Stringer("acceptedID", acceptedID), 1187 zap.Error(err), 1188 ) 1189 return 1190 } 1191 1192 // Send the message over the network. 1193 nodeIDs := set.Of(nodeID) 1194 sentTo := s.sender.Send( 1195 outMsg, 1196 common.SendConfig{ 1197 NodeIDs: nodeIDs, 1198 }, 1199 s.ctx.SubnetID, 1200 s.subnet, 1201 ) 1202 if sentTo.Len() == 0 { 1203 s.ctx.Log.Debug("failed to send message", 1204 zap.Stringer("messageOp", message.ChitsOp), 1205 zap.Stringer("nodeID", nodeID), 1206 zap.Stringer("chainID", s.ctx.ChainID), 1207 zap.Uint32("requestID", requestID), 1208 zap.Stringer("preferredID", preferredID), 1209 zap.Stringer("preferredIDAtHeight", preferredIDAtHeight), 1210 zap.Stringer("acceptedID", acceptedID), 1211 ) 1212 } 1213 } 1214 1215 func (s *sender) SendCrossChainAppRequest(ctx context.Context, chainID ids.ID, requestID uint32, appRequestBytes []byte) error { 1216 ctx = context.WithoutCancel(ctx) 1217 1218 // The failed message is treated as if it was sent by the requested chain 1219 failedMsg := message.InternalCrossChainAppError( 1220 s.ctx.NodeID, 1221 chainID, 1222 s.ctx.ChainID, 1223 requestID, 1224 common.ErrTimeout.Code, 1225 common.ErrTimeout.Message, 1226 ) 1227 s.router.RegisterRequest( 1228 ctx, 1229 s.ctx.NodeID, 1230 s.ctx.ChainID, 1231 chainID, 1232 requestID, 1233 message.CrossChainAppResponseOp, 1234 failedMsg, 1235 p2p.EngineType_ENGINE_TYPE_UNSPECIFIED, 1236 ) 1237 1238 inMsg := message.InternalCrossChainAppRequest( 1239 s.ctx.NodeID, 1240 s.ctx.ChainID, 1241 chainID, 1242 requestID, 1243 s.timeouts.TimeoutDuration(), 1244 appRequestBytes, 1245 ) 1246 go s.router.HandleInbound(ctx, inMsg) 1247 return nil 1248 } 1249 1250 func (s *sender) SendCrossChainAppResponse(ctx context.Context, chainID ids.ID, requestID uint32, appResponseBytes []byte) error { 1251 ctx = context.WithoutCancel(ctx) 1252 1253 inMsg := message.InternalCrossChainAppResponse( 1254 s.ctx.NodeID, 1255 s.ctx.ChainID, 1256 chainID, 1257 requestID, 1258 appResponseBytes, 1259 ) 1260 go s.router.HandleInbound(ctx, inMsg) 1261 return nil 1262 } 1263 1264 func (s *sender) SendCrossChainAppError(ctx context.Context, chainID ids.ID, requestID uint32, errorCode int32, errorMessage string) error { 1265 ctx = context.WithoutCancel(ctx) 1266 1267 inMsg := message.InternalCrossChainAppError( 1268 s.ctx.NodeID, 1269 s.ctx.ChainID, 1270 chainID, 1271 requestID, 1272 errorCode, 1273 errorMessage, 1274 ) 1275 go s.router.HandleInbound(ctx, inMsg) 1276 return nil 1277 } 1278 1279 func (s *sender) SendAppRequest(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, appRequestBytes []byte) error { 1280 ctx = context.WithoutCancel(ctx) 1281 1282 // Tell the router to expect a response message or a message notifying 1283 // that we won't get a response from each of these nodes. 1284 // We register timeouts for all nodes, regardless of whether we fail 1285 // to send them a message, to avoid busy looping when disconnected from 1286 // the internet. 1287 for nodeID := range nodeIDs { 1288 inMsg := message.InboundAppError( 1289 nodeID, 1290 s.ctx.ChainID, 1291 requestID, 1292 common.ErrTimeout.Code, 1293 common.ErrTimeout.Message, 1294 ) 1295 s.router.RegisterRequest( 1296 ctx, 1297 nodeID, 1298 s.ctx.ChainID, 1299 s.ctx.ChainID, 1300 requestID, 1301 message.AppResponseOp, 1302 inMsg, 1303 p2p.EngineType_ENGINE_TYPE_UNSPECIFIED, 1304 ) 1305 } 1306 1307 // Note that this timeout duration won't exactly match the one that gets 1308 // registered. That's OK. 1309 deadline := s.timeouts.TimeoutDuration() 1310 1311 // Sending a message to myself. No need to send it over the network. Just 1312 // put it right into the router. Do so asynchronously to avoid deadlock. 1313 if nodeIDs.Contains(s.ctx.NodeID) { 1314 nodeIDs.Remove(s.ctx.NodeID) 1315 inMsg := message.InboundAppRequest( 1316 s.ctx.ChainID, 1317 requestID, 1318 deadline, 1319 appRequestBytes, 1320 s.ctx.NodeID, 1321 ) 1322 go s.router.HandleInbound(ctx, inMsg) 1323 } 1324 1325 // Some of the nodes in [nodeIDs] may be benched. That is, they've been 1326 // unresponsive so we don't even bother sending messages to them. We just 1327 // have them immediately fail. 1328 for nodeID := range nodeIDs { 1329 if s.timeouts.IsBenched(nodeID, s.ctx.ChainID) { 1330 s.failedDueToBench.With(prometheus.Labels{ 1331 opLabel: message.AppRequestOp.String(), 1332 }).Inc() 1333 nodeIDs.Remove(nodeID) 1334 s.timeouts.RegisterRequestToUnreachableValidator() 1335 1336 // Immediately register a failure. Do so asynchronously to avoid 1337 // deadlock. 1338 inMsg := message.InboundAppError( 1339 nodeID, 1340 s.ctx.ChainID, 1341 requestID, 1342 common.ErrTimeout.Code, 1343 common.ErrTimeout.Message, 1344 ) 1345 go s.router.HandleInbound(ctx, inMsg) 1346 } 1347 } 1348 1349 // Create the outbound message. 1350 outMsg, err := s.msgCreator.AppRequest( 1351 s.ctx.ChainID, 1352 requestID, 1353 deadline, 1354 appRequestBytes, 1355 ) 1356 1357 // Send the message over the network. 1358 // [sentTo] are the IDs of nodes who may receive the message. 1359 var sentTo set.Set[ids.NodeID] 1360 if err == nil { 1361 sentTo = s.sender.Send( 1362 outMsg, 1363 common.SendConfig{ 1364 NodeIDs: nodeIDs, 1365 }, 1366 s.ctx.SubnetID, 1367 s.subnet, 1368 ) 1369 } else { 1370 s.ctx.Log.Error("failed to build message", 1371 zap.Stringer("messageOp", message.AppRequestOp), 1372 zap.Stringer("chainID", s.ctx.ChainID), 1373 zap.Uint32("requestID", requestID), 1374 zap.Binary("payload", appRequestBytes), 1375 zap.Error(err), 1376 ) 1377 } 1378 1379 for nodeID := range nodeIDs { 1380 if !sentTo.Contains(nodeID) { 1381 if s.ctx.Log.Enabled(logging.Verbo) { 1382 s.ctx.Log.Verbo("failed to send message", 1383 zap.Stringer("messageOp", message.AppRequestOp), 1384 zap.Stringer("nodeID", nodeID), 1385 zap.Stringer("chainID", s.ctx.ChainID), 1386 zap.Uint32("requestID", requestID), 1387 zap.Binary("payload", appRequestBytes), 1388 ) 1389 } else { 1390 s.ctx.Log.Debug("failed to send message", 1391 zap.Stringer("messageOp", message.AppRequestOp), 1392 zap.Stringer("nodeID", nodeID), 1393 zap.Stringer("chainID", s.ctx.ChainID), 1394 zap.Uint32("requestID", requestID), 1395 ) 1396 } 1397 1398 // Register failures for nodes we didn't send a request to. 1399 s.timeouts.RegisterRequestToUnreachableValidator() 1400 inMsg := message.InboundAppError( 1401 nodeID, 1402 s.ctx.ChainID, 1403 requestID, 1404 common.ErrTimeout.Code, 1405 common.ErrTimeout.Message, 1406 ) 1407 go s.router.HandleInbound(ctx, inMsg) 1408 } 1409 } 1410 return nil 1411 } 1412 1413 func (s *sender) SendAppResponse(ctx context.Context, nodeID ids.NodeID, requestID uint32, appResponseBytes []byte) error { 1414 ctx = context.WithoutCancel(ctx) 1415 1416 if nodeID == s.ctx.NodeID { 1417 inMsg := message.InboundAppResponse( 1418 s.ctx.ChainID, 1419 requestID, 1420 appResponseBytes, 1421 nodeID, 1422 ) 1423 go s.router.HandleInbound(ctx, inMsg) 1424 return nil 1425 } 1426 1427 // Create the outbound message. 1428 outMsg, err := s.msgCreator.AppResponse( 1429 s.ctx.ChainID, 1430 requestID, 1431 appResponseBytes, 1432 ) 1433 if err != nil { 1434 s.ctx.Log.Error("failed to build message", 1435 zap.Stringer("messageOp", message.AppResponseOp), 1436 zap.Stringer("chainID", s.ctx.ChainID), 1437 zap.Uint32("requestID", requestID), 1438 zap.Binary("payload", appResponseBytes), 1439 zap.Error(err), 1440 ) 1441 return nil 1442 } 1443 1444 // Send the message over the network. 1445 nodeIDs := set.Of(nodeID) 1446 sentTo := s.sender.Send( 1447 outMsg, 1448 common.SendConfig{ 1449 NodeIDs: nodeIDs, 1450 }, 1451 s.ctx.SubnetID, 1452 s.subnet, 1453 ) 1454 if sentTo.Len() == 0 { 1455 if s.ctx.Log.Enabled(logging.Verbo) { 1456 s.ctx.Log.Verbo("failed to send message", 1457 zap.Stringer("messageOp", message.AppResponseOp), 1458 zap.Stringer("nodeID", nodeID), 1459 zap.Stringer("chainID", s.ctx.ChainID), 1460 zap.Uint32("requestID", requestID), 1461 zap.Binary("payload", appResponseBytes), 1462 ) 1463 } else { 1464 s.ctx.Log.Debug("failed to send message", 1465 zap.Stringer("messageOp", message.AppResponseOp), 1466 zap.Stringer("nodeID", nodeID), 1467 zap.Stringer("chainID", s.ctx.ChainID), 1468 zap.Uint32("requestID", requestID), 1469 ) 1470 } 1471 } 1472 return nil 1473 } 1474 1475 func (s *sender) SendAppError(ctx context.Context, nodeID ids.NodeID, requestID uint32, errorCode int32, errorMessage string) error { 1476 ctx = context.WithoutCancel(ctx) 1477 1478 if nodeID == s.ctx.NodeID { 1479 inMsg := message.InboundAppError( 1480 nodeID, 1481 s.ctx.ChainID, 1482 requestID, 1483 errorCode, 1484 errorMessage, 1485 ) 1486 go s.router.HandleInbound(ctx, inMsg) 1487 return nil 1488 } 1489 1490 // Create the outbound message. 1491 outMsg, err := s.msgCreator.AppError( 1492 s.ctx.ChainID, 1493 requestID, 1494 errorCode, 1495 errorMessage, 1496 ) 1497 if err != nil { 1498 s.ctx.Log.Error("failed to build message", 1499 zap.Stringer("messageOp", message.AppErrorOp), 1500 zap.Stringer("nodeID", nodeID), 1501 zap.Stringer("chainID", s.ctx.ChainID), 1502 zap.Uint32("requestID", requestID), 1503 zap.Int32("errorCode", errorCode), 1504 zap.String("errorMessage", errorMessage), 1505 zap.Error(err), 1506 ) 1507 return nil 1508 } 1509 1510 // Send the message over the network. 1511 sentTo := s.sender.Send( 1512 outMsg, 1513 common.SendConfig{ 1514 NodeIDs: set.Of(nodeID), 1515 }, 1516 s.ctx.SubnetID, 1517 s.subnet, 1518 ) 1519 if sentTo.Len() == 0 { 1520 if s.ctx.Log.Enabled(logging.Verbo) { 1521 s.ctx.Log.Verbo("failed to send message", 1522 zap.Stringer("messageOp", message.AppErrorOp), 1523 zap.Stringer("nodeID", nodeID), 1524 zap.Stringer("chainID", s.ctx.ChainID), 1525 zap.Uint32("requestID", requestID), 1526 zap.Int32("errorCode", errorCode), 1527 zap.String("errorMessage", errorMessage), 1528 ) 1529 } else { 1530 s.ctx.Log.Debug("failed to send message", 1531 zap.Stringer("messageOp", message.AppErrorOp), 1532 zap.Stringer("nodeID", nodeID), 1533 zap.Stringer("chainID", s.ctx.ChainID), 1534 zap.Uint32("requestID", requestID), 1535 zap.Int32("errorCode", errorCode), 1536 zap.String("errorMessage", errorMessage), 1537 ) 1538 } 1539 } 1540 return nil 1541 } 1542 1543 func (s *sender) SendAppGossip( 1544 _ context.Context, 1545 config common.SendConfig, 1546 appGossipBytes []byte, 1547 ) error { 1548 // Create the outbound message. 1549 outMsg, err := s.msgCreator.AppGossip(s.ctx.ChainID, appGossipBytes) 1550 if err != nil { 1551 s.ctx.Log.Error("failed to build message", 1552 zap.Stringer("messageOp", message.AppGossipOp), 1553 zap.Stringer("chainID", s.ctx.ChainID), 1554 zap.Binary("payload", appGossipBytes), 1555 zap.Error(err), 1556 ) 1557 return nil 1558 } 1559 1560 sentTo := s.sender.Send( 1561 outMsg, 1562 config, 1563 s.ctx.SubnetID, 1564 s.subnet, 1565 ) 1566 if sentTo.Len() == 0 { 1567 if s.ctx.Log.Enabled(logging.Verbo) { 1568 s.ctx.Log.Verbo("failed to send message", 1569 zap.Stringer("messageOp", message.AppGossipOp), 1570 zap.Stringer("chainID", s.ctx.ChainID), 1571 zap.Binary("payload", appGossipBytes), 1572 ) 1573 } else { 1574 s.ctx.Log.Debug("failed to send message", 1575 zap.Stringer("messageOp", message.AppGossipOp), 1576 zap.Stringer("chainID", s.ctx.ChainID), 1577 ) 1578 } 1579 } 1580 return nil 1581 }