p2p: Implement `encoding` traits for `AddrPayload`
What changed, and why it matters
This commit adds standard encoding and decoding support for the Bitcoin P2P `addr` message payload (a list of network addresses). It is a routine feature addition that lets the library serialize and deserialize this message type. There is no indication in the commit that it fixes a security bug or introduces a vulnerability.
No security action required. Review as normal code-quality/functional change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change implements the project’s encoding::Encodable and encoding::Decodable traits for AddrPayload (a newtype around Vec<AddrV1Message>). It adds an encoder that writes a compact-size length prefix followed by the address records, plus a decoder and a matching error type. The implementation mirrors the existing AddrV2Payload pattern and does not alter parsing limits, memory allocation behavior, or consensus logic. No security-relevant fixes or unsafe code are present.
Changed components
p2p/src/message.rsAddrPayloadAddrPayloadEncoderAddrPayloadDecoderAddrPayloadDecoderErrorInspect captured patch +65 / −0
diff --git a/p2p/src/message.rs b/p2p/src/message.rs
index c6f8c17f..98a0557b 100644
--- a/p2p/src/message.rs
+++ b/p2p/src/message.rs
@@ -401,6 +401,71 @@ impl std::error::Error for InventoryPayloadDecoderError {
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct AddrPayload(pub Vec<AddrV1Message>);
+encoding::encoder_newtype! {
+ /// The encoder for an [`AddrPayload`].
+ pub struct AddrPayloadEncoder<'e>(Encoder2<CompactSizeEncoder, SliceEncoder<'e, AddrV1Message>>);
+}
+
+impl encoding::Encodable for AddrPayload {
+ type Encoder<'e> = AddrPayloadEncoder<'e>;
+
+ fn encoder(&self) -> Self::Encoder<'_> {
+ AddrPayloadEncoder::new(Encoder2::new(
+ CompactSizeEncoder::new(self.0.len()),
+ SliceEncoder::without_length_prefix(&self.0),
+ ))
+ }
+}
+
+type AddrPayloadInnerDecoder = VecDecoder<AddrV1Message>;
+
+/// Decoder type for [`AddrPayload`].
+pub struct AddrPayloadDecoder(AddrPayloadInnerDecoder);
+
+impl encoding::Decoder for AddrPayloadDecoder {
+ type Output = AddrPayload;
+ type Error = AddrPayloadDecoderError;
+
+ #[inline]
+ fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
+ self.0.push_bytes(bytes).map_err(AddrPayloadDecoderError)
+ }
+
+ #[inline]
+ fn end(self) -> Result<Self::Output, Self::Error> {
+ Ok(AddrPayload(self.0.end().map_err(AddrPayloadDecoderError)?))
+ }
+
+ #[inline]
+ fn read_limit(&self) -> usize { self.0.read_limit() }
+}
+
+impl encoding::Decodable for AddrPayload {
+ type Decoder = AddrPayloadDecoder;
+ fn decoder() -> Self::Decoder {
+ AddrPayloadDecoder(VecDecoder::new())
+ }
+}
+
+/// An error decoding a [`AddrPayload`].
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct AddrPayloadDecoderError(<AddrPayloadInnerDecoder as encoding::Decoder>::Error);
+
+impl From<Infallible> for AddrPayloadDecoderError {
+ fn from(never: Infallible) -> Self { match never {} }
+}
+
+impl fmt::Display for AddrPayloadDecoderError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write_err!(f, "addrv1 payload error"; self.0)
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for AddrPayloadDecoderError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
+}
+
/// A list of v2 address messages.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct AddrV2Payload(pub Vec<AddrV2Message>);
Why this scored 16/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.