From 08a3c3fc2177c7b6fc4a28b62d0e1c47f4d922b6 Mon Sep 17 00:00:00 2001 From: skaunov Date: Fri, 10 Oct 2025 18:49:49 +0300 Subject: [PATCH 1/4] fix[kad]: enable putting `Record` with `None` `publisher` in a confusing way. Sorry for that, see for some details. --- protocols/kad/CHANGELOG.md | 2 ++ protocols/kad/src/behaviour.rs | 4 +++- protocols/kad/src/behaviour/test.rs | 6 +++++- protocols/kad/src/record.rs | 10 ++++++++++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index d50f7319af8..ba0478c7341 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -1,3 +1,5 @@ +- minimized #6176 + ## 0.49.0 - Remove no longer constructed GetRecordError::QuorumFailed. diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index f5f44baec74..f3eaaa6c592 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -870,7 +870,9 @@ where mut record: Record, quorum: Quorum, ) -> Result { - record.publisher = Some(*self.kbuckets.local_key().preimage()); + if record.publisher.is_some() { + record.publisher = Some(*self.kbuckets.local_key().preimage()) + } self.store.put(record.clone())?; record.expires = record .expires diff --git a/protocols/kad/src/behaviour/test.rs b/protocols/kad/src/behaviour/test.rs index 3819276d350..0c8cbf66adc 100644 --- a/protocols/kad/src/behaviour/test.rs +++ b/protocols/kad/src/behaviour/test.rs @@ -562,7 +562,11 @@ fn get_record_not_found() { /// is equal to the configured replication factor. #[test] fn put_record() { - fn prop(records: Vec, seed: Seed, filter_records: bool, drop_records: bool) { + fn prop(mut records: Vec, seed: Seed, filter_records: bool, drop_records: bool) { + tracing::trace!("remove records without a publisher"); + // this test relies on counting republished `Record` against `records.len()` + records.retain(|r| r.publisher.is_some()); + let mut rng = StdRng::from_seed(seed.0); let replication_factor = NonZeroUsize::new(rng.gen_range(1..(K_VALUE.get() / 2) + 1)).unwrap(); diff --git a/protocols/kad/src/record.rs b/protocols/kad/src/record.rs index fea17f826a4..f0a99db22ef 100644 --- a/protocols/kad/src/record.rs +++ b/protocols/kad/src/record.rs @@ -94,6 +94,16 @@ impl Record { where K: Into, { + Record { + key: key.into(), + value, + publisher: Some(PeerId::random()), + expires: None, + } + } + + /// Creates a new record for insertion into the DHT. + pub fn new_anonymous(key: impl Into, value: Vec) -> Self { Record { key: key.into(), value, From bf0866cb597c09d0b7fe9615bd1e249dff3db1a2 Mon Sep 17 00:00:00 2001 From: skaunov Date: Sat, 11 Oct 2025 01:48:03 +0300 Subject: [PATCH 2/4] fmt --- protocols/kad/src/behaviour/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/kad/src/behaviour/test.rs b/protocols/kad/src/behaviour/test.rs index 0c8cbf66adc..41d03f4f772 100644 --- a/protocols/kad/src/behaviour/test.rs +++ b/protocols/kad/src/behaviour/test.rs @@ -566,7 +566,7 @@ fn put_record() { tracing::trace!("remove records without a publisher"); // this test relies on counting republished `Record` against `records.len()` records.retain(|r| r.publisher.is_some()); - + let mut rng = StdRng::from_seed(seed.0); let replication_factor = NonZeroUsize::new(rng.gen_range(1..(K_VALUE.get() / 2) + 1)).unwrap(); From 8783cf9f2952fec5c137d009e95abc72d12006a8 Mon Sep 17 00:00:00 2001 From: Sergey Kaunov Date: Mon, 20 Oct 2025 17:03:23 +0300 Subject: [PATCH 3/4] Update protocols/kad/CHANGELOG.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: João Oliveira --- protocols/kad/CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index ba0478c7341..81ae5ee5649 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -1,4 +1,5 @@ -- minimized #6176 + Add new `new_anonymous` function to enable putting Records without a publisher. + See [PR 6176](https://github.com/libp2p/rust-libp2p/pull/6176) ## 0.49.0 From 82c7d6d325c24feb6928f5092809e94083dc50bb Mon Sep 17 00:00:00 2001 From: skaunov Date: Tue, 21 Oct 2025 21:17:24 +0300 Subject: [PATCH 4/4] address review --- protocols/kad/src/behaviour.rs | 7 ++++--- protocols/kad/src/behaviour/test.rs | 10 ++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index f3eaaa6c592..460fd29a775 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -870,9 +870,10 @@ where mut record: Record, quorum: Quorum, ) -> Result { - if record.publisher.is_some() { - record.publisher = Some(*self.kbuckets.local_key().preimage()) - } + record + .publisher + .and(Some(*self.kbuckets.local_key().preimage())); + self.store.put(record.clone())?; record.expires = record .expires diff --git a/protocols/kad/src/behaviour/test.rs b/protocols/kad/src/behaviour/test.rs index 41d03f4f772..6c419e4d28c 100644 --- a/protocols/kad/src/behaviour/test.rs +++ b/protocols/kad/src/behaviour/test.rs @@ -557,16 +557,12 @@ fn get_record_not_found() { })) } -/// A node joining a fully connected network via three (ALPHA_VALUE) bootnodes +/// A node joining a fully connected network via three (`ALPHA_VALUE`) bootnodes /// should be able to put a record to the X closest nodes of the network where X /// is equal to the configured replication factor. #[test] fn put_record() { - fn prop(mut records: Vec, seed: Seed, filter_records: bool, drop_records: bool) { - tracing::trace!("remove records without a publisher"); - // this test relies on counting republished `Record` against `records.len()` - records.retain(|r| r.publisher.is_some()); - + fn prop(records: Vec, seed: Seed, filter_records: bool, drop_records: bool) { let mut rng = StdRng::from_seed(seed.0); let replication_factor = NonZeroUsize::new(rng.gen_range(1..(K_VALUE.get() / 2) + 1)).unwrap(); @@ -613,6 +609,8 @@ fn put_record() { #[allow(clippy::mutable_key_type)] // False positive, we never modify `Bytes`. let records = records .into_iter() + // Exclude records without a publisher. + .filter(|r| r.publisher.is_some()) .take(num_total) .map(|mut r| { // We don't want records to expire prematurely, as they would