Skip to content

Commit 8d9b7ef

Browse files
committed
feat(core): add peer-record-interop feature for cross-implementation compatibility
Add optional `peer-record-interop` feature flag to enable standard libp2p peer-record format for interoperability with Go and JavaScript implementations. When enabled, uses: - PAYLOAD_TYPE: [0x03, 0x01] (multicodec identifier) - DOMAIN_SEP: "libp2p-peer-record" When disabled (default), maintains backward compatibility with existing Rust libp2p peer records using legacy constants: - PAYLOAD_TYPE: "/libp2p/routing-state-record" - DOMAIN_SEP: "libp2p-routing-state" The legacy format is marked as deprecated to guide users toward the standard format in future releases. Changes: - Add `peer-record-interop` feature flag to core/Cargo.toml - Add conditional compilation for PAYLOAD_TYPE and DOMAIN_SEP constants - Mark legacy constants as deprecated with migration guidance - Update internal methods to handle both constant types (&[u8] vs &str) - Gate interop tests to only run with feature enabled - Update CHANGELOG and add inline documentation Migration: Users needing cross-implementation compatibility should add: `libp2p-core = { version = "0.43.2", features = ["peer-record-interop"] }`
1 parent 93a2d93 commit 8d9b7ef

File tree

6 files changed

+78
-12
lines changed

6 files changed

+78
-12
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ libp2p = { version = "0.56.1", path = "libp2p" }
7878
libp2p-allow-block-list = { version = "0.6.0", path = "misc/allow-block-list" }
7979
libp2p-autonat = { version = "0.15.0", path = "protocols/autonat" }
8080
libp2p-connection-limits = { version = "0.6.0", path = "misc/connection-limits" }
81-
libp2p-core = { version = "0.44.0", path = "core" }
81+
libp2p-core = { version = "0.43.2", path = "core" }
8282
libp2p-dcutr = { version = "0.14.0", path = "protocols/dcutr" }
8383
libp2p-dns = { version = "0.44.0", path = "transports/dns" }
8484
libp2p-floodsub = { version = "0.47.0", path = "protocols/floodsub" }

core/CHANGELOG.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1-
## 0.44.0
2-
- Update `libp2p::core::peer_record` Fix peer record domain and payload type to match Go/JS implementations.
1+
## 0.43.2
2+
3+
- Add `peer-record-interop` feature for cross-implementation compatibility with Go and JavaScript libp2p.
4+
When enabled, uses standard libp2p-peer-record domain and payload type constants for interoperability.
5+
When disabled (default), maintains backward compatibility with existing Rust libp2p peer records using legacy routing-state-record constants.
6+
7+
To enable: Add `features = ["peer-record-interop"]` to your `libp2p-core` dependency.
8+
9+
**Note:** Legacy constants are deprecated and will become opt-in in a future version.
10+
311
See [PR 6205](https://github.com/libp2p/rust-libp2p/pull/6205).
412

513
## 0.43.1

core/Cargo.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "libp2p-core"
33
edition.workspace = true
44
rust-version = { workspace = true }
55
description = "Core traits and structs of libp2p"
6-
version = "0.44.0"
6+
version = "0.43.2"
77
authors = ["Parity Technologies <admin@parity.io>"]
88
license = "MIT"
99
repository = "https://github.com/libp2p/rust-libp2p"
@@ -39,6 +39,13 @@ libp2p-identity = { workspace = true, features = ["ed25519", "rand"] }
3939
[features]
4040
serde = ["multihash/serde-codec", "libp2p-identity/serde"]
4141

42+
# Enable standard libp2p peer-record format for cross-implementation compatibility.
43+
# When enabled, peer records use the standard multicodec identifier (0x0301) and
44+
# "libp2p-peer-record" domain, ensuring compatibility with Go and JavaScript implementations.
45+
# When disabled (default), uses legacy "libp2p-routing-state" format for backward compatibility
46+
# with existing Rust libp2p deployments. The legacy format is deprecated.
47+
peer-record-interop = []
48+
4249
# Passing arguments to the docsrs builder in order to properly document cfg's.
4350
# More information: https://docs.rs/about/builds#cross-compiling
4451
[package.metadata.docs.rs]

core/src/peer_record.rs

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,46 @@ use web_time::SystemTime;
44

55
use crate::{proto, signed_envelope, signed_envelope::SignedEnvelope, DecodeError, Multiaddr};
66

7+
// ## Cross-Implementation Compatibility
8+
//
9+
// By default, this implementation uses legacy constants for backward compatibility with existing
10+
// Rust libp2p peer records. To enable interoperability with Go and JavaScript libp2p implementations,
11+
// enable the `peer-record-interop` feature in your Cargo.toml:
12+
//
13+
// ```toml
14+
// libp2p-core = { version = "0.43.2", features = ["peer-record-interop"] }
15+
// ```
16+
//
17+
// The legacy format is deprecated and will become opt-in in a future release.
18+
719
// The type hint used to identify peer records in an Envelope.
8-
// Defined in https://github.com/multiformats/multicodec/blob/master/table.csv
9-
// with name "libp2p-peer-record"
20+
// With the `peer-record-interop` feature, uses the standard libp2p-peer-record
21+
// multicodec identifier as defined in https://github.com/multiformats/multicodec/blob/master/table.csv
22+
// Without the feature (default), uses the legacy routing-state-record format.
23+
#[cfg(feature = "peer-record-interop")]
1024
const PAYLOAD_TYPE: &[u8] = &[0x03, 0x01];
1125

26+
#[cfg(not(feature = "peer-record-interop"))]
27+
#[deprecated(
28+
since = "0.43.2",
29+
note = "Legacy routing-state-record format. Enable the `peer-record-interop` feature for cross-implementation compatibility with Go/JS libp2p"
30+
)]
31+
const PAYLOAD_TYPE: &str = "/libp2p/routing-state-record";
32+
1233
// The domain string used for peer records contained in a Envelope.
13-
// See https://github.com/libp2p/specs/blob/master/RFC/0002-signed-envelopes.md
34+
// With the `peer-record-interop` feature, uses the standard domain string
35+
// as defined in https://github.com/libp2p/specs/blob/master/RFC/0002-signed-envelopes.md
36+
// Without the feature (default), uses the legacy domain string.
37+
#[cfg(feature = "peer-record-interop")]
1438
const DOMAIN_SEP: &str = "libp2p-peer-record";
1539

40+
#[cfg(not(feature = "peer-record-interop"))]
41+
#[deprecated(
42+
since = "0.43.2",
43+
note = "Legacy routing-state domain. Enable the `peer-record-interop` feature for cross-implementation compatibility with Go/JS libp2p"
44+
)]
45+
const DOMAIN_SEP: &str = "libp2p-routing-state";
46+
1647
/// Represents a peer routing record.
1748
///
1849
/// Peer records are designed to be distributable and carry a signature by being wrapped in a signed
@@ -35,11 +66,17 @@ impl PeerRecord {
3566
///
3667
/// If this function succeeds, the [`SignedEnvelope`] contained a peer record with a valid
3768
/// signature and can hence be considered authenticated.
69+
#[cfg_attr(not(feature = "peer-record-interop"), allow(deprecated))]
3870
pub fn from_signed_envelope(envelope: SignedEnvelope) -> Result<Self, FromEnvelopeError> {
3971
use quick_protobuf::MessageRead;
4072

73+
#[cfg(feature = "peer-record-interop")]
74+
let payload_type = PAYLOAD_TYPE;
75+
#[cfg(not(feature = "peer-record-interop"))]
76+
let payload_type = PAYLOAD_TYPE.as_bytes();
77+
4178
let (payload, signing_key) =
42-
envelope.payload_and_signing_key(String::from(DOMAIN_SEP), PAYLOAD_TYPE)?;
79+
envelope.payload_and_signing_key(String::from(DOMAIN_SEP), payload_type)?;
4380
let mut reader = BytesReader::from_bytes(payload);
4481
let record = proto::PeerRecord::from_reader(&mut reader, payload).map_err(DecodeError)?;
4582

@@ -68,6 +105,7 @@ impl PeerRecord {
68105
///
69106
/// This is the same key that is used for authenticating every libp2p connection of your
70107
/// application, i.e. what you use when setting up your [`crate::transport::Transport`].
108+
#[cfg_attr(not(feature = "peer-record-interop"), allow(deprecated))]
71109
pub fn new(key: &Keypair, addresses: Vec<Multiaddr>) -> Result<Self, SigningError> {
72110
use quick_protobuf::MessageWrite;
73111

@@ -98,10 +136,15 @@ impl PeerRecord {
98136
buf
99137
};
100138

139+
#[cfg(feature = "peer-record-interop")]
140+
let payload_type = PAYLOAD_TYPE.to_vec();
141+
#[cfg(not(feature = "peer-record-interop"))]
142+
let payload_type = PAYLOAD_TYPE.as_bytes().to_vec();
143+
101144
let envelope = SignedEnvelope::new(
102145
key,
103146
String::from(DOMAIN_SEP),
104-
PAYLOAD_TYPE.to_vec(),
147+
payload_type,
105148
payload,
106149
)?;
107150

@@ -172,6 +215,7 @@ mod tests {
172215
}
173216

174217
#[test]
218+
#[cfg_attr(not(feature = "peer-record-interop"), allow(deprecated))]
175219
fn mismatched_signature() {
176220
use quick_protobuf::MessageWrite;
177221

@@ -199,10 +243,15 @@ mod tests {
199243
buf
200244
};
201245

246+
#[cfg(feature = "peer-record-interop")]
247+
let payload_type = PAYLOAD_TYPE.to_vec();
248+
#[cfg(not(feature = "peer-record-interop"))]
249+
let payload_type = PAYLOAD_TYPE.as_bytes().to_vec();
250+
202251
SignedEnvelope::new(
203252
&identity_b,
204253
String::from(DOMAIN_SEP),
205-
PAYLOAD_TYPE.to_vec(),
254+
payload_type,
206255
payload,
207256
)
208257
.unwrap()

core/tests/peer_record_interop.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
#[cfg(test)]
1+
// These tests verify interoperability with Go and JS libp2p implementations
2+
// and require the peer-record-interop feature to use the standard constants.
3+
#[cfg(all(test, feature = "peer-record-interop"))]
24
mod tests {
35
use libp2p_core::{PeerRecord, SignedEnvelope};
46

0 commit comments

Comments
 (0)