From 7f11766c6566d123648316a54f6feb4b45dea36f Mon Sep 17 00:00:00 2001 From: Carl Dong Date: Sun, 2 Sep 2018 21:18:28 -0700 Subject: [PATCH 1/6] Remove nu_select macro --- src/macros.rs | 65 --------------------------------------------------- 1 file changed, 65 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index 1f00615e..718d4ae5 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -16,71 +16,6 @@ //! //! Macros available to users of the Bitcoin library -#[macro_export] -macro_rules! nu_select { - ($($name:pat = $rx:expr => $code:expr),+) => ({ - nu_select!{ $($name = $rx, recv => $code),+ } - }); - ($($name:pat = $rx:expr, $meth:ident => $code:expr),+) => ({ - use rustrt::local::Local; - use rustrt::task::Task; - use sync::comm::Packet; - - // Is anything already ready to receive? Grab it without waiting. - $( - if (&$rx as &Packet).can_recv() { - let $name = $rx.$meth(); - $code - } - )else+ - else { - // Start selecting on as many as we need to before getting a bite. - // Keep count of how many, since we need to abort every selection - // that we started. - let mut started_count = 0; - // Restrict lifetime of borrows in `packets` - { - let packets = [ $( &$rx as &Packet, )+ ]; - - let task: Box = Local::take(); - task.deschedule(packets.len(), |task| { - match packets[started_count].start_selection(task) { - Ok(()) => { - started_count += 1; - Ok(()) - } - Err(task) => Err(task) - } - }); - } - - let mut i = 0; - let ret = $( - // Abort the receivers, stopping at the first ready one to get its data. - if { i += 1; i <= started_count } && - // If start_selection() failed, abort_selection() will fail too, - // but it still counts as "data available". - ($rx.abort_selection() || i == started_count) { - // React to the first - let $name = $rx.$meth(); - $code - })else+ - else { - fail!("we didn't find the ready receiver, but we should have had one"); - }; - // At this point, the first i receivers have been aborted. We need to abort the rest: - $(if i > 0 { - i -= 1; - } else { - $rx.abort_selection(); - })+ - let _ = i; // Shut up `i -= 1 but i is never read` warning - // Return - ret - } - }) -} - #[macro_export] macro_rules! user_enum { ( From 7e9d393d03a2233eca7dfbdf0551464c66aca7dc Mon Sep 17 00:00:00 2001 From: Carl Dong Date: Sun, 2 Sep 2018 22:04:05 -0700 Subject: [PATCH 2/6] Remove low-level networking support - Modify VersionMessage constructor to take in parameters directly that would have otherwise been extracted from a Socket (now removed) --- src/network/listener.rs | 90 --------------- src/network/message_network.rs | 34 +++--- src/network/mod.rs | 2 - src/network/socket.rs | 195 --------------------------------- 4 files changed, 17 insertions(+), 304 deletions(-) delete mode 100644 src/network/listener.rs delete mode 100644 src/network/socket.rs diff --git a/src/network/listener.rs b/src/network/listener.rs deleted file mode 100644 index 9d48de9a..00000000 --- a/src/network/listener.rs +++ /dev/null @@ -1,90 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Abstract Bitcoin listener -//! -//! This module defines a listener on the Bitcoin network which is able -//! to connect to a peer, send network messages, and receive Bitcoin data. -//! - -use std::thread; -use std::sync::mpsc::{channel, Receiver}; - -use network::constants::Network; -use network::message; -use network::message::NetworkMessage::Verack; -use network::socket::Socket; -use util; - -/// A message which can be sent on the Bitcoin network -pub trait Listener { - /// Return a string encoding of the peer's network address - fn peer(&self) -> &str; - /// Return the port we have connected to the peer on - fn port(&self) -> u16; - /// Return the network this `Listener` is operating on - fn network(&self) -> Network; - /// Main listen loop - fn start(&self) -> Result<(Receiver, Socket), util::Error> { - // Open socket - let mut ret_sock = Socket::new(self.network()); - ret_sock.connect(self.peer(), self.port())?; - let mut sock = ret_sock.clone(); - - let (recv_tx, recv_rx) = channel(); - - // Send version message to peer - let version_message = sock.version_message(0)?; - sock.send_message(version_message)?; - - // Message loop - thread::spawn(move || { - let mut handshake_complete = false; - loop { - // Receive new message - match sock.receive_message() { - Ok(payload) => { - // React to any network messages that affect our state. - if let Verack = payload { - // Make an exception for verack since there is no response required - // TODO: when the timeout stuff in std::io::net::tcp is sorted out we should - // actually time out if the verack doesn't come in in time - if handshake_complete { - println!("Received second verack (peer is misbehaving)"); - } else { - handshake_complete = true; - } - }; - // We have to pass the message to the main thread for processing, - // unfortunately, because sipa says we have to handle everything - // in order. - recv_tx.send(message::SocketResponse::MessageReceived(payload)).unwrap(); - } - Err(e) => { - // On failure we send an error message to the main thread, along with - // a channel to receive an acknowledgement that we may tear down this - // thread. (If we simply exited immediately, the channel would be torn - // down and the main thread would never see the error message.) - let (tx, rx) = channel(); - recv_tx.send(message::SocketResponse::ConnectionFailed(e, tx)).unwrap(); - rx.recv().unwrap(); - break; - } - } - } - }); - Ok((recv_rx, ret_sock)) - } -} - diff --git a/src/network/message_network.rs b/src/network/message_network.rs index 93c4dfab..ff349899 100644 --- a/src/network/message_network.rs +++ b/src/network/message_network.rs @@ -18,10 +18,8 @@ //! capabilities //! -use network::constants; use network::address::Address; -use network::socket::Socket; -use util; +use network::constants; /// Some simple messages @@ -53,21 +51,26 @@ pub struct VersionMessage { impl VersionMessage { // TODO: we have fixed services and relay to 0 /// Constructs a new `version` message - pub fn new(timestamp: i64, mut socket: Socket, nonce: u64, start_height: i32) -> Result { - let recv_addr = socket.receiver_address()?; - let send_addr = socket.sender_address()?; - - Ok(VersionMessage { + pub fn new( + services: u64, + timestamp: i64, + receiver: Address, + sender: Address, + nonce: u64, + user_agent: String, + start_height: i32, + ) -> VersionMessage { + VersionMessage { version: constants::PROTOCOL_VERSION, - services: socket.services, + services: services, timestamp: timestamp, - receiver: recv_addr, - sender: send_addr, + receiver: receiver, + sender: sender, nonce: nonce, - user_agent: socket.user_agent, + user_agent: user_agent, start_height: start_height, - relay: false - }) + relay: false, + } } } @@ -103,6 +106,3 @@ mod tests { assert_eq!(serialize(&real_decode).ok(), Some(from_sat)); } } - - - diff --git a/src/network/mod.rs b/src/network/mod.rs index e93876a4..b19077a6 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -25,11 +25,9 @@ use std::error; pub mod constants; pub mod consensus_params; pub mod encodable; -pub mod socket; pub mod serialize; pub mod address; -pub mod listener; pub mod message; pub mod message_blockdata; pub mod message_network; diff --git a/src/network/socket.rs b/src/network/socket.rs deleted file mode 100644 index ee682a41..00000000 --- a/src/network/socket.rs +++ /dev/null @@ -1,195 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Sockets -//! -//! This module provides support for low-level network communication. -//! - -use std::time::{UNIX_EPOCH, SystemTime}; -use rand::{thread_rng, Rng}; -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::{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] { - match *addr { - net::SocketAddr::V4(ref addr) => addr.ip().to_ipv6_mapped().segments(), - net::SocketAddr::V6(ref addr) => addr.ip().segments() - } -} - -/// A network socket along with information about the peer -#[derive(Clone)] -pub struct Socket { - /// The underlying TCP socket - socket: Arc>>, - /// Services supported by us - pub services: u64, - /// Our user agent - pub user_agent: String, - /// Nonce to identify our `version` messages - pub version_nonce: u64, - /// Network magic - pub magic: u32 -} - -macro_rules! with_socket(($s:ident, $sock:ident, $body:block) => ({ - use ::std::ops::DerefMut; - let sock_lock = $s.socket.lock(); - match sock_lock { - Err(_) => { - Err(network::Error::SocketMutexPoisoned.into()) - } - Ok(mut guard) => { - match *guard.deref_mut() { - Some(ref mut $sock) => { - $body - } - None => { - Err(network::Error::SocketNotConnectedToPeer.into()) - } - } - } - } -})); - -impl Socket { - // TODO: we fix services to 0 - /// Construct a new socket - pub fn new(network: constants::Network) -> Socket { - let mut rng = thread_rng(); - Socket { - socket: Arc::new(Mutex::new(None)), - services: 0, - version_nonce: rng.gen(), - user_agent: constants::USER_AGENT.to_owned(), - magic: network.magic(), - } - } - - /// (Re)connect to the peer - 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)) { - Ok(s) => { - self.socket = Arc::new(Mutex::new(Some(s))); - Ok(()) - } - Err(e) => { - self.socket = Arc::new(Mutex::new(None)); - Err(network::Error::Io(e)) - } - } - } - - /// Peer address - pub fn receiver_address(&mut self) -> Result { - with_socket!(self, sock, { - match sock.peer_addr() { - Ok(addr) => { - Ok(Address { - services: self.services, - address: ipaddr_to_bitcoin_addr(&addr), - port: addr.port() - }) - }, - Err(e) => Err(network::Error::Io(e)) - } - }) - } - - /// Our own address - pub fn sender_address(&mut self) -> Result { - with_socket!(self, sock, { - match sock.local_addr() { - Ok(addr) => { - Ok(Address { - services: self.services, - address: ipaddr_to_bitcoin_addr(&addr), - port: addr.port() - }) - }, - 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 { - let recv_addr = self.receiver_address()?; - let send_addr = self.sender_address()?; - let timestamp = match SystemTime::now().duration_since(UNIX_EPOCH) { - Ok(dur) => dur, - Err(err) => err.duration(), - }.as_secs() as i64; - - Ok(Version(VersionMessage { - version: constants::PROTOCOL_VERSION, - services: constants::SERVICES, - timestamp: timestamp, - receiver: recv_addr, - sender: send_addr, - nonce: self.version_nonce, - user_agent: self.user_agent.clone(), - start_height: start_height, - relay: false - })) - } - - /// Send a general message across the line - pub fn send_message(&mut self, payload: NetworkMessage) -> Result<(), util::Error> { - with_socket!(self, sock, { - let message = RawNetworkMessage { magic: self.magic, payload: payload }; - message.consensus_encode(&mut RawEncoder::new(&mut *sock))?; - sock.flush().map_err(network::Error::Io).map_err(util::Error::Network) - }) - } - - /// Receive the next message from the peer, decoding the network header - /// and verifying its correctness. Returns the undecoded payload. - pub fn receive_message(&mut self) -> Result { - with_socket!(self, sock, { - // 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 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(serialize::Error::UnexpectedNetworkMagic { - expected: self.magic, - actual: decoded.magic, - }.into()) - } else { - Ok(decoded.payload) - } - }) - } -} - From 97937b1b5f2d6979439169f2753b7c8196e20648 Mon Sep 17 00:00:00 2001 From: Carl Dong Date: Sun, 2 Sep 2018 22:18:57 -0700 Subject: [PATCH 3/6] Move network::consensus_params to consensus::params --- src/consensus/mod.rs | 21 +++++++++++++++++++ .../params.rs} | 10 ++++----- src/network/mod.rs | 1 - 3 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 src/consensus/mod.rs rename src/{network/consensus_params.rs => consensus/params.rs} (96%) diff --git a/src/consensus/mod.rs b/src/consensus/mod.rs new file mode 100644 index 00000000..d645b9d5 --- /dev/null +++ b/src/consensus/mod.rs @@ -0,0 +1,21 @@ +// Rust Bitcoin Library +// Written by +// The Rust Bitcoin developers +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +//! Consensus +//! +//! This module defines structures, functions, and traits which are needed to +//! conform to Bitcoin consensus. +//! + +pub mod params; diff --git a/src/network/consensus_params.rs b/src/consensus/params.rs similarity index 96% rename from src/network/consensus_params.rs rename to src/consensus/params.rs index 759b4ea8..f39f3a8e 100644 --- a/src/network/consensus_params.rs +++ b/src/consensus/params.rs @@ -44,7 +44,7 @@ const MAX_BITS_REGTEST: Uint256 = Uint256([ #[derive(Debug, Clone)] /// Parameters that influence chain consensus. -pub struct ConsensusParams { +pub struct Params { /// Network for which parameters are valid. pub network: Network, /// Time when BIP16 becomes active. @@ -73,11 +73,11 @@ pub struct ConsensusParams { pub no_pow_retargeting: bool, } -impl ConsensusParams { +impl Params { /// Creates parameters set for the given network. pub fn new(network: Network) -> Self { match network { - Network::Bitcoin => ConsensusParams { + Network::Bitcoin => Params { network: Network::Bitcoin, bip16_time: 1333238400, // Apr 1 2012 bip34_height: 227931, // 000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8 @@ -91,7 +91,7 @@ impl ConsensusParams { allow_min_difficulty_blocks: false, no_pow_retargeting: false, }, - Network::Testnet => ConsensusParams { + Network::Testnet => Params { network: Network::Testnet, bip16_time: 1333238400, // Apr 1 2012 bip34_height: 21111, // 0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8 @@ -105,7 +105,7 @@ impl ConsensusParams { allow_min_difficulty_blocks: true, no_pow_retargeting: false, }, - Network::Regtest => ConsensusParams { + Network::Regtest => Params { network: Network::Regtest, bip16_time: 1333238400, // Apr 1 2012 bip34_height: 100000000, // not activated on regtest diff --git a/src/network/mod.rs b/src/network/mod.rs index b19077a6..bf1fa340 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -23,7 +23,6 @@ use std::io; use std::error; pub mod constants; -pub mod consensus_params; pub mod encodable; pub mod serialize; From 8e0e4eb55a62e4dd7b2b904d8029db828960f663 Mon Sep 17 00:00:00 2001 From: Carl Dong Date: Sun, 2 Sep 2018 22:41:08 -0700 Subject: [PATCH 4/6] Move serialize::BitcoinHash to util::hash::BitcoinHash - Use Sha256dEncoder for calculating merkle root - Remove BitcoinHash implementation for Vec --- src/blockdata/block.rs | 3 +-- src/blockdata/constants.rs | 3 ++- src/blockdata/transaction.rs | 7 +++---- src/lib.rs | 2 +- src/network/serialize.rs | 14 -------------- src/util/hash.rs | 12 ++++++++---- 6 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/blockdata/block.rs b/src/blockdata/block.rs index 3761e2b4..3ef1040d 100644 --- a/src/blockdata/block.rs +++ b/src/blockdata/block.rs @@ -22,10 +22,9 @@ use util; use util::Error::{SpvBadTarget, SpvBadProofOfWork}; -use util::hash::Sha256dHash; +use util::hash::{BitcoinHash, Sha256dHash}; use util::uint::Uint256; use network::encodable::VarInt; -use network::serialize::BitcoinHash; use network::constants::Network; use blockdata::transaction::Transaction; use blockdata::constants::max_target; diff --git a/src/blockdata/constants.rs b/src/blockdata/constants.rs index 408af931..43776421 100644 --- a/src/blockdata/constants.rs +++ b/src/blockdata/constants.rs @@ -143,9 +143,10 @@ mod test { use hex::decode as hex_decode; use network::constants::Network; - use network::serialize::{BitcoinHash, serialize}; + use network::serialize::serialize; use blockdata::constants::{genesis_block, bitcoin_genesis_tx}; use blockdata::constants::{MAX_SEQUENCE, COIN_VALUE}; + use util::hash::BitcoinHash; #[test] fn bitcoin_genesis_first_transaction() { diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 19e88934..93aa4f72 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -28,10 +28,10 @@ use std::default::Default; use std::fmt; #[cfg(feature="bitcoinconsensus")] use std::collections::HashMap; -use util::hash::Sha256dHash; +use util::hash::{BitcoinHash, Sha256dHash}; #[cfg(feature="bitcoinconsensus")] use blockdata::script; use blockdata::script::Script; -use network::serialize::{self, serialize, BitcoinHash, SimpleEncoder, SimpleDecoder}; +use network::serialize::{self, serialize, SimpleEncoder, SimpleDecoder}; use network::encodable::{ConsensusEncodable, ConsensusDecodable, VarInt}; /// A reference to a transaction output @@ -499,11 +499,10 @@ mod tests { use super::{Transaction, TxIn}; use blockdata::script::Script; - use network::serialize::BitcoinHash; #[cfg(all(feature = "serde", feature = "strason"))] use network::serialize::serialize; use network::serialize::deserialize; - use util::hash::Sha256dHash; + use util::hash::{BitcoinHash, Sha256dHash}; use util::misc::hex_bytes; #[test] diff --git a/src/lib.rs b/src/lib.rs index d2f7da80..c6d9c20b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,9 +72,9 @@ pub use blockdata::transaction::TxOut; pub use blockdata::transaction::OutPoint; pub use blockdata::transaction::SigHashType; pub use network::encodable::VarInt; -pub use network::serialize::BitcoinHash; pub use util::Error; pub use util::address::Address; +pub use util::hash::BitcoinHash; pub use util::privkey::Privkey; pub use util::decimal::Decimal; pub use util::decimal::UDecimal; diff --git a/src/network/serialize.rs b/src/network/serialize.rs index 81df314d..34e18f9a 100644 --- a/src/network/serialize.rs +++ b/src/network/serialize.rs @@ -30,7 +30,6 @@ use bitcoin_bech32; use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use util::base58; -use util::hash::Sha256dHash; /// Serialization error #[derive(Debug)] @@ -158,19 +157,6 @@ impl From for Error { } } -/// Objects which are referred to by hash -pub trait BitcoinHash { - /// Produces a Sha256dHash which can be used to refer to the object - fn bitcoin_hash(&self) -> Sha256dHash; -} - -impl BitcoinHash for Vec { - #[inline] - fn bitcoin_hash(&self) -> Sha256dHash { - Sha256dHash::from_data(&self[..]) - } -} - /// Encode an object into a vector pub fn serialize(data: &T) -> Result, Error> where T: ConsensusEncodable>>>, diff --git a/src/util/hash.rs b/src/util/hash.rs index d740fe0d..a70b06d2 100644 --- a/src/util/hash.rs +++ b/src/util/hash.rs @@ -20,7 +20,6 @@ use std::cmp::min; use std::default::Default; use std::error; use std::fmt; -use std::io::Cursor; use std::mem; #[cfg(feature = "serde")] use serde; @@ -29,7 +28,7 @@ use crypto::digest::Digest; use crypto::ripemd160::Ripemd160; use network::encodable::{ConsensusDecodable, ConsensusEncodable}; -use network::serialize::{self, SimpleEncoder, RawEncoder, BitcoinHash}; +use network::serialize::{self, SimpleEncoder}; use util::uint::Uint256; #[cfg(feature="fuzztarget")] use util::sha2::Sha256; @@ -462,10 +461,10 @@ pub fn bitcoin_merkle_root(data: Vec) -> Sha256dHash { for idx in 0..((data.len() + 1) / 2) { let idx1 = 2 * idx; let idx2 = min(idx1 + 1, data.len() - 1); - let mut encoder = RawEncoder::new(Cursor::new(vec![])); + let mut encoder = Sha256dEncoder::new(); data[idx1].consensus_encode(&mut encoder).unwrap(); data[idx2].consensus_encode(&mut encoder).unwrap(); - next.push(encoder.into_inner().into_inner().bitcoin_hash()); + next.push(encoder.into_hash()); } bitcoin_merkle_root(next) } @@ -482,6 +481,11 @@ impl MerkleRoot for Vec { } } +/// Objects which are referred to by hash +pub trait BitcoinHash { + /// Produces a Sha256dHash which can be used to refer to the object + fn bitcoin_hash(&self) -> Sha256dHash; +} #[cfg(test)] mod tests { From 0f42ca69b0dbf0e92b403e2cad23be3e9402b6c7 Mon Sep 17 00:00:00 2001 From: Carl Dong Date: Thu, 20 Sep 2018 03:15:45 -0700 Subject: [PATCH 5/6] Move relevant names into consensus::encode - Move network::encodable::* to consensus::encode::* - Rename Consensus{En,De}codable to {En,De}codable (now under consensus::encode) - Move network::serialize::Error to consensus::encode::Error - Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read} instead - Move network::serialize::Simple{En,De}coder to consensus::encode::{En,De}coder - Rename util::Error::Serialize to util::Error::Encode - Modify comments to refer to new names - Modify files to refer to new names - Expose {En,De}cod{able,er}, {de,}serialize, Params - Do not return Result for serialize{,_hex} as serializing to a Vec should never fail --- fuzz/fuzz_targets/deserialize_block.rs | 2 +- fuzz/fuzz_targets/deserialize_script.rs | 6 +- fuzz/fuzz_targets/deserialize_transaction.rs | 6 +- src/blockdata/block.rs | 20 +- src/blockdata/constants.rs | 10 +- src/blockdata/opcodes.rs | 12 +- src/blockdata/script.rs | 18 +- src/blockdata/transaction.rs | 98 +- src/consensus/encode.rs | 889 +++++++++++++++++++ src/consensus/mod.rs | 4 + src/internal_macros.rs | 22 +- src/lib.rs | 4 +- src/network/address.rs | 26 +- src/network/constants.rs | 34 +- src/network/encodable.rs | 612 ------------- src/network/message.rs | 109 ++- src/network/message_blockdata.rs | 26 +- src/network/message_network.rs | 4 +- src/network/mod.rs | 2 - src/network/serialize.rs | 333 ------- src/util/address.rs | 14 +- src/util/bip143.rs | 4 +- src/util/hash.rs | 39 +- src/util/misc.rs | 10 +- src/util/mod.rs | 18 +- src/util/privkey.rs | 10 +- src/util/uint.rs | 20 +- 27 files changed, 1146 insertions(+), 1206 deletions(-) create mode 100644 src/consensus/encode.rs delete mode 100644 src/network/encodable.rs delete mode 100644 src/network/serialize.rs diff --git a/fuzz/fuzz_targets/deserialize_block.rs b/fuzz/fuzz_targets/deserialize_block.rs index f9364f4a..3e2b7a1b 100644 --- a/fuzz/fuzz_targets/deserialize_block.rs +++ b/fuzz/fuzz_targets/deserialize_block.rs @@ -1,7 +1,7 @@ extern crate bitcoin; fn do_test(data: &[u8]) { - let _: Result= bitcoin::network::serialize::deserialize(data); + let _: Result= bitcoin::consensus::encode::deserialize(data); } #[cfg(feature = "afl")] diff --git a/fuzz/fuzz_targets/deserialize_script.rs b/fuzz/fuzz_targets/deserialize_script.rs index 8bf7ab19..fb8fd43d 100644 --- a/fuzz/fuzz_targets/deserialize_script.rs +++ b/fuzz/fuzz_targets/deserialize_script.rs @@ -1,10 +1,10 @@ extern crate bitcoin; use bitcoin::blockdata::script; -use bitcoin::network::serialize; +use bitcoin::consensus::encode; fn do_test(data: &[u8]) { - let s: Result = serialize::deserialize(data); + let s: Result = encode::deserialize(data); if let Ok(script) = s { let _: Vec = script.iter(false).collect(); let enforce_min: Vec = script.iter(true).collect(); @@ -31,7 +31,7 @@ fn do_test(data: &[u8]) { } } assert_eq!(b.into_script(), script); - assert_eq!(data, &serialize::serialize(&script).unwrap()[..]); + assert_eq!(data, &encode::serialize(&script)[..]); } } diff --git a/fuzz/fuzz_targets/deserialize_transaction.rs b/fuzz/fuzz_targets/deserialize_transaction.rs index 7df5ffd0..a3b251d6 100644 --- a/fuzz/fuzz_targets/deserialize_transaction.rs +++ b/fuzz/fuzz_targets/deserialize_transaction.rs @@ -1,16 +1,16 @@ extern crate bitcoin; fn do_test(data: &[u8]) { - let tx_result: Result = bitcoin::network::serialize::deserialize(data); + let tx_result: Result = bitcoin::consensus::encode::deserialize(data); match tx_result { Err(_) => {}, Ok(mut tx) => { - let len = bitcoin::network::serialize::serialize(&tx).unwrap().len() as u64; + let len = bitcoin::consensus::encode::serialize(&tx).len() as u64; let calculated_weight = tx.get_weight(); for input in &mut tx.input { input.witness = vec![]; } - let no_witness_len = bitcoin::network::serialize::serialize(&tx).unwrap().len() as u64; + let no_witness_len = bitcoin::consensus::encode::serialize(&tx).len() as u64; assert_eq!(no_witness_len * 3 + len, calculated_weight); }, } diff --git a/src/blockdata/block.rs b/src/blockdata/block.rs index 3ef1040d..ca098519 100644 --- a/src/blockdata/block.rs +++ b/src/blockdata/block.rs @@ -24,7 +24,7 @@ use util; use util::Error::{SpvBadTarget, SpvBadProofOfWork}; use util::hash::{BitcoinHash, Sha256dHash}; use util::uint::Uint256; -use network::encodable::VarInt; +use consensus::encode::VarInt; use network::constants::Network; use blockdata::transaction::Transaction; use blockdata::constants::max_target; @@ -142,8 +142,8 @@ impl BlockHeader { impl BitcoinHash for BlockHeader { fn bitcoin_hash(&self) -> Sha256dHash { - use network::serialize::serialize; - Sha256dHash::from_data(&serialize(self).unwrap()) + use consensus::encode::serialize; + Sha256dHash::from_data(&serialize(self)) } } @@ -162,7 +162,7 @@ mod tests { use hex::decode as hex_decode; use blockdata::block::{Block, BlockHeader}; - use network::serialize::{deserialize, serialize}; + use consensus::encode::{deserialize, serialize}; #[test] fn block_test() { @@ -179,15 +179,15 @@ mod tests { assert!(bad_decode.is_err()); let real_decode = decode.unwrap(); assert_eq!(real_decode.header.version, 1); - assert_eq!(serialize(&real_decode.header.prev_blockhash).ok(), Some(prevhash)); + assert_eq!(serialize(&real_decode.header.prev_blockhash), prevhash); // [test] TODO: actually compute the merkle root - assert_eq!(serialize(&real_decode.header.merkle_root).ok(), Some(merkle)); + assert_eq!(serialize(&real_decode.header.merkle_root), merkle); assert_eq!(real_decode.header.time, 1231965655); assert_eq!(real_decode.header.bits, 486604799); assert_eq!(real_decode.header.nonce, 2067413810); // [test] TODO: check the transaction data - assert_eq!(serialize(&real_decode).ok(), Some(some_block)); + assert_eq!(serialize(&real_decode), some_block); } // Check testnet block 000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b @@ -203,14 +203,14 @@ mod tests { assert!(decode.is_ok()); let real_decode = decode.unwrap(); assert_eq!(real_decode.header.version, 0x20000000); // VERSIONBITS but no bits set - assert_eq!(serialize(&real_decode.header.prev_blockhash).ok(), Some(prevhash)); - assert_eq!(serialize(&real_decode.header.merkle_root).ok(), Some(merkle)); + assert_eq!(serialize(&real_decode.header.prev_blockhash), prevhash); + assert_eq!(serialize(&real_decode.header.merkle_root), merkle); assert_eq!(real_decode.header.time, 1472004949); assert_eq!(real_decode.header.bits, 0x1a06d450); assert_eq!(real_decode.header.nonce, 1879759182); // [test] TODO: check the transaction data - assert_eq!(serialize(&real_decode).ok(), Some(segwit_block)); + assert_eq!(serialize(&real_decode), segwit_block); } #[test] diff --git a/src/blockdata/constants.rs b/src/blockdata/constants.rs index 43776421..340c799d 100644 --- a/src/blockdata/constants.rs +++ b/src/blockdata/constants.rs @@ -143,7 +143,7 @@ mod test { use hex::decode as hex_decode; use network::constants::Network; - use network::serialize::serialize; + use consensus::encode::serialize; use blockdata::constants::{genesis_block, bitcoin_genesis_tx}; use blockdata::constants::{MAX_SEQUENCE, COIN_VALUE}; use util::hash::BitcoinHash; @@ -156,13 +156,13 @@ mod test { assert_eq!(gen.input.len(), 1); assert_eq!(gen.input[0].previous_output.txid, Default::default()); assert_eq!(gen.input[0].previous_output.vout, 0xFFFFFFFF); - assert_eq!(serialize(&gen.input[0].script_sig).ok(), - Some(hex_decode("4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73").unwrap())); + assert_eq!(serialize(&gen.input[0].script_sig), + hex_decode("4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73").unwrap()); assert_eq!(gen.input[0].sequence, MAX_SEQUENCE); assert_eq!(gen.output.len(), 1); - assert_eq!(serialize(&gen.output[0].script_pubkey).ok(), - Some(hex_decode("434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac").unwrap())); + assert_eq!(serialize(&gen.output[0].script_pubkey), + hex_decode("434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac").unwrap()); assert_eq!(gen.output[0].value, 50 * COIN_VALUE); assert_eq!(gen.lock_time, 0); diff --git a/src/blockdata/opcodes.rs b/src/blockdata/opcodes.rs index 004daf94..ad5e0257 100644 --- a/src/blockdata/opcodes.rs +++ b/src/blockdata/opcodes.rs @@ -25,8 +25,8 @@ // Heavy stick to translate between opcode types use std::mem::transmute; -use network::serialize::{self, SimpleDecoder, SimpleEncoder}; -use network::encodable::{ConsensusDecodable, ConsensusEncodable}; +use consensus::encode::{self, Decoder, Encoder}; +use consensus::encode::{Decodable, Encodable}; // Note: I am deliberately not implementing PartialOrd or Ord on the // opcode enum. If you want to check ranges of opcodes, etc., @@ -606,16 +606,16 @@ impl From for All { display_from_debug!(All); -impl ConsensusDecodable for All { +impl Decodable 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 { +impl Encodable for All { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> { s.emit_u8(*self as u8) } } diff --git a/src/blockdata/script.rs b/src/blockdata/script.rs index 45e6a715..2c153104 100644 --- a/src/blockdata/script.rs +++ b/src/blockdata/script.rs @@ -31,8 +31,8 @@ use crypto::digest::Digest; #[cfg(feature = "serde")] use serde; use blockdata::opcodes; -use network::encodable::{ConsensusDecodable, ConsensusEncodable}; -use network::serialize::{self, SimpleDecoder, SimpleEncoder}; +use consensus::encode::{Decodable, Encodable}; +use consensus::encode::{self, Decoder, Encoder}; use util::hash::Hash160; #[cfg(feature="bitcoinconsensus")] use bitcoinconsensus; #[cfg(feature="bitcoinconsensus")] use std::convert; @@ -671,17 +671,17 @@ impl serde::Serialize for Script { } // Network serialization -impl ConsensusEncodable for Script { +impl Encodable for Script { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> { self.0.consensus_encode(s) } } -impl ConsensusDecodable for Script { +impl Decodable for Script { #[inline] - fn consensus_decode(d: &mut D) -> Result { - Ok(Script(ConsensusDecodable::consensus_decode(d)?)) + fn consensus_decode(d: &mut D) -> Result { + Ok(Script(Decodable::consensus_decode(d)?)) } } @@ -692,7 +692,7 @@ mod test { use super::*; use super::build_scriptint; - use network::serialize::{deserialize, serialize}; + use consensus::encode::{deserialize, serialize}; use blockdata::opcodes; #[test] @@ -740,7 +740,7 @@ mod test { let hex_script = hex_decode("6c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52").unwrap(); let script: Result = deserialize(&hex_script); assert!(script.is_ok()); - assert_eq!(serialize(&script.unwrap()).ok(), Some(hex_script)); + assert_eq!(serialize(&script.unwrap()), hex_script); } #[test] diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 93aa4f72..849b54ed 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -31,8 +31,8 @@ use std::fmt; use util::hash::{BitcoinHash, Sha256dHash}; #[cfg(feature="bitcoinconsensus")] use blockdata::script; use blockdata::script::Script; -use network::serialize::{self, serialize, SimpleEncoder, SimpleDecoder}; -use network::encodable::{ConsensusEncodable, ConsensusDecodable, VarInt}; +use consensus::encode::{self, serialize, Encoder, Decoder}; +use consensus::encode::{Encodable, Decodable, VarInt}; /// A reference to a transaction output #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] @@ -104,9 +104,9 @@ pub struct TxIn { pub sequence: u32, /// Witness data: an array of byte-arrays. /// Note that this field is *not* (de)serialized with the rest of the TxIn in - /// ConsensusEncodable/ConsennsusDecodable, as it is (de)serialized at the end of the full - /// Transaction. It *is* (de)serialized with the rest of the TxIn in other (de)serializationn - /// routines. + /// Encodable/Decodable, as it is (de)serialized at the end of the full + /// Transaction. It *is* (de)serialized with the rest of the TxIn in other + /// (de)serialization routines. pub witness: Vec> } serde_struct_impl!(TxIn, previous_output, script_sig, sequence, witness); @@ -238,7 +238,7 @@ impl Transaction { _ => unreachable!() }; // hash the result - let mut raw_vec = serialize(&tx).unwrap(); + let mut raw_vec = serialize(&tx); raw_vec.write_u32::(sighash_u32).unwrap(); Sha256dHash::from_data(&raw_vec) } @@ -288,23 +288,19 @@ impl Transaction { #[cfg(feature="bitcoinconsensus")] /// Verify that this transaction is able to spend some outputs of spent transactions pub fn verify(&self, spent: &HashMap) -> Result<(), script::Error> { - if let Ok(tx) = serialize(&*self) { - for (idx, input) in self.input.iter().enumerate() { - if let Some(ref s) = spent.get(&input.previous_output.txid) { - if let Some(ref output) = s.output.get(input.previous_output.vout as usize) { - output.script_pubkey.verify(idx, output.value, tx.as_slice())?; - } else { - return Err(script::Error::WrongSpentOutputIndex(input.previous_output.vout as usize)); - } + let tx = serialize(&*self); + for (idx, input) in self.input.iter().enumerate() { + if let Some(ref s) = spent.get(&input.previous_output.txid) { + if let Some(ref output) = s.output.get(input.previous_output.vout as usize) { + output.script_pubkey.verify(idx, output.value, tx.as_slice())?; } else { - return Err(script::Error::UnknownSpentTransaction(input.previous_output.txid)); + return Err(script::Error::WrongSpentOutputIndex(input.previous_output.vout as usize)); } + } else { + return Err(script::Error::UnknownSpentTransaction(input.previous_output.txid)); } - Ok(()) - } - else { - Err(script::Error::SerializationError) } + Ok(()) } /// Is this a coin base transaction? @@ -325,41 +321,41 @@ impl BitcoinHash for Transaction { impl_consensus_encoding!(TxOut, value, script_pubkey); -impl ConsensusEncodable for OutPoint { - fn consensus_encode(&self, s: &mut S) -> Result <(), serialize::Error> { +impl Encodable for OutPoint { + fn consensus_encode(&self, s: &mut S) -> Result <(), encode::Error> { self.txid.consensus_encode(s)?; self.vout.consensus_encode(s) } } -impl ConsensusDecodable for OutPoint { - fn consensus_decode(d: &mut D) -> Result { +impl Decodable for OutPoint { + fn consensus_decode(d: &mut D) -> Result { Ok(OutPoint { - txid: ConsensusDecodable::consensus_decode(d)?, - vout: ConsensusDecodable::consensus_decode(d)?, + txid: Decodable::consensus_decode(d)?, + vout: Decodable::consensus_decode(d)?, }) } } -impl ConsensusEncodable for TxIn { - fn consensus_encode(&self, s: &mut S) -> Result <(), serialize::Error> { +impl Encodable for TxIn { + fn consensus_encode(&self, s: &mut S) -> Result <(), encode::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 { +impl Decodable for TxIn { + fn consensus_decode(d: &mut D) -> Result { Ok(TxIn { - previous_output: ConsensusDecodable::consensus_decode(d)?, - script_sig: ConsensusDecodable::consensus_decode(d)?, - sequence: ConsensusDecodable::consensus_decode(d)?, + previous_output: Decodable::consensus_decode(d)?, + script_sig: Decodable::consensus_decode(d)?, + sequence: Decodable::consensus_decode(d)?, witness: vec![], }) } } -impl ConsensusEncodable for Transaction { - fn consensus_encode(&self, s: &mut S) -> Result <(), serialize::Error> { +impl Encodable for Transaction { + fn consensus_encode(&self, s: &mut S) -> Result <(), encode::Error> { self.version.consensus_encode(s)?; let mut have_witness = false; for input in &self.input { @@ -384,13 +380,13 @@ impl ConsensusEncodable for Transaction { } } -impl ConsensusDecodable for Transaction { - fn consensus_decode(d: &mut D) -> Result { - let version: u32 = ConsensusDecodable::consensus_decode(d)?; - let input: Vec = ConsensusDecodable::consensus_decode(d)?; +impl Decodable for Transaction { + fn consensus_decode(d: &mut D) -> Result { + let version: u32 = Decodable::consensus_decode(d)?; + let input: Vec = Decodable::consensus_decode(d)?; // segwit if input.is_empty() { - let segwit_flag: u8 = ConsensusDecodable::consensus_decode(d)?; + let segwit_flag: u8 = Decodable::consensus_decode(d)?; match segwit_flag { // Empty tx 0 => { @@ -398,30 +394,30 @@ impl ConsensusDecodable for Transaction { version: version, input: input, output: vec![], - lock_time: ConsensusDecodable::consensus_decode(d)?, + lock_time: Decodable::consensus_decode(d)?, }) } // BIP144 input witnesses 1 => { - let mut input: Vec = ConsensusDecodable::consensus_decode(d)?; - let output: Vec = ConsensusDecodable::consensus_decode(d)?; + let mut input: Vec = Decodable::consensus_decode(d)?; + let output: Vec = Decodable::consensus_decode(d)?; for txin in input.iter_mut() { - txin.witness = ConsensusDecodable::consensus_decode(d)?; + txin.witness = Decodable::consensus_decode(d)?; } if !input.is_empty() && input.iter().all(|input| input.witness.is_empty()) { - Err(serialize::Error::ParseFailed("witness flag set but no witnesses present")) + Err(encode::Error::ParseFailed("witness flag set but no witnesses present")) } else { Ok(Transaction { version: version, input: input, output: output, - lock_time: ConsensusDecodable::consensus_decode(d)?, + lock_time: Decodable::consensus_decode(d)?, }) } } // We don't support anything else x => { - Err(serialize::Error::UnsupportedSegwitFlag(x)) + Err(encode::Error::UnsupportedSegwitFlag(x)) } } // non-segwit @@ -429,8 +425,8 @@ impl ConsensusDecodable for Transaction { Ok(Transaction { version: version, input: input, - output: ConsensusDecodable::consensus_decode(d)?, - lock_time: ConsensusDecodable::consensus_decode(d)?, + output: Decodable::consensus_decode(d)?, + lock_time: Decodable::consensus_decode(d)?, }) } } @@ -500,8 +496,8 @@ mod tests { use blockdata::script::Script; #[cfg(all(feature = "serde", feature = "strason"))] - use network::serialize::serialize; - use network::serialize::deserialize; + use consensus::encode::serialize; + use consensus::encode::deserialize; use util::hash::{BitcoinHash, Sha256dHash}; use util::misc::hex_bytes; @@ -650,7 +646,7 @@ mod tests { let decoded = encoded.into_deserialize().unwrap(); assert_eq!(tx, decoded); - let consensus_encoded = serialize(&tx).unwrap(); + let consensus_encoded = serialize(&tx); assert_eq!(consensus_encoded, hex_tx); } diff --git a/src/consensus/encode.rs b/src/consensus/encode.rs new file mode 100644 index 00000000..521cd8ee --- /dev/null +++ b/src/consensus/encode.rs @@ -0,0 +1,889 @@ +// Rust Bitcoin Library +// Written in 2014 by +// Andrew Poelstra +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +//! Consensus-encodable types +//! +//! This is basically a replacement of the `Encodable` trait which does +//! normalization for endianness, etc., to ensure that the encoding +//! matches for endianness, etc., to ensure that the encoding matches +//! the network consensus encoding. +//! +//! Essentially, anything that must go on the -disk- or -network- must +//! be encoded using the `Encodable` trait, since this data +//! must be the same for all systems. Any data going to the -user-, e.g. +//! over JSONRPC, should use the ordinary `Encodable` trait. (This +//! should also be the same across systems, of course, but has some +//! critical differences from the network format, e.g. scripts come +//! with an opcode decode, hashes are big-endian, numbers are typically +//! big-endian decimals, etc.) +//! + +use std::collections::HashMap; +use std::hash::Hash; +use std::{mem, u32}; + +use util::hash::Sha256dHash; + +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 util::base58; + +/// Encoding 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 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(&'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::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), + } + } +} + +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::UnexpectedNetworkMagic { .. } + | Error::OversizedVectorAllocation { .. } + | Error::InvalidChecksum { .. } + | Error::UnknownNetworkMagic(..) + | Error::ParseFailed(..) + | Error::UnsupportedWitnessVersion(..) + | Error::UnsupportedSegwitFlag(..) + | Error::UnrecognizedNetworkCommand(..) + | Error::UnexpectedHexDigit(..) => 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::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", + } + } +} + +#[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) + } +} + +/// Encode an object into a vector +pub fn serialize(data: &T) -> Vec + where T: Encodable>>, +{ + let mut encoder = Cursor::new(vec![]); + data.consensus_encode(&mut encoder).unwrap(); + encoder.into_inner() +} + +/// Encode an object into a hex-encoded string +pub fn serialize_hex(data: &T) -> String + where T: Encodable>> +{ + hex_encode(serialize(data)) +} + +/// 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 + where T: Decodable> +{ + let mut decoder = Cursor::new(data); + let rv = Decodable::consensus_decode(&mut decoder)?; + + // Fail if data is not consumed entirely. + if decoder.position() == data.len() as u64 { + Ok(rv) + } else { + Err(Error::ParseFailed("data not consumed entirely when explicitly deserializing")) + } +} + +/// A simple Encoder trait +pub trait Encoder { + /// Output a 64-bit uint + fn emit_u64(&mut self, v: u64) -> Result<(), Error>; + /// Output a 32-bit uint + fn emit_u32(&mut self, v: u32) -> Result<(), Error>; + /// Output a 16-bit uint + fn emit_u16(&mut self, v: u16) -> Result<(), Error>; + /// Output a 8-bit uint + fn emit_u8(&mut self, v: u8) -> Result<(), Error>; + + /// Output a 64-bit int + fn emit_i64(&mut self, v: i64) -> Result<(), Error>; + /// Output a 32-bit int + fn emit_i32(&mut self, v: i32) -> Result<(), Error>; + /// Output a 16-bit int + fn emit_i16(&mut self, v: i16) -> Result<(), Error>; + /// Output a 8-bit int + fn emit_i8(&mut self, v: i8) -> Result<(), Error>; + + /// Output a boolean + fn emit_bool(&mut self, v: bool) -> Result<(), Error>; +} + +/// A simple Decoder trait +pub trait Decoder { + /// Read a 64-bit uint + fn read_u64(&mut self) -> Result; + /// Read a 32-bit uint + fn read_u32(&mut self) -> Result; + /// Read a 16-bit uint + fn read_u16(&mut self) -> Result; + /// Read a 8-bit uint + fn read_u8(&mut self) -> Result; + + /// Read a 64-bit int + fn read_i64(&mut self) -> Result; + /// Read a 32-bit int + fn read_i32(&mut self) -> Result; + /// Read a 16-bit int + fn read_i16(&mut self) -> Result; + /// Read a 8-bit int + fn read_i8(&mut self) -> Result; + + /// Read a boolean + fn read_bool(&mut self) -> Result; +} + +macro_rules! encoder_fn { + ($name:ident, $val_type:ty, $writefn:ident) => { + #[inline] + fn $name(&mut self, v: $val_type) -> Result<(), Error> { + WriteBytesExt::$writefn::(self, v).map_err(Error::Io) + } + } +} + +macro_rules! decoder_fn { + ($name:ident, $val_type:ty, $readfn:ident) => { + #[inline] + fn $name(&mut self) -> Result<$val_type, Error> { + ReadBytesExt::$readfn::(self).map_err(Error::Io) + } + } +} + +impl Encoder for W { + encoder_fn!(emit_u64, u64, write_u64); + encoder_fn!(emit_u32, u32, write_u32); + encoder_fn!(emit_u16, u16, write_u16); + encoder_fn!(emit_i64, i64, write_i64); + encoder_fn!(emit_i32, i32, write_i32); + encoder_fn!(emit_i16, i16, write_i16); + + #[inline] + fn emit_i8(&mut self, v: i8) -> Result<(), Error> { + self.write_i8(v).map_err(Error::Io) + } + #[inline] + fn emit_u8(&mut self, v: u8) -> Result<(), Error> { + self.write_u8(v).map_err(Error::Io) + } + #[inline] + fn emit_bool(&mut self, v: bool) -> Result<(), Error> { + self.write_i8(if v {1} else {0}).map_err(Error::Io) + } +} + +impl Decoder for R { + decoder_fn!(read_u64, u64, read_u64); + decoder_fn!(read_u32, u32, read_u32); + decoder_fn!(read_u16, u16, read_u16); + decoder_fn!(read_i64, i64, read_i64); + decoder_fn!(read_i32, i32, read_i32); + decoder_fn!(read_i16, i16, read_i16); + + #[inline] + fn read_u8(&mut self) -> Result { + ReadBytesExt::read_u8(self).map_err(Error::Io) + } + #[inline] + fn read_i8(&mut self) -> Result { + ReadBytesExt::read_i8(self).map_err(Error::Io) + } + #[inline] + fn read_bool(&mut self) -> Result { + Decoder::read_i8(self).map(|bit| bit != 0) + } +} + +/// Maximum size, in bytes, of a vector we are allowed to decode +pub const MAX_VEC_SIZE: usize = 32 * 1024 * 1024; + +/// Data which can be encoded in a consensus-consistent way +pub trait Encodable { + /// Encode an object with a well-defined format, should only ever error if + /// the underlying Encoder errors. + fn consensus_encode(&self, e: &mut S) -> Result<(), self::Error>; +} + +/// Data which can be encoded in a consensus-consistent way +pub trait Decodable: Sized { + /// Decode an object with a well-defined format + fn consensus_decode(d: &mut D) -> Result; +} + +/// A variable-length unsigned integer +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)] +pub struct VarInt(pub u64); + +/// Data which must be preceded by a 4-byte checksum +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct CheckedData(pub Vec); + +// Primitive types +macro_rules! impl_int_encodable{ + ($ty:ident, $meth_dec:ident, $meth_enc:ident) => ( + impl Decodable for $ty { + #[inline] + fn consensus_decode(d: &mut D) -> Result<$ty, self::Error> { d.$meth_dec().map($ty::from_le) } + } + + impl Encodable for $ty { + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { s.$meth_enc(self.to_le()) } + } + ) +} + +impl_int_encodable!(u8, read_u8, emit_u8); +impl_int_encodable!(u16, read_u16, emit_u16); +impl_int_encodable!(u32, read_u32, emit_u32); +impl_int_encodable!(u64, read_u64, emit_u64); +impl_int_encodable!(i8, read_i8, emit_i8); +impl_int_encodable!(i16, read_i16, emit_i16); +impl_int_encodable!(i32, read_i32, emit_i32); +impl_int_encodable!(i64, read_i64, emit_i64); + +impl VarInt { + /// Gets the length of this VarInt when encoded. + /// Returns 1 for 0...0xFC, 3 for 0xFD...(2^16-1), 5 for 0x10000...(2^32-1), + /// and 9 otherwise. + #[inline] + pub fn encoded_length(&self) -> u64 { + match self.0 { + 0...0xFC => { 1 } + 0xFD...0xFFFF => { 3 } + 0x10000...0xFFFFFFFF => { 5 } + _ => { 9 } + } + } +} + +impl Encodable for VarInt { + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::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) } + 0x10000...0xFFFFFFFF => { s.emit_u8(0xFE)?; (self.0 as u32).consensus_encode(s) } + _ => { s.emit_u8(0xFF)?; (self.0 as u64).consensus_encode(s) } + } + } +} + +impl Decodable for VarInt { + #[inline] + fn consensus_decode(d: &mut D) -> Result { + let n = d.read_u8()?; + match n { + 0xFF => { + let x = d.read_u64()?; + if x < 0x100000000 { + Err(self::Error::ParseFailed("non-minimal varint")) + } else { + Ok(VarInt(x)) + } + } + 0xFE => { + let x = d.read_u32()?; + if x < 0x10000 { + Err(self::Error::ParseFailed("non-minimal varint")) + } else { + Ok(VarInt(x as u64)) + } + } + 0xFD => { + let x = d.read_u16()?; + if x < 0xFD { + Err(self::Error::ParseFailed("non-minimal varint")) + } else { + Ok(VarInt(x as u64)) + } + } + n => Ok(VarInt(n as u64)) + } + } +} + + +// Booleans +impl Encodable for bool { + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { s.emit_u8(if *self {1} else {0}) } +} + +impl Decodable for bool { + #[inline] + fn consensus_decode(d: &mut D) -> Result { d.read_u8().map(|n| n != 0) } +} + +// Strings +impl Encodable for String { + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { + self.as_bytes().consensus_encode(s) + } +} + +impl Decodable for String { + #[inline] + fn consensus_decode(d: &mut D) -> Result { + String::from_utf8(Decodable::consensus_decode(d)?) + .map_err(|_| self::Error::ParseFailed("String was not valid UTF8")) + } +} + + +// Arrays +macro_rules! impl_array { + ( $size:expr ) => ( + impl> Encodable for [T; $size] { + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { + for i in self.iter() { i.consensus_encode(s)?; } + Ok(()) + } + } + + impl + Copy> Decodable for [T; $size] { + #[inline] + fn consensus_decode(d: &mut D) -> Result<[T; $size], self::Error> { + // Set everything to the first decode + let mut ret = [Decodable::consensus_decode(d)?; $size]; + // Set the rest + for item in ret.iter_mut().take($size).skip(1) { *item = Decodable::consensus_decode(d)?; } + Ok(ret) + } + } + ); +} + +impl_array!(2); +impl_array!(4); +impl_array!(8); +impl_array!(12); +impl_array!(16); +impl_array!(32); + +impl> Encodable for [T] { + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { + VarInt(self.len() as u64).consensus_encode(s)?; + for c in self.iter() { c.consensus_encode(s)?; } + Ok(()) + } +} + +// Cannot decode a slice + +// Vectors +impl> Encodable for Vec { + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { (&self[..]).consensus_encode(s) } +} + +impl> Decodable for Vec { + #[inline] + fn consensus_decode(d: &mut D) -> Result, self::Error> { + let len = VarInt::consensus_decode(d)?.0; + let byte_size = (len as usize) + .checked_mul(mem::size_of::()) + .ok_or(self::Error::ParseFailed("Invalid length"))?; + if byte_size > MAX_VEC_SIZE { + return Err(self::Error::OversizedVectorAllocation { requested: byte_size, max: MAX_VEC_SIZE }) + } + let mut ret = Vec::with_capacity(len as usize); + for _ in 0..len { ret.push(Decodable::consensus_decode(d)?); } + Ok(ret) + } +} + +impl> Encodable for Box<[T]> { + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { (&self[..]).consensus_encode(s) } +} + +impl> Decodable for Box<[T]> { + #[inline] + fn consensus_decode(d: &mut D) -> Result, self::Error> { + let len = VarInt::consensus_decode(d)?.0; + let len = len as usize; + if len > MAX_VEC_SIZE { + return Err(self::Error::OversizedVectorAllocation { requested: len, max: MAX_VEC_SIZE }) + } + let mut ret = Vec::with_capacity(len); + for _ in 0..len { ret.push(Decodable::consensus_decode(d)?); } + Ok(ret.into_boxed_slice()) + } +} + +// Options (encoded as vectors of length 0 or 1) +impl> Encodable for Option { + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { + match *self { + Some(ref data) => { + 1u8.consensus_encode(s)?; + data.consensus_encode(s)?; + } + None => { 0u8.consensus_encode(s)?; } + } + Ok(()) + } +} + +impl> Decodable for Option { + #[inline] + fn consensus_decode(d: &mut D) -> Result, self::Error> { + let bit: u8 = Decodable::consensus_decode(d)?; + Ok(if bit != 0 { + Some(Decodable::consensus_decode(d)?) + } else { + None + }) + } +} + + +/// Do a double-SHA256 on some data and return the first 4 bytes +fn sha2_checksum(data: &[u8]) -> [u8; 4] { + let checksum = Sha256dHash::from_data(data); + [checksum[0], checksum[1], checksum[2], checksum[3]] +} + +// Checked data +impl Encodable for CheckedData { + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::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 + for ch in &self.0 { + ch.consensus_encode(s)?; + } + Ok(()) + } +} + +impl Decodable for CheckedData { + #[inline] + fn consensus_decode(d: &mut D) -> Result { + let len: u32 = Decodable::consensus_decode(d)?; + let checksum: [u8; 4] = Decodable::consensus_decode(d)?; + let mut ret = Vec::with_capacity(len as usize); + for _ in 0..len { ret.push(Decodable::consensus_decode(d)?); } + let expected_checksum = sha2_checksum(&ret); + if expected_checksum != checksum { + Err(self::Error::InvalidChecksum { + expected: expected_checksum, + actual: checksum, + }) + } else { + Ok(CheckedData(ret)) + } + } +} + +// Tuples +macro_rules! tuple_encode { + ($($x:ident),*) => ( + impl ),*> Encodable for ($($x),*) { + #[inline] + #[allow(non_snake_case)] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { + let &($(ref $x),*) = self; + $( $x.consensus_encode(s)?; )* + Ok(()) + } + } + + impl),*> Decodable for ($($x),*) { + #[inline] + #[allow(non_snake_case)] + fn consensus_decode(d: &mut D) -> Result<($($x),*), self::Error> { + Ok(($({let $x = Decodable::consensus_decode(d)?; $x }),*)) + } + } + ); +} + +tuple_encode!(T0, T1); +tuple_encode!(T0, T1, T2, T3); +tuple_encode!(T0, T1, T2, T3, T4, T5); +tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7); + +// References +impl> Encodable for Box { + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { (**self).consensus_encode(s) } +} + +impl> Decodable for Box { + #[inline] + fn consensus_decode(d: &mut D) -> Result, self::Error> { + Decodable::consensus_decode(d).map(Box::new) + } +} + +// HashMap +impl Encodable for HashMap + where S: Encoder, + K: Encodable + Eq + Hash, + V: Encodable +{ + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { + VarInt(self.len() as u64).consensus_encode(s)?; + for (key, value) in self.iter() { + key.consensus_encode(s)?; + value.consensus_encode(s)?; + } + Ok(()) + } +} + +impl Decodable for HashMap + where D: Decoder, + K: Decodable + Eq + Hash, + V: Decodable +{ + #[inline] + fn consensus_decode(d: &mut D) -> Result, self::Error> { + let len = VarInt::consensus_decode(d)?.0; + + let mut ret = HashMap::with_capacity(len as usize); + for _ in 0..len { + ret.insert(Decodable::consensus_decode(d)?, + Decodable::consensus_decode(d)?); + } + Ok(ret) + } +} + + + +// Tests +#[cfg(test)] +mod tests { + use super::{CheckedData, VarInt}; + + use super::{deserialize, serialize, Error}; + + #[test] + fn serialize_int_test() { + // bool + assert_eq!(serialize(&false), vec![0u8]); + assert_eq!(serialize(&true), vec![1u8]); + // u8 + assert_eq!(serialize(&1u8), vec![1u8]); + assert_eq!(serialize(&0u8), vec![0u8]); + assert_eq!(serialize(&255u8), vec![255u8]); + // u16 + assert_eq!(serialize(&1u16), vec![1u8, 0]); + assert_eq!(serialize(&256u16), vec![0u8, 1]); + assert_eq!(serialize(&5000u16), vec![136u8, 19]); + // u32 + assert_eq!(serialize(&1u32), vec![1u8, 0, 0, 0]); + assert_eq!(serialize(&256u32), vec![0u8, 1, 0, 0]); + assert_eq!(serialize(&5000u32), vec![136u8, 19, 0, 0]); + assert_eq!(serialize(&500000u32), vec![32u8, 161, 7, 0]); + assert_eq!(serialize(&168430090u32), vec![10u8, 10, 10, 10]); + // TODO: test negative numbers + assert_eq!(serialize(&1i32), vec![1u8, 0, 0, 0]); + assert_eq!(serialize(&256i32), vec![0u8, 1, 0, 0]); + assert_eq!(serialize(&5000i32), vec![136u8, 19, 0, 0]); + assert_eq!(serialize(&500000i32), vec![32u8, 161, 7, 0]); + assert_eq!(serialize(&168430090i32), vec![10u8, 10, 10, 10]); + // u64 + assert_eq!(serialize(&1u64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!(serialize(&256u64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]); + assert_eq!(serialize(&5000u64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]); + assert_eq!(serialize(&500000u64), vec![32u8, 161, 7, 0, 0, 0, 0, 0]); + assert_eq!(serialize(&723401728380766730u64), vec![10u8, 10, 10, 10, 10, 10, 10, 10]); + // TODO: test negative numbers + assert_eq!(serialize(&1i64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!(serialize(&256i64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]); + assert_eq!(serialize(&5000i64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]); + assert_eq!(serialize(&500000i64), vec![32u8, 161, 7, 0, 0, 0, 0, 0]); + assert_eq!(serialize(&723401728380766730i64), vec![10u8, 10, 10, 10, 10, 10, 10, 10]); + } + + #[test] + fn serialize_varint_test() { + assert_eq!(serialize(&VarInt(10)), vec![10u8]); + assert_eq!(serialize(&VarInt(0xFC)), vec![0xFCu8]); + assert_eq!(serialize(&VarInt(0xFD)), vec![0xFDu8, 0xFD, 0]); + assert_eq!(serialize(&VarInt(0xFFF)), vec![0xFDu8, 0xFF, 0xF]); + assert_eq!(serialize(&VarInt(0xF0F0F0F)), vec![0xFEu8, 0xF, 0xF, 0xF, 0xF]); + assert_eq!(serialize(&VarInt(0xF0F0F0F0F0E0)), vec![0xFFu8, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0, 0]); + } + + #[test] + fn deserialize_nonminimal_vec() { + match deserialize::>(&[0xfd, 0x00, 0x00]) { + Err(Error::ParseFailed("non-minimal varint")) => {}, + x => panic!(x) + } + match deserialize::>(&[0xfd, 0xfc, 0x00]) { + Err(Error::ParseFailed("non-minimal varint")) => {}, + x => panic!(x) + } + match deserialize::>(&[0xfe, 0xff, 0x00, 0x00, 0x00]) { + Err(Error::ParseFailed("non-minimal varint")) => {}, + x => panic!(x) + } + match deserialize::>(&[0xfe, 0xff, 0xff, 0x00, 0x00]) { + Err(Error::ParseFailed("non-minimal varint")) => {}, + x => panic!(x) + } + match deserialize::>(&[0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) { + Err(Error::ParseFailed("non-minimal varint")) => {}, + x => panic!(x) + } + match deserialize::>(&[0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00]) { + Err(Error::ParseFailed("non-minimal varint")) => {}, + x => panic!(x) + } + + let mut vec_256 = vec![0; 259]; + vec_256[0] = 0xfd; + vec_256[1] = 0x00; + vec_256[2] = 0x01; + assert!(deserialize::>(&vec_256).is_ok()); + + let mut vec_253 = vec![0; 256]; + vec_253[0] = 0xfd; + vec_253[1] = 0xfd; + vec_253[2] = 0x00; + assert!(deserialize::>(&vec_253).is_ok()); + } + + #[test] + fn serialize_checkeddata_test() { + let cd = CheckedData(vec![1u8, 2, 3, 4, 5]); + assert_eq!(serialize(&cd), vec![5, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5]); + } + + #[test] + fn serialize_vector_test() { + assert_eq!(serialize(&vec![1u8, 2, 3]), vec![3u8, 1, 2, 3]); + assert_eq!(serialize(&[1u8, 2, 3][..]), vec![3u8, 1, 2, 3]); + // TODO: test vectors of more interesting objects + } + + #[test] + fn serialize_strbuf_test() { + assert_eq!(serialize(&"Andrew".to_string()), vec![6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]); + } + + #[test] + fn serialize_box_test() { + assert_eq!(serialize(&Box::new(1u8)), vec![1u8]); + assert_eq!(serialize(&Box::new(1u16)), vec![1u8, 0]); + assert_eq!(serialize(&Box::new(1u64)), vec![1u8, 0, 0, 0, 0, 0, 0, 0]); + } + + #[test] + fn serialize_option_test() { + assert_eq!(serialize(&None::), vec![0]); + assert_eq!(serialize(&Some(0xFFu8)), vec![1, 0xFF]); + } + + #[test] + fn deserialize_int_test() { + // bool + assert!((deserialize(&[58u8, 0]) as Result).is_err()); + assert_eq!(deserialize(&[58u8]).ok(), Some(true)); + assert_eq!(deserialize(&[1u8]).ok(), Some(true)); + assert_eq!(deserialize(&[0u8]).ok(), Some(false)); + assert!((deserialize(&[0u8, 1]) as Result).is_err()); + + // u8 + assert_eq!(deserialize(&[58u8]).ok(), Some(58u8)); + + // u16 + assert_eq!(deserialize(&[0x01u8, 0x02]).ok(), Some(0x0201u16)); + assert_eq!(deserialize(&[0xABu8, 0xCD]).ok(), Some(0xCDABu16)); + assert_eq!(deserialize(&[0xA0u8, 0x0D]).ok(), Some(0xDA0u16)); + let failure16: Result = deserialize(&[1u8]); + assert!(failure16.is_err()); + + // u32 + assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABu32)); + assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD]).ok(), Some(0xCDAB0DA0u32)); + let failure32: Result = deserialize(&[1u8, 2, 3]); + assert!(failure32.is_err()); + // TODO: test negative numbers + assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABi32)); + assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0x2D]).ok(), Some(0x2DAB0DA0i32)); + let failurei32: Result = deserialize(&[1u8, 2, 3]); + assert!(failurei32.is_err()); + + // u64 + assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), Some(0xCDABu64)); + assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), Some(0x99000099CDAB0DA0u64)); + let failure64: Result = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]); + assert!(failure64.is_err()); + // TODO: test negative numbers + assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), Some(0xCDABi64)); + assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), Some(-0x66ffff663254f260i64)); + let failurei64: Result = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]); + assert!(failurei64.is_err()); + } + + #[test] + fn deserialize_vec_test() { + assert_eq!(deserialize(&[3u8, 2, 3, 4]).ok(), Some(vec![2u8, 3, 4])); + assert!((deserialize(&[4u8, 2, 3, 4, 5, 6]) as Result, _>).is_err()); + // found by cargo fuzz + assert!(deserialize::>(&[0xff,0xff,0xff,0xff,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0xa,0xa,0x3a]).is_err()); + } + + #[test] + fn deserialize_strbuf_test() { + assert_eq!(deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(), Some("Andrew".to_string())); + } + + #[test] + fn deserialize_checkeddata_test() { + let cd: Result = deserialize(&[5u8, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5]); + assert_eq!(cd.ok(), Some(CheckedData(vec![1u8, 2, 3, 4, 5]))); + } + + #[test] + fn deserialize_option_test() { + let none: Result, _> = deserialize(&[0u8]); + let good: Result, _> = deserialize(&[1u8, 0xFF]); + let bad: Result, _> = deserialize(&[2u8]); + assert!(bad.is_err()); + assert_eq!(none.ok(), Some(None)); + assert_eq!(good.ok(), Some(Some(0xFF))); + } + + #[test] + fn deserialize_box_test() { + let zero: Result, _> = deserialize(&[0u8]); + let one: Result, _> = deserialize(&[1u8]); + assert_eq!(zero.ok(), Some(Box::new(0))); + assert_eq!(one.ok(), Some(Box::new(1))); + } +} + diff --git a/src/consensus/mod.rs b/src/consensus/mod.rs index d645b9d5..db59ce40 100644 --- a/src/consensus/mod.rs +++ b/src/consensus/mod.rs @@ -18,4 +18,8 @@ //! conform to Bitcoin consensus. //! +pub mod encode; pub mod params; + +pub use self::encode::{Encodable, Decodable, Encoder, Decoder, serialize, deserialize}; +pub use self::params::Params; diff --git a/src/internal_macros.rs b/src/internal_macros.rs index cdb84c78..afb66580 100644 --- a/src/internal_macros.rs +++ b/src/internal_macros.rs @@ -14,20 +14,20 @@ macro_rules! impl_consensus_encoding { ($thing:ident, $($field:ident),+) => ( - impl ::network::encodable::ConsensusEncodable for $thing { + impl ::consensus::encode::Encodable for $thing { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), ::network::serialize::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), ::consensus::encode::Error> { $( self.$field.consensus_encode(s)?; )+ Ok(()) } } - impl ::network::encodable::ConsensusDecodable for $thing { + impl ::consensus::encode::Decodable for $thing { #[inline] - fn consensus_decode(d: &mut D) -> Result<$thing, ::network::serialize::Error> { - use network::encodable::ConsensusDecodable; + fn consensus_decode(d: &mut D) -> Result<$thing, ::consensus::encode::Error> { + use consensus::encode::Decodable; Ok($thing { - $( $field: ConsensusDecodable::consensus_decode(d)?, )+ + $( $field: Decodable::consensus_decode(d)?, )+ }) } } @@ -36,18 +36,18 @@ macro_rules! impl_consensus_encoding { macro_rules! impl_newtype_consensus_encoding { ($thing:ident) => ( - impl ::network::encodable::ConsensusEncodable for $thing { + impl ::consensus::encode::Encodable for $thing { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), ::network::serialize::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), ::consensus::encode::Error> { let &$thing(ref data) = self; data.consensus_encode(s) } } - impl ::network::encodable::ConsensusDecodable for $thing { + impl ::consensus::encode::Decodable for $thing { #[inline] - fn consensus_decode(d: &mut D) -> Result<$thing, ::network::serialize::Error> { - Ok($thing(ConsensusDecodable::consensus_decode(d)?)) + fn consensus_decode(d: &mut D) -> Result<$thing, ::consensus::encode::Error> { + Ok($thing(Decodable::consensus_decode(d)?)) } } ); diff --git a/src/lib.rs b/src/lib.rs index c6d9c20b..99aaa6a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,6 +62,7 @@ pub mod macros; pub mod network; pub mod blockdata; pub mod util; +pub mod consensus; pub use blockdata::block::Block; pub use blockdata::block::BlockHeader; @@ -71,11 +72,10 @@ pub use blockdata::transaction::TxIn; pub use blockdata::transaction::TxOut; pub use blockdata::transaction::OutPoint; pub use blockdata::transaction::SigHashType; -pub use network::encodable::VarInt; +pub use consensus::encode::VarInt; pub use util::Error; pub use util::address::Address; pub use util::hash::BitcoinHash; pub use util::privkey::Privkey; pub use util::decimal::Decimal; pub use util::decimal::UDecimal; - diff --git a/src/network/address.rs b/src/network/address.rs index ab3cd5b5..c6871486 100644 --- a/src/network/address.rs +++ b/src/network/address.rs @@ -22,8 +22,8 @@ use std::io; use std::fmt; use std::net::{SocketAddr, Ipv6Addr, SocketAddrV4, SocketAddrV6}; -use network::serialize::{self, SimpleEncoder, SimpleDecoder}; -use network::encodable::{ConsensusDecodable, ConsensusEncodable}; +use consensus::encode::{self, Encoder, Decoder}; +use consensus::encode::{Decodable, Encodable}; /// A message which can be sent on the Bitcoin network pub struct Address { @@ -72,22 +72,22 @@ fn addr_to_be(addr: [u16; 8]) -> [u16; 8] { addr[4].to_be(), addr[5].to_be(), addr[6].to_be(), addr[7].to_be()] } -impl ConsensusEncodable for Address { +impl Encodable for Address { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> { self.services.consensus_encode(s)?; addr_to_be(self.address).consensus_encode(s)?; self.port.to_be().consensus_encode(s) } } -impl ConsensusDecodable for Address { +impl Decodable 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)?), - port: u16::from_be(ConsensusDecodable::consensus_decode(d)?) + services: Decodable::consensus_decode(d)?, + address: addr_to_be(Decodable::consensus_decode(d)?), + port: u16::from_be(Decodable::consensus_decode(d)?) }) } } @@ -126,7 +126,7 @@ mod test { use super::Address; use std::net::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr}; - use network::serialize::{deserialize, serialize}; + use consensus::encode::{deserialize, serialize}; #[test] fn serialize_address_test() { @@ -134,9 +134,9 @@ mod test { services: 1, address: [0, 0, 0, 0, 0, 0xffff, 0x0a00, 0x0001], port: 8333 - }).ok(), - Some(vec![1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1, 0x20, 0x8d])); + }), + vec![1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1, 0x20, 0x8d]); } #[test] diff --git a/src/network/constants.rs b/src/network/constants.rs index 244551d7..0315fb13 100644 --- a/src/network/constants.rs +++ b/src/network/constants.rs @@ -17,28 +17,28 @@ //! This module provides various constants relating to the Bitcoin network //! protocol, such as protocol versioning and magic header bytes. //! -//! The [`Network`][1] type implements the [`ConsensusDecodable`][2] and -//! [`ConsensusEncodable`][3] and encodes the magic bytes of the given +//! The [`Network`][1] type implements the [`Decodable`][2] and +//! [`Encodable`][3] traits and encodes the magic bytes of the given //! network //! //! [1]: enum.Network.html -//! [2]: ../encodable/trait.ConsensusDecodable.html -//! [3]: ../encodable/trait.ConsensusEncodable.html +//! [2]: ../../consensus/encode/trait.Decodable.html +//! [3]: ../../consensus/encode/trait.Encodable.html //! //! # Example: encoding a network's magic bytes //! //! ```rust //! use bitcoin::network::constants::Network; -//! use bitcoin::network::serialize::serialize; +//! use bitcoin::consensus::encode::serialize; //! //! let network = Network::Bitcoin; -//! let bytes = serialize(&network).unwrap(); +//! let bytes = serialize(&network); //! //! assert_eq!(&bytes[..], &[0xF9, 0xBE, 0xB4, 0xD9]); //! ``` -use network::encodable::{ConsensusDecodable, ConsensusEncodable}; -use network::serialize::{self, SimpleEncoder, SimpleDecoder}; +use consensus::encode::{Decodable, Encodable}; +use consensus::encode::{self, Encoder, Decoder}; /// Version of the protocol as appearing in network message headers pub const PROTOCOL_VERSION: u32 = 70001; @@ -102,22 +102,22 @@ impl Network { } } -impl ConsensusEncodable for Network { +impl Encodable for Network { /// Encodes the magic bytes of `Network`. #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> { self.magic().consensus_encode(s) } } -impl ConsensusDecodable for Network { +impl Decodable 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) - .ok_or(serialize::Error::UnknownNetworkMagic(m)) + .ok_or(encode::Error::UnknownNetworkMagic(m)) }) } } @@ -125,13 +125,13 @@ impl ConsensusDecodable for Network { #[cfg(test)] mod tests { use super::Network; - use network::serialize::{deserialize, serialize}; + use consensus::encode::{deserialize, serialize}; #[test] fn serialize_test() { - assert_eq!(serialize(&Network::Bitcoin).unwrap(), vec![0xf9, 0xbe, 0xb4, 0xd9]); - assert_eq!(serialize(&Network::Testnet).unwrap(), vec![0x0b, 0x11, 0x09, 0x07]); - assert_eq!(serialize(&Network::Regtest).unwrap(), vec![0xfa, 0xbf, 0xb5, 0xda]); + assert_eq!(serialize(&Network::Bitcoin), vec![0xf9, 0xbe, 0xb4, 0xd9]); + assert_eq!(serialize(&Network::Testnet), vec![0x0b, 0x11, 0x09, 0x07]); + assert_eq!(serialize(&Network::Regtest), vec![0xfa, 0xbf, 0xb5, 0xda]); assert_eq!(deserialize(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), Some(Network::Bitcoin)); assert_eq!(deserialize(&[0x0b, 0x11, 0x09, 0x07]).ok(), Some(Network::Testnet)); diff --git a/src/network/encodable.rs b/src/network/encodable.rs deleted file mode 100644 index 6551c91a..00000000 --- a/src/network/encodable.rs +++ /dev/null @@ -1,612 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Consensus-encodable types -//! -//! This is basically a replacement of the `Encodable` trait which does -//! normalization for endianness, etc., to ensure that the encoding -//! matches for endianness, etc., to ensure that the encoding matches -//! the network consensus encoding. -//! -//! Essentially, anything that must go on the -disk- or -network- must -//! be encoded using the `ConsensusEncodable` trait, since this data -//! must be the same for all systems. Any data going to the -user-, e.g. -//! over JSONRPC, should use the ordinary `Encodable` trait. (This -//! should also be the same across systems, of course, but has some -//! critical differences from the network format, e.g. scripts come -//! with an opcode decode, hashes are big-endian, numbers are typically -//! big-endian decimals, etc.) -//! - -use std::collections::HashMap; -use std::hash::Hash; -use std::{mem, u32}; - -use util::hash::Sha256dHash; -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; - -/// 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<(), 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; -} - -/// A variable-length unsigned integer -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)] -pub struct VarInt(pub u64); - -/// Data which must be preceded by a 4-byte checksum -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct CheckedData(pub Vec); - -// Primitive types -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, serialize::Error> { d.$meth_dec().map($ty::from_le) } - } - - impl ConsensusEncodable for $ty { - #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { s.$meth_enc(self.to_le()) } - } - ) -} - -impl_int_encodable!(u8, read_u8, emit_u8); -impl_int_encodable!(u16, read_u16, emit_u16); -impl_int_encodable!(u32, read_u32, emit_u32); -impl_int_encodable!(u64, read_u64, emit_u64); -impl_int_encodable!(i8, read_i8, emit_i8); -impl_int_encodable!(i16, read_i16, emit_i16); -impl_int_encodable!(i32, read_i32, emit_i32); -impl_int_encodable!(i64, read_i64, emit_i64); - -impl VarInt { - /// Gets the length of this VarInt when encoded. - /// Returns 1 for 0...0xFC, 3 for 0xFD...(2^16-1), 5 for 0x10000...(2^32-1), - /// and 9 otherwise. - #[inline] - pub fn encoded_length(&self) -> u64 { - match self.0 { - 0...0xFC => { 1 } - 0xFD...0xFFFF => { 3 } - 0x10000...0xFFFFFFFF => { 5 } - _ => { 9 } - } - } -} - -impl ConsensusEncodable for VarInt { - #[inline] - 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) } - 0x10000...0xFFFFFFFF => { s.emit_u8(0xFE)?; (self.0 as u32).consensus_encode(s) } - _ => { s.emit_u8(0xFF)?; (self.0 as u64).consensus_encode(s) } - } - } -} - -impl ConsensusDecodable for VarInt { - #[inline] - fn consensus_decode(d: &mut D) -> Result { - let n = d.read_u8()?; - match n { - 0xFF => { - let x = d.read_u64()?; - if x < 0x100000000 { - Err(serialize::Error::ParseFailed("non-minimal varint")) - } else { - Ok(VarInt(x)) - } - } - 0xFE => { - let x = d.read_u32()?; - if x < 0x10000 { - Err(serialize::Error::ParseFailed("non-minimal varint")) - } else { - Ok(VarInt(x as u64)) - } - } - 0xFD => { - let x = d.read_u16()?; - if x < 0xFD { - Err(serialize::Error::ParseFailed("non-minimal varint")) - } else { - Ok(VarInt(x as u64)) - } - } - n => Ok(VarInt(n as u64)) - } - } -} - - -// Booleans -impl ConsensusEncodable for bool { - #[inline] - 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) } -} - -// Strings -impl ConsensusEncodable for String { - #[inline] - 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 { - String::from_utf8(ConsensusDecodable::consensus_decode(d)?) - .map_err(|_| serialize::Error::ParseFailed("String was not valid UTF8")) - } -} - - -// Arrays -macro_rules! impl_array { - ( $size:expr ) => ( - impl> ConsensusEncodable for [T; $size] { - #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { - for i in self.iter() { i.consensus_encode(s)?; } - Ok(()) - } - } - - impl + Copy> ConsensusDecodable for [T; $size] { - #[inline] - 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 - for item in ret.iter_mut().take($size).skip(1) { *item = ConsensusDecodable::consensus_decode(d)?; } - Ok(ret) - } - } - ); -} - -impl_array!(2); -impl_array!(4); -impl_array!(8); -impl_array!(12); -impl_array!(16); -impl_array!(32); - -impl> ConsensusEncodable for [T] { - #[inline] - 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(()) - } -} - -// Cannot decode a slice - -// Vectors -impl> ConsensusEncodable for Vec { - #[inline] - 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, serialize::Error> { - let len = VarInt::consensus_decode(d)?.0; - let byte_size = (len as usize) - .checked_mul(mem::size_of::()) - .ok_or(serialize::Error::ParseFailed("Invalid length"))?; - if 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)?); } - Ok(ret) - } -} - -impl> ConsensusEncodable for Box<[T]> { - #[inline] - 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, serialize::Error> { - let len = VarInt::consensus_decode(d)?.0; - let len = len as usize; - if 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)?); } - Ok(ret.into_boxed_slice()) - } -} - -// Options (encoded as vectors of length 0 or 1) -impl> ConsensusEncodable for Option { - #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { - match *self { - Some(ref data) => { - 1u8.consensus_encode(s)?; - data.consensus_encode(s)?; - } - None => { 0u8.consensus_encode(s)?; } - } - Ok(()) - } -} - -impl> ConsensusDecodable for Option { - #[inline] - 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)?) - } else { - None - }) - } -} - - -/// Do a double-SHA256 on some data and return the first 4 bytes -fn sha2_checksum(data: &[u8]) -> [u8; 4] { - let checksum = Sha256dHash::from_data(data); - [checksum[0], checksum[1], checksum[2], checksum[3]] -} - -// Checked data -impl ConsensusEncodable for CheckedData { - #[inline] - 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 - for ch in &self.0 { - ch.consensus_encode(s)?; - } - Ok(()) - } -} - -impl ConsensusDecodable for CheckedData { - #[inline] - 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); - for _ in 0..len { ret.push(ConsensusDecodable::consensus_decode(d)?); } - let expected_checksum = sha2_checksum(&ret); - if expected_checksum != checksum { - Err(serialize::Error::InvalidChecksum { - expected: expected_checksum, - actual: checksum, - }) - } else { - Ok(CheckedData(ret)) - } - } -} - -// Tuples -macro_rules! tuple_encode { - ($($x:ident),*) => ( - impl ),*> ConsensusEncodable for ($($x),*) { - #[inline] - #[allow(non_snake_case)] - fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { - let &($(ref $x),*) = self; - $( $x.consensus_encode(s)?; )* - Ok(()) - } - } - - impl),*> ConsensusDecodable for ($($x),*) { - #[inline] - #[allow(non_snake_case)] - fn consensus_decode(d: &mut D) -> Result<($($x),*), serialize::Error> { - Ok(($({let $x = ConsensusDecodable::consensus_decode(d)?; $x }),*)) - } - } - ); -} - -tuple_encode!(T0, T1); -tuple_encode!(T0, T1, T2, T3); -tuple_encode!(T0, T1, T2, T3, T4, T5); -tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7); - -// References -impl> ConsensusEncodable for Box { - #[inline] - 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, serialize::Error> { - ConsensusDecodable::consensus_decode(d).map(Box::new) - } -} - -// HashMap -impl ConsensusEncodable for HashMap - where S: SimpleEncoder, - K: ConsensusEncodable + Eq + Hash, - V: ConsensusEncodable -{ - #[inline] - 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)?; - value.consensus_encode(s)?; - } - Ok(()) - } -} - -impl ConsensusDecodable for HashMap - where D: SimpleDecoder, - K: ConsensusDecodable + Eq + Hash, - V: ConsensusDecodable -{ - #[inline] - fn consensus_decode(d: &mut D) -> Result, serialize::Error> { - let len = VarInt::consensus_decode(d)?.0; - - let mut ret = HashMap::with_capacity(len as usize); - for _ in 0..len { - ret.insert(ConsensusDecodable::consensus_decode(d)?, - ConsensusDecodable::consensus_decode(d)?); - } - Ok(ret) - } -} - - - -// Tests -#[cfg(test)] -mod tests { - use super::{CheckedData, VarInt}; - - use network::serialize::{deserialize, serialize, Error}; - - #[test] - fn serialize_int_test() { - // bool - assert_eq!(serialize(&false).ok(), Some(vec![0u8])); - assert_eq!(serialize(&true).ok(), Some(vec![1u8])); - // u8 - assert_eq!(serialize(&1u8).ok(), Some(vec![1u8])); - assert_eq!(serialize(&0u8).ok(), Some(vec![0u8])); - assert_eq!(serialize(&255u8).ok(), Some(vec![255u8])); - // u16 - assert_eq!(serialize(&1u16).ok(), Some(vec![1u8, 0])); - assert_eq!(serialize(&256u16).ok(), Some(vec![0u8, 1])); - assert_eq!(serialize(&5000u16).ok(), Some(vec![136u8, 19])); - // u32 - assert_eq!(serialize(&1u32).ok(), Some(vec![1u8, 0, 0, 0])); - assert_eq!(serialize(&256u32).ok(), Some(vec![0u8, 1, 0, 0])); - assert_eq!(serialize(&5000u32).ok(), Some(vec![136u8, 19, 0, 0])); - assert_eq!(serialize(&500000u32).ok(), Some(vec![32u8, 161, 7, 0])); - assert_eq!(serialize(&168430090u32).ok(), Some(vec![10u8, 10, 10, 10])); - // TODO: test negative numbers - assert_eq!(serialize(&1i32).ok(), Some(vec![1u8, 0, 0, 0])); - assert_eq!(serialize(&256i32).ok(), Some(vec![0u8, 1, 0, 0])); - assert_eq!(serialize(&5000i32).ok(), Some(vec![136u8, 19, 0, 0])); - assert_eq!(serialize(&500000i32).ok(), Some(vec![32u8, 161, 7, 0])); - assert_eq!(serialize(&168430090i32).ok(), Some(vec![10u8, 10, 10, 10])); - // u64 - assert_eq!(serialize(&1u64).ok(), Some(vec![1u8, 0, 0, 0, 0, 0, 0, 0])); - assert_eq!(serialize(&256u64).ok(), Some(vec![0u8, 1, 0, 0, 0, 0, 0, 0])); - assert_eq!(serialize(&5000u64).ok(), Some(vec![136u8, 19, 0, 0, 0, 0, 0, 0])); - assert_eq!(serialize(&500000u64).ok(), Some(vec![32u8, 161, 7, 0, 0, 0, 0, 0])); - assert_eq!(serialize(&723401728380766730u64).ok(), Some(vec![10u8, 10, 10, 10, 10, 10, 10, 10])); - // TODO: test negative numbers - assert_eq!(serialize(&1i64).ok(), Some(vec![1u8, 0, 0, 0, 0, 0, 0, 0])); - assert_eq!(serialize(&256i64).ok(), Some(vec![0u8, 1, 0, 0, 0, 0, 0, 0])); - assert_eq!(serialize(&5000i64).ok(), Some(vec![136u8, 19, 0, 0, 0, 0, 0, 0])); - assert_eq!(serialize(&500000i64).ok(), Some(vec![32u8, 161, 7, 0, 0, 0, 0, 0])); - assert_eq!(serialize(&723401728380766730i64).ok(), Some(vec![10u8, 10, 10, 10, 10, 10, 10, 10])); - } - - #[test] - fn serialize_varint_test() { - assert_eq!(serialize(&VarInt(10)).ok(), Some(vec![10u8])); - assert_eq!(serialize(&VarInt(0xFC)).ok(), Some(vec![0xFCu8])); - assert_eq!(serialize(&VarInt(0xFD)).ok(), Some(vec![0xFDu8, 0xFD, 0])); - assert_eq!(serialize(&VarInt(0xFFF)).ok(), Some(vec![0xFDu8, 0xFF, 0xF])); - assert_eq!(serialize(&VarInt(0xF0F0F0F)).ok(), Some(vec![0xFEu8, 0xF, 0xF, 0xF, 0xF])); - assert_eq!(serialize(&VarInt(0xF0F0F0F0F0E0)).ok(), Some(vec![0xFFu8, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0, 0])); - } - - #[test] - fn deserialize_nonminimal_vec() { - match deserialize::>(&[0xfd, 0x00, 0x00]) { - Err(Error::ParseFailed("non-minimal varint")) => {}, - x => panic!(x) - } - match deserialize::>(&[0xfd, 0xfc, 0x00]) { - Err(Error::ParseFailed("non-minimal varint")) => {}, - x => panic!(x) - } - match deserialize::>(&[0xfe, 0xff, 0x00, 0x00, 0x00]) { - Err(Error::ParseFailed("non-minimal varint")) => {}, - x => panic!(x) - } - match deserialize::>(&[0xfe, 0xff, 0xff, 0x00, 0x00]) { - Err(Error::ParseFailed("non-minimal varint")) => {}, - x => panic!(x) - } - match deserialize::>(&[0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) { - Err(Error::ParseFailed("non-minimal varint")) => {}, - x => panic!(x) - } - match deserialize::>(&[0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00]) { - Err(Error::ParseFailed("non-minimal varint")) => {}, - x => panic!(x) - } - - let mut vec_256 = vec![0; 259]; - vec_256[0] = 0xfd; - vec_256[1] = 0x00; - vec_256[2] = 0x01; - assert!(deserialize::>(&vec_256).is_ok()); - - let mut vec_253 = vec![0; 256]; - vec_253[0] = 0xfd; - vec_253[1] = 0xfd; - vec_253[2] = 0x00; - assert!(deserialize::>(&vec_253).is_ok()); - } - - #[test] - fn serialize_checkeddata_test() { - let cd = CheckedData(vec![1u8, 2, 3, 4, 5]); - assert_eq!(serialize(&cd).ok(), Some(vec![5, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5])); - } - - #[test] - fn serialize_vector_test() { - assert_eq!(serialize(&vec![1u8, 2, 3]).ok(), Some(vec![3u8, 1, 2, 3])); - assert_eq!(serialize(&[1u8, 2, 3][..]).ok(), Some(vec![3u8, 1, 2, 3])); - // TODO: test vectors of more interesting objects - } - - #[test] - fn serialize_strbuf_test() { - assert_eq!(serialize(&"Andrew".to_string()).ok(), Some(vec![6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77])); - } - - #[test] - fn serialize_box_test() { - assert_eq!(serialize(&Box::new(1u8)).ok(), Some(vec![1u8])); - assert_eq!(serialize(&Box::new(1u16)).ok(), Some(vec![1u8, 0])); - assert_eq!(serialize(&Box::new(1u64)).ok(), Some(vec![1u8, 0, 0, 0, 0, 0, 0, 0])); - } - - #[test] - fn serialize_option_test() { - let none_ser = serialize(&None::); - let some_ser = serialize(&Some(0xFFu8)); - assert_eq!(none_ser.ok(), Some(vec![0])); - assert_eq!(some_ser.ok(), Some(vec![1, 0xFF])); - } - - #[test] - fn deserialize_int_test() { - // bool - assert!((deserialize(&[58u8, 0]) as Result).is_err()); - assert_eq!(deserialize(&[58u8]).ok(), Some(true)); - assert_eq!(deserialize(&[1u8]).ok(), Some(true)); - assert_eq!(deserialize(&[0u8]).ok(), Some(false)); - assert!((deserialize(&[0u8, 1]) as Result).is_err()); - - // u8 - assert_eq!(deserialize(&[58u8]).ok(), Some(58u8)); - - // u16 - assert_eq!(deserialize(&[0x01u8, 0x02]).ok(), Some(0x0201u16)); - assert_eq!(deserialize(&[0xABu8, 0xCD]).ok(), Some(0xCDABu16)); - assert_eq!(deserialize(&[0xA0u8, 0x0D]).ok(), Some(0xDA0u16)); - let failure16: Result = deserialize(&[1u8]); - assert!(failure16.is_err()); - - // u32 - assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABu32)); - assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD]).ok(), Some(0xCDAB0DA0u32)); - let failure32: Result = deserialize(&[1u8, 2, 3]); - assert!(failure32.is_err()); - // TODO: test negative numbers - assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABi32)); - assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0x2D]).ok(), Some(0x2DAB0DA0i32)); - let failurei32: Result = deserialize(&[1u8, 2, 3]); - assert!(failurei32.is_err()); - - // u64 - assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), Some(0xCDABu64)); - assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), Some(0x99000099CDAB0DA0u64)); - let failure64: Result = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]); - assert!(failure64.is_err()); - // TODO: test negative numbers - assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), Some(0xCDABi64)); - assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), Some(-0x66ffff663254f260i64)); - let failurei64: Result = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]); - assert!(failurei64.is_err()); - } - - #[test] - fn deserialize_vec_test() { - assert_eq!(deserialize(&[3u8, 2, 3, 4]).ok(), Some(vec![2u8, 3, 4])); - assert!((deserialize(&[4u8, 2, 3, 4, 5, 6]) as Result, _>).is_err()); - // found by cargo fuzz - assert!(deserialize::>(&[0xff,0xff,0xff,0xff,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0xa,0xa,0x3a]).is_err()); - } - - #[test] - fn deserialize_strbuf_test() { - assert_eq!(deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(), Some("Andrew".to_string())); - } - - #[test] - fn deserialize_checkeddata_test() { - let cd: Result = deserialize(&[5u8, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5]); - assert_eq!(cd.ok(), Some(CheckedData(vec![1u8, 2, 3, 4, 5]))); - } - - #[test] - fn deserialize_option_test() { - let none: Result, _> = deserialize(&[0u8]); - let good: Result, _> = deserialize(&[1u8, 0xFF]); - let bad: Result, _> = deserialize(&[2u8]); - assert!(bad.is_err()); - assert_eq!(none.ok(), Some(None)); - assert_eq!(good.ok(), Some(Some(0xFF))); - } - - #[test] - fn deserialize_box_test() { - let zero: Result, _> = deserialize(&[0u8]); - let one: Result, _> = deserialize(&[1u8]); - assert_eq!(zero.ok(), Some(Box::new(0))); - assert_eq!(one.ok(), Some(Box::new(1))); - } -} - diff --git a/src/network/message.rs b/src/network/message.rs index 69e1436c..2b6853b5 100644 --- a/src/network/message.rs +++ b/src/network/message.rs @@ -28,18 +28,18 @@ use blockdata::transaction; use network::address::Address; use network::message_network; use network::message_blockdata; -use network::encodable::{ConsensusDecodable, ConsensusEncodable}; -use network::encodable::CheckedData; -use network::serialize::{self, serialize, RawDecoder, SimpleEncoder, SimpleDecoder}; +use consensus::encode::{Decodable, Encodable}; +use consensus::encode::CheckedData; +use consensus::encode::{self, serialize, Encoder, Decoder}; use util; /// Serializer for command string #[derive(PartialEq, Eq, Clone, Debug)] pub struct CommandString(pub String); -impl ConsensusEncodable for CommandString { +impl Encodable for CommandString { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> { let &CommandString(ref inner_str) = self; let mut rawbytes = [0u8; 12]; let strbytes = inner_str.as_bytes(); @@ -53,10 +53,10 @@ impl ConsensusEncodable for CommandString { } } -impl ConsensusDecodable for CommandString { +impl Decodable for CommandString { #[inline] - fn consensus_decode(d: &mut D) -> Result { - let rawbytes: [u8; 12] = ConsensusDecodable::consensus_decode(d)?; + fn consensus_decode(d: &mut D) -> Result { + let rawbytes: [u8; 12] = Decodable::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)) } @@ -146,57 +146,56 @@ impl RawNetworkMessage { } } -impl ConsensusEncodable for RawNetworkMessage { - fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { +impl Encodable for RawNetworkMessage { + fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> { self.magic.consensus_encode(s)?; CommandString(self.command()).consensus_encode(s)?; CheckedData(match self.payload { NetworkMessage::Version(ref dat) => serialize(dat), - NetworkMessage::Verack => Ok(vec![]), NetworkMessage::Addr(ref dat) => serialize(dat), NetworkMessage::Inv(ref dat) => serialize(dat), NetworkMessage::GetData(ref dat) => serialize(dat), NetworkMessage::NotFound(ref dat) => serialize(dat), NetworkMessage::GetBlocks(ref dat) => serialize(dat), NetworkMessage::GetHeaders(ref dat) => serialize(dat), - NetworkMessage::MemPool => Ok(vec![]), NetworkMessage::Tx(ref dat) => serialize(dat), NetworkMessage::Block(ref dat) => serialize(dat), NetworkMessage::Headers(ref dat) => serialize(dat), - NetworkMessage::GetAddr => Ok(vec![]), NetworkMessage::Ping(ref dat) => serialize(dat), NetworkMessage::Pong(ref dat) => serialize(dat), - NetworkMessage::Alert(ref dat) => serialize(dat) - }.unwrap()).consensus_encode(s)?; - Ok(()) + NetworkMessage::Alert(ref dat) => serialize(dat), + NetworkMessage::Verack + | NetworkMessage::MemPool + | NetworkMessage::GetAddr => vec![], + }).consensus_encode(s) } } -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)?; +impl Decodable for RawNetworkMessage { + fn consensus_decode(d: &mut D) -> Result { + let magic = Decodable::consensus_decode(d)?; + let CommandString(cmd): CommandString= Decodable::consensus_decode(d)?; + let CheckedData(raw_payload): CheckedData = Decodable::consensus_decode(d)?; - let mut mem_d = RawDecoder::new(Cursor::new(raw_payload)); + let mut mem_d = Cursor::new(raw_payload); let payload = match &cmd[..] { - "version" => NetworkMessage::Version(ConsensusDecodable::consensus_decode(&mut mem_d)?), + "version" => NetworkMessage::Version(Decodable::consensus_decode(&mut mem_d)?), "verack" => NetworkMessage::Verack, - "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)?), + "addr" => NetworkMessage::Addr(Decodable::consensus_decode(&mut mem_d)?), + "inv" => NetworkMessage::Inv(Decodable::consensus_decode(&mut mem_d)?), + "getdata" => NetworkMessage::GetData(Decodable::consensus_decode(&mut mem_d)?), + "notfound" => NetworkMessage::NotFound(Decodable::consensus_decode(&mut mem_d)?), + "getblocks" => NetworkMessage::GetBlocks(Decodable::consensus_decode(&mut mem_d)?), + "getheaders" => NetworkMessage::GetHeaders(Decodable::consensus_decode(&mut mem_d)?), "mempool" => NetworkMessage::MemPool, - "block" => NetworkMessage::Block(ConsensusDecodable::consensus_decode(&mut mem_d)?), - "headers" => NetworkMessage::Headers(ConsensusDecodable::consensus_decode(&mut mem_d)?), + "block" => NetworkMessage::Block(Decodable::consensus_decode(&mut mem_d)?), + "headers" => NetworkMessage::Headers(Decodable::consensus_decode(&mut mem_d)?), "getaddr" => NetworkMessage::GetAddr, - "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)?), - _ => return Err(serialize::Error::UnrecognizedNetworkCommand(cmd)), + "ping" => NetworkMessage::Ping(Decodable::consensus_decode(&mut mem_d)?), + "pong" => NetworkMessage::Pong(Decodable::consensus_decode(&mut mem_d)?), + "tx" => NetworkMessage::Tx(Decodable::consensus_decode(&mut mem_d)?), + "alert" => NetworkMessage::Alert(Decodable::consensus_decode(&mut mem_d)?), + _ => return Err(encode::Error::UnrecognizedNetworkCommand(cmd)), }; Ok(RawNetworkMessage { magic: magic, @@ -209,12 +208,12 @@ impl ConsensusDecodable for RawNetworkMessage { mod test { use super::{RawNetworkMessage, NetworkMessage, CommandString}; - use network::serialize::{deserialize, serialize}; + use consensus::encode::{deserialize, serialize}; #[test] fn serialize_commandstring_test() { let cs = CommandString("Andrew".to_owned()); - assert_eq!(serialize(&cs).ok(), Some(vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0])); + assert_eq!(serialize(&cs), vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]); } #[test] @@ -229,36 +228,36 @@ mod test { #[test] fn serialize_verack_test() { - assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Verack }).ok(), - Some(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61, - 0x63, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2])); + assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Verack }), + vec![0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61, + 0x63, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]); } #[test] fn serialize_ping_test() { - assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Ping(100) }).ok(), - Some(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d, - 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])); + assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Ping(100) }), + vec![0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d, + 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); } #[test] fn serialize_mempool_test() { - assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::MemPool }).ok(), - Some(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x6d, 0x65, 0x6d, 0x70, - 0x6f, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2])); + assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::MemPool }), + vec![0xf9, 0xbe, 0xb4, 0xd9, 0x6d, 0x65, 0x6d, 0x70, + 0x6f, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]); } #[test] fn serialize_getaddr_test() { - assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::GetAddr }).ok(), - Some(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61, - 0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2])); + assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::GetAddr }), + vec![0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61, + 0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]); } } diff --git a/src/network/message_blockdata.rs b/src/network/message_blockdata.rs index 83b7dfda..8c9755f1 100644 --- a/src/network/message_blockdata.rs +++ b/src/network/message_blockdata.rs @@ -19,8 +19,8 @@ //! use network::constants; -use network::encodable::{ConsensusDecodable, ConsensusEncodable}; -use network::serialize::{self, SimpleDecoder, SimpleEncoder}; +use consensus::encode::{Decodable, Encodable}; +use consensus::encode::{self, Decoder, Encoder}; use util::hash::Sha256dHash; #[derive(PartialEq, Eq, Clone, Debug)] @@ -101,9 +101,9 @@ impl GetHeadersMessage { impl_consensus_encoding!(GetHeadersMessage, version, locator_hashes, stop_hash); -impl ConsensusEncodable for Inventory { +impl Encodable for Inventory { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> { match self.inv_type { InvType::Error => 0u32, InvType::Transaction => 1, @@ -115,10 +115,10 @@ impl ConsensusEncodable for Inventory { } } -impl ConsensusDecodable for Inventory { +impl Decodable for Inventory { #[inline] - fn consensus_decode(d: &mut D) -> Result { - let int_type: u32 = ConsensusDecodable::consensus_decode(d)?; + fn consensus_decode(d: &mut D) -> Result { + let int_type: u32 = Decodable::consensus_decode(d)?; Ok(Inventory { inv_type: match int_type { 0 => InvType::Error, @@ -127,7 +127,7 @@ impl ConsensusDecodable for Inventory { // TODO do not fail here _ => { panic!("bad inventory type field") } }, - hash: ConsensusDecodable::consensus_decode(d)? + hash: Decodable::consensus_decode(d)? }) } } @@ -138,7 +138,7 @@ mod tests { use hex::decode as hex_decode; - use network::serialize::{deserialize, serialize}; + use consensus::encode::{deserialize, serialize}; use std::default::Default; #[test] @@ -151,10 +151,10 @@ mod tests { let real_decode = decode.unwrap(); assert_eq!(real_decode.version, 70002); assert_eq!(real_decode.locator_hashes.len(), 1); - assert_eq!(serialize(&real_decode.locator_hashes[0]).ok(), Some(genhash)); + assert_eq!(serialize(&real_decode.locator_hashes[0]), genhash); assert_eq!(real_decode.stop_hash, Default::default()); - assert_eq!(serialize(&real_decode).ok(), Some(from_sat)); + assert_eq!(serialize(&real_decode), from_sat); } #[test] @@ -167,10 +167,10 @@ mod tests { let real_decode = decode.unwrap(); assert_eq!(real_decode.version, 70002); assert_eq!(real_decode.locator_hashes.len(), 1); - assert_eq!(serialize(&real_decode.locator_hashes[0]).ok(), Some(genhash)); + assert_eq!(serialize(&real_decode.locator_hashes[0]), genhash); assert_eq!(real_decode.stop_hash, Default::default()); - assert_eq!(serialize(&real_decode).ok(), Some(from_sat)); + assert_eq!(serialize(&real_decode), from_sat); } } diff --git a/src/network/message_network.rs b/src/network/message_network.rs index ff349899..297e87e4 100644 --- a/src/network/message_network.rs +++ b/src/network/message_network.rs @@ -84,7 +84,7 @@ mod tests { use hex::decode as hex_decode; - use network::serialize::{deserialize, serialize}; + use consensus::encode::{deserialize, serialize}; #[test] fn version_message_test() { @@ -103,6 +103,6 @@ mod tests { assert_eq!(real_decode.start_height, 302892); assert_eq!(real_decode.relay, true); - assert_eq!(serialize(&real_decode).ok(), Some(from_sat)); + assert_eq!(serialize(&real_decode), from_sat); } } diff --git a/src/network/mod.rs b/src/network/mod.rs index bf1fa340..6167f342 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -23,8 +23,6 @@ use std::io; use std::error; pub mod constants; -pub mod encodable; -pub mod serialize; pub mod address; pub mod message; diff --git a/src/network/serialize.rs b/src/network/serialize.rs deleted file mode 100644 index 34e18f9a..00000000 --- a/src/network/serialize.rs +++ /dev/null @@ -1,333 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Network Serialization -//! -//! This module defines the `Serializable` trait which is used for -//! (de)serializing Bitcoin objects for transmission on the network. -//! 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; - -/// 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 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(&'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::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), - } - } -} - -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::UnexpectedNetworkMagic { .. } - | Error::OversizedVectorAllocation { .. } - | Error::InvalidChecksum { .. } - | Error::UnknownNetworkMagic(..) - | Error::ParseFailed(..) - | Error::UnsupportedWitnessVersion(..) - | Error::UnsupportedSegwitFlag(..) - | Error::UnrecognizedNetworkCommand(..) - | Error::UnexpectedHexDigit(..) => 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::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", - } - } -} - -#[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) - } -} - -/// Encode an object into a vector -pub fn serialize(data: &T) -> Result, Error> - where T: ConsensusEncodable>>>, -{ - let mut encoder = RawEncoder::new(Cursor::new(vec![])); - data.consensus_encode(&mut encoder)?; - Ok(encoder.into_inner().into_inner()) -} - -/// Encode an object into a hex-encoded string -pub fn serialize_hex(data: &T) -> Result - where T: ConsensusEncodable>>> -{ - let serial = serialize(data)?; - Ok(hex_encode(serial)) -} - -/// 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 - where T: ConsensusDecodable>> -{ - let mut decoder = RawDecoder::new(Cursor::new(data)); - let rv = ConsensusDecodable::consensus_decode(&mut decoder)?; - - // Fail if data is not consumed entirely. - if decoder.into_inner().position() == data.len() as u64 { - Ok(rv) - } else { - Err(Error::ParseFailed("data not consumed entirely when explicitly deserializing")) - } -} - -/// An encoder for raw binary data -pub struct RawEncoder { - writer: W -} - -/// An decoder for raw binary data -pub struct RawDecoder { - reader: R -} - -impl RawEncoder { - /// Constructor - pub fn new(writer: W) -> RawEncoder { RawEncoder { writer: writer } } - /// Returns the underlying Writer - pub fn into_inner(self) -> W { self.writer } -} - -impl RawDecoder { - /// Constructor - pub fn new(reader: R) -> RawDecoder { RawDecoder { reader: reader } } - /// Returns the underlying Reader - pub fn into_inner(self) -> R { self.reader } -} - -/// A simple Encoder trait -pub trait SimpleEncoder { - /// Output a 64-bit uint - fn emit_u64(&mut self, v: u64) -> Result<(), Error>; - /// Output a 32-bit uint - fn emit_u32(&mut self, v: u32) -> Result<(), Error>; - /// Output a 16-bit uint - fn emit_u16(&mut self, v: u16) -> Result<(), Error>; - /// Output a 8-bit uint - fn emit_u8(&mut self, v: u8) -> Result<(), Error>; - - /// Output a 64-bit int - fn emit_i64(&mut self, v: i64) -> Result<(), Error>; - /// Output a 32-bit int - fn emit_i32(&mut self, v: i32) -> Result<(), Error>; - /// Output a 16-bit int - fn emit_i16(&mut self, v: i16) -> Result<(), Error>; - /// Output a 8-bit int - fn emit_i8(&mut self, v: i8) -> Result<(), Error>; - - /// Output a boolean - fn emit_bool(&mut self, v: bool) -> Result<(), Error>; -} - -/// A simple Decoder trait -pub trait SimpleDecoder { - /// Read a 64-bit uint - fn read_u64(&mut self) -> Result; - /// Read a 32-bit uint - fn read_u32(&mut self) -> Result; - /// Read a 16-bit uint - fn read_u16(&mut self) -> Result; - /// Read a 8-bit uint - fn read_u8(&mut self) -> Result; - - /// Read a 64-bit int - fn read_i64(&mut self) -> Result; - /// Read a 32-bit int - fn read_i32(&mut self) -> Result; - /// Read a 16-bit int - fn read_i16(&mut self) -> Result; - /// Read a 8-bit int - fn read_i8(&mut self) -> Result; - - /// Read a boolean - fn read_bool(&mut self) -> Result; -} - -macro_rules! encoder_fn { - ($name:ident, $val_type:ty, $writefn:ident) => { - #[inline] - fn $name(&mut self, v: $val_type) -> Result<(), Error> { - self.writer.$writefn::(v).map_err(Error::Io) - } - } -} - -macro_rules! decoder_fn { - ($name:ident, $val_type:ty, $readfn:ident) => { - #[inline] - fn $name(&mut self) -> Result<$val_type, Error> { - self.reader.$readfn::().map_err(Error::Io) - } - } -} - -impl SimpleEncoder for RawEncoder { - encoder_fn!(emit_u64, u64, write_u64); - encoder_fn!(emit_u32, u32, write_u32); - encoder_fn!(emit_u16, u16, write_u16); - encoder_fn!(emit_i64, i64, write_i64); - encoder_fn!(emit_i32, i32, write_i32); - encoder_fn!(emit_i16, i16, write_i16); - - #[inline] - 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<(), Error> { - self.writer.write_u8(v).map_err(Error::Io) - } - #[inline] - 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 { - decoder_fn!(read_u64, u64, read_u64); - decoder_fn!(read_u32, u32, read_u32); - decoder_fn!(read_u16, u16, read_u16); - decoder_fn!(read_i64, i64, read_i64); - decoder_fn!(read_i32, i32, read_i32); - decoder_fn!(read_i16, i16, read_i16); - - #[inline] - 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(Error::Io) - } - #[inline] - fn read_bool(&mut self) -> Result { - match self.reader.read_i8() { - Ok(bit) => Ok(bit != 0), - Err(e) => Err(Error::Io(e)) - } - } -} - -// Aren't really any tests here.. the main functions are serialize and -// deserialize, which get the crap tested out of them it every other -// module. - diff --git a/src/util/address.rs b/src/util/address.rs index 7fe4c278..ee6f6d74 100644 --- a/src/util/address.rs +++ b/src/util/address.rs @@ -28,7 +28,7 @@ use serde; use blockdata::opcodes; use blockdata::script; use network::constants::Network; -use network::serialize; +use consensus::encode; use util::hash::Hash160; use util::base58; @@ -246,9 +246,9 @@ impl Display for Address { } impl FromStr for Address { - type Err = serialize::Error; + type Err = encode::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") || @@ -262,7 +262,7 @@ impl FromStr for Address { _ => panic!("unknown network") }; if witprog.version().to_u8() != 0 { - return Err(serialize::Error::UnsupportedWitnessVersion(witprog.version().to_u8())); + return Err(encode::Error::UnsupportedWitnessVersion(witprog.version().to_u8())); } return Ok(Address { network: network, @@ -271,14 +271,14 @@ impl FromStr for Address { } if s.len() > 50 { - return Err(serialize::Error::Base58(base58::Error::InvalidLength(s.len() * 11 / 15))); + return Err(encode::Error::Base58(base58::Error::InvalidLength(s.len() * 11 / 15))); } // Base 58 let data = base58::from_check(s)?; if data.len() != 21 { - return Err(serialize::Error::Base58(base58::Error::InvalidLength(data.len()))); + return Err(encode::Error::Base58(base58::Error::InvalidLength(data.len()))); } let (network, payload) = match data[0] { @@ -298,7 +298,7 @@ impl FromStr for Address { Network::Testnet, Payload::ScriptHash(Hash160::from(&data[1..])) ), - x => return Err(serialize::Error::Base58(base58::Error::InvalidVersion(vec![x]))) + x => return Err(encode::Error::Base58(base58::Error::InvalidVersion(vec![x]))) }; Ok(Address { diff --git a/src/util/bip143.rs b/src/util/bip143.rs index 4b199d29..c172c639 100644 --- a/src/util/bip143.rs +++ b/src/util/bip143.rs @@ -21,7 +21,7 @@ use blockdata::script::Script; use blockdata::transaction::{Transaction, TxIn}; -use network::encodable::ConsensusEncodable; +use consensus::encode::Encodable; use util::hash::{Sha256dHash, Sha256dEncoder}; /// Parts of a sighash which are common across inputs or signatures, and which are @@ -101,7 +101,7 @@ impl SighashComponents { #[cfg(test)] mod tests { use blockdata::transaction::Transaction; - use network::serialize::deserialize; + use consensus::encode::deserialize; use util::misc::hex_bytes; use super::*; diff --git a/src/util/hash.rs b/src/util/hash.rs index a70b06d2..400fee7e 100644 --- a/src/util/hash.rs +++ b/src/util/hash.rs @@ -27,8 +27,7 @@ use byteorder::{LittleEndian, WriteBytesExt}; use crypto::digest::Digest; use crypto::ripemd160::Ripemd160; -use network::encodable::{ConsensusDecodable, ConsensusEncodable}; -use network::serialize::{self, SimpleEncoder}; +use consensus::encode::{self, Encodable, Decodable, Encoder}; use util::uint::Uint256; #[cfg(feature="fuzztarget")] use util::sha2::Sha256; @@ -107,60 +106,60 @@ impl Sha256dEncoder { } } -impl SimpleEncoder for Sha256dEncoder { - fn emit_u64(&mut self, v: u64) -> Result<(), serialize::Error> { +impl Encoder for Sha256dEncoder { + fn emit_u64(&mut self, v: u64) -> Result<(), encode::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<(), serialize::Error> { + fn emit_u32(&mut self, v: u32) -> Result<(), encode::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<(), serialize::Error> { + fn emit_u16(&mut self, v: u16) -> Result<(), encode::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<(), serialize::Error> { + fn emit_i64(&mut self, v: i64) -> Result<(), encode::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<(), serialize::Error> { + fn emit_i32(&mut self, v: i32) -> Result<(), encode::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<(), serialize::Error> { + fn emit_i16(&mut self, v: i16) -> Result<(), encode::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<(), serialize::Error> { + fn emit_i8(&mut self, v: i8) -> Result<(), encode::Error> { self.0.input(&[v as u8]); Ok(()) } - fn emit_u8(&mut self, v: u8) -> Result<(), serialize::Error> { + fn emit_u8(&mut self, v: u8) -> Result<(), encode::Error> { self.0.input(&[v]); Ok(()) } - fn emit_bool(&mut self, v: bool) -> Result<(), serialize::Error> { + fn emit_bool(&mut self, v: bool) -> Result<(), encode::Error> { self.0.input(&[if v {1} else {0}]); Ok(()) } @@ -355,9 +354,9 @@ impl serde::Serialize for Sha256dHash { /// Note that this outputs hashes as big endian hex numbers, so this should be /// used only for user-facing stuff. Internal and network serialization is /// little-endian and should be done using the consensus - /// [`ConsensusEncodable`][1] interface. + /// [`Encodable`][1] interface. /// - /// [1]: ../../network/encodable/trait.ConsensusEncodable.html + /// [1]: ../../network/encodable/trait.Encodable.html fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, @@ -492,8 +491,8 @@ mod tests { #[cfg(all(feature = "serde", feature = "strason"))] use strason::Json; - use network::encodable::{ConsensusEncodable, VarInt}; - use network::serialize::{serialize, deserialize}; + use consensus::encode::{Encodable, VarInt}; + use consensus::encode::{serialize, deserialize}; use util::uint::{Uint128, Uint256}; use super::*; @@ -545,7 +544,7 @@ mod tests { let test = vec![true, false, true, true, false]; let mut enc = Sha256dEncoder::new(); assert!(test.consensus_encode(&mut enc).is_ok()); - assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test).unwrap())); + assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test))); macro_rules! array_encode_test ( ($ty:ty) => ({ @@ -553,7 +552,7 @@ mod tests { let test: [$ty; 1000] = [1; 1000]; let mut enc = Sha256dEncoder::new(); assert!((&test[..]).consensus_encode(&mut enc).is_ok()); - assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test[..]).unwrap())); + assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test[..]))); // try doing it just one object at a time let mut enc = Sha256dEncoder::new(); @@ -561,7 +560,7 @@ mod tests { for obj in &test[..] { assert!(obj.consensus_encode(&mut enc).is_ok()); } - assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test[..]).unwrap())); + assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test[..]))); }) ); @@ -578,7 +577,7 @@ mod tests { #[test] fn test_consenus_encode_roundtrip() { let hash = Sha256dHash::from_data(&[]); - let serial = serialize(&hash).unwrap(); + let serial = serialize(&hash); let deserial = deserialize(&serial).unwrap(); assert_eq!(hash, deserial); } diff --git a/src/util/misc.rs b/src/util/misc.rs index 9d90534f..f94a274d 100644 --- a/src/util/misc.rs +++ b/src/util/misc.rs @@ -18,10 +18,10 @@ use blockdata::opcodes; use util::iter::Pairable; -use network::serialize; +use consensus::encode; /// Convert a hexadecimal-encoded string to its corresponding bytes -pub fn hex_bytes(s: &str) -> Result, serialize::Error> { +pub fn hex_bytes(s: &str) -> Result, encode::Error> { let mut v = vec![]; let mut iter = s.chars().pair(); // Do the parsing @@ -29,15 +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::UnexpectedHexDigit(f)), - (_, None) => Err(serialize::Error::UnexpectedHexDigit(s)), + (None, _) => Err(encode::Error::UnexpectedHexDigit(f)), + (_, None) => Err(encode::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::ParseFailed("hexstring of odd length")), + Some(_) => Err(encode::Error::ParseFailed("hexstring of odd length")), None => Ok(v) } } diff --git a/src/util/mod.rs b/src/util/mod.rs index 0188c26b..07cbc4c8 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -36,7 +36,7 @@ use std::{error, fmt}; use secp256k1; use network; -use network::serialize; +use consensus::encode; /// A trait which allows numbers to act as fixed-size bit arrays pub trait BitArray { @@ -65,8 +65,8 @@ pub trait BitArray { pub enum Error { /// secp-related error Secp256k1(secp256k1::Error), - /// Serialization error - Serialize(serialize::Error), + /// Encoding error + Encode(encode::Error), /// Network error Network(network::Error), /// The header hash is not below the target @@ -79,7 +79,7 @@ impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::Secp256k1(ref e) => fmt::Display::fmt(e, f), - Error::Serialize(ref e) => fmt::Display::fmt(e, f), + Error::Encode(ref e) => fmt::Display::fmt(e, f), Error::Network(ref e) => fmt::Display::fmt(e, f), Error::SpvBadProofOfWork | Error::SpvBadTarget => f.write_str(error::Error::description(self)), } @@ -90,7 +90,7 @@ impl error::Error for Error { fn cause(&self) -> Option<&error::Error> { match *self { Error::Secp256k1(ref e) => Some(e), - Error::Serialize(ref e) => Some(e), + Error::Encode(ref e) => Some(e), Error::Network(ref e) => Some(e), Error::SpvBadProofOfWork | Error::SpvBadTarget => None } @@ -99,7 +99,7 @@ impl error::Error for Error { fn description(&self) -> &str { match *self { Error::Secp256k1(ref e) => e.description(), - Error::Serialize(ref e) => e.description(), + Error::Encode(ref e) => e.description(), Error::Network(ref e) => e.description(), Error::SpvBadProofOfWork => "target correct but not attained", Error::SpvBadTarget => "target incorrect", @@ -115,9 +115,9 @@ impl From for Error { } #[doc(hidden)] -impl From for Error { - fn from(e: serialize::Error) -> Error { - Error::Serialize(e) +impl From for Error { + fn from(e: encode::Error) -> Error { + Error::Encode(e) } } diff --git a/src/util/privkey.rs b/src/util/privkey.rs index 87311df2..74e2dcaa 100644 --- a/src/util/privkey.rs +++ b/src/util/privkey.rs @@ -21,7 +21,7 @@ use std::str::FromStr; use secp256k1::{self, Secp256k1}; use secp256k1::key::{PublicKey, SecretKey}; use util::address::Address; -use network::serialize; +use consensus::encode; use network::constants::Network; use util::base58; @@ -113,21 +113,21 @@ impl Display for Privkey { } impl FromStr for Privkey { - type Err = serialize::Error; + type Err = encode::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(serialize::Error::Base58(base58::Error::InvalidLength(data.len()))); } + _ => { return Err(encode::Error::Base58(base58::Error::InvalidLength(data.len()))); } }; let network = match data[0] { 128 => Network::Bitcoin, 239 => Network::Testnet, - x => { return Err(serialize::Error::Base58(base58::Error::InvalidVersion(vec![x]))); } + x => { return Err(encode::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 2dd5dcf3..6a0c9f66 100644 --- a/src/util/uint.rs +++ b/src/util/uint.rs @@ -20,7 +20,7 @@ use std::fmt; -use network::serialize; +use consensus::encode; use util::BitArray; macro_rules! construct_uint { @@ -336,19 +336,19 @@ macro_rules! construct_uint { } } - impl ::network::encodable::ConsensusEncodable for $name { + impl ::consensus::encode::Encodable for $name { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), serialize::Error> { + fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> { let &$name(ref data) = self; for word in data.iter() { word.consensus_encode(s)?; } Ok(()) } } - impl ::network::encodable::ConsensusDecodable for $name { - fn consensus_decode(d: &mut D) -> Result<$name, serialize::Error> { - use network::encodable::ConsensusDecodable; - let ret: [u64; $n_words] = ConsensusDecodable::consensus_decode(d)?; + impl ::consensus::encode::Decodable for $name { + fn consensus_decode(d: &mut D) -> Result<$name, encode::Error> { + use consensus::encode::Decodable; + let ret: [u64; $n_words] = Decodable::consensus_decode(d)?; Ok($name(ret)) } } @@ -385,7 +385,7 @@ impl Uint256 { #[cfg(test)] mod tests { - use network::serialize::{deserialize, serialize}; + use consensus::encode::{deserialize, serialize}; use util::uint::Uint256; use util::BitArray; @@ -535,8 +535,8 @@ mod tests { pub fn uint256_serialize_test() { let start1 = Uint256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]); let start2 = Uint256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0xABCD, 0xFFFF]); - let serial1 = serialize(&start1).unwrap(); - let serial2 = serialize(&start2).unwrap(); + let serial1 = serialize(&start1); + let serial2 = serialize(&start2); let end1: Result = deserialize(&serial1); let end2: Result = deserialize(&serial2); From c42252c1daae23cc3e980ed8dcc613c15e8670dd Mon Sep 17 00:00:00 2001 From: Carl Dong Date: Sun, 16 Sep 2018 14:36:46 -0700 Subject: [PATCH 6/6] Use default impl for Encoder for Sha256dEncoder --- src/util/hash.rs | 62 ++++++------------------------------------------ 1 file changed, 7 insertions(+), 55 deletions(-) diff --git a/src/util/hash.rs b/src/util/hash.rs index 400fee7e..396c9e35 100644 --- a/src/util/hash.rs +++ b/src/util/hash.rs @@ -20,14 +20,14 @@ use std::cmp::min; use std::default::Default; use std::error; use std::fmt; +use std::io::{self, Write}; use std::mem; #[cfg(feature = "serde")] use serde; -use byteorder::{LittleEndian, WriteBytesExt}; use crypto::digest::Digest; use crypto::ripemd160::Ripemd160; -use consensus::encode::{self, Encodable, Decodable, Encoder}; +use consensus::encode::{Encodable, Decodable}; use util::uint::Uint256; #[cfg(feature="fuzztarget")] use util::sha2::Sha256; @@ -106,61 +106,13 @@ impl Sha256dEncoder { } } -impl Encoder for Sha256dEncoder { - fn emit_u64(&mut self, v: u64) -> Result<(), encode::Error> { - let mut data = [0; 8]; - (&mut data[..]).write_u64::(v).unwrap(); - self.0.input(&data); - Ok(()) +impl Write for Sha256dEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.input(buf); + Ok(buf.len()) } - fn emit_u32(&mut self, v: u32) -> Result<(), encode::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<(), encode::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<(), encode::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<(), encode::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<(), encode::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<(), encode::Error> { - self.0.input(&[v as u8]); - Ok(()) - } - - fn emit_u8(&mut self, v: u8) -> Result<(), encode::Error> { - self.0.input(&[v]); - Ok(()) - } - - fn emit_bool(&mut self, v: bool) -> Result<(), encode::Error> { - self.0.input(&[if v {1} else {0}]); + fn flush(&mut self) -> io::Result<()> { Ok(()) } }