Merge rust-bitcoin/rust-bitcoin#968: Refactor address byte swapping
07c75304d2
Refactor address byte swapping (Tobin C. Harding) Pull request description: Refactor address byte swapping When encoding a `network::Address` two of the fields are encoded big-endian instead of little-endian as is done by `consensus_encode`. In order to achieve this we have a helper function `addr_to_be` that swaps the bytes. This function is miss-named because it is not converting to a specific endian-ness (which implies different behaviour on machines with different endian-ness) but is reversing the byte order irrespective of the underlying architecture. - Remove function `addr_to_be` - Inline the endian-ness code when encoding an address - Remove TODO and use `to_be_bytes` when encoding port - Add a function for reading big-endian bytes `read_be_address` - Use `read_be_address` when decoding `Address` and `Addrv2` Refactor only, no logic changes. Code path is already covered by unit tests. ACKs for top commit: apoelstra: ACK07c75304d2
Kixunil: ACK07c75304d2
Tree-SHA512: 186bc86512e264a7b306f3bc2e18d1619f3cd84fc54412148cfc2663e8d6e9616ea9e2fe19eafec72d76cc11367a9b39cac2b73210d9e43eb8f453bd253b33de
This commit is contained in:
commit
324fa0f7be
|
@ -67,25 +67,19 @@ impl Address {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addr_to_be(addr: [u16; 8]) -> [u16; 8] {
|
|
||||||
// consensus_encode always encodes in LE, and we want to encode in BE.
|
|
||||||
// this utility fn swap bytes before encoding so that the encoded result will be BE
|
|
||||||
let mut result = addr;
|
|
||||||
for word in &mut result {
|
|
||||||
*word = word.swap_bytes();
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Encodable for Address {
|
impl Encodable for Address {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_encode<S: io::Write>(&self, mut s: S) -> Result<usize, io::Error> {
|
fn consensus_encode<S: io::Write>(&self, mut s: S) -> Result<usize, io::Error> {
|
||||||
let len = self.services.consensus_encode(&mut s)?
|
let mut len = self.services.consensus_encode(&mut s)?;
|
||||||
+ addr_to_be(self.address).consensus_encode(&mut s)?
|
|
||||||
|
for word in &self.address {
|
||||||
|
s.write_all(&word.to_be_bytes())?;
|
||||||
|
len += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
s.write_all(&self.port.to_be_bytes())?;
|
||||||
|
len += 2;
|
||||||
|
|
||||||
// consensus_encode always encodes in LE, and we want to encode in BE.
|
|
||||||
//TODO `len += io::Write::write(&mut e, &self.port.to_be_bytes())?;` when MSRV >= 1.32
|
|
||||||
+ self.port.swap_bytes().consensus_encode(s)?;
|
|
||||||
Ok(len)
|
Ok(len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,12 +89,24 @@ impl Decodable for Address {
|
||||||
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, encode::Error> {
|
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, encode::Error> {
|
||||||
Ok(Address {
|
Ok(Address {
|
||||||
services: Decodable::consensus_decode(&mut d)?,
|
services: Decodable::consensus_decode(&mut d)?,
|
||||||
address: addr_to_be(Decodable::consensus_decode(&mut d)?),
|
address: read_be_address(&mut d)?,
|
||||||
port: u16::swap_bytes(Decodable::consensus_decode(d)?)
|
port: u16::swap_bytes(Decodable::consensus_decode(d)?)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read a big-endian address from reader.
|
||||||
|
fn read_be_address<R: io::Read>(mut r: R) -> Result<[u16; 8], encode::Error> {
|
||||||
|
let mut address = [0u16; 8];
|
||||||
|
let mut buf = [0u8; 2];
|
||||||
|
|
||||||
|
for word in &mut address {
|
||||||
|
io::Read::read_exact(&mut r, &mut buf)?;
|
||||||
|
*word = u16::from_be_bytes(buf)
|
||||||
|
}
|
||||||
|
Ok(address)
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Address {
|
impl fmt::Debug for Address {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let ipv6 = Ipv6Addr::from(self.address);
|
let ipv6 = Ipv6Addr::from(self.address);
|
||||||
|
@ -180,7 +186,7 @@ impl Decodable for AddrV2 {
|
||||||
if len != 16 {
|
if len != 16 {
|
||||||
return Err(encode::Error::ParseFailed("Invalid IPv6 address"));
|
return Err(encode::Error::ParseFailed("Invalid IPv6 address"));
|
||||||
}
|
}
|
||||||
let addr: [u16; 8] = addr_to_be(Decodable::consensus_decode(&mut d)?);
|
let addr: [u16; 8] = read_be_address(&mut d)?;
|
||||||
if addr[0..3] == ONION {
|
if addr[0..3] == ONION {
|
||||||
return Err(encode::Error::ParseFailed("OnionCat address sent with IPv6 network id"));
|
return Err(encode::Error::ParseFailed("OnionCat address sent with IPv6 network id"));
|
||||||
}
|
}
|
||||||
|
@ -214,12 +220,11 @@ impl Decodable for AddrV2 {
|
||||||
if len != 16 {
|
if len != 16 {
|
||||||
return Err(encode::Error::ParseFailed("Invalid CJDNS address"));
|
return Err(encode::Error::ParseFailed("Invalid CJDNS address"));
|
||||||
}
|
}
|
||||||
let addr: [u16; 8] = Decodable::consensus_decode(&mut d)?;
|
let addr: [u16; 8] = read_be_address(&mut d)?;
|
||||||
// check the first byte for the CJDNS marker
|
// check the first byte for the CJDNS marker
|
||||||
if addr[0] as u8 != 0xFC {
|
if addr[0] != u16::from_be_bytes([0xFC, 0x00]) {
|
||||||
return Err(encode::Error::ParseFailed("Invalid CJDNS address"));
|
return Err(encode::Error::ParseFailed("Invalid CJDNS address"));
|
||||||
}
|
}
|
||||||
let addr = addr_to_be(addr);
|
|
||||||
AddrV2::Cjdns(Ipv6Addr::new(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]))
|
AddrV2::Cjdns(Ipv6Addr::new(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]))
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
|
Loading…
Reference in New Issue