From 0bb7a35141c12a58001b481851d33291d2a6ec98 Mon Sep 17 00:00:00 2001 From: tv Date: Fri, 30 Oct 2026 17:36:23 +0100 Subject: add links messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce two new wire messages, LINKS and LINKS_REPLY (swarm::links). A member answers with its links: for each peer, the transport, whether it’s relayed, the RTT, and whether it’s dormant. It answers members only, at most every 5 s. This bumps wire::VERSION to 7. Every build answers, with or without the feature, so every node needs this patch before the map shows anything beyond its own node. --- src/transport/wire.rs | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) (limited to 'src/transport/wire.rs') diff --git a/src/transport/wire.rs b/src/transport/wire.rs index 53fd460..3e1ab10 100644 --- a/src/transport/wire.rs +++ b/src/transport/wire.rs @@ -14,7 +14,7 @@ use super::{MessageKind, ParsedMessage}; /// The wire format's version, the first byte of every payload. Bump it with every change /// to a message type or a codec (`golden_bytes` fails then). -pub(crate) const VERSION: u8 = 6; +pub(crate) const VERSION: u8 = 7; /// What the second byte of a payload says. fn tag(kind: MessageKind) -> u8 { @@ -29,6 +29,8 @@ fn tag(kind: MessageKind) -> u8 { MessageKind::Me => 7, MessageKind::Ping => 8, MessageKind::Pong => 9, + MessageKind::Links => 10, + MessageKind::LinksReply => 11, } } @@ -67,6 +69,8 @@ pub(crate) fn encode(message: &ParsedMessage) -> Result, WireError> { ParsedMessage::Ping(nonce) | ParsedMessage::Pong(nonce) => { rmp_serde::encode::write(&mut payload, nonce)? } + ParsedMessage::Links(request) => rmp_serde::encode::write(&mut payload, request)?, + ParsedMessage::LinksReply(reply) => rmp_serde::encode::write(&mut payload, reply)?, } Ok(payload) } @@ -99,6 +103,10 @@ pub(crate) fn decode(payload: &[u8]) -> Result { ParsedMessage::Ping(rmp_serde::from_slice(body)?) } else if is(MessageKind::Pong) { ParsedMessage::Pong(rmp_serde::from_slice(body)?) + } else if is(MessageKind::Links) { + ParsedMessage::Links(rmp_serde::from_slice(body)?) + } else if is(MessageKind::LinksReply) { + ParsedMessage::LinksReply(rmp_serde::from_slice(body)?) } else { return Err(WireError::UnknownKind(kind)); }) @@ -396,6 +404,23 @@ pub(crate) fn samples() -> Vec { ParsedMessage::Me(proof), ParsedMessage::Ping(7), ParsedMessage::Pong(u64::MAX), + ParsedMessage::Links(crate::transport::LinksRequest { + epoch, + epoch_seq: 1, + nonce: 3, + }), + ParsedMessage::LinksReply(crate::transport::LinksReply { + epoch, + epoch_seq: 1, + nonce: 3, + links: vec![crate::transport::Link { + peer: "p".into(), + transport: Some("libp2p".into()), + relayed: true, + rtt_us: Some(1500), + dormant: false, + }], + }), ] } @@ -413,7 +438,7 @@ mod tests { #[test] fn every_kind_round_trips() { let samples = samples(); - assert_eq!(samples.len(), 10, "a kind is missing from `samples`"); + assert_eq!(samples.len(), 12, "a kind is missing from `samples`"); for message in samples { let bytes = encode(&message).unwrap(); let decoded = decode(&bytes).unwrap(); @@ -566,7 +591,7 @@ mod tests { }); assert_eq!( hex(&encode(&hello).unwrap()), - format!("060097a5737761726d{epoch_hex}01c403010203c3{}07", run("04")) + format!("070097a5737761726d{epoch_hex}01c403010203c3{}07", run("04")) ); let reply = ParsedMessage::HelloReply(HelloReply { @@ -586,7 +611,7 @@ mod tests { assert_eq!( hex(&encode(&reply).unwrap()), format!( - "060199a5737761726d9192a17091a161{epoch_hex}01c400c2{}05{}", + "070199a5737761726d9192a17091a161{epoch_hex}01c400c2{}05{}", run("04"), run("06") ) @@ -601,7 +626,7 @@ mod tests { }); assert_eq!( hex(&encode(&status).unwrap()), - format!("0603959290c400{epoch_hex}01c3c2") + format!("0703959290c400{epoch_hex}01c3c2") ); let who = ParsedMessage::Who(IdentityProof { @@ -610,7 +635,7 @@ mod tests { }); assert_eq!( hex(&encode(&who).unwrap()), - format!("060692c420{}c440{}", "08".repeat(32), "09".repeat(64)) + format!("070692c420{}c440{}", "08".repeat(32), "09".repeat(64)) ); let ParsedMessage::Me(proof) = decode( &encode(&ParsedMessage::Me(IdentityProof { @@ -624,10 +649,10 @@ mod tests { }; assert_eq!((proof.key, proof.signature), ([8; 32], [9; 64])); - assert_eq!(hex(&encode(&ParsedMessage::Ping(7)).unwrap()), "060807"); + assert_eq!(hex(&encode(&ParsedMessage::Ping(7)).unwrap()), "070807"); assert_eq!( hex(&encode(&ParsedMessage::Pong(u64::MAX)).unwrap()), - "0609cfffffffffffffffff" + "0709cfffffffffffffffff" ); let ParsedMessage::Pong(nonce) = decode(&[VERSION, 9, 0x2a]).unwrap() else { panic!("not a PONG"); -- cgit v1.3.1