From 4bbadf6fdc4733b4c3c5eeb575508b2f9334ebdb Mon Sep 17 00:00:00 2001 From: tv Date: Mon, 26 Oct 2026 19:29:59 +0100 Subject: keepalive sends head samples alongside digest When there are more than 32 heads that can be send in a single keepalive message, the digest is accompanied by 32 heads, a different window each time, so after a few keepalives every head has been listed. --- src/transport/wire.rs | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) (limited to 'src/transport/wire.rs') diff --git a/src/transport/wire.rs b/src/transport/wire.rs index 11d36cf..3c80b11 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 = 1; +pub(crate) const VERSION: u8 = 2; /// What the second byte of a payload says. fn tag(kind: MessageKind) -> u8 { @@ -200,7 +200,10 @@ pub(crate) mod codec { heads.iter().map(|head| Bytes::new(&head.0)).collect(), Bytes::new(&[]), ), - HeadsSummary::Digest(digest) => (Vec::new(), Bytes::new(digest)), + HeadsSummary::Digest { digest, sample } => ( + sample.iter().map(|head| Bytes::new(&head.0)).collect(), + Bytes::new(digest), + ), }; (listed, digest).serialize(s) } @@ -209,21 +212,24 @@ pub(crate) mod codec { d: D, ) -> Result { let (listed, digest): (Vec, ByteBuf) = Deserialize::deserialize(d)?; - if !digest.is_empty() { - return Ok(HeadsSummary::Digest(fixed(&digest, "a heads digest")?)); - } if listed.len() > MAX_LISTED_HEADS { return Err(D::Error::custom(format!( "more than {MAX_LISTED_HEADS} heads listed" ))); } - listed + let listed = listed .iter() .map(|head| -> Result { Ok(ChangeHash(fixed(head, "a head")?)) }) - .collect::, _>>() - .map(HeadsSummary::Heads) + .collect::, _>>()?; + if digest.is_empty() { + return Ok(HeadsSummary::Heads(listed)); + } + Ok(HeadsSummary::Digest { + digest: fixed(&digest, "a heads digest")?, + sample: listed, + }) } } @@ -317,7 +323,10 @@ mod tests { #[test] fn keepalives_keep_their_kind_and_heads() { let keepalive = Keepalive { - heads: HeadsSummary::Digest([8; 32]), + heads: HeadsSummary::Digest { + digest: [8; 32], + sample: vec![ChangeHash([9; 32])], + }, epoch: Epoch::GENESIS, epoch_seq: 0, ready: true, @@ -328,6 +337,7 @@ mod tests { panic!("not a PONG"); }; assert_eq!(decoded.heads, keepalive.heads); + assert_eq!(decoded.heads.listed(), [ChangeHash([9; 32])]); } #[test] @@ -401,7 +411,7 @@ mod tests { }); assert_eq!( hex(&encode(&hello).unwrap()), - format!("010097a5737761726d{epoch_hex}01c403010203c3{}07", run("04")) + format!("020097a5737761726d{epoch_hex}01c403010203c3{}07", run("04")) ); let reply = ParsedMessage::HelloReply(HelloReply { @@ -418,7 +428,7 @@ mod tests { assert_eq!( hex(&encode(&reply).unwrap()), format!( - "010199a5737761726d91a170{epoch_hex}01c400c2{}05{}", + "020199a5737761726d91a170{epoch_hex}01c400c2{}05{}", run("04"), run("06") ) @@ -433,7 +443,7 @@ mod tests { }); assert_eq!( hex(&encode(&ping).unwrap()), - format!("0103959290c400{epoch_hex}01c3c2") + format!("0203959290c400{epoch_hex}01c3c2") ); } } -- cgit v1.3.1