From c99cb96e8c8ab408a6425cd5a99fb6f4a655c709 Mon Sep 17 00:00:00 2001 From: Suphanat Chunhapanya Date: Sun, 16 Nov 2025 18:35:49 -0300 Subject: [PATCH 1/3] identify: have MaxMultiselectVersion --- p2p/protocol/identify/id.go | 8 ++++++++ p2p/protocol/identify/pb/identify.pb.go | 19 +++++++++++++++---- p2p/protocol/identify/pb/identify.proto | 4 ++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/p2p/protocol/identify/id.go b/p2p/protocol/identify/id.go index ca56c364f9..b8e5934294 100644 --- a/p2p/protocol/identify/id.go +++ b/p2p/protocol/identify/id.go @@ -44,6 +44,8 @@ const ( DefaultTimeout = 5 * time.Second // ServiceName is the default identify service name ServiceName = "libp2p.identify" + // Maximum multistream-select version this implementation supports + MaxMultiselectVersion = 2 legacyIDSize = 2 * 1024 signedIDSize = 8 * 1024 @@ -151,6 +153,8 @@ type idService struct { UserAgent string ProtocolVersion string + MaxMultiselectVersion uint32 + metricsTracer MetricsTracer setupCompleted chan struct{} // is closed when Start has finished setting up @@ -204,6 +208,7 @@ func NewIDService(h host.Host, opts ...Option) (*idService, error) { Host: h, UserAgent: userAgent, ProtocolVersion: cfg.protocolVersion, + MaxMultiselectVersion: MaxMultiselectVersion, ctx: ctx, ctxCancel: cancel, conns: make(map[network.Conn]entry), @@ -679,6 +684,7 @@ func (ids *idService) createBaseIdentifyResponse(conn network.Conn, snapshot *id // set protocol versions mes.ProtocolVersion = &ids.ProtocolVersion mes.AgentVersion = &ids.UserAgent + mes.MaxMultiselectVersion = &ids.MaxMultiselectVersion return mes } @@ -823,9 +829,11 @@ func (ids *idService) consumeMessage(mes *pb.Identify, c network.Conn, isPush bo // get protocol versions pv := mes.GetProtocolVersion() av := mes.GetAgentVersion() + mv := mes.GetMaxMultiselectVersion() ids.Host.Peerstore().Put(p, "ProtocolVersion", pv) ids.Host.Peerstore().Put(p, "AgentVersion", av) + ids.Host.Peerstore().Put(p, "MaxMultiselectVersion", mv) // get the key from the other side. we may not have it (no-auth transport) ids.consumeReceivedPubKey(c, mes.PublicKey) diff --git a/p2p/protocol/identify/pb/identify.pb.go b/p2p/protocol/identify/pb/identify.pb.go index fc92dc9a05..45cee4a6ed 100644 --- a/p2p/protocol/identify/pb/identify.pb.go +++ b/p2p/protocol/identify/pb/identify.pb.go @@ -46,8 +46,11 @@ type Identify struct { // see github.com/libp2p/go-libp2p/core/record/pb/envelope.proto and // github.com/libp2p/go-libp2p/core/peer/pb/peer_record.proto for message definitions. SignedPeerRecord []byte `protobuf:"bytes,8,opt,name=signedPeerRecord" json:"signedPeerRecord,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // maxMultiselectVersion contains the maximum multistream-select version the node supports. + // If it's absent, we assume that it's 1. + MaxMultiselectVersion *uint32 `protobuf:"varint,9,opt,name=maxMultiselectVersion" json:"maxMultiselectVersion,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Identify) Reset() { @@ -129,11 +132,18 @@ func (x *Identify) GetSignedPeerRecord() []byte { return nil } +func (x *Identify) GetMaxMultiselectVersion() uint32 { + if x != nil && x.MaxMultiselectVersion != nil { + return *x.MaxMultiselectVersion + } + return 0 +} + var File_p2p_protocol_identify_pb_identify_proto protoreflect.FileDescriptor const file_p2p_protocol_identify_pb_identify_proto_rawDesc = "" + "\n" + - "'p2p/protocol/identify/pb/identify.proto\x12\videntify.pb\"\x86\x02\n" + + "'p2p/protocol/identify/pb/identify.proto\x12\videntify.pb\"\xbc\x02\n" + "\bIdentify\x12(\n" + "\x0fprotocolVersion\x18\x05 \x01(\tR\x0fprotocolVersion\x12\"\n" + "\fagentVersion\x18\x06 \x01(\tR\fagentVersion\x12\x1c\n" + @@ -141,7 +151,8 @@ const file_p2p_protocol_identify_pb_identify_proto_rawDesc = "" + "\vlistenAddrs\x18\x02 \x03(\fR\vlistenAddrs\x12\"\n" + "\fobservedAddr\x18\x04 \x01(\fR\fobservedAddr\x12\x1c\n" + "\tprotocols\x18\x03 \x03(\tR\tprotocols\x12*\n" + - "\x10signedPeerRecord\x18\b \x01(\fR\x10signedPeerRecordB6Z4github.com/libp2p/go-libp2p/p2p/protocol/identify/pb" + "\x10signedPeerRecord\x18\b \x01(\fR\x10signedPeerRecord\x124\n" + + "\x15maxMultiselectVersion\x18\t \x01(\rR\x15maxMultiselectVersionB6Z4github.com/libp2p/go-libp2p/p2p/protocol/identify/pb" var ( file_p2p_protocol_identify_pb_identify_proto_rawDescOnce sync.Once diff --git a/p2p/protocol/identify/pb/identify.proto b/p2p/protocol/identify/pb/identify.proto index 113438708a..5e5fc74ba3 100644 --- a/p2p/protocol/identify/pb/identify.proto +++ b/p2p/protocol/identify/pb/identify.proto @@ -35,4 +35,8 @@ message Identify { // see github.com/libp2p/go-libp2p/core/record/pb/envelope.proto and // github.com/libp2p/go-libp2p/core/peer/pb/peer_record.proto for message definitions. optional bytes signedPeerRecord = 8; + + // maxMultiselectVersion contains the maximum multistream-select version the node supports. + // If it's absent, we assume that it's 1. + optional uint32 maxMultiselectVersion = 9; } From db2544333e5eee66b6b35612bcc39223829c1949 Mon Sep 17 00:00:00 2001 From: Suphanat Chunhapanya Date: Mon, 17 Nov 2025 12:40:22 -0300 Subject: [PATCH 2/3] basichost: initial commit for protocol id compress --- p2p/host/basic/basic_host.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/p2p/host/basic/basic_host.go b/p2p/host/basic/basic_host.go index d98aa0e337..e80f4dd0a6 100644 --- a/p2p/host/basic/basic_host.go +++ b/p2p/host/basic/basic_host.go @@ -477,6 +477,10 @@ func (h *BasicHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.I return nil, err } + if h.supportProtocolAbbreviation(p) { + // TODO: if the protocol ID abbreviation is supported, do something here. + } + if pref != "" { if err := s.SetProtocol(pref); err != nil { return nil, err @@ -528,6 +532,17 @@ func (h *BasicHost) preferredProtocol(p peer.ID, pids []protocol.ID) (protocol.I return out, nil } +func (h *BasicHost) supportProtocolAbbreviation(p peer.ID) bool { + mv, err := h.Peerstore().Get(p, "MaxMultiselectVersion") + if err != nil { + // if there is no value, assume it's not supported. + return false + } + // TODO: Check the version with go-multistream + _ = mv + return false +} + // Connect ensures there is a connection between this host and the peer with // given peer.ID. If there is not an active connection, Connect will issue a // h.Network.Dial, and block until a connection is open, or an error is returned. From bf5158c9eb7f501fd1cfd417402b0a83f90a254f Mon Sep 17 00:00:00 2001 From: Suphanat Chunhapanya Date: Mon, 17 Nov 2025 16:52:31 -0300 Subject: [PATCH 3/3] basichost: use multistream2 --- go.mod | 3 +++ go.sum | 4 ++-- p2p/host/basic/basic_host.go | 19 +++++++++++-------- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 2cf7144b66..ec93d66fde 100644 --- a/go.mod +++ b/go.mod @@ -105,3 +105,6 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.4.1 // indirect ) + +// TODO: remove this when it's done +replace github.com/multiformats/go-multistream => github.com/ppopth/go-multistream v0.0.0-20251120232627-f8839ce1ab11 diff --git a/go.sum b/go.sum index f879d2c2c1..eb2ff41d31 100644 --- a/go.sum +++ b/go.sum @@ -104,8 +104,6 @@ github.com/multiformats/go-multicodec v0.9.1/go.mod h1:LLWNMtyV5ithSBUo3vFIMaeDy github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -github.com/multiformats/go-multistream v0.6.1 h1:4aoX5v6T+yWmc2raBHsTvzmFhOI8WVOer28DeBBEYdQ= -github.com/multiformats/go-multistream v0.6.1/go.mod h1:ksQf6kqHAb6zIsyw7Zm+gAuVo57Qbq84E27YlYqavqw= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -156,6 +154,8 @@ github.com/pion/webrtc/v4 v4.1.2 h1:mpuUo/EJ1zMNKGE79fAdYNFZBX790KE7kQQpLMjjR54= github.com/pion/webrtc/v4 v4.1.2/go.mod h1:xsCXiNAmMEjIdFxAYU0MbB3RwRieJsegSB2JZsGN+8U= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ppopth/go-multistream v0.0.0-20251120232627-f8839ce1ab11 h1:gMuSK7z8Tn0w9v4BEvWkpNREQ1ntq6pTJyleZdB9fXM= +github.com/ppopth/go-multistream v0.0.0-20251120232627-f8839ce1ab11/go.mod h1:sIFlNOs3fTbw+XPuWqQ0MgfxtPcVu5N8R5Xg5+H/bcE= github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= diff --git a/p2p/host/basic/basic_host.go b/p2p/host/basic/basic_host.go index e80f4dd0a6..25ea763fb3 100644 --- a/p2p/host/basic/basic_host.go +++ b/p2p/host/basic/basic_host.go @@ -477,15 +477,16 @@ func (h *BasicHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.I return nil, err } - if h.supportProtocolAbbreviation(p) { - // TODO: if the protocol ID abbreviation is supported, do something here. - } - if pref != "" { if err := s.SetProtocol(pref); err != nil { return nil, err } - lzcon := msmux.NewMSSelect(s, pref) + var lzcon msmux.LazyConn + if h.supportProtocolAbbreviation(p) { + lzcon = msmux.NewMSSelect2(s, pref, pids) + } else { + lzcon = msmux.NewMSSelect(s, pref) + } return &streamWrapper{ Stream: s, rw: lzcon, @@ -538,9 +539,11 @@ func (h *BasicHost) supportProtocolAbbreviation(p peer.ID) bool { // if there is no value, assume it's not supported. return false } - // TODO: Check the version with go-multistream - _ = mv - return false + maxVersion, ok := mv.(uint32) + if !ok { + return false + } + return maxVersion >= msmux.AbbrevSupportedMSSVersion } // Connect ensures there is a connection between this host and the peer with