p2p: Implement `encoding` traits for `NetworkHeader`
What changed, and why it matters
This commit adds new serialization/deserialization code for a Bitcoin P2P message wrapper type called NetworkHeader. It is a routine feature addition that implements internal encoding traits so NetworkHeader can be used inside another message type (HeadersMessage). There is no indication in the commit of a security bug, vulnerability, or fix.
No security action required. Review as normal code-quality change if desired.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff implements the project’s internal encoding::Encodable and encoding::Decodable traits for NetworkHeader in p2p/src/message.rs. It introduces NetworkHeaderEncoder, NetworkHeaderDecoder, and NetworkHeaderDecoderError, delegating to a tuple decoder for a block::Header plus a one-byte length array. The existing Decodable/Encodable consensus traits remain untouched. No bounds checks, validation logic, or parsing behavior changes are visible beyond the new trait implementations.
Changed components
p2p/src/message.rsNetworkHeaderNetworkHeaderEncoderNetworkHeaderDecoderNetworkHeaderDecoderErrorInspect captured patch +74 / −2
diff --git a/p2p/src/message.rs b/p2p/src/message.rs
index 169928b2..71584e06 100644
--- a/p2p/src/message.rs
+++ b/p2p/src/message.rs
@@ -16,12 +16,12 @@ use core::{cmp, fmt};
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
use bitcoin::consensus::encode::{self, Decodable, Encodable, ReadExt, WriteExt};
-use encoding::{self, CompactSizeEncoder, Encoder2, SliceEncoder, VecDecoder};
+use encoding::{self, ArrayDecoder, ArrayEncoder, CompactSizeEncoder, Decoder2, Encoder2, SliceEncoder, VecDecoder};
use hashes::sha256d;
use internals::ToU64 as _;
use internals::write_err;
use io::{self, BufRead, Read, Write};
-use primitives::{block, transaction};
+use primitives::{block::{self, HeaderDecoder, HeaderEncoder}, transaction};
use units::FeeRate;
use crate::address::{AddrV2Message, Address};
@@ -1388,6 +1388,78 @@ impl NetworkHeader {
}
}
+encoding::encoder_newtype! {
+ /// The encoder type for a [`NetworkHeader`].
+ pub struct NetworkHeaderEncoder<'e>(Encoder2<HeaderEncoder<'e>, ArrayEncoder<1>>);
+}
+
+impl encoding::Encodable for NetworkHeader {
+ type Encoder<'e> = NetworkHeaderEncoder<'e>;
+
+ fn encoder(&self) -> Self::Encoder<'_> {
+ NetworkHeaderEncoder::new(Encoder2::new(
+ self.header.encoder(),
+ ArrayEncoder::without_length_prefix([self.length]),
+ ))
+ }
+}
+
+type NetworkHeaderInnerDecoder = Decoder2<HeaderDecoder, ArrayDecoder<1>>;
+
+/// The decoder type for a [`NetworkHeader`].
+pub struct NetworkHeaderDecoder(NetworkHeaderInnerDecoder);
+
+impl encoding::Decoder for NetworkHeaderDecoder {
+ type Output = NetworkHeader;
+ type Error = NetworkHeaderDecoderError;
+
+ #[inline]
+ fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
+ self.0.push_bytes(bytes).map_err(NetworkHeaderDecoderError)
+ }
+
+ #[inline]
+ fn end(self) -> Result<Self::Output, Self::Error> {
+ let (header, length) = self.0.end().map_err(NetworkHeaderDecoderError)?;
+ Ok(NetworkHeader {
+ header,
+ length: u8::from_le_bytes(length),
+ })
+ }
+
+ #[inline]
+ fn read_limit(&self) -> usize { self.0.read_limit() }
+}
+
+impl encoding::Decodable for NetworkHeader {
+ type Decoder = NetworkHeaderDecoder;
+
+ fn decoder() -> Self::Decoder {
+ NetworkHeaderDecoder(
+ Decoder2::new(block::Header::decoder(), ArrayDecoder::new()),
+ )
+ }
+}
+
+/// An error decoding a [`NetworkHeader`] message.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct NetworkHeaderDecoderError(<NetworkHeaderInnerDecoder as encoding::Decoder>::Error);
+
+impl From<Infallible> for NetworkHeaderDecoderError {
+ fn from(never: Infallible) -> Self { match never {} }
+}
+
+impl fmt::Display for NetworkHeaderDecoderError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write_err!(f, "network header error"; self.0)
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for NetworkHeaderDecoderError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
+}
+
impl Decodable for NetworkHeader {
fn consensus_decode<R: BufRead + ?Sized>(
reader: &mut R,
Why this scored 12/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.