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