p2p: Remove legacy encoding from `address`
What changed, and why it matters
This commit removes old, unused code that encoded and decoded Bitcoin peer network addresses using a legacy 'consensus' encoding system. It is a cleanup change: the deleted code appears to have been superseded by newer encoding machinery elsewhere in the crate. There is no indication in the commit that this fixes a security bug or that the removed code was reachable by attackers.
No security action required. Treat as normal maintenance/refactoring. Reviewers may want to confirm that downstream users no longer depend on the removed Encodable/Decodable implementations, but that is an API-compatibility concern, not a security one.
Security signals we found
No security-relevant signal: code deletion is a refactoring/cleanup of superseded encoding implementations.
No change to input validation, buffer sizes, or parsing logic; the newer encoders already existed and are left untouched.
No vendor disclosure, CVE, or researcher attribution present in commit or supplied references.
Evidence from the diff
The patch deletes the p2p/src/consensus.rs module and removes the legacy bitcoin::consensus::{Encodable, Decodable} implementations from Address, AddrV2, and AddrV2Message in p2p/src/address.rs. It also removes the impl_consensus_encoding! macro usage for AddrV1Message. The crate already has newer encoding traits (Encoder2/Encoder4/Decoder2/Decoder4) and these types continue to implement those. The change is purely subtractive and there is no accompanying fix, bounds check change, or validation logic change that would indicate a vulnerability was being closed.
Changed components
p2p/src/address.rsp2p/src/consensus.rsp2p/src/lib.rsInspect captured patch +0 / −221
diff --git a/p2p/src/address.rs b/p2p/src/address.rs
index e36d4e1d..d649d3d7 100644
--- a/p2p/src/address.rs
+++ b/p2p/src/address.rs
@@ -5,20 +5,17 @@
//! This module defines the structures and functions needed to encode
//! network addresses in Bitcoin messages.
-use alloc::vec;
use alloc::vec::Vec;
use core::{fmt, iter};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
-use bitcoin::consensus::encode::{self, Decodable, Encodable, ReadExt, WriteExt};
use encoding::{
ArrayDecoder, ArrayEncoder, ByteVecDecoder, BytesEncoder, CompactSizeEncoder,
CompactSizeU64Decoder, Decoder2, Decoder4, Encoder2, Encoder4,
};
use internals::array::ArrayExt;
-use io::{BufRead, Read, Write};
use crate::ServiceFlags;
@@ -80,46 +77,6 @@ impl Address {
}
}
-impl Encodable for Address {
- #[inline]
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- let mut len = self.services.consensus_encode(w)?;
-
- for word in &self.address {
- w.write_all(&word.to_be_bytes())?;
- len += 2;
- }
-
- w.write_all(&self.port.to_be_bytes())?;
- len += 2;
-
- Ok(len)
- }
-}
-
-impl Decodable for Address {
- #[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- Ok(Self {
- services: Decodable::consensus_decode(r)?,
- address: read_be_address(r)?,
- port: u16::swap_bytes(Decodable::consensus_decode(r)?),
- })
- }
-}
-
-/// Reads a big-endian address from reader.
-fn read_be_address<R: Read + ?Sized>(r: &mut R) -> Result<[u16; 8], encode::Error> {
- let mut address = [0u16; 8];
- let mut buf = [0u8; 2];
-
- for word in &mut address {
- Read::read_exact(r, &mut buf)?;
- *word = u16::from_be_bytes(buf);
- }
- Ok(address)
-}
-
fn address_from_u8(s: [u8; 16]) -> [u16; 8] {
[
u16::from_be_bytes(*s.sub_array::<0, 2>()),
@@ -299,8 +256,6 @@ impl encoding::Decode for AddrV1Message {
}
}
-crate::consensus::impl_consensus_encoding!(AddrV1Message, time, address);
-
/// Supported networks for use in BIP-0155 addrv2 message
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum AddrV2 {
@@ -640,99 +595,6 @@ impl encoding::Decode for AddrV2 {
}
}
-impl Encodable for AddrV2 {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- fn encode_addr<W: Write + ?Sized>(
- w: &mut W,
- network: u8,
- bytes: &[u8],
- ) -> Result<usize, io::Error> {
- Ok(network.consensus_encode(w)?
- + crate::consensus::consensus_encode_with_size(bytes, w)?)
- }
- Ok(match *self {
- Self::Ipv4(ref addr) => encode_addr(w, 1, &addr.octets())?,
- Self::Ipv6(ref addr) => encode_addr(w, 2, &addr.octets())?,
- Self::TorV3(ref bytes) => encode_addr(w, 4, bytes)?,
- Self::I2p(ref bytes) => encode_addr(w, 5, bytes)?,
- Self::Cjdns(ref addr) => encode_addr(w, 6, &addr.octets())?,
- Self::Unknown(network, ref bytes) => encode_addr(w, network, bytes)?,
- })
- }
-}
-
-impl Decodable for AddrV2 {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- let network_id = u8::consensus_decode(r)?;
- let len = r.read_compact_size()?;
- if len > 512 {
- return Err(crate::consensus::parse_failed_error("IP must be <= 512 bytes"));
- }
- Ok(match network_id {
- 1 => {
- if len != 4 {
- return Err(crate::consensus::parse_failed_error("invalid IPv4 address"));
- }
- let addr: [u8; 4] = Decodable::consensus_decode(r)?;
- Self::Ipv4(Ipv4Addr::new(addr[0], addr[1], addr[2], addr[3]))
- }
- 2 => {
- if len != 16 {
- return Err(crate::consensus::parse_failed_error("invalid IPv6 address"));
- }
- let addr: [u16; 8] = read_be_address(r)?;
- if addr[0..3] == ONION {
- return Err(crate::consensus::parse_failed_error(
- "OnionCat address sent with IPv6 network id",
- ));
- }
- if addr[0..6] == [0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF] {
- return Err(crate::consensus::parse_failed_error(
- "IPV4 wrapped address sent with IPv6 network id",
- ));
- }
- Self::Ipv6(Ipv6Addr::new(
- addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
- ))
- }
-
- 4 => {
- if len != 32 {
- return Err(crate::consensus::parse_failed_error("invalid TorV3 address"));
- }
- let pubkey = Decodable::consensus_decode(r)?;
- Self::TorV3(pubkey)
- }
- 5 => {
- if len != 32 {
- return Err(crate::consensus::parse_failed_error("invalid I2P address"));
- }
- let hash = Decodable::consensus_decode(r)?;
- Self::I2p(hash)
- }
- 6 => {
- if len != 16 {
- return Err(crate::consensus::parse_failed_error("invalid CJDNS address"));
- }
- let addr: [u16; 8] = read_be_address(r)?;
- // check the first byte for the CJDNS marker
- if addr[0] >> 8 != 0xFC {
- return Err(crate::consensus::parse_failed_error("invalid CJDNS address"));
- }
- Self::Cjdns(Ipv6Addr::new(
- addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
- ))
- }
- _ => {
- // len already checked above to be <= 512
- let mut addr = vec![0u8; len as usize];
- r.read_slice(&mut addr)?;
- Self::Unknown(network_id, addr)
- }
- })
- }
-}
-
/// Address received from BIP-0155 addrv2 message
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct AddrV2Message {
@@ -765,31 +627,6 @@ impl AddrV2Message {
}
}
-impl Encodable for AddrV2Message {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- let mut len = 0;
- len += self.time.consensus_encode(w)?;
- len += w.emit_compact_size(self.services.to_u64())?;
- len += self.addr.consensus_encode(w)?;
-
- w.write_all(&self.port.to_be_bytes())?;
- len += 2; // port u16 is two bytes.
-
- Ok(len)
- }
-}
-
-impl Decodable for AddrV2Message {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- Ok(Self {
- time: Decodable::consensus_decode(r)?,
- services: ServiceFlags::from(r.read_compact_size()?),
- addr: Decodable::consensus_decode(r)?,
- port: u16::swap_bytes(Decodable::consensus_decode(r)?),
- })
- }
-}
-
impl ToSocketAddrs for AddrV2Message {
type Iter = iter::Once<SocketAddr>;
fn to_socket_addrs(&self) -> Result<Self::Iter, std::io::Error> {
diff --git a/p2p/src/consensus.rs b/p2p/src/consensus.rs
deleted file mode 100644
index 6a0a3c2f..00000000
--- a/p2p/src/consensus.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-#[cfg(feature = "std")]
-use bitcoin::consensus::encode::WriteExt;
-#[cfg(feature = "std")]
-use io::Write;
-
-#[cfg(feature = "std")]
-pub(crate) fn consensus_encode_with_size<W: Write + ?Sized>(
- data: &[u8],
- w: &mut W,
-) -> Result<usize, io::Error> {
- Ok(w.emit_compact_size(data.len())? + w.emit_slice(data)?)
-}
-
-pub(crate) fn parse_failed_error(msg: &'static str) -> bitcoin::consensus::encode::Error {
- bitcoin::consensus::encode::Error::Parse(bitcoin::consensus::encode::ParseError::ParseFailed(
- msg,
- ))
-}
-
-macro_rules! impl_consensus_encoding {
- ($thing:ident, $($field:ident),+) => (
- impl bitcoin::consensus::Encodable for $thing {
- #[inline]
- fn consensus_encode<W: io::Write + ?Sized>(
- &self,
- w: &mut W,
- ) -> core::result::Result<usize, io::Error> {
- let mut len = 0;
- $(len += self.$field.consensus_encode(w)?;)+
- Ok(len)
- }
- }
-
- impl bitcoin::consensus::Decodable for $thing {
-
- #[inline]
- fn consensus_decode_from_finite_reader<R: io::BufRead + ?Sized>(
- r: &mut R,
- ) -> core::result::Result<$thing, bitcoin::consensus::encode::Error> {
- Ok($thing {
- $($field: bitcoin::consensus::Decodable::consensus_decode_from_finite_reader(r)?),+
- })
- }
-
- #[inline]
- fn consensus_decode<R: io::BufRead + ?Sized>(
- r: &mut R,
- ) -> core::result::Result<$thing, bitcoin::consensus::encode::Error> {
- let mut r = io::Read::take(r, internals::ToU64::to_u64(bitcoin::consensus::encode::MAX_VEC_SIZE));
- Ok($thing {
- $($field: bitcoin::consensus::Decodable::consensus_decode(&mut r)?),+
- })
- }
- }
- );
-}
-pub(crate) use impl_consensus_encoding;
diff --git a/p2p/src/lib.rs b/p2p/src/lib.rs
index 161b1194..e51af80d 100644
--- a/p2p/src/lib.rs
+++ b/p2p/src/lib.rs
@@ -8,7 +8,6 @@
#![warn(deprecated_in_future)]
#![doc(test(attr(warn(unused))))]
-mod consensus;
mod network_ext;
#[cfg(feature = "std")]
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.