p2p: Implement `encoding` traits for `Magic`
What changed, and why it matters
This commit adds new serialization/deserialization code for the Bitcoin network 'magic' bytes (the 4-byte identifier at the start of P2P messages). It is a routine feature addition that mirrors existing consensus encoding support. There is no indication of a security bug, fix, or vulnerability in the change itself.
No security action required. Review as normal code-quality/ API-consistency change.
Security signals we found
No security-relevant signals detected in the diff or commit message.
Change is a symmetric, fixed-length (4-byte) encoding trait implementation.
No unsafe blocks, no panics, no unwraps, and no user-controlled length parsing observed.
Evidence from the diff
The patch implements the project’s newer encoding::Encodable/Decodable traits for the Magic type in p2p/src/lib.rs. It introduces MagicEncoder, MagicDecoder, and MagicDecoderError, delegating to ArrayEncoder<4>/ArrayDecoder<4>. The type already had bitcoin::consensus::encode::{Encodable, Decodable} implementations; this change adds equivalent support under the separate encoding module. No unsafe code, no parsing of variable-length data, and no behavioral changes to existing consensus encoding are present.
Changed components
rust-bitcoin p2p crate (`p2p/src/lib.rs`)`Magic` type serialization/deserializationInspect captured patch +67 / −0
diff --git a/p2p/src/lib.rs b/p2p/src/lib.rs
index 9ee838d2..38b8d908 100644
--- a/p2p/src/lib.rs
+++ b/p2p/src/lib.rs
@@ -37,6 +37,7 @@ use core::{fmt, ops};
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
use bitcoin::consensus::encode::{self, Decodable, Encodable};
+use encoding::{ArrayEncoder, ArrayDecoder};
use hex::FromHex;
use internals::{impl_to_hex_from_lower_hex, write_err};
use io::{BufRead, Write};
@@ -507,6 +508,72 @@ impl Decodable for Magic {
}
}
+encoding::encoder_newtype_exact! {
+ /// The encoder type for network [`Magic`].
+ pub struct MagicEncoder<'e>(ArrayEncoder<4>);
+}
+
+impl encoding::Encodable for Magic {
+ type Encoder<'e> = MagicEncoder<'e>;
+
+ fn encoder(&self) -> Self::Encoder<'_> {
+ MagicEncoder::new(ArrayEncoder::without_length_prefix(self.0))
+ }
+}
+
+type MagicInnerDecoder = ArrayDecoder<4>;
+
+/// The decoder type for a network [`Magic`].
+pub struct MagicDecoder(MagicInnerDecoder);
+
+impl encoding::Decoder for MagicDecoder {
+ type Output = Magic;
+ type Error = MagicDecoderError;
+
+ #[inline]
+ fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
+ self.0.push_bytes(bytes).map_err(MagicDecoderError)
+ }
+
+ #[inline]
+ fn end(self) -> Result<Self::Output, Self::Error> {
+ let bytes = self.0.end().map_err(MagicDecoderError)?;
+ Ok(Magic::from_bytes(bytes))
+ }
+
+ #[inline]
+ fn read_limit(&self) -> usize { self.0.read_limit() }
+}
+
+impl encoding::Decodable for Magic {
+ type Decoder = MagicDecoder;
+
+ fn decoder() -> Self::Decoder {
+ MagicDecoder(ArrayDecoder::new())
+ }
+}
+
+/// Errors occuring when decoding a network [`Magic`].
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct MagicDecoderError(<MagicInnerDecoder as encoding::Decoder>::Error);
+
+impl From<Infallible> for MagicDecoderError {
+ fn from(never: Infallible) -> Self { match never {} }
+}
+
+impl fmt::Display for MagicDecoderError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write_err!(f, "magic error"; self.0)
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for MagicDecoderError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ Some(&self.0)
+ }
+}
+
impl AsRef<[u8]> for Magic {
fn as_ref(&self) -> &[u8] { &self.0 }
}
Why this scored 18/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.