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 }