What changed, and why it matters
This commit adds a new way to decode Bitcoin peer-to-peer network addresses in the rust-bitcoin library. It is a feature/refactoring change that introduces a new decoder implementation and swaps test cases to use it. There is no indication in the commit that it fixes a security bug, vulnerability, or crash.
No security action required. Review as normal code-quality/refactoring change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change implements AddressDecoder using the crate’s newer encoding::Decoder trait for Address (services + 16-byte address + 2-byte port). It explicitly interprets IPv4-mapped IPv6 address bytes and port as big-endian, matching the existing read_be_address helper and Bitcoin P2P spec. Tests are updated from deserialize to encoding::decode_from_slice. No bounds-checking, panic, or memory-safety defects are visible in the diff.
Changed components
p2p/src/address.rsAddressDecoderAddress decoding/serializationInspect captured patch +75 / −2
diff --git a/p2p/src/address.rs b/p2p/src/address.rs
index 50c1586e..07b4fe9b 100644
--- a/p2p/src/address.rs
+++ b/p2p/src/address.rs
@@ -17,6 +17,7 @@ use bitcoin::consensus::encode::{self, Decodable, Encodable, ReadExt, WriteExt};
use encoding::{
ArrayDecoder, ArrayEncoder, ByteVecDecoder, BytesEncoder, CompactSizeEncoder, Decoder2,
};
+use internals::array::ArrayExt;
use internals::write_err;
use io::{BufRead, Read, Write};
@@ -112,6 +113,19 @@ fn read_be_address<R: Read + ?Sized>(r: &mut R) -> Result<[u16; 8], encode::Erro
Ok(address)
}
+fn address_from_u8(s: [u8; 16]) -> [u16; 8] {
+ [
+ u16::from_be_bytes(*s.sub_array::<0, 2>()),
+ u16::from_be_bytes(*s.sub_array::<2, 2>()),
+ u16::from_be_bytes(*s.sub_array::<4, 2>()),
+ u16::from_be_bytes(*s.sub_array::<6, 2>()),
+ u16::from_be_bytes(*s.sub_array::<8, 2>()),
+ u16::from_be_bytes(*s.sub_array::<10, 2>()),
+ u16::from_be_bytes(*s.sub_array::<12, 2>()),
+ u16::from_be_bytes(*s.sub_array::<14, 2>()),
+ ]
+}
+
impl fmt::Debug for Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let ipv6 = Ipv6Addr::from(self.address);
@@ -140,6 +154,65 @@ impl ToSocketAddrs for Address {
}
}
+type AddressInnerDecoder = encoding::Decoder3<
+ crate::ServiceFlagsDecoder,
+ encoding::ArrayDecoder<16>,
+ encoding::ArrayDecoder<2>,
+>;
+
+/// The Decoder for [`Address`].
+pub struct AddressDecoder(AddressInnerDecoder);
+
+impl encoding::Decoder for AddressDecoder {
+ type Output = Address;
+ type Error = AddressDecoderError;
+
+ #[inline]
+ fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
+ self.0.push_bytes(bytes).map_err(AddressDecoderError)
+ }
+
+ #[inline]
+ fn end(self) -> Result<Self::Output, Self::Error> {
+ let (services, raw_address, port) = self.0.end().map_err(AddressDecoderError)?;
+ let address = address_from_u8(raw_address);
+ Ok(Address { services, address, port: u16::from_be_bytes(port) })
+ }
+
+ #[inline]
+ fn read_limit(&self) -> usize { self.0.read_limit() }
+}
+
+impl encoding::Decodable for Address {
+ type Decoder = AddressDecoder;
+ fn decoder() -> Self::Decoder {
+ AddressDecoder(encoding::Decoder3::new(
+ ServiceFlags::decoder(),
+ encoding::ArrayDecoder::<16>::new(),
+ encoding::ArrayDecoder::<2>::new(),
+ ))
+ }
+}
+
+/// An error consensus decoding a [`AddressDecoderError`].
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct AddressDecoderError(<AddressInnerDecoder as encoding::Decoder>::Error);
+
+impl From<Infallible> for AddressDecoderError {
+ fn from(never: Infallible) -> Self { match never {} }
+}
+
+impl fmt::Display for AddressDecoderError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ internals::write_err!(f, "address decoder error"; self.0)
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for AddressDecoderError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
+}
+
/// Supported networks for use in BIP-0155 addrv2 message
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum AddrV2 {
@@ -910,7 +983,7 @@ mod test {
#[test]
fn deserialize_address() {
- let mut addr: Result<Address, _> = deserialize(&[
+ let mut addr: Result<Address, _> = encoding::decode_from_slice(&[
1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1,
0x20, 0x8d,
]);
@@ -921,7 +994,7 @@ mod test {
assert_eq!(full.address, [0, 0, 0, 0, 0, 0xffff, 0x0a00, 0x0001]);
assert_eq!(full.port, 8333);
- addr = deserialize(&[
+ addr = encoding::decode_from_slice(&[
1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1,
]);
assert!(addr.is_err());
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.