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  }