github.com/ava-labs/avalanchego@v1.11.11/message/outbound_msg_builder.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package message
     5  
     6  import (
     7  	"net/netip"
     8  	"time"
     9  
    10  	"github.com/ava-labs/avalanchego/ids"
    11  	"github.com/ava-labs/avalanchego/proto/pb/p2p"
    12  	"github.com/ava-labs/avalanchego/utils/compression"
    13  	"github.com/ava-labs/avalanchego/utils/ips"
    14  )
    15  
    16  var _ OutboundMsgBuilder = (*outMsgBuilder)(nil)
    17  
    18  // OutboundMsgBuilder builds outbound messages. Outbound messages are returned
    19  // with a reference count of 1. Once the reference count hits 0, the message
    20  // bytes should no longer be accessed.
    21  type OutboundMsgBuilder interface {
    22  	Handshake(
    23  		networkID uint32,
    24  		myTime uint64,
    25  		ip netip.AddrPort,
    26  		client string,
    27  		major uint32,
    28  		minor uint32,
    29  		patch uint32,
    30  		ipSigningTime uint64,
    31  		ipNodeIDSig []byte,
    32  		ipBLSSig []byte,
    33  		trackedSubnets []ids.ID,
    34  		supportedACPs []uint32,
    35  		objectedACPs []uint32,
    36  		knownPeersFilter []byte,
    37  		knownPeersSalt []byte,
    38  		requestAllSubnetIPs bool,
    39  	) (OutboundMessage, error)
    40  
    41  	GetPeerList(
    42  		knownPeersFilter []byte,
    43  		knownPeersSalt []byte,
    44  		requestAllSubnetIPs bool,
    45  	) (OutboundMessage, error)
    46  
    47  	PeerList(
    48  		peers []*ips.ClaimedIPPort,
    49  		bypassThrottling bool,
    50  	) (OutboundMessage, error)
    51  
    52  	Ping(
    53  		primaryUptime uint32,
    54  		subnetUptimes []*p2p.SubnetUptime,
    55  	) (OutboundMessage, error)
    56  
    57  	Pong() (OutboundMessage, error)
    58  
    59  	GetStateSummaryFrontier(
    60  		chainID ids.ID,
    61  		requestID uint32,
    62  		deadline time.Duration,
    63  	) (OutboundMessage, error)
    64  
    65  	StateSummaryFrontier(
    66  		chainID ids.ID,
    67  		requestID uint32,
    68  		summary []byte,
    69  	) (OutboundMessage, error)
    70  
    71  	GetAcceptedStateSummary(
    72  		chainID ids.ID,
    73  		requestID uint32,
    74  		deadline time.Duration,
    75  		heights []uint64,
    76  	) (OutboundMessage, error)
    77  
    78  	AcceptedStateSummary(
    79  		chainID ids.ID,
    80  		requestID uint32,
    81  		summaryIDs []ids.ID,
    82  	) (OutboundMessage, error)
    83  
    84  	GetAcceptedFrontier(
    85  		chainID ids.ID,
    86  		requestID uint32,
    87  		deadline time.Duration,
    88  	) (OutboundMessage, error)
    89  
    90  	AcceptedFrontier(
    91  		chainID ids.ID,
    92  		requestID uint32,
    93  		containerID ids.ID,
    94  	) (OutboundMessage, error)
    95  
    96  	GetAccepted(
    97  		chainID ids.ID,
    98  		requestID uint32,
    99  		deadline time.Duration,
   100  		containerIDs []ids.ID,
   101  	) (OutboundMessage, error)
   102  
   103  	Accepted(
   104  		chainID ids.ID,
   105  		requestID uint32,
   106  		containerIDs []ids.ID,
   107  	) (OutboundMessage, error)
   108  
   109  	GetAncestors(
   110  		chainID ids.ID,
   111  		requestID uint32,
   112  		deadline time.Duration,
   113  		containerID ids.ID,
   114  		engineType p2p.EngineType,
   115  	) (OutboundMessage, error)
   116  
   117  	Ancestors(
   118  		chainID ids.ID,
   119  		requestID uint32,
   120  		containers [][]byte,
   121  	) (OutboundMessage, error)
   122  
   123  	Get(
   124  		chainID ids.ID,
   125  		requestID uint32,
   126  		deadline time.Duration,
   127  		containerID ids.ID,
   128  	) (OutboundMessage, error)
   129  
   130  	Put(
   131  		chainID ids.ID,
   132  		requestID uint32,
   133  		container []byte,
   134  	) (OutboundMessage, error)
   135  
   136  	PushQuery(
   137  		chainID ids.ID,
   138  		requestID uint32,
   139  		deadline time.Duration,
   140  		container []byte,
   141  		requestedHeight uint64,
   142  	) (OutboundMessage, error)
   143  
   144  	PullQuery(
   145  		chainID ids.ID,
   146  		requestID uint32,
   147  		deadline time.Duration,
   148  		containerID ids.ID,
   149  		requestedHeight uint64,
   150  	) (OutboundMessage, error)
   151  
   152  	Chits(
   153  		chainID ids.ID,
   154  		requestID uint32,
   155  		preferredID ids.ID,
   156  		preferredIDAtHeight ids.ID,
   157  		acceptedID ids.ID,
   158  	) (OutboundMessage, error)
   159  
   160  	AppRequest(
   161  		chainID ids.ID,
   162  		requestID uint32,
   163  		deadline time.Duration,
   164  		msg []byte,
   165  	) (OutboundMessage, error)
   166  
   167  	AppResponse(
   168  		chainID ids.ID,
   169  		requestID uint32,
   170  		msg []byte,
   171  	) (OutboundMessage, error)
   172  
   173  	AppError(
   174  		chainID ids.ID,
   175  		requestID uint32,
   176  		errorCode int32,
   177  		errorMessage string,
   178  	) (OutboundMessage, error)
   179  
   180  	AppGossip(
   181  		chainID ids.ID,
   182  		msg []byte,
   183  	) (OutboundMessage, error)
   184  }
   185  
   186  type outMsgBuilder struct {
   187  	compressionType compression.Type
   188  
   189  	builder *msgBuilder
   190  }
   191  
   192  // Use "message.NewCreator" to import this function
   193  // since we do not expose "msgBuilder" yet
   194  func newOutboundBuilder(compressionType compression.Type, builder *msgBuilder) OutboundMsgBuilder {
   195  	return &outMsgBuilder{
   196  		compressionType: compressionType,
   197  		builder:         builder,
   198  	}
   199  }
   200  
   201  func (b *outMsgBuilder) Ping(
   202  	primaryUptime uint32,
   203  	subnetUptimes []*p2p.SubnetUptime,
   204  ) (OutboundMessage, error) {
   205  	return b.builder.createOutbound(
   206  		&p2p.Message{
   207  			Message: &p2p.Message_Ping{
   208  				Ping: &p2p.Ping{
   209  					Uptime:        primaryUptime,
   210  					SubnetUptimes: subnetUptimes,
   211  				},
   212  			},
   213  		},
   214  		compression.TypeNone,
   215  		false,
   216  	)
   217  }
   218  
   219  func (b *outMsgBuilder) Pong() (OutboundMessage, error) {
   220  	return b.builder.createOutbound(
   221  		&p2p.Message{
   222  			Message: &p2p.Message_Pong{
   223  				Pong: &p2p.Pong{},
   224  			},
   225  		},
   226  		compression.TypeNone,
   227  		false,
   228  	)
   229  }
   230  
   231  func (b *outMsgBuilder) Handshake(
   232  	networkID uint32,
   233  	myTime uint64,
   234  	ip netip.AddrPort,
   235  	client string,
   236  	major uint32,
   237  	minor uint32,
   238  	patch uint32,
   239  	ipSigningTime uint64,
   240  	ipNodeIDSig []byte,
   241  	ipBLSSig []byte,
   242  	trackedSubnets []ids.ID,
   243  	supportedACPs []uint32,
   244  	objectedACPs []uint32,
   245  	knownPeersFilter []byte,
   246  	knownPeersSalt []byte,
   247  	requestAllSubnetIPs bool,
   248  ) (OutboundMessage, error) {
   249  	subnetIDBytes := make([][]byte, len(trackedSubnets))
   250  	encodeIDs(trackedSubnets, subnetIDBytes)
   251  	// TODO: Use .AsSlice() after v1.12.x activates.
   252  	addr := ip.Addr().As16()
   253  	return b.builder.createOutbound(
   254  		&p2p.Message{
   255  			Message: &p2p.Message_Handshake{
   256  				Handshake: &p2p.Handshake{
   257  					NetworkId:      networkID,
   258  					MyTime:         myTime,
   259  					IpAddr:         addr[:],
   260  					IpPort:         uint32(ip.Port()),
   261  					IpSigningTime:  ipSigningTime,
   262  					IpNodeIdSig:    ipNodeIDSig,
   263  					TrackedSubnets: subnetIDBytes,
   264  					Client: &p2p.Client{
   265  						Name:  client,
   266  						Major: major,
   267  						Minor: minor,
   268  						Patch: patch,
   269  					},
   270  					SupportedAcps: supportedACPs,
   271  					ObjectedAcps:  objectedACPs,
   272  					KnownPeers: &p2p.BloomFilter{
   273  						Filter: knownPeersFilter,
   274  						Salt:   knownPeersSalt,
   275  					},
   276  					IpBlsSig:   ipBLSSig,
   277  					AllSubnets: requestAllSubnetIPs,
   278  				},
   279  			},
   280  		},
   281  		compression.TypeNone,
   282  		true,
   283  	)
   284  }
   285  
   286  func (b *outMsgBuilder) GetPeerList(
   287  	knownPeersFilter []byte,
   288  	knownPeersSalt []byte,
   289  	requestAllSubnetIPs bool,
   290  ) (OutboundMessage, error) {
   291  	return b.builder.createOutbound(
   292  		&p2p.Message{
   293  			Message: &p2p.Message_GetPeerList{
   294  				GetPeerList: &p2p.GetPeerList{
   295  					KnownPeers: &p2p.BloomFilter{
   296  						Filter: knownPeersFilter,
   297  						Salt:   knownPeersSalt,
   298  					},
   299  					AllSubnets: requestAllSubnetIPs,
   300  				},
   301  			},
   302  		},
   303  		b.compressionType,
   304  		false,
   305  	)
   306  }
   307  
   308  func (b *outMsgBuilder) PeerList(peers []*ips.ClaimedIPPort, bypassThrottling bool) (OutboundMessage, error) {
   309  	claimIPPorts := make([]*p2p.ClaimedIpPort, len(peers))
   310  	for i, p := range peers {
   311  		// TODO: Use .AsSlice() after v1.12.x activates.
   312  		ip := p.AddrPort.Addr().As16()
   313  		claimIPPorts[i] = &p2p.ClaimedIpPort{
   314  			X509Certificate: p.Cert.Raw,
   315  			IpAddr:          ip[:],
   316  			IpPort:          uint32(p.AddrPort.Port()),
   317  			Timestamp:       p.Timestamp,
   318  			Signature:       p.Signature,
   319  			TxId:            ids.Empty[:],
   320  		}
   321  	}
   322  	return b.builder.createOutbound(
   323  		&p2p.Message{
   324  			Message: &p2p.Message_PeerList_{
   325  				PeerList_: &p2p.PeerList{
   326  					ClaimedIpPorts: claimIPPorts,
   327  				},
   328  			},
   329  		},
   330  		b.compressionType,
   331  		bypassThrottling,
   332  	)
   333  }
   334  
   335  func (b *outMsgBuilder) GetStateSummaryFrontier(
   336  	chainID ids.ID,
   337  	requestID uint32,
   338  	deadline time.Duration,
   339  ) (OutboundMessage, error) {
   340  	return b.builder.createOutbound(
   341  		&p2p.Message{
   342  			Message: &p2p.Message_GetStateSummaryFrontier{
   343  				GetStateSummaryFrontier: &p2p.GetStateSummaryFrontier{
   344  					ChainId:   chainID[:],
   345  					RequestId: requestID,
   346  					Deadline:  uint64(deadline),
   347  				},
   348  			},
   349  		},
   350  		compression.TypeNone,
   351  		false,
   352  	)
   353  }
   354  
   355  func (b *outMsgBuilder) StateSummaryFrontier(
   356  	chainID ids.ID,
   357  	requestID uint32,
   358  	summary []byte,
   359  ) (OutboundMessage, error) {
   360  	return b.builder.createOutbound(
   361  		&p2p.Message{
   362  			Message: &p2p.Message_StateSummaryFrontier_{
   363  				StateSummaryFrontier_: &p2p.StateSummaryFrontier{
   364  					ChainId:   chainID[:],
   365  					RequestId: requestID,
   366  					Summary:   summary,
   367  				},
   368  			},
   369  		},
   370  		b.compressionType,
   371  		false,
   372  	)
   373  }
   374  
   375  func (b *outMsgBuilder) GetAcceptedStateSummary(
   376  	chainID ids.ID,
   377  	requestID uint32,
   378  	deadline time.Duration,
   379  	heights []uint64,
   380  ) (OutboundMessage, error) {
   381  	return b.builder.createOutbound(
   382  		&p2p.Message{
   383  			Message: &p2p.Message_GetAcceptedStateSummary{
   384  				GetAcceptedStateSummary: &p2p.GetAcceptedStateSummary{
   385  					ChainId:   chainID[:],
   386  					RequestId: requestID,
   387  					Deadline:  uint64(deadline),
   388  					Heights:   heights,
   389  				},
   390  			},
   391  		},
   392  		b.compressionType,
   393  		false,
   394  	)
   395  }
   396  
   397  func (b *outMsgBuilder) AcceptedStateSummary(
   398  	chainID ids.ID,
   399  	requestID uint32,
   400  	summaryIDs []ids.ID,
   401  ) (OutboundMessage, error) {
   402  	summaryIDBytes := make([][]byte, len(summaryIDs))
   403  	encodeIDs(summaryIDs, summaryIDBytes)
   404  	return b.builder.createOutbound(
   405  		&p2p.Message{
   406  			Message: &p2p.Message_AcceptedStateSummary_{
   407  				AcceptedStateSummary_: &p2p.AcceptedStateSummary{
   408  					ChainId:    chainID[:],
   409  					RequestId:  requestID,
   410  					SummaryIds: summaryIDBytes,
   411  				},
   412  			},
   413  		},
   414  		b.compressionType,
   415  		false,
   416  	)
   417  }
   418  
   419  func (b *outMsgBuilder) GetAcceptedFrontier(
   420  	chainID ids.ID,
   421  	requestID uint32,
   422  	deadline time.Duration,
   423  ) (OutboundMessage, error) {
   424  	return b.builder.createOutbound(
   425  		&p2p.Message{
   426  			Message: &p2p.Message_GetAcceptedFrontier{
   427  				GetAcceptedFrontier: &p2p.GetAcceptedFrontier{
   428  					ChainId:   chainID[:],
   429  					RequestId: requestID,
   430  					Deadline:  uint64(deadline),
   431  				},
   432  			},
   433  		},
   434  		compression.TypeNone,
   435  		false,
   436  	)
   437  }
   438  
   439  func (b *outMsgBuilder) AcceptedFrontier(
   440  	chainID ids.ID,
   441  	requestID uint32,
   442  	containerID ids.ID,
   443  ) (OutboundMessage, error) {
   444  	return b.builder.createOutbound(
   445  		&p2p.Message{
   446  			Message: &p2p.Message_AcceptedFrontier_{
   447  				AcceptedFrontier_: &p2p.AcceptedFrontier{
   448  					ChainId:     chainID[:],
   449  					RequestId:   requestID,
   450  					ContainerId: containerID[:],
   451  				},
   452  			},
   453  		},
   454  		compression.TypeNone,
   455  		false,
   456  	)
   457  }
   458  
   459  func (b *outMsgBuilder) GetAccepted(
   460  	chainID ids.ID,
   461  	requestID uint32,
   462  	deadline time.Duration,
   463  	containerIDs []ids.ID,
   464  ) (OutboundMessage, error) {
   465  	containerIDBytes := make([][]byte, len(containerIDs))
   466  	encodeIDs(containerIDs, containerIDBytes)
   467  	return b.builder.createOutbound(
   468  		&p2p.Message{
   469  			Message: &p2p.Message_GetAccepted{
   470  				GetAccepted: &p2p.GetAccepted{
   471  					ChainId:      chainID[:],
   472  					RequestId:    requestID,
   473  					Deadline:     uint64(deadline),
   474  					ContainerIds: containerIDBytes,
   475  				},
   476  			},
   477  		},
   478  		compression.TypeNone,
   479  		false,
   480  	)
   481  }
   482  
   483  func (b *outMsgBuilder) Accepted(
   484  	chainID ids.ID,
   485  	requestID uint32,
   486  	containerIDs []ids.ID,
   487  ) (OutboundMessage, error) {
   488  	containerIDBytes := make([][]byte, len(containerIDs))
   489  	encodeIDs(containerIDs, containerIDBytes)
   490  	return b.builder.createOutbound(
   491  		&p2p.Message{
   492  			Message: &p2p.Message_Accepted_{
   493  				Accepted_: &p2p.Accepted{
   494  					ChainId:      chainID[:],
   495  					RequestId:    requestID,
   496  					ContainerIds: containerIDBytes,
   497  				},
   498  			},
   499  		},
   500  		compression.TypeNone,
   501  		false,
   502  	)
   503  }
   504  
   505  func (b *outMsgBuilder) GetAncestors(
   506  	chainID ids.ID,
   507  	requestID uint32,
   508  	deadline time.Duration,
   509  	containerID ids.ID,
   510  	engineType p2p.EngineType,
   511  ) (OutboundMessage, error) {
   512  	return b.builder.createOutbound(
   513  		&p2p.Message{
   514  			Message: &p2p.Message_GetAncestors{
   515  				GetAncestors: &p2p.GetAncestors{
   516  					ChainId:     chainID[:],
   517  					RequestId:   requestID,
   518  					Deadline:    uint64(deadline),
   519  					ContainerId: containerID[:],
   520  					EngineType:  engineType,
   521  				},
   522  			},
   523  		},
   524  		compression.TypeNone,
   525  		false,
   526  	)
   527  }
   528  
   529  func (b *outMsgBuilder) Ancestors(
   530  	chainID ids.ID,
   531  	requestID uint32,
   532  	containers [][]byte,
   533  ) (OutboundMessage, error) {
   534  	return b.builder.createOutbound(
   535  		&p2p.Message{
   536  			Message: &p2p.Message_Ancestors_{
   537  				Ancestors_: &p2p.Ancestors{
   538  					ChainId:    chainID[:],
   539  					RequestId:  requestID,
   540  					Containers: containers,
   541  				},
   542  			},
   543  		},
   544  		b.compressionType,
   545  		false,
   546  	)
   547  }
   548  
   549  func (b *outMsgBuilder) Get(
   550  	chainID ids.ID,
   551  	requestID uint32,
   552  	deadline time.Duration,
   553  	containerID ids.ID,
   554  ) (OutboundMessage, error) {
   555  	return b.builder.createOutbound(
   556  		&p2p.Message{
   557  			Message: &p2p.Message_Get{
   558  				Get: &p2p.Get{
   559  					ChainId:     chainID[:],
   560  					RequestId:   requestID,
   561  					Deadline:    uint64(deadline),
   562  					ContainerId: containerID[:],
   563  				},
   564  			},
   565  		},
   566  		compression.TypeNone,
   567  		false,
   568  	)
   569  }
   570  
   571  func (b *outMsgBuilder) Put(
   572  	chainID ids.ID,
   573  	requestID uint32,
   574  	container []byte,
   575  ) (OutboundMessage, error) {
   576  	return b.builder.createOutbound(
   577  		&p2p.Message{
   578  			Message: &p2p.Message_Put{
   579  				Put: &p2p.Put{
   580  					ChainId:   chainID[:],
   581  					RequestId: requestID,
   582  					Container: container,
   583  				},
   584  			},
   585  		},
   586  		b.compressionType,
   587  		false,
   588  	)
   589  }
   590  
   591  func (b *outMsgBuilder) PushQuery(
   592  	chainID ids.ID,
   593  	requestID uint32,
   594  	deadline time.Duration,
   595  	container []byte,
   596  	requestedHeight uint64,
   597  ) (OutboundMessage, error) {
   598  	return b.builder.createOutbound(
   599  		&p2p.Message{
   600  			Message: &p2p.Message_PushQuery{
   601  				PushQuery: &p2p.PushQuery{
   602  					ChainId:         chainID[:],
   603  					RequestId:       requestID,
   604  					Deadline:        uint64(deadline),
   605  					Container:       container,
   606  					RequestedHeight: requestedHeight,
   607  				},
   608  			},
   609  		},
   610  		b.compressionType,
   611  		false,
   612  	)
   613  }
   614  
   615  func (b *outMsgBuilder) PullQuery(
   616  	chainID ids.ID,
   617  	requestID uint32,
   618  	deadline time.Duration,
   619  	containerID ids.ID,
   620  	requestedHeight uint64,
   621  ) (OutboundMessage, error) {
   622  	return b.builder.createOutbound(
   623  		&p2p.Message{
   624  			Message: &p2p.Message_PullQuery{
   625  				PullQuery: &p2p.PullQuery{
   626  					ChainId:         chainID[:],
   627  					RequestId:       requestID,
   628  					Deadline:        uint64(deadline),
   629  					ContainerId:     containerID[:],
   630  					RequestedHeight: requestedHeight,
   631  				},
   632  			},
   633  		},
   634  		compression.TypeNone,
   635  		false,
   636  	)
   637  }
   638  
   639  func (b *outMsgBuilder) Chits(
   640  	chainID ids.ID,
   641  	requestID uint32,
   642  	preferredID ids.ID,
   643  	preferredIDAtHeight ids.ID,
   644  	acceptedID ids.ID,
   645  ) (OutboundMessage, error) {
   646  	return b.builder.createOutbound(
   647  		&p2p.Message{
   648  			Message: &p2p.Message_Chits{
   649  				Chits: &p2p.Chits{
   650  					ChainId:             chainID[:],
   651  					RequestId:           requestID,
   652  					PreferredId:         preferredID[:],
   653  					PreferredIdAtHeight: preferredIDAtHeight[:],
   654  					AcceptedId:          acceptedID[:],
   655  				},
   656  			},
   657  		},
   658  		compression.TypeNone,
   659  		false,
   660  	)
   661  }
   662  
   663  func (b *outMsgBuilder) AppRequest(
   664  	chainID ids.ID,
   665  	requestID uint32,
   666  	deadline time.Duration,
   667  	msg []byte,
   668  ) (OutboundMessage, error) {
   669  	return b.builder.createOutbound(
   670  		&p2p.Message{
   671  			Message: &p2p.Message_AppRequest{
   672  				AppRequest: &p2p.AppRequest{
   673  					ChainId:   chainID[:],
   674  					RequestId: requestID,
   675  					Deadline:  uint64(deadline),
   676  					AppBytes:  msg,
   677  				},
   678  			},
   679  		},
   680  		b.compressionType,
   681  		false,
   682  	)
   683  }
   684  
   685  func (b *outMsgBuilder) AppResponse(chainID ids.ID, requestID uint32, msg []byte) (OutboundMessage, error) {
   686  	return b.builder.createOutbound(
   687  		&p2p.Message{
   688  			Message: &p2p.Message_AppResponse{
   689  				AppResponse: &p2p.AppResponse{
   690  					ChainId:   chainID[:],
   691  					RequestId: requestID,
   692  					AppBytes:  msg,
   693  				},
   694  			},
   695  		},
   696  		b.compressionType,
   697  		false,
   698  	)
   699  }
   700  
   701  func (b *outMsgBuilder) AppError(chainID ids.ID, requestID uint32, errorCode int32, errorMessage string) (OutboundMessage, error) {
   702  	return b.builder.createOutbound(
   703  		&p2p.Message{
   704  			Message: &p2p.Message_AppError{
   705  				AppError: &p2p.AppError{
   706  					ChainId:      chainID[:],
   707  					RequestId:    requestID,
   708  					ErrorCode:    errorCode,
   709  					ErrorMessage: errorMessage,
   710  				},
   711  			},
   712  		},
   713  		b.compressionType,
   714  		false,
   715  	)
   716  }
   717  
   718  func (b *outMsgBuilder) AppGossip(chainID ids.ID, msg []byte) (OutboundMessage, error) {
   719  	return b.builder.createOutbound(
   720  		&p2p.Message{
   721  			Message: &p2p.Message_AppGossip{
   722  				AppGossip: &p2p.AppGossip{
   723  					ChainId:  chainID[:],
   724  					AppBytes: msg,
   725  				},
   726  			},
   727  		},
   728  		b.compressionType,
   729  		false,
   730  	)
   731  }