p2p: Implement `encoding` traits for `SendCmpct`
What changed, and why it matters
This commit adds a new way to encode and decode the Bitcoin 'sendcmpct' P2P network message in the rust-bitcoin library. It is a straightforward feature addition that mirrors existing behavior: any non-zero byte is treated as 'true' for the send_compact flag. There is no indication of a security bug being fixed or introduced.
No security action required. Review as a normal code-quality change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch implements the new encoding::Encodable and encoding::Decodable traits for SendCmpct in p2p/src/message_compact_blocks.rs. It introduces SendCmpctEncoder, SendCmpctDecoder, and SendCmpctDecoderError types. The decoder reads a 1-byte boolean and an 8-byte little-endian version, matching the existing impl_consensus_encoding! macro behavior. The decoding semantics for the boolean remain unchanged: u8::from_le_bytes(send_cmpct) != 0.
Changed components
p2p/src/message_compact_blocks.rsSendCmpct P2P message encoding/decodingInspect captured patch +81 / −0
diff --git a/p2p/src/message_compact_blocks.rs b/p2p/src/message_compact_blocks.rs
index b81db352..227faab3 100644
--- a/p2p/src/message_compact_blocks.rs
+++ b/p2p/src/message_compact_blocks.rs
@@ -3,10 +3,15 @@
//!
//! BIP-0152 Compact Blocks network messages
+use core::convert::Infallible;
+use core::fmt;
+
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
use crate::consensus::impl_consensus_encoding;
+use encoding::{ArrayDecoder, ArrayEncoder, Decoder2, Encoder2};
+use internals::write_err;
/// sendcmpct message
#[derive(PartialEq, Eq, Clone, Debug, Copy, PartialOrd, Ord, Hash)]
@@ -16,6 +21,82 @@ pub struct SendCmpct {
/// Compact Blocks protocol version number.
pub version: u64,
}
+
+encoding::encoder_newtype! {
+ /// Encoder type for the [`SendCmpct`] message.
+ pub struct SendCmpctEncoder<'e>(Encoder2<ArrayEncoder<1>, ArrayEncoder<8>>);
+}
+
+impl encoding::Encodable for SendCmpct {
+ type Encoder<'e> = SendCmpctEncoder<'e>;
+
+ fn encoder(&self) -> Self::Encoder<'_> {
+ SendCmpctEncoder::new(
+ Encoder2::new(
+ ArrayEncoder::without_length_prefix([u8::from(self.send_compact)]),
+ ArrayEncoder::without_length_prefix(self.version.to_le_bytes()),
+ )
+ )
+ }
+}
+
+type SendCmpctInnerDecoder = Decoder2<ArrayDecoder<1>, ArrayDecoder<8>>;
+
+/// Decoder type for the [`SendCmpct`] message.
+pub struct SendCmpctDecoder(SendCmpctInnerDecoder);
+
+impl encoding::Decoder for SendCmpctDecoder {
+ type Output = SendCmpct;
+ type Error = SendCmpctDecoderError;
+
+ #[inline]
+ fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
+ self.0.push_bytes(bytes).map_err(SendCmpctDecoderError)
+ }
+
+ #[inline]
+ fn end(self) -> Result<Self::Output, Self::Error> {
+ let (send_cmpct, version) = self.0.end().map_err(SendCmpctDecoderError)?;
+ let send_compact = u8::from_le_bytes(send_cmpct) != 0;
+ Ok(SendCmpct {
+ send_compact,
+ version: u64::from_le_bytes(version),
+ })
+ }
+
+ #[inline]
+ fn read_limit(&self) -> usize { self.0.read_limit() }
+}
+
+impl encoding::Decodable for SendCmpct {
+ type Decoder = SendCmpctDecoder;
+
+ fn decoder() -> Self::Decoder {
+ SendCmpctDecoder(
+ Decoder2::new(ArrayDecoder::new(), ArrayDecoder::new())
+ )
+ }
+}
+
+/// Errors occuring when decoding a [`SendCmpct`] message.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct SendCmpctDecoderError(<SendCmpctInnerDecoder as encoding::Decoder>::Error);
+
+impl From<Infallible> for SendCmpctDecoderError {
+ fn from(never: Infallible) -> Self { match never {} }
+}
+
+impl fmt::Display for SendCmpctDecoderError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write_err!(f, "sendcmpct error"; self.0)
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for SendCmpctDecoderError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
+}
+
impl_consensus_encoding!(SendCmpct, send_compact, version);
#[cfg(feature = "arbitrary")]
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.