Replace `Version` `MetaAddr` with `(Services, SocketAddr)`. (#12)

* Replace Version MetaAddr by (Services, SocketAddr).

The version handshake message doesn't include last-seen timestamps for
the address fields, unlike other messages, so instead of modeling the
message data with a `MetaAddr` (which includes a timestamp), we should
just use a tuple.

* Simplify try_read_version implementation.

Because we no longer need to construct fake timestamps for the
`MetaAddr` fields, we don't need to use any of the parsed fields while
parsing later fields, and we can neatly wrap up the entire parsing logic
into a single expression.

* fmt

I didn't have the toolchain-specified `rustfmt` because I was mostly
offline and couldn't download it.
This commit is contained in:
Henry de Valence 2019-09-19 09:38:02 -07:00 committed by GitHub
parent 73740841e1
commit f45bbeba98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 46 additions and 68 deletions

View File

@ -5,7 +5,7 @@
#[macro_use] #[macro_use]
extern crate failure; extern crate failure;
pub mod message;
pub mod types;
mod constants; mod constants;
pub mod message;
mod meta_addr; mod meta_addr;
pub mod types;

View File

@ -1,6 +1,7 @@
//! Definitions of network messages. //! Definitions of network messages.
use std::io; use std::io;
use std::net;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use chrono::{DateTime, TimeZone, Utc}; use chrono::{DateTime, TimeZone, Utc};
@ -57,17 +58,15 @@ pub enum Message {
/// The time when the version message was sent. /// The time when the version message was sent.
timestamp: DateTime<Utc>, timestamp: DateTime<Utc>,
/// The network address of the node receiving this message. /// The network address of the node receiving this message, and its
/// advertised network services.
/// ///
/// Note that the timestamp field of the [`MetaAddr`] is not included in /// Q: how does the handshake know the remote peer's services already?
/// the serialization of `version` messages. address_recv: (Services, net::SocketAddr),
address_receiving: MetaAddr,
/// The network address of the node emitting this message. /// The network address of the node sending this message, and its
/// /// advertised network services.
/// Note that the timestamp field of the [`MetaAddr`] is not included in address_from: (Services, net::SocketAddr),
/// the serialization of `version` messages.
address_from: MetaAddr,
/// Node random nonce, randomly generated every time a version /// Node random nonce, randomly generated every time a version
/// packet is sent. This nonce is used to detect connections /// packet is sent. This nonce is used to detect connections
@ -353,7 +352,7 @@ impl Message {
ref version, ref version,
ref services, ref services,
ref timestamp, ref timestamp,
ref address_receiving, ref address_recv,
ref address_from, ref address_from,
ref nonce, ref nonce,
ref user_agent, ref user_agent,
@ -364,14 +363,13 @@ impl Message {
writer.write_u64::<LittleEndian>(services.0)?; writer.write_u64::<LittleEndian>(services.0)?;
writer.write_i64::<LittleEndian>(timestamp.timestamp())?; writer.write_i64::<LittleEndian>(timestamp.timestamp())?;
// We represent a Bitcoin net_addr as a `MetaAddr` internally. let (recv_services, recv_addr) = address_recv;
// However, the version message encodes net_addrs without the writer.write_u64::<LittleEndian>(recv_services.0)?;
// timestamp field, so we encode the `MetaAddr`s manually here. writer.write_socket_addr(*recv_addr)?;
writer.write_u64::<LittleEndian>(address_receiving.services.0)?;
writer.write_socket_addr(address_receiving.addr)?;
writer.write_u64::<LittleEndian>(address_from.services.0)?; let (from_services, from_addr) = address_from;
writer.write_socket_addr(address_from.addr)?; writer.write_u64::<LittleEndian>(from_services.0)?;
writer.write_socket_addr(*from_addr)?;
writer.write_u64::<LittleEndian>(nonce.0)?; writer.write_u64::<LittleEndian>(nonce.0)?;
writer.write_string(&user_agent)?; writer.write_string(&user_agent)?;
@ -459,44 +457,26 @@ fn try_read_version<R: io::Read>(
mut reader: R, mut reader: R,
_parsing_version: Version, _parsing_version: Version,
) -> Result<Message, SerializationError> { ) -> Result<Message, SerializationError> {
let version = Version(reader.read_u32::<LittleEndian>()?); Ok(Message::Version {
let services = Services(reader.read_u64::<LittleEndian>()?); version: Version(reader.read_u32::<LittleEndian>()?),
let timestamp = Utc.timestamp(reader.read_i64::<LittleEndian>()?, 0);
// We represent a Bitcoin `net_addr` as a `MetaAddr` internally. However,
// the version message encodes `net_addr`s without timestamps, so we fill in
// the timestamp field of the `MetaAddr`s with the version message's
// timestamp.
let address_receiving = MetaAddr {
services: Services(reader.read_u64::<LittleEndian>()?), services: Services(reader.read_u64::<LittleEndian>()?),
addr: reader.read_socket_addr()?, timestamp: Utc.timestamp(reader.read_i64::<LittleEndian>()?, 0),
last_seen: timestamp, address_recv: (
}; Services(reader.read_u64::<LittleEndian>()?),
let address_from = MetaAddr { reader.read_socket_addr()?,
services: Services(reader.read_u64::<LittleEndian>()?), ),
addr: reader.read_socket_addr()?, address_from: (
last_seen: timestamp, Services(reader.read_u64::<LittleEndian>()?),
}; reader.read_socket_addr()?,
),
let nonce = Nonce(reader.read_u64::<LittleEndian>()?); nonce: Nonce(reader.read_u64::<LittleEndian>()?),
let user_agent = reader.read_string()?; user_agent: reader.read_string()?,
let start_height = BlockHeight(reader.read_u32::<LittleEndian>()?); start_height: BlockHeight(reader.read_u32::<LittleEndian>()?),
let relay = match reader.read_u8()? { relay: match reader.read_u8()? {
0 => false, 0 => false,
1 => true, 1 => true,
_ => return Err(SerializationError::ParseError("non-bool value")), _ => return Err(SerializationError::ParseError("non-bool value")),
}; },
Ok(Message::Version {
version,
services,
timestamp,
address_receiving,
address_from,
nonce,
user_agent,
start_height,
relay,
}) })
} }
@ -648,16 +628,14 @@ mod tests {
services, services,
timestamp, timestamp,
// XXX maybe better to have Version keep only (Services, SocketAddr) // XXX maybe better to have Version keep only (Services, SocketAddr)
address_receiving: MetaAddr { address_recv: (
services, services,
addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)), 8233), SocketAddr::new(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)), 8233),
last_seen: timestamp, ),
}, address_from: (
address_from: MetaAddr {
services, services,
addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)), 8233), SocketAddr::new(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)), 8233),
last_seen: timestamp, ),
},
nonce: Nonce(0x9082_4908_8927_9238), nonce: Nonce(0x9082_4908_8927_9238),
user_agent: "Zebra".to_owned(), user_agent: "Zebra".to_owned(),
start_height: BlockHeight(540_000), start_height: BlockHeight(540_000),