diff --git a/src/blockdata/block.rs b/src/blockdata/block.rs index cae3f9a1..1f4de270 100644 --- a/src/blockdata/block.rs +++ b/src/blockdata/block.rs @@ -32,7 +32,7 @@ use blockdata::transaction::Transaction; /// A block header, which contains all the block's information except /// the actual transactions -#[derive(PartialEq, Eq, Clone, Debug)] +#[derive(Copy, PartialEq, Eq, Clone, Debug)] pub struct BlockHeader { /// The protocol version. Should always be 1. pub version: u32, diff --git a/src/blockdata/opcodes.rs b/src/blockdata/opcodes.rs index 8599c045..c2d5e87e 100644 --- a/src/blockdata/opcodes.rs +++ b/src/blockdata/opcodes.rs @@ -34,7 +34,7 @@ use network::encodable::{ConsensusDecodable, ConsensusEncodable}; // write an #[inline] helper function which casts to u8s. /// A script Opcode -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[repr(u8)] pub enum All { /// Push an empty array onto the stack @@ -633,7 +633,7 @@ pub static OP_FALSE: All = All::OP_PUSHBYTES_0; pub static OP_TRUE: All = All::OP_PUSHNUM_1; /// Broad categories of opcodes with similar behavior -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Class { /// Pushes the given number onto the stack PushNum(i32), @@ -663,7 +663,7 @@ macro_rules! ordinary_opcode { ($($op:ident),*) => ( #[repr(u8)] #[doc(hidden)] - #[derive(Clone, PartialEq, Eq, Debug)] + #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Ordinary { $( $op = All::$op as u8 ),* } diff --git a/src/blockdata/script.rs b/src/blockdata/script.rs index eeef98a8..8bcc6219 100644 --- a/src/blockdata/script.rs +++ b/src/blockdata/script.rs @@ -1628,10 +1628,10 @@ macro_rules! stack_opcode { macro_rules! num_opcode { ($stack:ident($($var:ident),*): $op:expr) => ({ $( - let $var = try!(read_scriptint(match $stack.pop() { - Some(elem) => &elem[..], + let $var = try!(read_scriptint(&match $stack.pop() { + Some(elem) => elem, None => { return Err(Error::PopEmptyStack); } - })); + }[..])); )* $stack.push(MaybeOwned::Owned(build_scriptint($op))); // Return a tuple of all the variables diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 81487c2a..a47de7fc 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -153,16 +153,15 @@ pub struct TransactionTrace { impl TxIn { /// Check an input's script for validity pub fn validate(&self, - utxoset: &UtxoSet, - txn: &Transaction, - index: usize) -> Result<(), Error> { + utxoset: &UtxoSet, + txn: &Transaction, + index: usize) -> Result<(), Error> { let txo = utxoset.get_utxo(self.prev_hash, self.prev_index); match txo { Some((_, txo)) => { - let mut p2sh_stack = Vec::new(); - let mut p2sh_script = Script::new(); + let (mut p2sh_stack, mut p2sh_script) = (vec![], Script::new()); - let mut stack = Vec::with_capacity(6); + let mut stack = vec![]; match self.script_sig.evaluate(&mut stack, Some((txn, index)), None) { Ok(_) => {} Err(e) => { return Err(Error::InputScriptFailure(e)); } @@ -220,7 +219,7 @@ impl Transaction { /// Produce a trace of a transaction's execution pub fn trace(&self, utxoset: &UtxoSet) -> TransactionTrace { let mut ret = TransactionTrace { txid: self.bitcoin_hash(), - inputs: Vec::with_capacity(self.input.len()) }; + inputs: Vec::with_capacity(self.input.len()) }; for (n, input) in self.input.iter().enumerate() { // Setup trace let mut trace = InputTrace { @@ -240,8 +239,7 @@ impl Transaction { let txo = utxoset.get_utxo(input.prev_hash, input.prev_index); match txo { Some((_, txo)) => { - let mut p2sh_stack = Vec::new(); - let mut p2sh_script = Script::new(); + let (mut p2sh_stack, mut p2sh_script) = (vec![], Script::new()); let mut stack = Vec::with_capacity(6); trace.sig_trace = input.script_sig.trace(&mut stack, Some((self, n))); diff --git a/src/blockdata/utxoset.rs b/src/blockdata/utxoset.rs index d26d43c1..77ee3e37 100644 --- a/src/blockdata/utxoset.rs +++ b/src/blockdata/utxoset.rs @@ -196,7 +196,7 @@ impl UtxoSet { }; // Check that this specific output is there if vout as usize >= node.outputs.len() { return None; } - let replace = node.outputs[vout as usize]; + let replace = &node.outputs[vout as usize]; Some((node.height as usize, replace.as_ref().unwrap())) } @@ -283,7 +283,7 @@ impl UtxoSet { // Return the last error since we need to finish every future before // leaving this function, and given that, it's easier to return the last. let mut last_err = Ok(()); - for res in future_vec.iter_mut().map(|f| f.await().unwrap()) { + for res in future_vec.into_iter().map(|f| f.await().unwrap()) { if res.is_err() { last_err = res; } } if last_err.is_err() { return last_err; } @@ -292,7 +292,7 @@ impl UtxoSet { for tx in block.txdata.iter().skip(1) { let txid = tx.bitcoin_hash(); // Put the removed utxos into the stxo cache, in case we need to rewind - (&self.spent_txos[spent_idx]).reserve(tx.input.len()); + (&mut self.spent_txos[spent_idx]).reserve(tx.input.len()); for (n, input) in tx.input.iter().enumerate() { let taken = self.take_utxo(input.prev_hash, input.prev_index); match taken { diff --git a/src/internal_macros.rs b/src/internal_macros.rs index 5d26ac87..0f36991e 100644 --- a/src/internal_macros.rs +++ b/src/internal_macros.rs @@ -117,6 +117,8 @@ macro_rules! impl_array_newtype { } } + impl Copy for $thing {} + impl ::std::hash::Hash for $thing { #[inline] fn hash(&self, state: &mut H) diff --git a/src/lib.rs b/src/lib.rs index 901f3dff..07e2968f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,9 +56,12 @@ extern crate rand; extern crate rustc_serialize as serialize; extern crate secp256k1; extern crate serde; -extern crate test; +#[cfg(test)] extern crate test; extern crate time; +#[cfg(test)] +#[macro_use] +mod test_macros; #[macro_use] mod internal_macros; #[macro_use] diff --git a/src/network/constants.rs b/src/network/constants.rs index 5812f0ad..213e27df 100644 --- a/src/network/constants.rs +++ b/src/network/constants.rs @@ -22,7 +22,7 @@ use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use network::serialize::{SimpleEncoder, SimpleDecoder}; user_enum! { - #[derive(PartialEq, Eq, Clone, Hash)] + #[derive(Copy, PartialEq, Eq, Clone, Hash)] #[doc="The cryptocurrency to act on"] pub enum Network { #[doc="Classic Bitcoin"] diff --git a/src/network/socket.rs b/src/network/socket.rs index 062d8a07..d1b032da 100644 --- a/src/network/socket.rs +++ b/src/network/socket.rs @@ -35,9 +35,9 @@ use util::{self, propagate_err}; /// Format an IP address in the 16-byte bitcoin protocol serialization fn ipaddr_to_bitcoin_addr(ipaddr: &net::IpAddr) -> [u16; 8] { match *ipaddr { - net::IpAddr::V4(ref addr) => &addr.to_ipv6_mapped(), - net::IpAddr::V6(ref addr) => addr - }.segments() + net::IpAddr::V4(ref addr) => addr.to_ipv6_mapped().segments(), + net::IpAddr::V6(ref addr) => addr.segments() + } } /// A network socket along with information about the peer @@ -55,6 +55,31 @@ pub struct Socket { pub magic: u32 } +macro_rules! with_socket(($s:ident, $sock:ident, $body:block) => ({ + use ::std::ops::DerefMut; + let mut sock_lock = $s.socket.lock(); + match sock_lock { + Err(_) => { + let io_err = io::Error::new(io::ErrorKind::NotConnected, + "socket: socket mutex was poisoned"); + return Err(util::Error::Io(io_err)); + } + Ok(mut guard) => { + match *guard.deref_mut() { + Some(ref mut $sock) => { + $body + } + None => { + let io_err = io::Error::new(io::ErrorKind::NotConnected, + "socket: not connected to peer"); + return Err(util::Error::Io(io_err)); + } + } + } + } +})); + + impl Socket { // TODO: we fix services to 0 /// Construct a new socket @@ -85,55 +110,36 @@ impl Socket { } } - fn socket(&mut self) -> Result<&mut net::TcpStream, util::Error> { - let mut sock_lock = self.socket.lock(); - match sock_lock { - Err(_) => { - let io_err = io::Error::new(io::ErrorKind::NotConnected, - "socket: socket mutex was poisoned"); - Err(util::Error::Io(io_err)) - } - Ok(guard) => { - match *guard { - Some(ref mut sock) => Ok(sock), - None => { - let io_err = io::Error::new(io::ErrorKind::NotConnected, - "socket: not connected to peer"); - Err(util::Error::Io(io_err)) - } - } - } - } - } - /// Peer address pub fn receiver_address(&mut self) -> Result { - let sock = try!(self.socket()); - match sock.peer_addr() { - Ok(addr) => { - Ok(Address { - services: self.services, - address: ipaddr_to_bitcoin_addr(&addr.ip()), - port: addr.port() - }) - }, - Err(e) => Err(util::Error::Io(e)) - } + with_socket!(self, sock, { + match sock.peer_addr() { + Ok(addr) => { + Ok(Address { + services: self.services, + address: ipaddr_to_bitcoin_addr(&addr.ip()), + port: addr.port() + }) + }, + Err(e) => Err(util::Error::Io(e)) + } + }) } /// Our own address pub fn sender_address(&mut self) -> Result { - let sock = try!(self.socket()); - match sock.local_addr() { - Ok(addr) => { - Ok(Address { - services: self.services, - address: ipaddr_to_bitcoin_addr(&addr.ip()), - port: addr.port() - }) - }, - Err(e) => Err(util::Error::Io(e)) - } + with_socket!(self, sock, { + match sock.local_addr() { + Ok(addr) => { + Ok(Address { + services: self.services, + address: ipaddr_to_bitcoin_addr(&addr.ip()), + port: addr.port() + }) + }, + Err(e) => Err(util::Error::Io(e)) + } + }) } /// Produce a version message appropriate for this socket @@ -157,35 +163,37 @@ impl Socket { /// Send a general message across the line pub fn send_message(&mut self, payload: NetworkMessage) -> Result<(), util::Error> { - let sock = try!(self.socket()); - let message = RawNetworkMessage { magic: self.magic, payload: payload }; - try!(message.consensus_encode(&mut RawEncoder::new(sock))); - sock.flush().map_err(util::Error::Io) + with_socket!(self, sock, { + let message = RawNetworkMessage { magic: self.magic, payload: payload }; + try!(message.consensus_encode(&mut RawEncoder::new(&mut *sock))); + sock.flush().map_err(util::Error::Io) + }) } /// 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 { - let sock = try!(self.socket()); - // We need a new scope since the closure in here borrows read_err, - // and we try to read it afterward. Letting `iter` go out fixes it. - let mut decoder = RawDecoder::new(sock); - let decode: Result = ConsensusDecodable::consensus_decode(&mut decoder); - match decode { - // Check for parse errors... - Err(e) => { - propagate_err("receive_message".to_string(), Err(e)) - }, - Ok(ret) => { - // Then for magic (this should come before parse error, but we can't - // get to it if the deserialization failed). TODO restructure this - if ret.magic != self.magic { - Err(util::Error::BadNetworkMagic(self.magic, ret.magic)) - } else { - Ok(ret.payload) + 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 decode: Result = ConsensusDecodable::consensus_decode(&mut decoder); + match decode { + // Check for parse errors... + Err(e) => { + propagate_err("receive_message".to_string(), Err(e)) + }, + Ok(ret) => { + // Then for magic (this should come before parse error, but we can't + // get to it if the deserialization failed). TODO restructure this + if ret.magic != self.magic { + Err(util::Error::BadNetworkMagic(self.magic, ret.magic)) + } else { + Ok(ret.payload) + } } } - } + }) } } diff --git a/src/util/hash.rs b/src/util/hash.rs index bb7e2cbf..90a095e4 100644 --- a/src/util/hash.rs +++ b/src/util/hash.rs @@ -48,15 +48,15 @@ pub struct Ripemd160Hash([u8; 20]); impl_array_newtype!(Ripemd160Hash, u8, 20); /// A 32-bit hash obtained by truncating a real hash -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Hash32((u8, u8, u8, u8)); /// A 48-bit hash obtained by truncating a real hash -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Hash48((u8, u8, u8, u8, u8, u8)); /// A 64-bit hash obtained by truncating a real hash -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Hash64((u8, u8, u8, u8, u8, u8, u8, u8)); impl Ripemd160Hash { @@ -268,8 +268,7 @@ mod tests { use std::io::Cursor; use std::num::FromPrimitive; use std::str::from_utf8; - use serialize::Encodable; - use serialize::json; + use serde::{json, Serialize, Deserialize}; use network::serialize::{serialize, deserialize}; use util::hash::Sha256dHash; @@ -296,15 +295,15 @@ mod tests { #[test] fn test_hash_encode_decode() { let hash = Sha256dHash::from_data(&[]); - let mut writer = Cursor::new(vec![]); + let mut writer = vec![]; { - let mut encoder = json::Encoder::new(&mut writer); - assert!(hash.encode(&mut encoder).is_ok()); + let mut serializer = json::ser::Serializer::new(&mut writer); + assert!(hash.serialize(&mut serializer).is_ok()); } - let res = writer.into_inner(); - assert_eq!(&res[..], + assert_eq!(&writer[..], "\"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d\"".as_bytes()); - assert_eq!(json::decode(from_utf8(res.as_slice()).unwrap()), Ok(hash)); + let mut deserializer = json::de::Deserializer::new(writer.iter().map(|c| Ok(*c))).unwrap(); + assert_eq!(hash, Deserialize::deserialize(&mut deserializer).unwrap()); } #[test] diff --git a/src/util/misc.rs b/src/util/misc.rs index 1e66d74b..0c9dd31e 100644 --- a/src/util/misc.rs +++ b/src/util/misc.rs @@ -25,7 +25,7 @@ pub fn hex_bytes(s: &str) -> Result, Error> { let mut v = vec![]; let mut iter = s.chars().pair(); // Do the parsing - try!(iter.fold(Ok(()), |e, (f, s)| + try!(iter.by_ref().fold(Ok(()), |e, (f, s)| if e.is_err() { e } else { match (f.to_digit(16), s.to_digit(16)) { @@ -73,9 +73,8 @@ pub fn script_find_and_remove(haystack: &mut Vec, needle: &[u8]) -> usize { let mut i = 0; while i <= top { if &haystack[i..(i + needle.len())] == needle { - let v = &mut haystack; for j in i..top { - v.swap(j + needle.len(), j); + haystack.swap(j + needle.len(), j); } n_deleted += 1; // This is ugly but prevents infinite loop in case of overflow diff --git a/src/util/patricia_tree.rs b/src/util/patricia_tree.rs index 4f916344..c49106a6 100644 --- a/src/util/patricia_tree.rs +++ b/src/util/patricia_tree.rs @@ -30,7 +30,7 @@ use network::serialize::{SimpleDecoder, SimpleEncoder}; use util::BitArray; /// Patricia troo -pub struct PatriciaTree { +pub struct PatriciaTree { data: Option, child_l: Option>>, child_r: Option>>, @@ -39,7 +39,7 @@ pub struct PatriciaTree { } impl PatriciaTree - where K: BitArray + cmp::Eq + Zero + One + + where K: Copy + BitArray + cmp::Eq + Zero + One + ops::BitXor + ops::Add + ops::Shr + @@ -221,7 +221,7 @@ impl PatriciaTree /// Return value is (deletable, actual return value), where `deletable` is true /// is true when the entire node can be deleted (i.e. it has no children) fn recurse(tree: &mut PatriciaTree, key: &K, key_len: usize) -> (bool, Option) - where K: BitArray + cmp::Eq + Zero + One + + where K: Copy + BitArray + cmp::Eq + Zero + One + ops::Add + ops::Shr + ops::Shl @@ -333,7 +333,7 @@ impl PatriciaTree /// Count all the nodes pub fn node_count(&self) -> usize { - fn recurse(node: &Option>>) -> usize { + fn recurse(node: &Option>>) -> usize { match node { &Some(ref node) => { 1 + recurse(&node.child_l) + recurse(&node.child_r) } &None => 0 @@ -362,10 +362,12 @@ impl PatriciaTree } } -impl Debug for PatriciaTree { +impl Debug for PatriciaTree { /// Print the entire tree fn fmt<'a>(&'a self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - fn recurse<'a, K:BitArray, V:Debug>(tree: &'a PatriciaTree, f: &mut fmt::Formatter, depth: usize) -> Result<(), fmt::Error> { + fn recurse<'a, K, V>(tree: &'a PatriciaTree, f: &mut fmt::Formatter, depth: usize) -> Result<(), fmt::Error> + where K: Copy + BitArray, V: Debug + { for i in 0..tree.skip_len as usize { try!(write!(f, "{:}", if tree.skip_prefix.bit(i) { 1 } else { 0 })); } @@ -400,7 +402,7 @@ impl Debug for PatriciaTree { impl ConsensusEncodable for PatriciaTree where S: SimpleEncoder, - K: ConsensusEncodable, + K: Copy + ConsensusEncodable, V: ConsensusEncodable { fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { @@ -416,7 +418,7 @@ impl ConsensusEncodable for PatriciaTree impl ConsensusDecodable for PatriciaTree where D: SimpleDecoder, - K: ConsensusDecodable, + K: Copy + ConsensusDecodable, V: ConsensusDecodable { fn consensus_decode(d: &mut D) -> Result, D::Error> { @@ -431,25 +433,25 @@ impl ConsensusDecodable for PatriciaTree } /// Iterator -pub struct Items<'tree, K: 'tree, V: 'tree> { +pub struct Items<'tree, K: Copy + 'tree, V: 'tree> { started: bool, node: Option<&'tree PatriciaTree>, parents: Vec<&'tree PatriciaTree> } /// Mutable iterator -pub struct MutItems<'tree, K: 'tree, V: 'tree> { +pub struct MutItems<'tree, K: Copy + 'tree, V: 'tree> { started: bool, node: *mut PatriciaTree, parents: Vec<*mut PatriciaTree>, marker: marker::PhantomData<&'tree PatriciaTree> } -impl<'a, K, V> Iterator for Items<'a, K, V> { +impl<'a, K: Copy, V> Iterator for Items<'a, K, V> { type Item = &'a V; fn next(&mut self) -> Option<&'a V> { - fn borrow_opt<'a, K, V>(opt_ptr: &'a Option>>) -> Option<&'a PatriciaTree> { + fn borrow_opt<'a, K: Copy, V>(opt_ptr: &'a Option>>) -> Option<&'a PatriciaTree> { opt_ptr.as_ref().map(|b| &**b) } @@ -491,11 +493,11 @@ impl<'a, K, V> Iterator for Items<'a, K, V> { } } -impl<'a, K, V> Iterator for MutItems<'a, K, V> { +impl<'a, K: Copy, V> Iterator for MutItems<'a, K, V> { type Item = &'a mut V; fn next(&mut self) -> Option<&'a mut V> { - fn borrow_opt<'a, K, V>(opt_ptr: &'a Option>>) -> *mut PatriciaTree { + fn borrow_opt<'a, K: Copy, V>(opt_ptr: &'a Option>>) -> *mut PatriciaTree { match *opt_ptr { Some(ref data) => &**data as *const _ as *mut _, None => ptr::null_mut() diff --git a/src/wallet/bip32.rs b/src/wallet/bip32.rs index 4fbfce4d..f51f2240 100644 --- a/src/wallet/bip32.rs +++ b/src/wallet/bip32.rs @@ -51,7 +51,7 @@ impl Default for Fingerprint { } /// Extended private key -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] pub struct ExtendedPrivKey { /// The network this key is to be used on pub network: Network, @@ -68,7 +68,7 @@ pub struct ExtendedPrivKey { } /// Extended public key -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] pub struct ExtendedPubKey { /// The network this key is to be used on pub network: Network, @@ -85,7 +85,7 @@ pub struct ExtendedPubKey { } /// A child number for a derived key -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum ChildNumber { /// Hardened key index, within [0, 2^31 - 1] Hardened(u32), @@ -292,9 +292,9 @@ impl ExtendedPubKey { impl ToBase58 for ExtendedPrivKey { fn base58_layout(&self) -> Vec { let mut ret = Vec::with_capacity(78); - ret.push_all(match self.network { - Network::Bitcoin => &[0x04, 0x88, 0xAD, 0xE4], - Network::Testnet => &[0x04, 0x35, 0x83, 0x94] + ret.push_all(&match self.network { + Network::Bitcoin => [0x04, 0x88, 0xAD, 0xE4], + Network::Testnet => [0x04, 0x35, 0x83, 0x94] }); ret.push(self.depth as u8); ret.push_all(&self.parent_fingerprint[..]); @@ -346,9 +346,9 @@ impl ToBase58 for ExtendedPubKey { fn base58_layout(&self) -> Vec { assert!(self.public_key.is_compressed()); let mut ret = Vec::with_capacity(78); - ret.push_all(match self.network { - Network::Bitcoin => &[0x04u8, 0x88, 0xB2, 0x1E], - Network::Testnet => &[0x04u8, 0x35, 0x87, 0xCF] + ret.push_all(&match self.network { + Network::Bitcoin => [0x04u8, 0x88, 0xB2, 0x1E], + Network::Testnet => [0x04u8, 0x35, 0x87, 0xCF] }); ret.push(self.depth as u8); ret.push_all(&self.parent_fingerprint[..]); @@ -510,21 +510,12 @@ mod tests { #[test] pub fn encode_decode_childnumber() { - use serialize::json; - - let h1 = Hardened(1); - let n1 = Normal(1); - - let h1_str = json::encode(&h1); - let n1_str = json::encode(&n1); - - assert!(h1 != n1); - assert!(h1_str != n1_str); - - let h1_dec = json::decode(&h1_str).unwrap(); - let n1_dec = json::decode(&n1_str).unwrap(); - assert_eq!(h1, h1_dec); - assert_eq!(n1, n1_dec); + serde_round_trip!(Normal(0)); + serde_round_trip!(Normal(1)); + serde_round_trip!(Normal((1 << 31) - 1)); + serde_round_trip!(Hardened(0)); + serde_round_trip!(Hardened(1)); + serde_round_trip!(Hardened((1 << 31) - 1)); } #[bench]