Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- Reject messages from invalid peers (P1.10-3)

### Changed

- Move to stable MSRV 1.85
- Move to rust edition 2024
- Limit the number of peers accepted in a single Nodes message (P1.10-4)
- Increase the POW produced during ID generation (P1.10-2)

## [0.7.0] - 2024-10-21

Expand Down
4 changes: 4 additions & 0 deletions src/handling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ impl MessageHandler {
let src = remote_peer_addr.ip();
if !PeerNode::verify_header(header, &src) {
error!("Invalid Id {header:?} - from {src}");
continue;
}

let remote_peer = PeerNode::from_socket(
Expand Down Expand Up @@ -278,6 +279,9 @@ impl MessageHandler {
.iter()
//filter out my ID to avoid loopback
.filter(|&n| &n.id != self.my_header.binary_id().as_binary())
// Limit the number of peers accepted in a single Nodes message to a
// reasonable bound
.take(K_K * 2)
.filter(|&n| {
let h = self.my_header.binary_id().calculate_distance(&n.id);
match h {
Expand Down
42 changes: 25 additions & 17 deletions src/kbucket/bucket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub enum NodeInsertError<TNode> {
MismatchVersion(TNode, Version),
}

impl<'a, TNode> NodeInsertOk<'a, TNode> {
impl<TNode> NodeInsertOk<'_, TNode> {
/// Returns an optional reference to the node pending eviction.
pub fn pending_eviction(&self) -> Option<&TNode> {
match self {
Expand Down Expand Up @@ -325,17 +325,33 @@ mod tests {

#[test]
fn test_lru_base_5secs() -> Result<()> {
// Create all the nodes at the beginning to ensure that PoW is not a
// factor in the test timing.
let root = PeerNode::generate("127.0.0.1:666", 0)?;
let node1 = PeerNode::generate("192.168.1.1:8080", 0)?;
let node1_copy = PeerNode::generate("192.168.1.1:8080", 0)?;
let node1_copy2 = PeerNode::generate("192.168.1.1:8080", 0)?;
let node2 = PeerNode::generate("192.168.1.2:8080", 0)?;

let mut additionals = vec![];
for i in 2..21 {
additionals.push(PeerNode::generate(
&format!("192.168.1.{}:8080", i)[..],
0,
)?);
}

let pending = PeerNode::generate("192.168.1.21:8080", 0)?;
let pending_2 = PeerNode::generate("192.168.1.21:8080", 0)?;
Comment on lines +328 to +345
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-generating PeerNodes here sets seen_at at generation time (Node::new uses Instant::now()), so if PeerNode::generate becomes slow (e.g., due to the increased PoW difficulty) nodes may already be close to (or past) node_ttl by the time they’re inserted. That can change the behavior of this TTL-sensitive test and make it flaky. To keep the PoW work out of the timed portion without aging the nodes, consider precomputing the BinaryIDs up front and constructing PeerNodes via PeerNode::from_socket right before insertion (so seen_at is set at insertion time).

Copilot uses AI. Check for mistakes.

let mut config = BucketConfig::default();
config.node_evict_after = Duration::from_millis(1000);
config.node_ttl = Duration::from_secs(5);

let mut route_table = Tree::new(root, config);

let bucket = route_table.bucket_for_test();
let node1 = PeerNode::generate("192.168.1.1:8080", 0)?;
let id_node1 = node1.id().as_binary().clone();
let node1_copy = PeerNode::generate("192.168.1.1:8080", 0)?;
match bucket.insert(node1).expect("This should return an ok()") {
NodeInsertOk::Inserted { .. } => {}
_ => assert!(false),
Expand All @@ -351,7 +367,6 @@ mod tests {
_ => assert!(false),
}
assert_eq!(Some(&id_node1), bucket.last_id());
let node2 = PeerNode::generate("192.168.1.2:8080", 0)?;
let id_node2 = node2.id().as_binary().clone();

match bucket.insert(node2).expect("This should return an ok()") {
Expand All @@ -364,7 +379,7 @@ mod tests {
assert_eq!(Some(&id_node1), bucket.least_used_id());

match bucket
.insert(PeerNode::generate("192.168.1.1:8080", 0)?)
.insert(node1_copy2)
.expect("This should return an ok()")
{
NodeInsertOk::Updated { .. } => {}
Expand All @@ -378,22 +393,15 @@ mod tests {
assert_eq!(&id_node2, a.unwrap().id().as_binary());
assert_eq!(Some(&id_node1), bucket.last_id());
assert_eq!(Some(&id_node1), bucket.least_used_id());
for i in 2..21 {
match bucket
.insert(PeerNode::generate(
&format!("192.168.1.{}:8080", i)[..],
0,
)?)
.expect("This should return an ok()")
{
for n in additionals {
match bucket.insert(n).expect("This should return an ok()") {
NodeInsertOk::Inserted { .. } => {
assert!(bucket.pick::<K_BETA>().count() <= K_BETA);
}
_ => assert!(false),
}
}
assert_eq!(bucket.pick::<K_BETA>().count(), K_BETA);
let pending = PeerNode::generate("192.168.1.21:8080", 0)?;
let pending_id = pending.id().as_binary().clone();
match bucket.insert(pending).expect_err("this should be error") {
NodeInsertError::Full(pending) => {
Expand All @@ -409,9 +417,9 @@ mod tests {
&pending_id
);
thread::sleep(Duration::from_secs(1));
let pending =
PeerNode::generate("192.168.1.21:8080", 0)?;
match bucket.insert(pending).expect("this should be ok")
match bucket
.insert(pending_2)
.expect("this should be ok")
{
NodeInsertOk::Inserted { inserted: _ } => {}
v => {
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const K_K: usize = get_k_k();
const K_ID_LEN_BYTES: usize = 16;
const K_NONCE_LEN: usize = 4;
const K_DIFF_MIN_BIT: usize = 8;
const K_DIFF_PRODUCED_BIT: usize = 8;
const K_DIFF_PRODUCED_BIT: usize = 20;
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raising K_DIFF_PRODUCED_BIT to 20 significantly increases the work done in BinaryID::generate (expected ~2^20 hash iterations per PeerNode::generate). This will substantially slow node startup and is also likely to make existing unit tests prohibitively slow (e.g., src/kbucket/key.rs has tests generating hundreds of PeerNodes). If the intent is to increase the required PoW for network participation, this constant alone won’t achieve that because verify_nonce() still checks K_DIFF_MIN_BIT; otherwise consider making the produced difficulty configurable and/or lowering it under cfg(test)/debug builds to keep test and startup times reasonable.

Copilot uses AI. Check for mistakes.

const fn get_k_k() -> usize {
match option_env!("KADCAST_K") {
Expand Down
2 changes: 1 addition & 1 deletion src/transport/encoding/raptorq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl BroadcastPayload {
Ok(hasher.finalize().into())
}
}
impl<'a> ChunkedPayload<'a> {
impl ChunkedPayload<'_> {
fn ray_id(&self) -> [u8; RAY_ID_SIZE] {
self.0.gossip_frame[0..RAY_ID_SIZE]
.try_into()
Expand Down