Skip to content

Commit b2cc3fd

Browse files
committed
Merge rust-bitcoin#5289: p2p: introduce consensus_encoding to the p2p package
4671923 p2p: add consensus_encoding to v1 network message (Nick Johnson) 213b85b p2p: remove io::Error from exposed API (Nick Johnson) 4c249f7 p2p: add consensus_encoding impls to CommandString (Nick Johnson) 6d95f4e p2p: add FeeFilter wrapper with consensus_encoding (Nick Johnson) Pull request description: These commits are not perfectly related, some are kind of standalone, but they are all a part of the larger migration discussed in rust-bitcoin#5331 to drop the `bitcoin` and `io` dependencies in the `p2p` package. The final commit shows the new `consensus_encoding` interface for an external caller which is nice to lock in with the handshake example. I think this is ready as-is and I (or others) can follow up with the remaining work since p2p hasn't been released yet. This should allow us to drop `bitcoin` and `io`. 1. BIP-152 addressed by rustaceanrob in rust-bitcoin#5333. 2. BIP-158. 3. Some dangling deps on the `BlockExt` in `bitcoin` which might just have to be re-implemented in p2p if not primitives worthy. 4. Convert all the old encoders/decoders in `p2p` to `consensus_encoding` versions. ACKs for top commit: apoelstra: ACK 4671923; successfully ran local tests Tree-SHA512: c99662ff0d3672e041e86fe303e1627456e495a94959a345af850d8af698233fa9ca7676ad141825be5598f440408e2a24eefe3a2f78661c90bdf5c2673befb5
2 parents 8efa42f + 4671923 commit b2cc3fd

File tree

6 files changed

+814
-49
lines changed

6 files changed

+814
-49
lines changed

Cargo-minimal.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ version = "0.1.0"
123123
dependencies = [
124124
"arbitrary",
125125
"bitcoin",
126+
"bitcoin-consensus-encoding",
126127
"bitcoin-internals",
127128
"bitcoin-io",
128129
"bitcoin-units",

Cargo-recent.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ version = "0.1.0"
122122
dependencies = [
123123
"arbitrary",
124124
"bitcoin",
125+
"bitcoin-consensus-encoding",
125126
"bitcoin-internals",
126127
"bitcoin-io",
127128
"bitcoin-units",

p2p/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ exclude = ["tests", "contrib"]
1414

1515
[features]
1616
default = ["std"]
17-
std = ["hashes/std", "hex/std", "internals/std", "io/std", "units/std", "bitcoin/std"]
17+
std = ["encoding/std", "hashes/std", "hex/std", "internals/std", "io/std", "units/std", "bitcoin/std"]
1818
arbitrary = ["dep:arbitrary", "bitcoin/arbitrary"]
1919

2020
[dependencies]
2121
bitcoin = { path = "../bitcoin/", default-features = false }
22+
encoding = { package = "bitcoin-consensus-encoding", version = "1.0.0-rc.1", path = "../consensus_encoding", default-features = false }
2223
hashes = { package = "bitcoin_hashes", version = "0.18.0", path = "../hashes", default-features = false }
2324
hex = { package = "hex-conservative", version = "0.3.0", default-features = false }
2425
internals = { package = "bitcoin-internals", path = "../internals", default-features = false }

p2p/examples/handshake.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
use std::io::{BufReader, Write};
1+
use std::io::BufReader;
22
use std::net::{IpAddr, Ipv4Addr, Shutdown, SocketAddr, TcpStream};
33
use std::time::{SystemTime, UNIX_EPOCH};
44
use std::{env, process};
55

6-
use bitcoin::consensus::{encode, Decodable};
76
use bitcoin_p2p_messages::message_network::{ClientSoftwareVersion, UserAgent, UserAgentVersion};
87
use bitcoin_p2p_messages::{
98
self, address, message, message_network, Magic, ProtocolVersion, ServiceFlags,
@@ -36,15 +35,17 @@ fn main() {
3635

3736
if let Ok(mut stream) = TcpStream::connect(address) {
3837
// Send the message
39-
let _ = stream.write_all(encode::serialize(&first_message).as_slice());
38+
encoding::encode_to_writer(&first_message, &mut stream).unwrap();
4039
println!("Sent version message");
4140

4241
// Setup StreamReader
4342
let read_stream = stream.try_clone().unwrap();
4443
let mut stream_reader = BufReader::new(read_stream);
4544
loop {
4645
// Loop and retrieve new messages
47-
let reply = message::RawNetworkMessage::consensus_decode(&mut stream_reader).unwrap();
46+
let reply =
47+
encoding::decode_from_read::<message::RawNetworkMessage, _>(&mut stream_reader)
48+
.unwrap();
4849
match reply.payload() {
4950
message::NetworkMessage::Version(_) => {
5051
println!("Received version message: {:?}", reply.payload());
@@ -54,7 +55,7 @@ fn main() {
5455
message::NetworkMessage::Verack,
5556
);
5657

57-
let _ = stream.write_all(encode::serialize(&second_message).as_slice());
58+
encoding::encode_to_writer(&second_message, &mut stream).unwrap();
5859
println!("Sent verack message");
5960
}
6061
message::NetworkMessage::Verack => {

p2p/src/address.rs

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,14 @@ impl Address {
4747
}
4848

4949
/// Extracts socket address from an [Address] message.
50-
/// This will return [io::Error] [io::ErrorKind::AddrNotAvailable]
51-
/// if the message contains a Tor address.
52-
pub fn socket_addr(&self) -> Result<SocketAddr, io::Error> {
50+
///
51+
/// # Errors
52+
///
53+
/// Returns an error if the message contains a Tor V2 onion address.
54+
pub fn socket_addr(&self) -> Result<SocketAddr, UnroutableAddressError> {
5355
let addr = &self.address;
5456
if addr[0..3] == ONION {
55-
return Err(io::Error::from(io::ErrorKind::AddrNotAvailable));
57+
return Err(UnroutableAddressError::TorV2);
5658
}
5759
let ipv6 =
5860
Ipv6Addr::new(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]);
@@ -126,7 +128,9 @@ impl fmt::Debug for Address {
126128
impl ToSocketAddrs for Address {
127129
type Iter = iter::Once<SocketAddr>;
128130
fn to_socket_addrs(&self) -> Result<Self::Iter, std::io::Error> {
129-
Ok(iter::once(self.socket_addr()?))
131+
self.socket_addr()
132+
.map(iter::once)
133+
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))
130134
}
131135
}
132136

@@ -148,16 +152,16 @@ pub enum AddrV2 {
148152
}
149153

150154
impl TryFrom<AddrV2> for IpAddr {
151-
type Error = AddrV2ToIpAddrError;
155+
type Error = UnroutableAddressError;
152156

153157
fn try_from(addr: AddrV2) -> Result<Self, Self::Error> {
154158
match addr {
155159
AddrV2::Ipv4(ip) => Ok(Self::V4(ip)),
156160
AddrV2::Ipv6(ip) => Ok(Self::V6(ip)),
157-
AddrV2::Cjdns(_) => Err(AddrV2ToIpAddrError::Cjdns),
158-
AddrV2::TorV3(_) => Err(AddrV2ToIpAddrError::TorV3),
159-
AddrV2::I2p(_) => Err(AddrV2ToIpAddrError::I2p),
160-
AddrV2::Unknown(_, _) => Err(AddrV2ToIpAddrError::Unknown),
161+
AddrV2::Cjdns(_) => Err(UnroutableAddressError::Cjdns),
162+
AddrV2::TorV3(_) => Err(UnroutableAddressError::TorV3),
163+
AddrV2::I2p(_) => Err(UnroutableAddressError::I2p),
164+
AddrV2::Unknown(_, _) => Err(UnroutableAddressError::Unknown),
161165
}
162166
}
163167
}
@@ -202,11 +206,15 @@ impl From<IpAddr> for AddrV2 {
202206
}
203207

204208
impl From<Ipv4Addr> for AddrV2 {
205-
fn from(addr: Ipv4Addr) -> Self { Self::Ipv4(addr) }
209+
fn from(addr: Ipv4Addr) -> Self {
210+
Self::Ipv4(addr)
211+
}
206212
}
207213

208214
impl From<Ipv6Addr> for AddrV2 {
209-
fn from(addr: Ipv6Addr) -> Self { Self::Ipv6(addr) }
215+
fn from(addr: Ipv6Addr) -> Self {
216+
Self::Ipv6(addr)
217+
}
210218
}
211219

212220
impl Encodable for AddrV2 {
@@ -317,13 +325,19 @@ pub struct AddrV2Message {
317325

318326
impl AddrV2Message {
319327
/// Extracts socket address from an [AddrV2Message] message.
320-
/// This will return [io::Error] [io::ErrorKind::AddrNotAvailable]
321-
/// if the address type can't be converted into a [SocketAddr].
322-
pub fn socket_addr(&self) -> Result<SocketAddr, io::Error> {
328+
///
329+
/// # Errors
330+
///
331+
/// Returns an error if the address type cannot be converted to a socket address
332+
/// (e.g. Tor, I2P, CJDNS addresses).
333+
pub fn socket_addr(&self) -> Result<SocketAddr, UnroutableAddressError> {
323334
match self.addr {
324335
AddrV2::Ipv4(addr) => Ok(SocketAddr::V4(SocketAddrV4::new(addr, self.port))),
325336
AddrV2::Ipv6(addr) => Ok(SocketAddr::V6(SocketAddrV6::new(addr, self.port, 0, 0))),
326-
_ => Err(io::Error::from(io::ErrorKind::AddrNotAvailable)),
337+
AddrV2::TorV3(_) => Err(UnroutableAddressError::TorV3),
338+
AddrV2::I2p(_) => Err(UnroutableAddressError::I2p),
339+
AddrV2::Cjdns(_) => Err(UnroutableAddressError::Cjdns),
340+
AddrV2::Unknown(_, _) => Err(UnroutableAddressError::Unknown),
327341
}
328342
}
329343
}
@@ -356,10 +370,46 @@ impl Decodable for AddrV2Message {
356370
impl ToSocketAddrs for AddrV2Message {
357371
type Iter = iter::Once<SocketAddr>;
358372
fn to_socket_addrs(&self) -> Result<Self::Iter, std::io::Error> {
359-
Ok(iter::once(self.socket_addr()?))
373+
self.socket_addr()
374+
.map(iter::once)
375+
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))
360376
}
361377
}
362378

379+
/// Error returned when an address cannot be converted to an IP-based address.
380+
///
381+
/// Addresses like Tor, I2P, and CJDNS use different routing mechanisms
382+
/// and cannot be represented as standard IP addresses or socket addresses.
383+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
384+
#[non_exhaustive]
385+
pub enum UnroutableAddressError {
386+
/// Tor V2 onion address.
387+
TorV2,
388+
/// Tor V3 onion address.
389+
TorV3,
390+
/// I2P address.
391+
I2p,
392+
/// CJDNS address.
393+
Cjdns,
394+
/// Unknown address type.
395+
Unknown,
396+
}
397+
398+
impl fmt::Display for UnroutableAddressError {
399+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
400+
match self {
401+
Self::TorV2 => write!(f, "Tor v2 addresses cannot be converted to IP addresses"),
402+
Self::TorV3 => write!(f, "Tor v3 addresses cannot be converted to IP addresses"),
403+
Self::I2p => write!(f, "I2P addresses cannot be converted to IP addresses"),
404+
Self::Cjdns => write!(f, "CJDNS addresses cannot be converted to IP addresses"),
405+
Self::Unknown => write!(f, "unknown address type cannot be converted to IP addresses"),
406+
}
407+
}
408+
}
409+
410+
#[cfg(feature = "std")]
411+
impl std::error::Error for UnroutableAddressError {}
412+
363413
/// Error types for [`AddrV2`] to [`IpAddr`] conversion.
364414
#[derive(Debug, PartialEq, Eq)]
365415
pub enum AddrV2ToIpAddrError {
@@ -794,7 +844,7 @@ mod test {
794844
let result = IpAddr::try_from(addr);
795845

796846
assert!(result.is_err());
797-
assert_eq!(result.unwrap_err(), AddrV2ToIpAddrError::Cjdns);
847+
assert_eq!(result.unwrap_err(), UnroutableAddressError::Cjdns);
798848
}
799849

800850
#[test]
@@ -803,7 +853,7 @@ mod test {
803853
let result = IpAddr::try_from(addr);
804854

805855
assert!(result.is_err());
806-
assert_eq!(result.unwrap_err(), AddrV2ToIpAddrError::TorV3);
856+
assert_eq!(result.unwrap_err(), UnroutableAddressError::TorV3);
807857
}
808858

809859
#[test]
@@ -812,7 +862,7 @@ mod test {
812862
let result = IpAddr::try_from(addr);
813863

814864
assert!(result.is_err());
815-
assert_eq!(result.unwrap_err(), AddrV2ToIpAddrError::I2p);
865+
assert_eq!(result.unwrap_err(), UnroutableAddressError::I2p);
816866
}
817867

818868
#[test]
@@ -821,7 +871,7 @@ mod test {
821871
let result = IpAddr::try_from(addr);
822872

823873
assert!(result.is_err());
824-
assert_eq!(result.unwrap_err(), AddrV2ToIpAddrError::Unknown);
874+
assert_eq!(result.unwrap_err(), UnroutableAddressError::Unknown);
825875
}
826876

827877
#[test]

0 commit comments

Comments
 (0)