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 d98aa0e337..25ea763fb3 100644 --- a/p2p/host/basic/basic_host.go +++ b/p2p/host/basic/basic_host.go @@ -481,7 +481,12 @@ func (h *BasicHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.I 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, @@ -528,6 +533,19 @@ 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 + } + 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 // 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. 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; }