diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 1202e02..e158290 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -34,7 +34,7 @@ use network::encodable::ConsensusEncodable; use network::serialize::BitcoinHash; /// A transaction input, which defines old coins to be consumed -#[deriving(Clone, PartialEq, Show)] +#[deriving(Clone, PartialEq, Eq, Show)] pub struct TxIn { /// The hash of the transaction whose output is being used an an input pub prev_hash: Sha256dHash, @@ -51,7 +51,7 @@ pub struct TxIn { } /// A transaction output, which defines new coins to be created from old ones. -#[deriving(Clone, PartialEq, Show)] +#[deriving(Clone, PartialEq, Eq, Show)] pub struct TxOut { /// The value of the output, in satoshis pub value: u64, @@ -67,7 +67,7 @@ impl Default for TxOut { } /// A Bitcoin transaction, which describes an authenticated movement of coins -#[deriving(Clone, PartialEq, Show)] +#[deriving(Clone, PartialEq, Eq, Show)] pub struct Transaction { /// The protocol version, should always be 1. pub version: u32, diff --git a/src/internal_macros.rs b/src/internal_macros.rs index 2a0afda..66cfa6f 100644 --- a/src/internal_macros.rs +++ b/src/internal_macros.rs @@ -36,6 +36,25 @@ macro_rules! impl_consensus_encoding( ); ) +macro_rules! impl_newtype_consensus_encoding( + ($thing:ident) => ( + impl, E> ::network::encodable::ConsensusEncodable for $thing { + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), E> { + let &$thing(ref data) = self; + data.consensus_encode(s) + } + } + + impl, E> ::network::encodable::ConsensusDecodable for $thing { + #[inline] + fn consensus_decode(d: &mut D) -> Result<$thing, E> { + Ok($thing(try!(ConsensusDecodable::consensus_decode(d)))) + } + } + ); +) + macro_rules! impl_json( ($thing:ident, $($field:ident),+) => ( impl ::serialize::json::ToJson for $thing { diff --git a/src/network/encodable.rs b/src/network/encodable.rs index 965a736..e9eb54e 100644 --- a/src/network/encodable.rs +++ b/src/network/encodable.rs @@ -319,23 +319,33 @@ impl, E> ConsensusDecodable for CheckedData { } // Tuples -impl, E, T: ConsensusEncodable, U: ConsensusEncodable> ConsensusEncodable for (T, U) { - #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), E> { - let &(ref s1, ref s2) = self; - try!(s1.consensus_encode(s)); - try!(s2.consensus_encode(s)); - Ok(()) - } -} +macro_rules! tuple_encode( + ($($x:ident),*) => ( + impl , EE, $($x: ConsensusEncodable),*> ConsensusEncodable for ($($x),*) { + #[inline] + #[allow(uppercase_variables)] + fn consensus_encode(&self, s: &mut SS) -> Result<(), EE> { + let &($(ref $x),*) = self; + $( try!($x.consensus_encode(s)); )* + Ok(()) + } + } + + impl, EE, $($x: ConsensusDecodable),*> ConsensusDecodable for ($($x),*) { + #[inline] + #[allow(uppercase_variables)] + fn consensus_decode(d: &mut DD) -> Result<($($x),*), EE> { + Ok(($(try!({let $x = ConsensusDecodable::consensus_decode(d); $x })),*)) + } + } + ); +) + +tuple_encode!(A, B) +tuple_encode!(A, B, C, D) +tuple_encode!(A, B, C, D, E, F) +tuple_encode!(A, B, C, D, E, F, G, H) -impl, E, T: ConsensusDecodable, U: ConsensusDecodable> ConsensusDecodable for (T, U) { - #[inline] - fn consensus_decode(d: &mut D) -> Result<(T, U), E> { - Ok((try!(ConsensusDecodable::consensus_decode(d)), - try!(ConsensusDecodable::consensus_decode(d)))) - } -} // References impl, E, T: ConsensusEncodable> ConsensusEncodable for Box { diff --git a/src/util/hash.rs b/src/util/hash.rs index 6d151c2..4b26753 100644 --- a/src/util/hash.rs +++ b/src/util/hash.rs @@ -28,7 +28,7 @@ use crypto::digest::Digest; use crypto::sha2; use network::encodable::{ConsensusDecodable, ConsensusEncodable}; -use network::serialize::{RawEncoder, BitcoinHash, SimpleDecoder, SimpleEncoder}; +use network::serialize::{RawEncoder, BitcoinHash, SimpleDecoder}; use util::uint::Uint128; use util::uint::Uint256; @@ -44,6 +44,19 @@ pub struct Ripemd160Hash([u8, ..20]); /// A "hasher" which just truncates pub struct DumbHasher; +/// A 32-bit hash obtained by truncating a real hash +#[deriving(Clone, PartialEq, Eq, Show)] +pub struct Hash32((u8, u8, u8, u8)); + +/// A 48-bit hash obtained by truncating a real hash +#[deriving(Clone, PartialEq, Eq, Show)] +pub struct Hash48((u8, u8, u8, u8, u8, u8)); + +/// A 64-bit hash obtained by truncating a real hash +#[deriving(Clone, PartialEq, Eq, Show)] +pub struct Hash64((u8, u8, u8, u8, u8, u8, u8, u8)); + + // Allow these to be used as a key for Rust's HashMap et. al. impl hash::Hash for Sha256dHash { #[inline] @@ -72,6 +85,32 @@ impl hash::Hash for Uint128 { } } +impl hash::Hash for Hash32 { + #[inline] + fn hash(&self, state: &mut u64) { + let &Hash32((a, b, c, d)) = self; + *state = a as u64 + (b as u64 << 8) + (c as u64 << 16) + (d as u64 << 24); + } +} + +impl hash::Hash for Hash48 { + #[inline] + fn hash(&self, state: &mut u64) { + let &Hash48((a, b, c, d, e, f)) = self; + *state = a as u64 + (b as u64 << 8) + (c as u64 << 16) + (d as u64 << 24) + + (e as u64 << 32) + (f as u64 << 40); + } +} + +impl hash::Hash for Hash64 { + #[inline] + fn hash(&self, state: &mut u64) { + let &Hash64((a, b, c, d, e, f, g, h)) = self; + *state = a as u64 + (b as u64 << 8) + (c as u64 << 16) + (d as u64 << 24) + + (e as u64 << 32) + (f as u64 << 40) + (g as u64 << 48) + (h as u64 << 56); + } +} + impl hash::Hasher for DumbHasher { #[inline] fn hash>(&self, value: &T) -> u64 { @@ -122,6 +161,30 @@ impl Sha256dHash { data[31]])) } } + /// Converts a hash to a Hash32 by truncation + #[inline] + pub fn into_hash32(self) -> Hash32 { + let Sha256dHash(data) = self; + unsafe { transmute([data[0], data[8], data[16], data[24]]) } + } + + /// Converts a hash to a Hash48 by truncation + #[inline] + pub fn into_hash48(self) -> Hash48 { + let Sha256dHash(data) = self; + unsafe { transmute([data[0], data[6], data[12], data[18], data[24], data[30]]) } + } + + /// Human-readable hex output + + /// Converts a hash to a Hash64 by truncation + #[inline] + pub fn into_hash64(self) -> Hash64 { + let Sha256dHash(data) = self; + unsafe { transmute([data[0], data[4], data[8], data[12], + data[16], data[20], data[24], data[28]]) } + } + /// Human-readable hex output pub fn le_hex_string(&self) -> String { let &Sha256dHash(data) = self; @@ -214,19 +277,10 @@ impl, E> ::serialize::Decodable for Sha256dHash } // Consensus encoding (little-endian) -impl, E> ConsensusEncodable for Sha256dHash { - #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), E> { - self.into_uint256().consensus_encode(s) - } -} - -impl, E> ConsensusDecodable for Sha256dHash { - #[inline] - fn consensus_decode(d: &mut D) -> Result { - Ok(Sha256dHash(try!(ConsensusDecodable::consensus_decode(d)))) - } -} +impl_newtype_consensus_encoding!(Hash32) +impl_newtype_consensus_encoding!(Hash48) +impl_newtype_consensus_encoding!(Hash64) +impl_newtype_consensus_encoding!(Sha256dHash) impl fmt::LowerHex for Sha256dHash { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {