From e5b5cbfadbf031213d8dc407ad8ad9bc4d0a81b4 Mon Sep 17 00:00:00 2001 From: Carl Dong Date: Fri, 17 Aug 2018 08:25:11 -0700 Subject: [PATCH 1/5] Fix Error type for SimpleDecoder and SimpleEncoder - Separate serialize::Error and network::Error from util::Error - Remove unneeded propagate_err and consume_err - Change fuzzing code to ignore Err type --- fuzz/fuzz_targets/deserialize_block.rs | 4 +- fuzz/fuzz_targets/deserialize_script.rs | 4 +- fuzz/fuzz_targets/deserialize_transaction.rs | 4 +- src/blockdata/block.rs | 2 +- src/blockdata/opcodes.rs | 6 +- src/blockdata/script.rs | 6 +- src/blockdata/transaction.rs | 14 +- src/internal_macros.rs | 8 +- src/network/address.rs | 6 +- src/network/constants.rs | 6 +- src/network/encodable.rs | 56 +++--- src/network/listener.rs | 4 +- src/network/message.rs | 42 ++--- src/network/message_blockdata.rs | 6 +- src/network/message_network.rs | 1 + src/network/mod.rs | 45 +++++ src/network/serialize.rs | 181 +++++++++++++------ src/network/socket.rs | 56 +++--- src/util/address.rs | 14 +- src/util/hash.rs | 22 +-- src/util/misc.rs | 25 +-- src/util/mod.rs | 98 +++------- src/util/privkey.rs | 10 +- src/util/uint.rs | 5 +- 24 files changed, 341 insertions(+), 284 deletions(-) diff --git a/fuzz/fuzz_targets/deserialize_block.rs b/fuzz/fuzz_targets/deserialize_block.rs index 52ba0cb..cb314ad 100644 --- a/fuzz/fuzz_targets/deserialize_block.rs +++ b/fuzz/fuzz_targets/deserialize_block.rs @@ -1,7 +1,7 @@ extern crate bitcoin; -type BResult = Result; + fn do_test(data: &[u8]) { - let _: BResult = bitcoin::network::serialize::deserialize(data); + let _: Result= bitcoin::network::serialize::deserialize(data); } #[cfg(feature = "afl")] diff --git a/fuzz/fuzz_targets/deserialize_script.rs b/fuzz/fuzz_targets/deserialize_script.rs index b336af0..a31a74c 100644 --- a/fuzz/fuzz_targets/deserialize_script.rs +++ b/fuzz/fuzz_targets/deserialize_script.rs @@ -1,7 +1,7 @@ extern crate bitcoin; -type BResult = Result; + fn do_test(data: &[u8]) { - let _: BResult = bitcoin::network::serialize::deserialize(data); + let _: Result = bitcoin::network::serialize::deserialize(data); } #[cfg(feature = "afl")] diff --git a/fuzz/fuzz_targets/deserialize_transaction.rs b/fuzz/fuzz_targets/deserialize_transaction.rs index 3334b31..505606c 100644 --- a/fuzz/fuzz_targets/deserialize_transaction.rs +++ b/fuzz/fuzz_targets/deserialize_transaction.rs @@ -1,7 +1,7 @@ extern crate bitcoin; -type BResult = Result; + fn do_test(data: &[u8]) { - let tx_result: BResult = bitcoin::network::serialize::deserialize(data); + let tx_result: Result = bitcoin::network::serialize::deserialize(data); match tx_result { Err(_) => {}, Ok(mut tx) => { diff --git a/src/blockdata/block.rs b/src/blockdata/block.rs index 3761e2b..c7919f5 100644 --- a/src/blockdata/block.rs +++ b/src/blockdata/block.rs @@ -25,7 +25,7 @@ use util::Error::{SpvBadTarget, SpvBadProofOfWork}; use util::hash::Sha256dHash; use util::uint::Uint256; use network::encodable::VarInt; -use network::serialize::BitcoinHash; +use network::serialize::{self, BitcoinHash}; use network::constants::Network; use blockdata::transaction::Transaction; use blockdata::constants::max_target; diff --git a/src/blockdata/opcodes.rs b/src/blockdata/opcodes.rs index 703de25..3e3f46c 100644 --- a/src/blockdata/opcodes.rs +++ b/src/blockdata/opcodes.rs @@ -25,7 +25,7 @@ // Heavy stick to translate between opcode types use std::mem::transmute; -use network::serialize::{SimpleDecoder, SimpleEncoder}; +use network::serialize::{self, SimpleDecoder, SimpleEncoder}; use network::encodable::{ConsensusDecodable, ConsensusEncodable}; // Note: I am deliberately not implementing PartialOrd or Ord on the @@ -608,14 +608,14 @@ display_from_debug!(All); impl ConsensusDecodable for All { #[inline] - fn consensus_decode(d: &mut D) -> Result { + fn consensus_decode(d: &mut D) -> Result { Ok(All::from(d.read_u8()?)) } } impl ConsensusEncodable for All { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { s.emit_u8(*self as u8) } } diff --git a/src/blockdata/script.rs b/src/blockdata/script.rs index 21c18a1..17bda08 100644 --- a/src/blockdata/script.rs +++ b/src/blockdata/script.rs @@ -32,7 +32,7 @@ use crypto::digest::Digest; use blockdata::opcodes; use network::encodable::{ConsensusDecodable, ConsensusEncodable}; -use network::serialize::{SimpleDecoder, SimpleEncoder}; +use network::serialize::{self, SimpleDecoder, SimpleEncoder}; use util::hash::Hash160; #[cfg(feature="bitcoinconsensus")] use bitcoinconsensus; #[cfg(feature="bitcoinconsensus")] use std::convert; @@ -621,14 +621,14 @@ impl serde::Serialize for Script { // Network serialization impl ConsensusEncodable for Script { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { self.0.consensus_encode(s) } } impl ConsensusDecodable for Script { #[inline] - fn consensus_decode(d: &mut D) -> Result { + fn consensus_decode(d: &mut D) -> Result { Ok(Script(ConsensusDecodable::consensus_decode(d)?)) } } diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 2462b9e..5f0af99 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -31,7 +31,7 @@ use std::fmt; use util::hash::Sha256dHash; #[cfg(feature="bitcoinconsensus")] use blockdata::script; use blockdata::script::Script; -use network::serialize::{serialize, BitcoinHash, SimpleEncoder, SimpleDecoder}; +use network::serialize::{self, serialize, BitcoinHash, SimpleEncoder, SimpleDecoder}; use network::encodable::{ConsensusEncodable, ConsensusDecodable, VarInt}; /// A reference to a transaction output @@ -326,13 +326,13 @@ impl BitcoinHash for Transaction { impl_consensus_encoding!(TxOut, value, script_pubkey); impl ConsensusEncodable for OutPoint { - fn consensus_encode(&self, s: &mut S) -> Result <(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result <(), serialize::Error> { self.txid.consensus_encode(s)?; self.vout.consensus_encode(s) } } impl ConsensusDecodable for OutPoint { - fn consensus_decode(d: &mut D) -> Result { + fn consensus_decode(d: &mut D) -> Result { Ok(OutPoint { txid: ConsensusDecodable::consensus_decode(d)?, vout: ConsensusDecodable::consensus_decode(d)?, @@ -341,14 +341,14 @@ impl ConsensusDecodable for OutPoint { } impl ConsensusEncodable for TxIn { - fn consensus_encode(&self, s: &mut S) -> Result <(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result <(), serialize::Error> { self.previous_output.consensus_encode(s)?; self.script_sig.consensus_encode(s)?; self.sequence.consensus_encode(s) } } impl ConsensusDecodable for TxIn { - fn consensus_decode(d: &mut D) -> Result { + fn consensus_decode(d: &mut D) -> Result { Ok(TxIn { previous_output: ConsensusDecodable::consensus_decode(d)?, script_sig: ConsensusDecodable::consensus_decode(d)?, @@ -359,7 +359,7 @@ impl ConsensusDecodable for TxIn { } impl ConsensusEncodable for Transaction { - fn consensus_encode(&self, s: &mut S) -> Result <(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result <(), serialize::Error> { self.version.consensus_encode(s)?; let mut have_witness = false; for input in &self.input { @@ -385,7 +385,7 @@ impl ConsensusEncodable for Transaction { } impl ConsensusDecodable for Transaction { - fn consensus_decode(d: &mut D) -> Result { + fn consensus_decode(d: &mut D) -> Result { let version: u32 = ConsensusDecodable::consensus_decode(d)?; let input: Vec = ConsensusDecodable::consensus_decode(d)?; // segwit diff --git a/src/internal_macros.rs b/src/internal_macros.rs index 5f756c2..b162183 100644 --- a/src/internal_macros.rs +++ b/src/internal_macros.rs @@ -16,7 +16,7 @@ macro_rules! impl_consensus_encoding { ($thing:ident, $($field:ident),+) => ( impl ::network::encodable::ConsensusEncodable for $thing { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { $( self.$field.consensus_encode(s)?; )+ Ok(()) } @@ -24,7 +24,7 @@ macro_rules! impl_consensus_encoding { impl ::network::encodable::ConsensusDecodable for $thing { #[inline] - fn consensus_decode(d: &mut D) -> Result<$thing, D::Error> { + fn consensus_decode(d: &mut D) -> Result<$thing, serialize::Error> { use network::encodable::ConsensusDecodable; Ok($thing { $( $field: ConsensusDecodable::consensus_decode(d)?, )+ @@ -38,7 +38,7 @@ macro_rules! impl_newtype_consensus_encoding { ($thing:ident) => ( impl ::network::encodable::ConsensusEncodable for $thing { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { let &$thing(ref data) = self; data.consensus_encode(s) } @@ -46,7 +46,7 @@ macro_rules! impl_newtype_consensus_encoding { impl ::network::encodable::ConsensusDecodable for $thing { #[inline] - fn consensus_decode(d: &mut D) -> Result<$thing, D::Error> { + fn consensus_decode(d: &mut D) -> Result<$thing, serialize::Error> { Ok($thing(ConsensusDecodable::consensus_decode(d)?)) } } diff --git a/src/network/address.rs b/src/network/address.rs index 06d549c..ab3cd5b 100644 --- a/src/network/address.rs +++ b/src/network/address.rs @@ -22,7 +22,7 @@ use std::io; use std::fmt; use std::net::{SocketAddr, Ipv6Addr, SocketAddrV4, SocketAddrV6}; -use network::serialize::{SimpleEncoder, SimpleDecoder}; +use network::serialize::{self, SimpleEncoder, SimpleDecoder}; use network::encodable::{ConsensusDecodable, ConsensusEncodable}; /// A message which can be sent on the Bitcoin network @@ -74,7 +74,7 @@ fn addr_to_be(addr: [u16; 8]) -> [u16; 8] { impl ConsensusEncodable for Address { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { self.services.consensus_encode(s)?; addr_to_be(self.address).consensus_encode(s)?; self.port.to_be().consensus_encode(s) @@ -83,7 +83,7 @@ impl ConsensusEncodable for Address { impl ConsensusDecodable for Address { #[inline] - fn consensus_decode(d: &mut D) -> Result { + fn consensus_decode(d: &mut D) -> Result { Ok(Address { services: ConsensusDecodable::consensus_decode(d)?, address: addr_to_be(ConsensusDecodable::consensus_decode(d)?), diff --git a/src/network/constants.rs b/src/network/constants.rs index 78b31f2..ba59c50 100644 --- a/src/network/constants.rs +++ b/src/network/constants.rs @@ -38,7 +38,7 @@ //! ``` use network::encodable::{ConsensusDecodable, ConsensusEncodable}; -use network::serialize::{SimpleEncoder, SimpleDecoder}; +use network::serialize::{self, SimpleEncoder, SimpleDecoder}; /// Version of the protocol as appearing in network message headers pub const PROTOCOL_VERSION: u32 = 70001; @@ -105,7 +105,7 @@ impl Network { impl ConsensusEncodable for Network { /// Encodes the magic bytes of `Network`. #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { self.magic().consensus_encode(s) } } @@ -113,7 +113,7 @@ impl ConsensusEncodable for Network { impl ConsensusDecodable for Network { /// Decodes the magic bytes of `Network`. #[inline] - fn consensus_decode(d: &mut D) -> Result { + fn consensus_decode(d: &mut D) -> Result { u32::consensus_decode(d) .and_then(|m| { Network::from_magic(m) diff --git a/src/network/encodable.rs b/src/network/encodable.rs index 6b395c4..c4c3cc7 100644 --- a/src/network/encodable.rs +++ b/src/network/encodable.rs @@ -34,7 +34,7 @@ use std::hash::Hash; use std::{mem, u32}; use util::hash::Sha256dHash; -use network::serialize::{SimpleDecoder, SimpleEncoder}; +use network::serialize::{self, SimpleDecoder, SimpleEncoder}; /// Maximum size, in bytes, of a vector we are allowed to decode pub const MAX_VEC_SIZE: usize = 32 * 1024 * 1024; @@ -42,13 +42,13 @@ pub const MAX_VEC_SIZE: usize = 32 * 1024 * 1024; /// Data which can be encoded in a consensus-consistent way pub trait ConsensusEncodable { /// Encode an object with a well-defined format - fn consensus_encode(&self, e: &mut S) -> Result<(), S::Error>; + fn consensus_encode(&self, e: &mut S) -> Result<(), serialize::Error>; } /// Data which can be encoded in a consensus-consistent way pub trait ConsensusDecodable: Sized { /// Decode an object with a well-defined format - fn consensus_decode(d: &mut D) -> Result; + fn consensus_decode(d: &mut D) -> Result; } /// A variable-length unsigned integer @@ -64,12 +64,12 @@ macro_rules! impl_int_encodable{ ($ty:ident, $meth_dec:ident, $meth_enc:ident) => ( impl ConsensusDecodable for $ty { #[inline] - fn consensus_decode(d: &mut D) -> Result<$ty, D::Error> { d.$meth_dec().map($ty::from_le) } + fn consensus_decode(d: &mut D) -> Result<$ty, serialize::Error> { d.$meth_dec().map($ty::from_le) } } impl ConsensusEncodable for $ty { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { s.$meth_enc(self.to_le()) } + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { s.$meth_enc(self.to_le()) } } ) } @@ -100,7 +100,7 @@ impl VarInt { impl ConsensusEncodable for VarInt { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { match self.0 { 0...0xFC => { (self.0 as u8).consensus_encode(s) } 0xFD...0xFFFF => { s.emit_u8(0xFD)?; (self.0 as u16).consensus_encode(s) } @@ -112,7 +112,7 @@ impl ConsensusEncodable for VarInt { impl ConsensusDecodable for VarInt { #[inline] - fn consensus_decode(d: &mut D) -> Result { + fn consensus_decode(d: &mut D) -> Result { let n = d.read_u8()?; match n { 0xFF => d.read_u64().map(|n| VarInt(u64::from_le(n))), @@ -126,25 +126,25 @@ impl ConsensusDecodable for VarInt { // Booleans impl ConsensusEncodable for bool { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u8(if *self {1} else {0}) } + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { s.emit_u8(if *self {1} else {0}) } } impl ConsensusDecodable for bool { #[inline] - fn consensus_decode(d: &mut D) -> Result { d.read_u8().map(|n| n != 0) } + fn consensus_decode(d: &mut D) -> Result { d.read_u8().map(|n| n != 0) } } // Strings impl ConsensusEncodable for String { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { self.as_bytes().consensus_encode(s) } } impl ConsensusDecodable for String { #[inline] - fn consensus_decode(d: &mut D) -> Result { + fn consensus_decode(d: &mut D) -> Result { String::from_utf8(ConsensusDecodable::consensus_decode(d)?) .map_err(|_| d.error("String was not valid UTF8".to_owned())) } @@ -156,7 +156,7 @@ macro_rules! impl_array { ( $size:expr ) => ( impl> ConsensusEncodable for [T; $size] { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { for i in self.iter() { i.consensus_encode(s)?; } Ok(()) } @@ -164,7 +164,7 @@ macro_rules! impl_array { impl + Copy> ConsensusDecodable for [T; $size] { #[inline] - fn consensus_decode(d: &mut D) -> Result<[T; $size], D::Error> { + fn consensus_decode(d: &mut D) -> Result<[T; $size], serialize::Error> { // Set everything to the first decode let mut ret = [ConsensusDecodable::consensus_decode(d)?; $size]; // Set the rest @@ -184,7 +184,7 @@ impl_array!(32); impl> ConsensusEncodable for [T] { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { VarInt(self.len() as u64).consensus_encode(s)?; for c in self.iter() { c.consensus_encode(s)?; } Ok(()) @@ -196,12 +196,12 @@ impl> ConsensusEncodable for [T] { // Vectors impl> ConsensusEncodable for Vec { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { (&self[..]).consensus_encode(s) } + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { (&self[..]).consensus_encode(s) } } impl> ConsensusDecodable for Vec { #[inline] - fn consensus_decode(d: &mut D) -> Result, D::Error> { + fn consensus_decode(d: &mut D) -> Result, serialize::Error> { let VarInt(len): VarInt = ConsensusDecodable::consensus_decode(d)?; let byte_size = (len as usize) .checked_mul(mem::size_of::()) @@ -217,12 +217,12 @@ impl> ConsensusDecodable for Vec> ConsensusEncodable for Box<[T]> { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { (&self[..]).consensus_encode(s) } + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { (&self[..]).consensus_encode(s) } } impl> ConsensusDecodable for Box<[T]> { #[inline] - fn consensus_decode(d: &mut D) -> Result, D::Error> { + fn consensus_decode(d: &mut D) -> Result, serialize::Error> { let VarInt(len): VarInt = ConsensusDecodable::consensus_decode(d)?; let len = len as usize; if len > MAX_VEC_SIZE { @@ -237,7 +237,7 @@ impl> ConsensusDecodable for Box<[ // Options (encoded as vectors of length 0 or 1) impl> ConsensusEncodable for Option { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { match *self { Some(ref data) => { 1u8.consensus_encode(s)?; @@ -251,7 +251,7 @@ impl> ConsensusEncodable for Optio impl> ConsensusDecodable for Option { #[inline] - fn consensus_decode(d: &mut D) -> Result, D::Error> { + fn consensus_decode(d: &mut D) -> Result, serialize::Error> { let bit: u8 = ConsensusDecodable::consensus_decode(d)?; Ok(if bit != 0 { Some(ConsensusDecodable::consensus_decode(d)?) @@ -271,7 +271,7 @@ fn sha2_checksum(data: &[u8]) -> [u8; 4] { // Checked data impl ConsensusEncodable for CheckedData { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { (self.0.len() as u32).consensus_encode(s)?; sha2_checksum(&self.0).consensus_encode(s)?; // We can't just pass to the slice encoder since it'll insert a length @@ -284,7 +284,7 @@ impl ConsensusEncodable for CheckedData { impl ConsensusDecodable for CheckedData { #[inline] - fn consensus_decode(d: &mut D) -> Result { + fn consensus_decode(d: &mut D) -> Result { let len: u32 = ConsensusDecodable::consensus_decode(d)?; let checksum: [u8; 4] = ConsensusDecodable::consensus_decode(d)?; let mut ret = Vec::with_capacity(len as usize); @@ -304,7 +304,7 @@ macro_rules! tuple_encode { impl ),*> ConsensusEncodable for ($($x),*) { #[inline] #[allow(non_snake_case)] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { let &($(ref $x),*) = self; $( $x.consensus_encode(s)?; )* Ok(()) @@ -314,7 +314,7 @@ macro_rules! tuple_encode { impl),*> ConsensusDecodable for ($($x),*) { #[inline] #[allow(non_snake_case)] - fn consensus_decode(d: &mut D) -> Result<($($x),*), D::Error> { + fn consensus_decode(d: &mut D) -> Result<($($x),*), serialize::Error> { Ok(($({let $x = ConsensusDecodable::consensus_decode(d)?; $x }),*)) } } @@ -329,12 +329,12 @@ tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7); // References impl> ConsensusEncodable for Box { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { (**self).consensus_encode(s) } + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { (**self).consensus_encode(s) } } impl> ConsensusDecodable for Box { #[inline] - fn consensus_decode(d: &mut D) -> Result, D::Error> { + fn consensus_decode(d: &mut D) -> Result, serialize::Error> { ConsensusDecodable::consensus_decode(d).map(Box::new) } } @@ -346,7 +346,7 @@ impl ConsensusEncodable for HashMap V: ConsensusEncodable { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { VarInt(self.len() as u64).consensus_encode(s)?; for (key, value) in self.iter() { key.consensus_encode(s)?; @@ -362,7 +362,7 @@ impl ConsensusDecodable for HashMap V: ConsensusDecodable { #[inline] - fn consensus_decode(d: &mut D) -> Result, D::Error> { + fn consensus_decode(d: &mut D) -> Result, serialize::Error> { let VarInt(len): VarInt = ConsensusDecodable::consensus_decode(d)?; let mut ret = HashMap::with_capacity(len as usize); diff --git a/src/network/listener.rs b/src/network/listener.rs index e1b4f89..ea2278e 100644 --- a/src/network/listener.rs +++ b/src/network/listener.rs @@ -22,7 +22,7 @@ use std::thread; use std::sync::mpsc::{channel, Receiver}; use network::constants::Network; -use network::message; +use network::{self, message}; use network::message::NetworkMessage::Verack; use network::socket::Socket; use util; @@ -40,7 +40,7 @@ pub trait Listener { // Open socket let mut ret_sock = Socket::new(self.network()); if let Err(e) = ret_sock.connect(self.peer(), self.port()) { - return Err(util::Error::Detail("listener".to_owned(), Box::new(e))); + return Err(util::Error::Network(network::Error::Detail("listener".to_owned(), Box::new(e)))); } let mut sock = ret_sock.clone(); diff --git a/src/network/message.rs b/src/network/message.rs index 50872a4..f775001 100644 --- a/src/network/message.rs +++ b/src/network/message.rs @@ -30,8 +30,8 @@ use network::message_network; use network::message_blockdata; use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use network::encodable::CheckedData; -use network::serialize::{serialize, RawDecoder, SimpleEncoder, SimpleDecoder}; -use util::{self, propagate_err}; +use network::serialize::{self, serialize, RawDecoder, SimpleEncoder, SimpleDecoder}; +use util; /// Serializer for command string #[derive(PartialEq, Eq, Clone, Debug)] @@ -39,7 +39,7 @@ pub struct CommandString(pub String); impl ConsensusEncodable for CommandString { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { let &CommandString(ref inner_str) = self; let mut rawbytes = [0u8; 12]; let strbytes = inner_str.as_bytes(); @@ -55,7 +55,7 @@ impl ConsensusEncodable for CommandString { impl ConsensusDecodable for CommandString { #[inline] - fn consensus_decode(d: &mut D) -> Result { + fn consensus_decode(d: &mut D) -> Result { let rawbytes: [u8; 12] = ConsensusDecodable::consensus_decode(d)?; let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| if u > 0 { Some(u as char) } else { None })); Ok(CommandString(rv)) @@ -147,7 +147,7 @@ impl RawNetworkMessage { } impl ConsensusEncodable for RawNetworkMessage { - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { self.magic.consensus_encode(s)?; CommandString(self.command()).consensus_encode(s)?; CheckedData(match self.payload { @@ -172,32 +172,30 @@ impl ConsensusEncodable for RawNetworkMessage { } } -// TODO: restriction on D::Error is so that `propagate_err` will work; -// is there a more generic way to handle this? -impl> ConsensusDecodable for RawNetworkMessage { - fn consensus_decode(d: &mut D) -> Result { +impl ConsensusDecodable for RawNetworkMessage { + fn consensus_decode(d: &mut D) -> Result { let magic = ConsensusDecodable::consensus_decode(d)?; let CommandString(cmd): CommandString= ConsensusDecodable::consensus_decode(d)?; let CheckedData(raw_payload): CheckedData = ConsensusDecodable::consensus_decode(d)?; let mut mem_d = RawDecoder::new(Cursor::new(raw_payload)); let payload = match &cmd[..] { - "version" => NetworkMessage::Version(propagate_err("version".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d))?), + "version" => NetworkMessage::Version(ConsensusDecodable::consensus_decode(&mut mem_d)?), "verack" => NetworkMessage::Verack, - "addr" => NetworkMessage::Addr(propagate_err("addr".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d))?), - "inv" => NetworkMessage::Inv(propagate_err("inv".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d))?), - "getdata" => NetworkMessage::GetData(propagate_err("getdata".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d))?), - "notfound" => NetworkMessage::NotFound(propagate_err("notfound".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d))?), - "getblocks" => NetworkMessage::GetBlocks(propagate_err("getblocks".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d))?), - "getheaders" => NetworkMessage::GetHeaders(propagate_err("getheaders".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d))?), + "addr" => NetworkMessage::Addr(ConsensusDecodable::consensus_decode(&mut mem_d)?), + "inv" => NetworkMessage::Inv(ConsensusDecodable::consensus_decode(&mut mem_d)?), + "getdata" => NetworkMessage::GetData(ConsensusDecodable::consensus_decode(&mut mem_d)?), + "notfound" => NetworkMessage::NotFound(ConsensusDecodable::consensus_decode(&mut mem_d)?), + "getblocks" => NetworkMessage::GetBlocks(ConsensusDecodable::consensus_decode(&mut mem_d)?), + "getheaders" => NetworkMessage::GetHeaders(ConsensusDecodable::consensus_decode(&mut mem_d)?), "mempool" => NetworkMessage::MemPool, - "block" => NetworkMessage::Block(propagate_err("block".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d))?), - "headers" => NetworkMessage::Headers(propagate_err("headers".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d))?), + "block" => NetworkMessage::Block(ConsensusDecodable::consensus_decode(&mut mem_d)?), + "headers" => NetworkMessage::Headers(ConsensusDecodable::consensus_decode(&mut mem_d)?), "getaddr" => NetworkMessage::GetAddr, - "ping" => NetworkMessage::Ping(propagate_err("ping".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d))?), - "pong" => NetworkMessage::Pong(propagate_err("pong".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d))?), - "tx" => NetworkMessage::Tx(propagate_err("tx".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d))?), - "alert" => NetworkMessage::Alert(propagate_err("alert".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d))?), + "ping" => NetworkMessage::Ping(ConsensusDecodable::consensus_decode(&mut mem_d)?), + "pong" => NetworkMessage::Pong(ConsensusDecodable::consensus_decode(&mut mem_d)?), + "tx" => NetworkMessage::Tx(ConsensusDecodable::consensus_decode(&mut mem_d)?), + "alert" => NetworkMessage::Alert(ConsensusDecodable::consensus_decode(&mut mem_d)?), cmd => return Err(d.error(format!("unrecognized network command `{}`", cmd))) }; Ok(RawNetworkMessage { diff --git a/src/network/message_blockdata.rs b/src/network/message_blockdata.rs index 28f17ea..83b7dfd 100644 --- a/src/network/message_blockdata.rs +++ b/src/network/message_blockdata.rs @@ -20,7 +20,7 @@ use network::constants; use network::encodable::{ConsensusDecodable, ConsensusEncodable}; -use network::serialize::{SimpleDecoder, SimpleEncoder}; +use network::serialize::{self, SimpleDecoder, SimpleEncoder}; use util::hash::Sha256dHash; #[derive(PartialEq, Eq, Clone, Debug)] @@ -103,7 +103,7 @@ impl_consensus_encoding!(GetHeadersMessage, version, locator_hashes, stop_hash); impl ConsensusEncodable for Inventory { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { match self.inv_type { InvType::Error => 0u32, InvType::Transaction => 1, @@ -117,7 +117,7 @@ impl ConsensusEncodable for Inventory { impl ConsensusDecodable for Inventory { #[inline] - fn consensus_decode(d: &mut D) -> Result { + fn consensus_decode(d: &mut D) -> Result { let int_type: u32 = ConsensusDecodable::consensus_decode(d)?; Ok(Inventory { inv_type: match int_type { diff --git a/src/network/message_network.rs b/src/network/message_network.rs index 93c4dfa..38abe8a 100644 --- a/src/network/message_network.rs +++ b/src/network/message_network.rs @@ -20,6 +20,7 @@ use network::constants; use network::address::Address; +use network::serialize; use network::socket::Socket; use util; diff --git a/src/network/mod.rs b/src/network/mod.rs index 9972745..696d720 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -18,6 +18,10 @@ //! of Bitcoin data and network messages. //! +use std::fmt; +use std::io; +use std::error; + pub mod constants; pub mod consensus_params; pub mod encodable; @@ -30,3 +34,44 @@ pub mod message; pub mod message_blockdata; pub mod message_network; +/// Network error +#[derive(Debug)] +pub enum Error { + /// And I/O error + Io(io::Error), + /// Socket mutex was poisoned + SocketMutexPoisoned, + /// Not connected to peer + SocketNotConnectedToPeer, + /// Error propagated from subsystem + Detail(String, Box), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::Io(ref e) => fmt::Display::fmt(e, f), + Error::Detail(ref s, ref e) => write!(f, "{}: {}", s, e), + ref x => f.write_str(error::Error::description(x)), + } + } +} + +impl error::Error for Error { + fn cause(&self) -> Option<&error::Error> { + match *self { + Error::Io(ref e) => Some(e), + Error::Detail(_, ref e) => Some(e), + _ => None + } + } + + fn description(&self) -> &str { + match *self { + Error::Io(ref e) => e.description(), + Error::SocketMutexPoisoned => "socket mutex was poisoned", + Error::SocketNotConnectedToPeer => "not connected to peer", + Error::Detail(_, ref e) => e.description(), + } + } +} diff --git a/src/network/serialize.rs b/src/network/serialize.rs index 4fde9d9..25a96bf 100644 --- a/src/network/serialize.rs +++ b/src/network/serialize.rs @@ -19,13 +19,100 @@ //! It also defines (de)serialization routines for many primitives. //! +use std::error; +use std::fmt; +use std::io; use std::io::{Cursor, Read, Write}; use byteorder::{LittleEndian, WriteBytesExt, ReadBytesExt}; use hex::encode as hex_encode; +use bitcoin_bech32; + use network::encodable::{ConsensusDecodable, ConsensusEncodable}; +use util::base58; use util::hash::Sha256dHash; -use util; + +/// Serialization error +#[derive(Debug)] +pub enum Error { + /// And I/O error + Io(io::Error), + /// Base58 encoding error + Base58(base58::Error), + /// Bech32 encoding error + Bech32(bitcoin_bech32::Error), + /// Error from the `byteorder` crate + ByteOrder(io::Error), + /// Network magic was not what we expected + BadNetworkMagic(u32, u32), + /// Network message was unrecognized + BadNetworkMessage(String), + /// Parsing error + ParseFailed, + /// Error propagated from subsystem + Detail(String, Box), + /// Unsupported witness version + UnsupportedWitnessVersion(u8), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::Io(ref e) => fmt::Display::fmt(e, f), + Error::Detail(ref s, ref e) => write!(f, "{}: {}", s, e), + ref x => f.write_str(error::Error::description(x)), + } + } +} + +impl error::Error for Error { + fn cause(&self) -> Option<&error::Error> { + match *self { + Error::Io(ref e) => Some(e), + Error::Base58(ref e) => Some(e), + Error::Bech32(ref e) => Some(e), + Error::ByteOrder(ref e) => Some(e), + Error::Detail(_, ref e) => Some(e), + _ => None + } + } + + fn description(&self) -> &str { + match *self { + Error::Io(ref e) => e.description(), + Error::ParseFailed => "parsing error", + Error::Detail(_, ref e) => e.description(), + Error::Base58(ref e) => e.description(), + Error::Bech32(ref e) => e.description(), + Error::ByteOrder(ref e) => e.description(), + Error::BadNetworkMagic(_, _) => "incorrect network magic", + Error::BadNetworkMessage(_) => "incorrect/unexpected network message", + Error::UnsupportedWitnessVersion(_) => "unsupported witness version", + } + } +} + +#[doc(hidden)] +impl From for Error { + fn from(e: base58::Error) -> Error { + Error::Base58(e) + } +} + +#[doc(hidden)] +impl From for Error { + fn from(e: bitcoin_bech32::Error) -> Error { + Error::Bech32(e) + } +} + + +#[doc(hidden)] +impl From for Error { + fn from(error: io::Error) -> Self { + Error::Io(error) + } +} /// Objects which are referred to by hash pub trait BitcoinHash { @@ -41,7 +128,7 @@ impl BitcoinHash for Vec { } /// Encode an object into a vector -pub fn serialize(data: &T) -> Result, util::Error> +pub fn serialize(data: &T) -> Result, Error> where T: ConsensusEncodable>>>, { let mut encoder = RawEncoder::new(Cursor::new(vec![])); @@ -50,7 +137,7 @@ pub fn serialize(data: &T) -> Result, util::Error> } /// Encode an object into a hex-encoded string -pub fn serialize_hex(data: &T) -> Result +pub fn serialize_hex(data: &T) -> Result where T: ConsensusEncodable>>> { let serial = serialize(data)?; @@ -59,7 +146,7 @@ pub fn serialize_hex(data: &T) -> Result /// Deserialize an object from a vector, will error if said deserialization /// doesn't consume the entire vector. -pub fn deserialize<'a, T>(data: &'a [u8]) -> Result +pub fn deserialize<'a, T>(data: &'a [u8]) -> Result where T: ConsensusDecodable>> { let mut decoder = RawDecoder::new(Cursor::new(data)); @@ -69,7 +156,7 @@ pub fn deserialize<'a, T>(data: &'a [u8]) -> Result if decoder.into_inner().position() == data.len() as u64 { Ok(rv) } else { - Err(util::Error::ParseFailed) + Err(Error::ParseFailed) } } @@ -99,66 +186,60 @@ impl RawDecoder { /// A simple Encoder trait pub trait SimpleEncoder { - /// An encoding error - type Error; - /// Output a 64-bit uint - fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error>; + fn emit_u64(&mut self, v: u64) -> Result<(), Error>; /// Output a 32-bit uint - fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error>; + fn emit_u32(&mut self, v: u32) -> Result<(), Error>; /// Output a 16-bit uint - fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error>; + fn emit_u16(&mut self, v: u16) -> Result<(), Error>; /// Output a 8-bit uint - fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error>; + fn emit_u8(&mut self, v: u8) -> Result<(), Error>; /// Output a 64-bit int - fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error>; + fn emit_i64(&mut self, v: i64) -> Result<(), Error>; /// Output a 32-bit int - fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error>; + fn emit_i32(&mut self, v: i32) -> Result<(), Error>; /// Output a 16-bit int - fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error>; + fn emit_i16(&mut self, v: i16) -> Result<(), Error>; /// Output a 8-bit int - fn emit_i8(&mut self, v: i8) -> Result<(), Self::Error>; + fn emit_i8(&mut self, v: i8) -> Result<(), Error>; /// Output a boolean - fn emit_bool(&mut self, v: bool) -> Result<(), Self::Error>; + fn emit_bool(&mut self, v: bool) -> Result<(), Error>; } /// A simple Decoder trait pub trait SimpleDecoder { - /// A decoding error - type Error; - /// Read a 64-bit uint - fn read_u64(&mut self) -> Result; + fn read_u64(&mut self) -> Result; /// Read a 32-bit uint - fn read_u32(&mut self) -> Result; + fn read_u32(&mut self) -> Result; /// Read a 16-bit uint - fn read_u16(&mut self) -> Result; + fn read_u16(&mut self) -> Result; /// Read a 8-bit uint - fn read_u8(&mut self) -> Result; + fn read_u8(&mut self) -> Result; /// Read a 64-bit int - fn read_i64(&mut self) -> Result; + fn read_i64(&mut self) -> Result; /// Read a 32-bit int - fn read_i32(&mut self) -> Result; + fn read_i32(&mut self) -> Result; /// Read a 16-bit int - fn read_i16(&mut self) -> Result; + fn read_i16(&mut self) -> Result; /// Read a 8-bit int - fn read_i8(&mut self) -> Result; + fn read_i8(&mut self) -> Result; /// Read a boolean - fn read_bool(&mut self) -> Result; + fn read_bool(&mut self) -> Result; /// Signal a decoding error - fn error(&mut self, err: String) -> Self::Error; + fn error(&mut self, err: String) -> Error; } macro_rules! encoder_fn { ($name:ident, $val_type:ty, $writefn:ident) => { #[inline] - fn $name(&mut self, v: $val_type) -> Result<(), util::Error> { - self.writer.$writefn::(v).map_err(util::Error::ByteOrder) + fn $name(&mut self, v: $val_type) -> Result<(), Error> { + self.writer.$writefn::(v).map_err(Error::Io) } } } @@ -166,15 +247,13 @@ macro_rules! encoder_fn { macro_rules! decoder_fn { ($name:ident, $val_type:ty, $readfn:ident) => { #[inline] - fn $name(&mut self) -> Result<$val_type, util::Error> { - self.reader.$readfn::().map_err(util::Error::ByteOrder) + fn $name(&mut self) -> Result<$val_type, Error> { + self.reader.$readfn::().map_err(Error::Io) } } } impl SimpleEncoder for RawEncoder { - type Error = util::Error; - encoder_fn!(emit_u64, u64, write_u64); encoder_fn!(emit_u32, u32, write_u32); encoder_fn!(emit_u16, u16, write_u16); @@ -183,22 +262,20 @@ impl SimpleEncoder for RawEncoder { encoder_fn!(emit_i16, i16, write_i16); #[inline] - fn emit_i8(&mut self, v: i8) -> Result<(), util::Error> { - self.writer.write_i8(v).map_err(util::Error::ByteOrder) + fn emit_i8(&mut self, v: i8) -> Result<(), Error> { + self.writer.write_i8(v).map_err(Error::Io) } #[inline] - fn emit_u8(&mut self, v: u8) -> Result<(), util::Error> { - self.writer.write_u8(v).map_err(util::Error::ByteOrder) + fn emit_u8(&mut self, v: u8) -> Result<(), Error> { + self.writer.write_u8(v).map_err(Error::Io) } #[inline] - fn emit_bool(&mut self, v: bool) -> Result<(), util::Error> { - self.writer.write_i8(if v {1} else {0}).map_err(util::Error::ByteOrder) + fn emit_bool(&mut self, v: bool) -> Result<(), Error> { + self.writer.write_i8(if v {1} else {0}).map_err(Error::Io) } } impl SimpleDecoder for RawDecoder { - type Error = util::Error; - decoder_fn!(read_u64, u64, read_u64); decoder_fn!(read_u32, u32, read_u32); decoder_fn!(read_u16, u16, read_u16); @@ -207,24 +284,24 @@ impl SimpleDecoder for RawDecoder { decoder_fn!(read_i16, i16, read_i16); #[inline] - fn read_u8(&mut self) -> Result { - self.reader.read_u8().map_err(util::Error::ByteOrder) + fn read_u8(&mut self) -> Result { + self.reader.read_u8().map_err(Error::Io) } #[inline] - fn read_i8(&mut self) -> Result { - self.reader.read_i8().map_err(util::Error::ByteOrder) + fn read_i8(&mut self) -> Result { + self.reader.read_i8().map_err(Error::Io) } #[inline] - fn read_bool(&mut self) -> Result { + fn read_bool(&mut self) -> Result { match self.reader.read_i8() { Ok(bit) => Ok(bit != 0), - Err(e) => Err(util::Error::ByteOrder(e)) + Err(e) => Err(Error::Io(e)) } } #[inline] - fn error(&mut self, err: String) -> util::Error { - util::Error::Detail(err, Box::new(util::Error::ParseFailed)) + fn error(&mut self, err: String) -> Error { + Error::Detail(err, Box::new(Error::ParseFailed)) } } diff --git a/src/network/socket.rs b/src/network/socket.rs index c101ba0..793d49b 100644 --- a/src/network/socket.rs +++ b/src/network/socket.rs @@ -19,18 +19,19 @@ use std::time::{UNIX_EPOCH, SystemTime}; use rand::{thread_rng, Rng}; -use std::io::{self, Write}; +use std::io::Write; use std::net; use std::sync::{Arc, Mutex}; +use network; use network::constants; use network::address::Address; use network::encodable::{ConsensusEncodable, ConsensusDecodable}; use network::message::{RawNetworkMessage, NetworkMessage}; use network::message::NetworkMessage::Version; use network::message_network::VersionMessage; -use network::serialize::{RawEncoder, RawDecoder}; -use util::{self, propagate_err}; +use network::serialize::{self, RawEncoder, RawDecoder}; +use util; /// Format an IP address in the 16-byte bitcoin protocol serialization fn ipaddr_to_bitcoin_addr(addr: &net::SocketAddr) -> [u16; 8] { @@ -60,9 +61,7 @@ macro_rules! with_socket(($s:ident, $sock:ident, $body:block) => ({ let sock_lock = $s.socket.lock(); match sock_lock { Err(_) => { - let io_err = io::Error::new(io::ErrorKind::NotConnected, - "socket: socket mutex was poisoned"); - Err(util::Error::Io(io_err)) + Err(network::Error::SocketMutexPoisoned.into()) } Ok(mut guard) => { match *guard.deref_mut() { @@ -70,16 +69,13 @@ macro_rules! with_socket(($s:ident, $sock:ident, $body:block) => ({ $body } None => { - let io_err = io::Error::new(io::ErrorKind::NotConnected, - "socket: not connected to peer"); - Err(util::Error::Io(io_err)) + Err(network::Error::SocketNotConnectedToPeer.into()) } } } } })); - impl Socket { // TODO: we fix services to 0 /// Construct a new socket @@ -95,7 +91,7 @@ impl Socket { } /// (Re)connect to the peer - pub fn connect(&mut self, host: &str, port: u16) -> Result<(), util::Error> { + pub fn connect(&mut self, host: &str, port: u16) -> Result<(), network::Error> { // Entirely replace the Mutex, in case it was poisoned; // this will also drop any preexisting socket that might be open match net::TcpStream::connect((host, port)) { @@ -105,13 +101,13 @@ impl Socket { } Err(e) => { self.socket = Arc::new(Mutex::new(None)); - Err(util::Error::Io(e)) + Err(network::Error::Io(e)) } } } /// Peer address - pub fn receiver_address(&mut self) -> Result { + pub fn receiver_address(&mut self) -> Result { with_socket!(self, sock, { match sock.peer_addr() { Ok(addr) => { @@ -121,13 +117,13 @@ impl Socket { port: addr.port() }) }, - Err(e) => Err(util::Error::Io(e)) + Err(e) => Err(network::Error::Io(e)) } }) } /// Our own address - pub fn sender_address(&mut self) -> Result { + pub fn sender_address(&mut self) -> Result { with_socket!(self, sock, { match sock.local_addr() { Ok(addr) => { @@ -137,13 +133,13 @@ impl Socket { port: addr.port() }) }, - Err(e) => Err(util::Error::Io(e)) + Err(e) => Err(network::Error::Io(e)) } }) } /// Produce a version message appropriate for this socket - pub fn version_message(&mut self, start_height: i32) -> Result { + pub fn version_message(&mut self, start_height: i32) -> Result { let recv_addr = self.receiver_address()?; let send_addr = self.sender_address()?; let timestamp = match SystemTime::now().duration_since(UNIX_EPOCH) { @@ -169,7 +165,7 @@ impl Socket { with_socket!(self, sock, { let message = RawNetworkMessage { magic: self.magic, payload: payload }; message.consensus_encode(&mut RawEncoder::new(&mut *sock))?; - sock.flush().map_err(util::Error::Io) + sock.flush().map_err(network::Error::Io).map_err(util::Error::Network) }) } @@ -180,21 +176,15 @@ impl Socket { // We need a new scope since the closure in here borrows read_err, // and we try to read it afterward. Letting `iter` go out fixes it. let mut decoder = RawDecoder::new(sock); - let decode: Result = ConsensusDecodable::consensus_decode(&mut decoder); - match decode { - // Check for parse errors... - Err(e) => { - propagate_err("receive_message".to_owned(), Err(e)) - }, - Ok(ret) => { - // Then for magic (this should come before parse error, but we can't - // get to it if the deserialization failed). TODO restructure this - if ret.magic != self.magic { - Err(util::Error::BadNetworkMagic(self.magic, ret.magic)) - } else { - Ok(ret.payload) - } - } + + let decoded: RawNetworkMessage = ConsensusDecodable::consensus_decode(&mut decoder)?; + + // Then for magic (this should come before parse error, but we can't + // get to it if the deserialization failed). TODO restructure this + if decoded.magic != self.magic { + Err(util::Error::Serialize(serialize::Error::BadNetworkMagic(self.magic, decoded.magic))) + } else { + Ok(decoded.payload) } }) } diff --git a/src/util/address.rs b/src/util/address.rs index d75a680..d0c8dd7 100644 --- a/src/util/address.rs +++ b/src/util/address.rs @@ -25,9 +25,9 @@ use secp256k1::key::PublicKey; use blockdata::script; use blockdata::opcodes; use network::constants::Network; +use network::serialize; use util::hash::Hash160; use util::base58; -use util::Error; /// The method used to produce an address #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -243,9 +243,9 @@ impl ToString for Address { } impl FromStr for Address { - type Err = Error; + type Err = serialize::Error; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { // bech32 (note that upper or lowercase is allowed but NOT mixed case) if s.starts_with("bc1") || s.starts_with("BC1") || s.starts_with("tb1") || s.starts_with("TB1") || @@ -259,7 +259,7 @@ impl FromStr for Address { _ => panic!("unknown network") }; if witprog.version().to_u8() != 0 { - return Err(Error::UnsupportedWitnessVersion(witprog.version().to_u8())); + return Err(serialize::Error::UnsupportedWitnessVersion(witprog.version().to_u8())); } return Ok(Address { network: network, @@ -268,14 +268,14 @@ impl FromStr for Address { } if s.len() > 50 { - return Err(Error::Base58(base58::Error::InvalidLength(s.len() * 11 / 15))); + return Err(serialize::Error::Base58(base58::Error::InvalidLength(s.len() * 11 / 15))); } // Base 58 let data = base58::from_check(s)?; if data.len() != 21 { - return Err(Error::Base58(base58::Error::InvalidLength(data.len()))); + return Err(serialize::Error::Base58(base58::Error::InvalidLength(data.len()))); } let (network, payload) = match data[0] { @@ -295,7 +295,7 @@ impl FromStr for Address { Network::Testnet, Payload::ScriptHash(Hash160::from(&data[1..])) ), - x => return Err(Error::Base58(base58::Error::InvalidVersion(vec![x]))) + x => return Err(serialize::Error::Base58(base58::Error::InvalidVersion(vec![x]))) }; Ok(Address { diff --git a/src/util/hash.rs b/src/util/hash.rs index 135b873..5a3e22c 100644 --- a/src/util/hash.rs +++ b/src/util/hash.rs @@ -29,7 +29,7 @@ use crypto::digest::Digest; use crypto::ripemd160::Ripemd160; use network::encodable::{ConsensusDecodable, ConsensusEncodable}; -use network::serialize::{SimpleEncoder, RawEncoder, BitcoinHash}; +use network::serialize::{self, SimpleEncoder, RawEncoder, BitcoinHash}; use util::uint::Uint256; #[cfg(feature="fuzztarget")] use util::sha2::Sha256; @@ -108,61 +108,59 @@ impl Sha256dEncoder { } impl SimpleEncoder for Sha256dEncoder { - type Error = (); - - fn emit_u64(&mut self, v: u64) -> Result<(), ()> { + fn emit_u64(&mut self, v: u64) -> Result<(), serialize::Error> { let mut data = [0; 8]; (&mut data[..]).write_u64::(v).unwrap(); self.0.input(&data); Ok(()) } - fn emit_u32(&mut self, v: u32) -> Result<(), ()> { + fn emit_u32(&mut self, v: u32) -> Result<(), serialize::Error> { let mut data = [0; 4]; (&mut data[..]).write_u32::(v).unwrap(); self.0.input(&data); Ok(()) } - fn emit_u16(&mut self, v: u16) -> Result<(), ()> { + fn emit_u16(&mut self, v: u16) -> Result<(), serialize::Error> { let mut data = [0; 2]; (&mut data[..]).write_u16::(v).unwrap(); self.0.input(&data); Ok(()) } - fn emit_i64(&mut self, v: i64) -> Result<(), ()> { + fn emit_i64(&mut self, v: i64) -> Result<(), serialize::Error> { let mut data = [0; 8]; (&mut data[..]).write_i64::(v).unwrap(); self.0.input(&data); Ok(()) } - fn emit_i32(&mut self, v: i32) -> Result<(), ()> { + fn emit_i32(&mut self, v: i32) -> Result<(), serialize::Error> { let mut data = [0; 4]; (&mut data[..]).write_i32::(v).unwrap(); self.0.input(&data); Ok(()) } - fn emit_i16(&mut self, v: i16) -> Result<(), ()> { + fn emit_i16(&mut self, v: i16) -> Result<(), serialize::Error> { let mut data = [0; 2]; (&mut data[..]).write_i16::(v).unwrap(); self.0.input(&data); Ok(()) } - fn emit_i8(&mut self, v: i8) -> Result<(), ()> { + fn emit_i8(&mut self, v: i8) -> Result<(), serialize::Error> { self.0.input(&[v as u8]); Ok(()) } - fn emit_u8(&mut self, v: u8) -> Result<(), ()> { + fn emit_u8(&mut self, v: u8) -> Result<(), serialize::Error> { self.0.input(&[v]); Ok(()) } - fn emit_bool(&mut self, v: bool) -> Result<(), ()> { + fn emit_bool(&mut self, v: bool) -> Result<(), serialize::Error> { self.0.input(&[if v {1} else {0}]); Ok(()) } diff --git a/src/util/misc.rs b/src/util/misc.rs index 0e9fa2f..3b38835 100644 --- a/src/util/misc.rs +++ b/src/util/misc.rs @@ -17,11 +17,11 @@ //! Various utility functions use blockdata::opcodes; -use util::Error; use util::iter::Pairable; +use network::serialize; /// Convert a hexadecimal-encoded string to its corresponding bytes -pub fn hex_bytes(s: &str) -> Result, Error> { +pub fn hex_bytes(s: &str) -> Result, serialize::Error> { let mut v = vec![]; let mut iter = s.chars().pair(); // Do the parsing @@ -29,13 +29,13 @@ pub fn hex_bytes(s: &str) -> Result, Error> { if e.is_err() { e } else { match (f.to_digit(16), s.to_digit(16)) { - (None, _) => Err(Error::Detail( + (None, _) => Err(serialize::Error::Detail( format!("expected hex, got {:}", f), - Box::new(Error::ParseFailed) + Box::new(serialize::Error::ParseFailed) )), - (_, None) => Err(Error::Detail( + (_, None) => Err(serialize::Error::Detail( format!("expected hex, got {:}", s), - Box::new(Error::ParseFailed) + Box::new(serialize::Error::ParseFailed) )), (Some(f), Some(s)) => { v.push((f * 0x10 + s) as u8); Ok(()) } } @@ -43,23 +43,14 @@ pub fn hex_bytes(s: &str) -> Result, Error> { )?; // Check that there was no remainder match iter.remainder() { - Some(_) => Err(Error::Detail( + Some(_) => Err(serialize::Error::Detail( "hexstring of odd length".to_owned(), - Box::new(Error::ParseFailed) + Box::new(serialize::Error::ParseFailed) )), None => Ok(v) } } -/// Dump an error message to the screen -/// TODO all uses of this should be replaced with some sort of logging infrastructure -pub fn consume_err(s: &str, res: Result) { - match res { - Ok(_) => {}, - Err(e) => { println!("{}: {:?}", s, e); } - }; -} - /// Search for `needle` in the vector `haystack` and remove every /// instance of it, returning the number of instances removed. /// Loops through the vector opcode by opcode, skipping pushed data. diff --git a/src/util/mod.rs b/src/util/mod.rs index 84ab4bc..4f09525 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -31,11 +31,13 @@ pub mod uint; #[cfg(feature = "fuzztarget")] pub mod sha2; -use std::{error, fmt, io}; +use std::{error, fmt}; -use bitcoin_bech32; use secp256k1; +use network; +use network::serialize; + /// A trait which allows numbers to act as fixed-size bit arrays pub trait BitArray { /// Is bit set? @@ -60,49 +62,23 @@ pub trait BitArray { /// A general error code #[derive(Debug)] pub enum Error { - /// An I/O error - Io(io::Error), - /// Base58 encoding error - Base58(base58::Error), - /// Bech32 encoding error - Bech32(bitcoin_bech32::Error), - /// Error from the `byteorder` crate - ByteOrder(io::Error), - /// Network magic was not what we expected - BadNetworkMagic(u32, u32), - /// Network message was unrecognized - BadNetworkMessage(String), - /// An object was attempted to be added twice - DuplicateHash, - /// Some operation was attempted on a block (or blockheader) that doesn't exist - BlockNotFound, - /// Parsing error - ParseFailed, - /// An object was added but it does not link into existing history - PrevHashNotFound, - /// secp-related error - Secp256k1(secp256k1::Error), /// The `target` field of a block header did not match the expected difficulty SpvBadTarget, /// The header hash is not below the target SpvBadProofOfWork, - /// Error propagated from subsystem - Detail(String, Box), - /// Unsupported witness version - UnsupportedWitnessVersion(u8) + /// secp-related error + Secp256k1(secp256k1::Error), + /// Serialization error + Serialize(serialize::Error), + /// Network error + Network(network::Error), } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Error::Io(ref e) => fmt::Display::fmt(e, f), - Error::Base58(ref e) => fmt::Display::fmt(e, f), - Error::Bech32(ref e) => fmt::Display::fmt(e, f), - Error::ByteOrder(ref e) => fmt::Display::fmt(e, f), - Error::BadNetworkMagic(exp, got) => write!(f, "expected network magic 0x{:x}, got 0x{:x}", exp, got), - Error::BadNetworkMessage(ref got) => write!(f, "incorrect network message {}", got), - Error::Detail(ref s, ref e) => write!(f, "{}: {}", s, e), Error::Secp256k1(ref e) => fmt::Display::fmt(e, f), + Error::Serialize(ref e) => fmt::Display::fmt(e, f), ref x => f.write_str(error::Error::description(x)) } } @@ -111,56 +87,23 @@ impl fmt::Display for Error { impl error::Error for Error { fn cause(&self) -> Option<&error::Error> { match *self { - Error::Io(ref e) => Some(e), - Error::Base58(ref e) => Some(e), - Error::Bech32(ref e) => Some(e), - Error::ByteOrder(ref e) => Some(e), - Error::Detail(_, ref e) => Some(e), Error::Secp256k1(ref e) => Some(e), + Error::Serialize(ref e) => Some(e), _ => None } } fn description(&self) -> &str { match *self { - Error::Io(ref e) => e.description(), - Error::Base58(ref e) => e.description(), - Error::Bech32(ref e) => e.description(), - Error::ByteOrder(ref e) => e.description(), - Error::BadNetworkMagic(_, _) => "incorrect network magic", - Error::BadNetworkMessage(_) => "incorrect/unexpected network message", - Error::DuplicateHash => "duplicate hash", - Error::BlockNotFound => "no such block", - Error::ParseFailed => "parsing error", - Error::PrevHashNotFound => "prevhash not found", Error::Secp256k1(ref e) => e.description(), Error::SpvBadTarget => "target incorrect", Error::SpvBadProofOfWork => "target correct but not attained", - Error::Detail(_, ref e) => e.description(), - Error::UnsupportedWitnessVersion(_) => "unsupported witness version" + Error::Serialize(ref e) => e.description(), + Error::Network(ref e) => e.description(), } } } -/// Prepend the detail of an `IoResult`'s error with some text to get poor man's backtracing -pub fn propagate_err(s: String, res: Result) -> Result { - res.map_err(|err| Error::Detail(s, Box::new(err))) -} - -#[doc(hidden)] -impl From for Error { - fn from(e: base58::Error) -> Error { - Error::Base58(e) - } -} - -#[doc(hidden)] -impl From for Error { - fn from(e: bitcoin_bech32::Error) -> Error { - Error::Bech32(e) - } -} - #[doc(hidden)] impl From for Error { fn from(e: secp256k1::Error) -> Error { @@ -168,3 +111,16 @@ impl From for Error { } } +#[doc(hidden)] +impl From for Error { + fn from(e: serialize::Error) -> Error { + Error::Serialize(e) + } +} + +#[doc(hidden)] +impl From for Error { + fn from(e: network::Error) -> Error { + Error::Network(e) + } +} diff --git a/src/util/privkey.rs b/src/util/privkey.rs index 32ba097..fc1b98c 100644 --- a/src/util/privkey.rs +++ b/src/util/privkey.rs @@ -16,10 +16,10 @@ //! A private key represents the secret data associated with its proposed use //! use std::str::FromStr; -use util::Error; use secp256k1::{self, Secp256k1}; use secp256k1::key::{PublicKey, SecretKey}; use util::address::Address; +use network::serialize; use network::constants::Network; use util::base58; @@ -110,21 +110,21 @@ impl ToString for Privkey { } impl FromStr for Privkey { - type Err = Error; + type Err = serialize::Error; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { let data = base58::from_check(s)?; let compressed = match data.len() { 33 => false, 34 => true, - _ => { return Err(Error::Base58(base58::Error::InvalidLength(data.len()))); } + _ => { return Err(serialize::Error::Base58(base58::Error::InvalidLength(data.len()))); } }; let network = match data[0] { 128 => Network::Bitcoin, 239 => Network::Testnet, - x => { return Err(Error::Base58(base58::Error::InvalidVersion(vec![x]))); } + x => { return Err(serialize::Error::Base58(base58::Error::InvalidVersion(vec![x]))); } }; let secp = Secp256k1::without_caps(); diff --git a/src/util/uint.rs b/src/util/uint.rs index fe664e4..2dd5dcf 100644 --- a/src/util/uint.rs +++ b/src/util/uint.rs @@ -20,6 +20,7 @@ use std::fmt; +use network::serialize; use util::BitArray; macro_rules! construct_uint { @@ -337,7 +338,7 @@ macro_rules! construct_uint { impl ::network::encodable::ConsensusEncodable for $name { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { let &$name(ref data) = self; for word in data.iter() { word.consensus_encode(s)?; } Ok(()) @@ -345,7 +346,7 @@ macro_rules! construct_uint { } impl ::network::encodable::ConsensusDecodable for $name { - fn consensus_decode(d: &mut D) -> Result<$name, D::Error> { + fn consensus_decode(d: &mut D) -> Result<$name, serialize::Error> { use network::encodable::ConsensusDecodable; let ret: [u64; $n_words] = ConsensusDecodable::consensus_decode(d)?; Ok($name(ret)) From 95303a1d2854246f14a753ed5467d863b5b11acc Mon Sep 17 00:00:00 2001 From: Carl Dong Date: Tue, 21 Aug 2018 01:00:10 -0700 Subject: [PATCH 2/5] Use full path in macros to to eliminate uses --- src/blockdata/block.rs | 2 +- src/internal_macros.rs | 8 ++++---- src/network/message_network.rs | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/blockdata/block.rs b/src/blockdata/block.rs index c7919f5..3761e2b 100644 --- a/src/blockdata/block.rs +++ b/src/blockdata/block.rs @@ -25,7 +25,7 @@ use util::Error::{SpvBadTarget, SpvBadProofOfWork}; use util::hash::Sha256dHash; use util::uint::Uint256; use network::encodable::VarInt; -use network::serialize::{self, BitcoinHash}; +use network::serialize::BitcoinHash; use network::constants::Network; use blockdata::transaction::Transaction; use blockdata::constants::max_target; diff --git a/src/internal_macros.rs b/src/internal_macros.rs index b162183..cdb84c7 100644 --- a/src/internal_macros.rs +++ b/src/internal_macros.rs @@ -16,7 +16,7 @@ macro_rules! impl_consensus_encoding { ($thing:ident, $($field:ident),+) => ( impl ::network::encodable::ConsensusEncodable for $thing { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), ::network::serialize::Error> { $( self.$field.consensus_encode(s)?; )+ Ok(()) } @@ -24,7 +24,7 @@ macro_rules! impl_consensus_encoding { impl ::network::encodable::ConsensusDecodable for $thing { #[inline] - fn consensus_decode(d: &mut D) -> Result<$thing, serialize::Error> { + fn consensus_decode(d: &mut D) -> Result<$thing, ::network::serialize::Error> { use network::encodable::ConsensusDecodable; Ok($thing { $( $field: ConsensusDecodable::consensus_decode(d)?, )+ @@ -38,7 +38,7 @@ macro_rules! impl_newtype_consensus_encoding { ($thing:ident) => ( impl ::network::encodable::ConsensusEncodable for $thing { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), ::network::serialize::Error> { let &$thing(ref data) = self; data.consensus_encode(s) } @@ -46,7 +46,7 @@ macro_rules! impl_newtype_consensus_encoding { impl ::network::encodable::ConsensusDecodable for $thing { #[inline] - fn consensus_decode(d: &mut D) -> Result<$thing, serialize::Error> { + fn consensus_decode(d: &mut D) -> Result<$thing, ::network::serialize::Error> { Ok($thing(ConsensusDecodable::consensus_decode(d)?)) } } diff --git a/src/network/message_network.rs b/src/network/message_network.rs index 38abe8a..93c4dfa 100644 --- a/src/network/message_network.rs +++ b/src/network/message_network.rs @@ -20,7 +20,6 @@ use network::constants; use network::address::Address; -use network::serialize; use network::socket::Socket; use util; From d12a861f855be499e8034f04fb74fe58a58f7515 Mon Sep 17 00:00:00 2001 From: Carl Dong Date: Tue, 21 Aug 2018 01:07:27 -0700 Subject: [PATCH 3/5] Remove unnecessary network::Error::Detail variant --- src/network/listener.rs | 6 ++---- src/network/mod.rs | 5 ----- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/network/listener.rs b/src/network/listener.rs index ea2278e..9d48de9 100644 --- a/src/network/listener.rs +++ b/src/network/listener.rs @@ -22,7 +22,7 @@ use std::thread; use std::sync::mpsc::{channel, Receiver}; use network::constants::Network; -use network::{self, message}; +use network::message; use network::message::NetworkMessage::Verack; use network::socket::Socket; use util; @@ -39,9 +39,7 @@ pub trait Listener { fn start(&self) -> Result<(Receiver, Socket), util::Error> { // Open socket let mut ret_sock = Socket::new(self.network()); - if let Err(e) = ret_sock.connect(self.peer(), self.port()) { - return Err(util::Error::Network(network::Error::Detail("listener".to_owned(), Box::new(e)))); - } + ret_sock.connect(self.peer(), self.port())?; let mut sock = ret_sock.clone(); let (recv_tx, recv_rx) = channel(); diff --git a/src/network/mod.rs b/src/network/mod.rs index 696d720..a7e6f7e 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -43,15 +43,12 @@ pub enum Error { SocketMutexPoisoned, /// Not connected to peer SocketNotConnectedToPeer, - /// Error propagated from subsystem - Detail(String, Box), } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::Io(ref e) => fmt::Display::fmt(e, f), - Error::Detail(ref s, ref e) => write!(f, "{}: {}", s, e), ref x => f.write_str(error::Error::description(x)), } } @@ -61,7 +58,6 @@ impl error::Error for Error { fn cause(&self) -> Option<&error::Error> { match *self { Error::Io(ref e) => Some(e), - Error::Detail(_, ref e) => Some(e), _ => None } } @@ -71,7 +67,6 @@ impl error::Error for Error { Error::Io(ref e) => e.description(), Error::SocketMutexPoisoned => "socket mutex was poisoned", Error::SocketNotConnectedToPeer => "not connected to peer", - Error::Detail(_, ref e) => e.description(), } } } From 0c172941afc7828b7dc80c31f9c267cf19eb7efc Mon Sep 17 00:00:00 2001 From: Carl Dong Date: Tue, 21 Aug 2018 01:31:54 -0700 Subject: [PATCH 4/5] Replace serialize::Error::Detail with variants - Add serialize::Error::ParseFailed(&'static str) variant for serialization errors without context - Add appropriate variants to replace network::Error::Detail for serialization error with context - Remove error method from SimpleDecoders --- src/blockdata/transaction.rs | 2 +- src/network/constants.rs | 2 +- src/network/encodable.rs | 13 +++--- src/network/message.rs | 2 +- src/network/serialize.rs | 76 ++++++++++++++++++++++++------------ src/network/socket.rs | 5 ++- src/util/misc.rs | 15 ++----- src/util/mod.rs | 15 +++---- 8 files changed, 78 insertions(+), 52 deletions(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 5f0af99..1270ffa 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -417,7 +417,7 @@ impl ConsensusDecodable for Transaction { } // We don't support anything else x => { - Err(d.error(format!("segwit flag {:02x} not understood", x))) + Err(serialize::Error::UnsupportedSegwitFlag(x)) } } // non-segwit diff --git a/src/network/constants.rs b/src/network/constants.rs index ba59c50..244551d 100644 --- a/src/network/constants.rs +++ b/src/network/constants.rs @@ -117,7 +117,7 @@ impl ConsensusDecodable for Network { u32::consensus_decode(d) .and_then(|m| { Network::from_magic(m) - .ok_or(d.error(format!("Unknown network (magic {:x})", m))) + .ok_or(serialize::Error::UnknownNetworkMagic(m)) }) } } diff --git a/src/network/encodable.rs b/src/network/encodable.rs index c4c3cc7..4fa62c5 100644 --- a/src/network/encodable.rs +++ b/src/network/encodable.rs @@ -146,7 +146,7 @@ impl ConsensusDecodable for String { #[inline] fn consensus_decode(d: &mut D) -> Result { String::from_utf8(ConsensusDecodable::consensus_decode(d)?) - .map_err(|_| d.error("String was not valid UTF8".to_owned())) + .map_err(|_| serialize::Error::ParseFailed("String was not valid UTF8")) } } @@ -205,9 +205,9 @@ impl> ConsensusDecodable for Vec()) - .ok_or(d.error("Invalid length".to_owned()))?; + .ok_or(serialize::Error::ParseFailed("Invalid length"))?; if byte_size > MAX_VEC_SIZE { - return Err(d.error(format!("tried to allocate vec of size {} (max {})", byte_size, MAX_VEC_SIZE))); + return Err(serialize::Error::OversizedVectorAllocation { requested: byte_size, max: MAX_VEC_SIZE }) } let mut ret = Vec::with_capacity(len as usize); for _ in 0..len { ret.push(ConsensusDecodable::consensus_decode(d)?); } @@ -226,7 +226,7 @@ impl> ConsensusDecodable for Box<[ let VarInt(len): VarInt = ConsensusDecodable::consensus_decode(d)?; let len = len as usize; if len > MAX_VEC_SIZE { - return Err(d.error(format!("tried to allocate vec of size {} (max {})", len, MAX_VEC_SIZE))); + return Err(serialize::Error::OversizedVectorAllocation { requested: len, max: MAX_VEC_SIZE }) } let mut ret = Vec::with_capacity(len); for _ in 0..len { ret.push(ConsensusDecodable::consensus_decode(d)?); } @@ -291,7 +291,10 @@ impl ConsensusDecodable for CheckedData { for _ in 0..len { ret.push(ConsensusDecodable::consensus_decode(d)?); } let expected_checksum = sha2_checksum(&ret); if expected_checksum != checksum { - Err(d.error(format!("bad checksum {:?} (expected {:?})", checksum, expected_checksum))) + Err(serialize::Error::InvalidChecksum { + expected: expected_checksum, + actual: checksum, + }) } else { Ok(CheckedData(ret)) } diff --git a/src/network/message.rs b/src/network/message.rs index f775001..69e1436 100644 --- a/src/network/message.rs +++ b/src/network/message.rs @@ -196,7 +196,7 @@ impl ConsensusDecodable for RawNetworkMessage { "pong" => NetworkMessage::Pong(ConsensusDecodable::consensus_decode(&mut mem_d)?), "tx" => NetworkMessage::Tx(ConsensusDecodable::consensus_decode(&mut mem_d)?), "alert" => NetworkMessage::Alert(ConsensusDecodable::consensus_decode(&mut mem_d)?), - cmd => return Err(d.error(format!("unrecognized network command `{}`", cmd))) + _ => return Err(serialize::Error::UnrecognizedNetworkCommand(cmd)), }; Ok(RawNetworkMessage { magic: magic, diff --git a/src/network/serialize.rs b/src/network/serialize.rs index 25a96bf..ce5e344 100644 --- a/src/network/serialize.rs +++ b/src/network/serialize.rs @@ -43,24 +43,57 @@ pub enum Error { Bech32(bitcoin_bech32::Error), /// Error from the `byteorder` crate ByteOrder(io::Error), - /// Network magic was not what we expected - BadNetworkMagic(u32, u32), - /// Network message was unrecognized - BadNetworkMessage(String), + /// Network magic was not expected + UnexpectedNetworkMagic { + /// The expected network magic + expected: u32, + /// The unexpected network magic + actual: u32, + }, + /// Tried to allocate an oversized vector + OversizedVectorAllocation{ + /// The capacity requested + requested: usize, + /// The maximum capacity + max: usize, + }, + /// Checksum was invalid + InvalidChecksum { + /// The expected checksum + expected: [u8; 4], + /// The invalid checksum + actual: [u8; 4], + }, + /// Network magic was unknown + UnknownNetworkMagic(u32), /// Parsing error - ParseFailed, - /// Error propagated from subsystem - Detail(String, Box), + ParseFailed(&'static str), /// Unsupported witness version UnsupportedWitnessVersion(u8), + /// Unsupported Segwit flag + UnsupportedSegwitFlag(u8), + /// Unrecognized network command + UnrecognizedNetworkCommand(String), + /// Unexpected hex digit + UnexpectedHexDigit(char), } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::Io(ref e) => fmt::Display::fmt(e, f), - Error::Detail(ref s, ref e) => write!(f, "{}: {}", s, e), - ref x => f.write_str(error::Error::description(x)), + Error::Base58(ref e) => fmt::Display::fmt(e, f), + Error::Bech32(ref e) => fmt::Display::fmt(e, f), + Error::ByteOrder(ref e) => fmt::Display::fmt(e, f), + Error::UnexpectedNetworkMagic { expected: ref e, actual: ref a } => write!(f, "{}: expected {}, actual {}", error::Error::description(self), e, a), + Error::OversizedVectorAllocation { requested: ref r, max: ref m } => write!(f, "{}: requested {}, maximum {}", error::Error::description(self), r, m), + Error::InvalidChecksum { expected: ref e, actual: ref a } => write!(f, "{}: expected {}, actual {}", error::Error::description(self), hex_encode(e), hex_encode(a)), + Error::UnknownNetworkMagic(ref m) => write!(f, "{}: {}", error::Error::description(self), m), + Error::ParseFailed(ref e) => write!(f, "{}: {}", error::Error::description(self), e), + Error::UnsupportedWitnessVersion(ref wver) => write!(f, "{}: {}", error::Error::description(self), wver), + Error::UnsupportedSegwitFlag(ref swflag) => write!(f, "{}: {}", error::Error::description(self), swflag), + Error::UnrecognizedNetworkCommand(ref nwcmd) => write!(f, "{}: {}", error::Error::description(self), nwcmd), + Error::UnexpectedHexDigit(ref d) => write!(f, "{}: {}", error::Error::description(self), d), } } } @@ -72,7 +105,6 @@ impl error::Error for Error { Error::Base58(ref e) => Some(e), Error::Bech32(ref e) => Some(e), Error::ByteOrder(ref e) => Some(e), - Error::Detail(_, ref e) => Some(e), _ => None } } @@ -80,14 +112,18 @@ impl error::Error for Error { fn description(&self) -> &str { match *self { Error::Io(ref e) => e.description(), - Error::ParseFailed => "parsing error", - Error::Detail(_, ref e) => e.description(), Error::Base58(ref e) => e.description(), Error::Bech32(ref e) => e.description(), Error::ByteOrder(ref e) => e.description(), - Error::BadNetworkMagic(_, _) => "incorrect network magic", - Error::BadNetworkMessage(_) => "incorrect/unexpected network message", - Error::UnsupportedWitnessVersion(_) => "unsupported witness version", + Error::UnexpectedNetworkMagic { .. } => "unexpected network magic", + Error::OversizedVectorAllocation { .. } => "allocation of oversized vector requested", + Error::InvalidChecksum { .. } => "invalid checksum", + Error::UnknownNetworkMagic(..) => "unknown network magic", + Error::ParseFailed(..) => "parse failed", + Error::UnsupportedWitnessVersion(..) => "unsupported witness version", + Error::UnsupportedSegwitFlag(..) => "unsupported segwit version", + Error::UnrecognizedNetworkCommand(..) => "unrecognized network command", + Error::UnexpectedHexDigit(..) => "unexpected hex digit", } } } @@ -156,7 +192,7 @@ pub fn deserialize<'a, T>(data: &'a [u8]) -> Result if decoder.into_inner().position() == data.len() as u64 { Ok(rv) } else { - Err(Error::ParseFailed) + Err(Error::ParseFailed("data not consumed entirely when explicitly deserializing")) } } @@ -230,9 +266,6 @@ pub trait SimpleDecoder { /// Read a boolean fn read_bool(&mut self) -> Result; - - /// Signal a decoding error - fn error(&mut self, err: String) -> Error; } macro_rules! encoder_fn { @@ -298,11 +331,6 @@ impl SimpleDecoder for RawDecoder { Err(e) => Err(Error::Io(e)) } } - - #[inline] - fn error(&mut self, err: String) -> Error { - Error::Detail(err, Box::new(Error::ParseFailed)) - } } // Aren't really any tests here.. the main functions are serialize and diff --git a/src/network/socket.rs b/src/network/socket.rs index 793d49b..ee682a4 100644 --- a/src/network/socket.rs +++ b/src/network/socket.rs @@ -182,7 +182,10 @@ impl Socket { // Then for magic (this should come before parse error, but we can't // get to it if the deserialization failed). TODO restructure this if decoded.magic != self.magic { - Err(util::Error::Serialize(serialize::Error::BadNetworkMagic(self.magic, decoded.magic))) + Err(serialize::Error::UnexpectedNetworkMagic { + expected: self.magic, + actual: decoded.magic, + }.into()) } else { Ok(decoded.payload) } diff --git a/src/util/misc.rs b/src/util/misc.rs index 3b38835..9d90534 100644 --- a/src/util/misc.rs +++ b/src/util/misc.rs @@ -29,24 +29,15 @@ pub fn hex_bytes(s: &str) -> Result, serialize::Error> { if e.is_err() { e } else { match (f.to_digit(16), s.to_digit(16)) { - (None, _) => Err(serialize::Error::Detail( - format!("expected hex, got {:}", f), - Box::new(serialize::Error::ParseFailed) - )), - (_, None) => Err(serialize::Error::Detail( - format!("expected hex, got {:}", s), - Box::new(serialize::Error::ParseFailed) - )), + (None, _) => Err(serialize::Error::UnexpectedHexDigit(f)), + (_, None) => Err(serialize::Error::UnexpectedHexDigit(s)), (Some(f), Some(s)) => { v.push((f * 0x10 + s) as u8); Ok(()) } } } )?; // Check that there was no remainder match iter.remainder() { - Some(_) => Err(serialize::Error::Detail( - "hexstring of odd length".to_owned(), - Box::new(serialize::Error::ParseFailed) - )), + Some(_) => Err(serialize::Error::ParseFailed("hexstring of odd length")), None => Ok(v) } } diff --git a/src/util/mod.rs b/src/util/mod.rs index 4f09525..08d01ae 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -59,19 +59,20 @@ pub trait BitArray { fn one() -> Self; } -/// A general error code +/// A general error code, other errors should implement conversions to/from this +/// if appropriate. #[derive(Debug)] pub enum Error { - /// The `target` field of a block header did not match the expected difficulty - SpvBadTarget, - /// The header hash is not below the target - SpvBadProofOfWork, /// secp-related error Secp256k1(secp256k1::Error), /// Serialization error Serialize(serialize::Error), /// Network error Network(network::Error), + /// The header hash is not below the target + SpvBadProofOfWork, + /// The `target` field of a block header did not match the expected difficulty + SpvBadTarget, } impl fmt::Display for Error { @@ -96,10 +97,10 @@ impl error::Error for Error { fn description(&self) -> &str { match *self { Error::Secp256k1(ref e) => e.description(), - Error::SpvBadTarget => "target incorrect", - Error::SpvBadProofOfWork => "target correct but not attained", Error::Serialize(ref e) => e.description(), Error::Network(ref e) => e.description(), + Error::SpvBadProofOfWork => "target correct but not attained", + Error::SpvBadTarget => "target incorrect", } } } From bccdd06794d4b7f167ad881b919dfbeda2edb1b2 Mon Sep 17 00:00:00 2001 From: Carl Dong Date: Tue, 21 Aug 2018 01:42:12 -0700 Subject: [PATCH 5/5] Replace catch-all match arms with specific ones --- src/network/mod.rs | 4 ++-- src/network/serialize.rs | 10 +++++++++- src/util/mod.rs | 6 ++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/network/mod.rs b/src/network/mod.rs index a7e6f7e..e93876a 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -49,7 +49,7 @@ impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::Io(ref e) => fmt::Display::fmt(e, f), - ref x => f.write_str(error::Error::description(x)), + Error::SocketMutexPoisoned | Error::SocketNotConnectedToPeer => f.write_str(error::Error::description(self)), } } } @@ -58,7 +58,7 @@ impl error::Error for Error { fn cause(&self) -> Option<&error::Error> { match *self { Error::Io(ref e) => Some(e), - _ => None + Error::SocketMutexPoisoned | Error::SocketNotConnectedToPeer => None, } } diff --git a/src/network/serialize.rs b/src/network/serialize.rs index ce5e344..81df314 100644 --- a/src/network/serialize.rs +++ b/src/network/serialize.rs @@ -105,7 +105,15 @@ impl error::Error for Error { Error::Base58(ref e) => Some(e), Error::Bech32(ref e) => Some(e), Error::ByteOrder(ref e) => Some(e), - _ => None + Error::UnexpectedNetworkMagic { .. } + | Error::OversizedVectorAllocation { .. } + | Error::InvalidChecksum { .. } + | Error::UnknownNetworkMagic(..) + | Error::ParseFailed(..) + | Error::UnsupportedWitnessVersion(..) + | Error::UnsupportedSegwitFlag(..) + | Error::UnrecognizedNetworkCommand(..) + | Error::UnexpectedHexDigit(..) => None, } } diff --git a/src/util/mod.rs b/src/util/mod.rs index 08d01ae..0188c26 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -80,7 +80,8 @@ impl fmt::Display for Error { match *self { Error::Secp256k1(ref e) => fmt::Display::fmt(e, f), Error::Serialize(ref e) => fmt::Display::fmt(e, f), - ref x => f.write_str(error::Error::description(x)) + Error::Network(ref e) => fmt::Display::fmt(e, f), + Error::SpvBadProofOfWork | Error::SpvBadTarget => f.write_str(error::Error::description(self)), } } } @@ -90,7 +91,8 @@ impl error::Error for Error { match *self { Error::Secp256k1(ref e) => Some(e), Error::Serialize(ref e) => Some(e), - _ => None + Error::Network(ref e) => Some(e), + Error::SpvBadProofOfWork | Error::SpvBadTarget => None } }