Skip to content

Commit 7601514

Browse files
authored
protocols/kad: Expose kbucket distance range (#1680)
Add `KBucketRef::range` exposing the minimum inclusive and maximum inclusive `Distance` for the bucket.
1 parent 18390fa commit 7601514

File tree

2 files changed

+63
-0
lines changed

2 files changed

+63
-0
lines changed

protocols/kad/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
- Update `libp2p-core` and `libp2p-swarm` dependencies.
44

5+
- Add `KBucketRef::range` exposing the minimum inclusive and maximum inclusive
6+
`Distance` for the bucket
7+
([PR 1680](https://github.com/libp2p/rust-libp2p/pull/1680)).
8+
59
# 0.21.0 [2020-07-01]
610

711
- Remove `KademliaEvent::Discovered`

protocols/kad/src/kbucket.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,18 @@ impl BucketIndex {
116116
self.0
117117
}
118118

119+
/// Returns the minimum inclusive and maximum inclusive [`Distance`]
120+
/// included in the bucket for this index.
121+
fn range(&self) -> (Distance, Distance) {
122+
let min = Distance(U256::pow(U256::from(2), U256::from(self.0)));
123+
if self.0 == u8::MAX.into() {
124+
(min, Distance(U256::MAX))
125+
} else {
126+
let max = Distance(U256::pow(U256::from(2), U256::from(self.0 + 1)) - 1);
127+
(min, max)
128+
}
129+
}
130+
119131
/// Generates a random distance that falls into the bucket for this index.
120132
fn rand_distance(&self, rng: &mut impl rand::Rng) -> Distance {
121133
let mut bytes = [0u8; 32];
@@ -447,6 +459,12 @@ where
447459
TKey: Clone + AsRef<KeyBytes>,
448460
TVal: Clone
449461
{
462+
/// Returns the minimum inclusive and maximum inclusive [`Distance`] for
463+
/// this bucket.
464+
pub fn range(&self) -> (Distance, Distance) {
465+
self.index.range()
466+
}
467+
450468
/// Checks whether the bucket is empty.
451469
pub fn is_empty(&self) -> bool {
452470
self.num_entries() == 0
@@ -525,6 +543,47 @@ mod tests {
525543
}
526544
}
527545

546+
#[test]
547+
fn buckets_are_non_overlapping_and_exhaustive() {
548+
let local_key = Key::from(PeerId::random());
549+
let timeout = Duration::from_secs(0);
550+
let mut table = KBucketsTable::<KeyBytes, ()>::new(local_key.into(), timeout);
551+
552+
let mut prev_max = U256::from(0);
553+
554+
for bucket in table.iter() {
555+
let (min, max) = bucket.range();
556+
assert_eq!(Distance(prev_max + U256::from(1)), min);
557+
prev_max = max.0;
558+
}
559+
560+
assert_eq!(U256::MAX, prev_max);
561+
}
562+
563+
#[test]
564+
fn bucket_contains_range() {
565+
fn prop(ix: u8) {
566+
let index = BucketIndex(ix as usize);
567+
let mut bucket = KBucket::<Key<PeerId>, ()>::new(Duration::from_secs(0));
568+
let bucket_ref = KBucketRef {
569+
index,
570+
bucket: &mut bucket,
571+
};
572+
573+
let (min, max) = bucket_ref.range();
574+
575+
assert!(min <= max);
576+
577+
assert!(bucket_ref.contains(&min));
578+
assert!(bucket_ref.contains(&max));
579+
580+
assert!(!bucket_ref.contains(&Distance(min.0 - 1)));
581+
assert!(!bucket_ref.contains(&Distance(max.0 + 1)));
582+
}
583+
584+
quickcheck(prop as fn(_));
585+
}
586+
528587
#[test]
529588
fn rand_distance() {
530589
fn prop(ix: u8) -> bool {

0 commit comments

Comments
 (0)