What changed, and why it matters
This commit adds a new way to encode and decode Bitcoin 'ping' network messages in the rust-bitcoin library. It is a routine feature addition: it introduces a dedicated Ping message type with proper serialization/deserialization and replaces older serialization tests with a round-trip test. There is no indication of a security bug being fixed.
No security action required; review as normal code change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff adds a Ping newtype wrapping u64, plus encoder/decoder implementations using an 8-byte fixed array encoder. It removes two old serialization tests for V1 and V2 ping messages and adds a round-trip encode/decode test. The change is localized to p2p/src/message.rs and is consistent with normal protocol message type implementation.
Changed components
p2p/src/message.rsInspect captured patch +78 / −18
diff --git a/p2p/src/message.rs b/p2p/src/message.rs
index 98a0557b..d015488a 100644
--- a/p2p/src/message.rs
+++ b/p2p/src/message.rs
@@ -609,6 +609,79 @@ impl<'a> Arbitrary<'a> for FeeFilter {
}
}
+/// Serializer for Ping
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct Ping(u64);
+
+impl Ping {
+ /// Constructs a new [`Ping`] message from nonce.
+ pub fn new(nonce: u64) -> Self {
+ Self(nonce)
+ }
+}
+
+encoding::encoder_newtype! {
+ /// The encoder for the [`Ping`] type.
+ pub struct PingEncoder<'e>(encoding::ArrayEncoder<8>);
+}
+
+impl encoding::Encodable for Ping {
+ type Encoder<'e>
+ = PingEncoder<'e>
+ where
+ Self: 'e;
+ fn encoder(&self) -> Self::Encoder<'_> {
+ let nonce = encoding::ArrayEncoder::without_length_prefix(self.0.to_le_bytes());
+ PingEncoder::new(nonce)
+ }
+}
+
+/// The Decoder for [`Ping`]
+pub struct PingDecoder(encoding::ArrayDecoder<8>);
+
+impl encoding::Decoder for PingDecoder {
+ type Output = Ping;
+ type Error = PingDecoderError;
+
+ #[inline]
+ fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
+ self.0.push_bytes(bytes).map_err(PingDecoderError)
+ }
+
+ #[inline]
+ fn end(self) -> Result<Self::Output, Self::Error> {
+ let nonce = self.0.end().map_err(PingDecoderError)?;
+ Ok(Ping(u64::from_le_bytes(nonce)))
+ }
+
+ #[inline]
+ fn read_limit(&self) -> usize { self.0.read_limit() }
+}
+
+impl encoding::Decodable for Ping {
+ type Decoder = PingDecoder;
+ fn decoder() -> Self::Decoder { PingDecoder(encoding::ArrayDecoder::<8>::new()) }
+}
+
+/// An error consensus decoding a [`PingDecoderError`].
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct PingDecoderError(<encoding::ArrayDecoder<8> as encoding::Decoder>::Error);
+
+impl From<Infallible> for PingDecoderError {
+ fn from(never: Infallible) -> Self { match never {} }
+}
+
+impl fmt::Display for PingDecoderError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ internals::write_err!(f, "ping decoder error"; self.0)
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for PingDecoderError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
+}
+
/// A Network message payload. Proper documentation is available at
/// [Bitcoin Wiki: Protocol Specification](https://en.bitcoin.it/wiki/Protocol_specification)
#[derive(Clone, PartialEq, Eq, Debug)]
@@ -2210,24 +2283,11 @@ mod test {
}
#[test]
- #[rustfmt::skip]
- fn serialize_ping() {
- assert_eq!(serialize(&V1NetworkMessage::new(Magic::BITCOIN, NetworkMessage::Ping(100))),
- [0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d,
- 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
- }
-
- #[test]
- fn serialize_v2_ping() {
- assert_eq!(
- serialize(&V2NetworkMessage::new(NetworkMessage::Ping(100))),
- [
- 0x12, // Ping command short ID
- 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ]
- );
+ fn roundtrip_encode_decode_ping() {
+ let ping = Ping(314);
+ let encoded_ping = encoding::encode_to_vec(&ping);
+ let decoded_ping = encoding::decode_from_slice::<Ping>(&encoded_ping).unwrap();
+ assert_eq!(decoded_ping, ping);
}
#[test]
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.