diff --git a/chain/src/txhashset/utxo_view.rs b/chain/src/txhashset/utxo_view.rs index 1b648ba72b..2823acbe80 100644 --- a/chain/src/txhashset/utxo_view.rs +++ b/chain/src/txhashset/utxo_view.rs @@ -14,7 +14,7 @@ //! Lightweight readonly view into output MMR for convenience. -use crate::core::core::hash::Hash; +use crate::core::core::hash::{Hash, Hashed}; use crate::core::core::pmmr::{self, ReadonlyPMMR}; use crate::core::core::{Block, BlockHeader, Input, Output, Transaction}; use crate::core::global; diff --git a/chain/src/types.rs b/chain/src/types.rs index 7e784b8099..27895e7c46 100644 --- a/chain/src/types.rs +++ b/chain/src/types.rs @@ -73,10 +73,11 @@ impl Tip { total_difficulty: header.total_difficulty(), } } +} - /// *Really* easy to accidentally call hash() on a tip (thinking its a header). - /// So lets make hash() do the right thing here. - pub fn hash(&self) -> Hash { +impl Hashed for Tip { + /// The hash of the underlying block. + fn hash(&self) -> Hash { self.last_block_h } } diff --git a/core/src/core/block.rs b/core/src/core/block.rs index c765d90eb3..5f1887af04 100644 --- a/core/src/core/block.rs +++ b/core/src/core/block.rs @@ -25,7 +25,7 @@ use std::sync::Arc; use crate::consensus::{reward, REWARD}; use crate::core::committed::{self, Committed}; use crate::core::compact_block::{CompactBlock, CompactBlockBody}; -use crate::core::hash::{Hash, Hashed, ZERO_HASH}; +use crate::core::hash::{DefaultHashable, Hash, Hashed, ZERO_HASH}; use crate::core::verifier_cache::VerifierCache; use crate::core::{ transaction, Commitment, Input, Output, Transaction, TransactionBody, TxKernel, Weighting, @@ -160,9 +160,9 @@ impl FixedLength for HeaderEntry { const LEN: usize = Hash::LEN + 8 + Difficulty::LEN + 4 + 1; } -impl HeaderEntry { +impl Hashed for HeaderEntry { /// The hash of the underlying block. - pub fn hash(&self) -> Hash { + fn hash(&self) -> Hash { self.hash } } @@ -197,6 +197,7 @@ pub struct BlockHeader { /// Proof of work and related pub pow: ProofOfWork, } +impl DefaultHashable for BlockHeader {} impl Default for BlockHeader { fn default() -> BlockHeader { @@ -353,6 +354,13 @@ pub struct Block { body: TransactionBody, } +impl Hashed for Block { + /// The hash of the underlying block. + fn hash(&self) -> Hash { + self.header.hash() + } +} + /// Implementation of Writeable for a block, defines how to write the block to a /// binary writer. Differentiates between writing the block for the purpose of /// full serialization and the one of just extracting a hash. @@ -570,11 +578,6 @@ impl Block { &mut self.body.kernels } - /// Blockhash, computed using only the POW - pub fn hash(&self) -> Hash { - self.header.hash() - } - /// Sum of all fees (inputs less outputs) in the block pub fn total_fees(&self) -> u64 { self.body diff --git a/core/src/core/compact_block.rs b/core/src/core/compact_block.rs index b143234ab4..ea7d2a634e 100644 --- a/core/src/core/compact_block.rs +++ b/core/src/core/compact_block.rs @@ -17,7 +17,7 @@ use rand::{thread_rng, Rng}; use crate::core::block::{Block, BlockHeader, Error}; -use crate::core::hash::Hashed; +use crate::core::hash::{DefaultHashable, Hashed}; use crate::core::id::ShortIdentifiable; use crate::core::{Output, ShortId, TxKernel}; use crate::ser::{self, read_multi, Readable, Reader, VerifySortedAndUnique, Writeable, Writer}; @@ -137,6 +137,8 @@ pub struct CompactBlock { body: CompactBlockBody, } +impl DefaultHashable for CompactBlock {} + impl CompactBlock { /// "Lightweight" validation. fn validate_read(&self) -> Result<(), Error> { diff --git a/core/src/core/hash.rs b/core/src/core/hash.rs index 446ee89103..e0638762c3 100644 --- a/core/src/core/hash.rs +++ b/core/src/core/hash.rs @@ -36,6 +36,19 @@ pub const ZERO_HASH: Hash = Hash([0; 32]); #[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] pub struct Hash([u8; 32]); +impl DefaultHashable for Hash {} + +impl Hash { + fn hash_with(&self, other: T) -> Hash { + let mut hasher = HashWriter::default(); + ser::Writeable::write(self, &mut hasher).unwrap(); + ser::Writeable::write(&other, &mut hasher).unwrap(); + let mut ret = [0; 32]; + hasher.finalize(&mut ret); + Hash(ret) + } +} + impl fmt::Debug for Hash { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let hash_hex = self.to_hex(); @@ -212,25 +225,26 @@ impl ser::Writer for HashWriter { pub trait Hashed { /// Obtain the hash of the object fn hash(&self) -> Hash; - /// Hash the object together with another writeable object - fn hash_with(&self, other: T) -> Hash; } -impl Hashed for W { +/// Implementing this trait enables the default +/// hash implementation +pub trait DefaultHashable: Writeable {} +impl Hashed for D { fn hash(&self) -> Hash { let mut hasher = HashWriter::default(); - ser::Writeable::write(self, &mut hasher).unwrap(); - let mut ret = [0; 32]; - hasher.finalize(&mut ret); - Hash(ret) - } - - fn hash_with(&self, other: T) -> Hash { - let mut hasher = HashWriter::default(); - ser::Writeable::write(self, &mut hasher).unwrap(); - ser::Writeable::write(&other, &mut hasher).unwrap(); + Writeable::write(self, &mut hasher).unwrap(); let mut ret = [0; 32]; hasher.finalize(&mut ret); Hash(ret) } } + +impl DefaultHashable for &D {} +impl DefaultHashable for (D, E) {} +impl DefaultHashable for (D, E, F) {} + +/// Implement Hashed trait for external types here +impl DefaultHashable for crate::util::secp::pedersen::RangeProof {} +impl DefaultHashable for Vec {} +impl DefaultHashable for u64 {} diff --git a/core/src/core/id.rs b/core/src/core/id.rs index 99ea8643ce..9921bb17cf 100644 --- a/core/src/core/id.rs +++ b/core/src/core/id.rs @@ -20,7 +20,7 @@ use std::cmp::Ordering; use byteorder::{ByteOrder, LittleEndian}; use siphasher::sip::SipHasher24; -use crate::core::hash::{Hash, Hashed}; +use crate::core::hash::{DefaultHashable, Hash, Hashed}; use crate::ser::{self, Readable, Reader, Writeable, Writer}; use crate::util; @@ -73,6 +73,7 @@ impl ShortIdentifiable for H { #[derive(Clone, Serialize, Deserialize, Hash)] pub struct ShortId([u8; 6]); +impl DefaultHashable for ShortId {} /// We want to sort short_ids in a canonical and consistent manner so we can /// verify sort order in the same way we do for full inputs|outputs|kernels /// themselves. @@ -168,6 +169,8 @@ mod test { } } + impl DefaultHashable for Foo {} + let foo = Foo(0); let expected_hash = diff --git a/core/src/core/transaction.rs b/core/src/core/transaction.rs index 70b8c61223..0e67e64899 100644 --- a/core/src/core/transaction.rs +++ b/core/src/core/transaction.rs @@ -14,7 +14,7 @@ //! Transactions -use crate::core::hash::Hashed; +use crate::core::hash::{DefaultHashable, Hashed}; use crate::core::verifier_cache::VerifierCache; use crate::core::{committed, Committed}; use crate::keychain::{self, BlindingFactor}; @@ -50,6 +50,8 @@ enum_from_primitive! { } } +impl DefaultHashable for KernelFeatures {} + impl Writeable for KernelFeatures { fn write(&self, writer: &mut W) -> Result<(), ser::Error> { writer.write_u8(*self as u8)?; @@ -170,6 +172,7 @@ pub struct TxKernel { pub excess_sig: secp::Signature, } +impl DefaultHashable for TxKernel {} hashable_ord!(TxKernel); impl ::std::hash::Hash for TxKernel { @@ -753,6 +756,8 @@ pub struct Transaction { body: TransactionBody, } +impl DefaultHashable for Transaction {} + /// PartialEq impl PartialEq for Transaction { fn eq(&self, tx: &Transaction) -> bool { @@ -1113,6 +1118,7 @@ pub struct Input { pub commit: Commitment, } +impl DefaultHashable for Input {} hashable_ord!(Input); impl ::std::hash::Hash for Input { @@ -1218,6 +1224,7 @@ pub struct Output { pub proof: RangeProof, } +impl DefaultHashable for Output {} hashable_ord!(Output); impl ::std::hash::Hash for Output { @@ -1330,6 +1337,8 @@ pub struct OutputIdentifier { pub commit: Commitment, } +impl DefaultHashable for OutputIdentifier {} + impl OutputIdentifier { /// Build a new output_identifier. pub fn new(features: OutputFeatures, commit: &Commitment) -> OutputIdentifier { diff --git a/core/src/pow/types.rs b/core/src/pow/types.rs index 1e83607bd6..49e53a76da 100644 --- a/core/src/pow/types.rs +++ b/core/src/pow/types.rs @@ -22,7 +22,7 @@ use rand::{thread_rng, Rng}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use crate::consensus::{graph_weight, MIN_DIFFICULTY, SECOND_POW_EDGE_BITS}; -use crate::core::hash::Hashed; +use crate::core::hash::{DefaultHashable, Hashed}; use crate::global; use crate::ser::{self, FixedLength, Readable, Reader, Writeable, Writer}; @@ -324,6 +324,8 @@ pub struct Proof { pub nonces: Vec, } +impl DefaultHashable for Proof {} + impl fmt::Debug for Proof { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Cuckoo{}(", self.edge_bits)?; diff --git a/core/src/ser.rs b/core/src/ser.rs index 7b8903db74..babebae79a 100644 --- a/core/src/ser.rs +++ b/core/src/ser.rs @@ -19,7 +19,7 @@ //! To use it simply implement `Writeable` or `Readable` and then use the //! `serialize` or `deserialize` functions on them as appropriate. -use crate::core::hash::{Hash, Hashed}; +use crate::core::hash::{DefaultHashable, Hash, Hashed}; use crate::keychain::{BlindingFactor, Identifier, IDENTIFIER_SIZE}; use crate::util::read_write::read_exact; use crate::util::secp::constants::{ @@ -615,7 +615,7 @@ where match elem { Ok(e) => buf.push(e), Err(Error::IOErr(ref _d, ref kind)) if *kind == io::ErrorKind::UnexpectedEof => { - break + break; } Err(e) => return Err(e), } @@ -706,7 +706,7 @@ pub trait FixedLength { } /// Trait for types that can be added to a PMMR. -pub trait PMMRable: Writeable + Clone + Debug { +pub trait PMMRable: Writeable + Clone + Debug + DefaultHashable { /// The type of element actually stored in the MMR data file. /// This allows us to store Hash elements in the header MMR for variable size BlockHeaders. type E: FixedLength + Readable + Writeable; @@ -721,7 +721,7 @@ pub trait PMMRIndexHashable { fn hash_with_index(&self, index: u64) -> Hash; } -impl PMMRIndexHashable for T { +impl PMMRIndexHashable for T { fn hash_with_index(&self, index: u64) -> Hash { (index, self).hash() } diff --git a/core/tests/vec_backend.rs b/core/tests/vec_backend.rs index 25143260b0..e7bae7cba8 100644 --- a/core/tests/vec_backend.rs +++ b/core/tests/vec_backend.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use self::core::core::hash::Hash; +use self::core::core::hash::{DefaultHashable, Hash}; use self::core::core::pmmr::{self, Backend}; use self::core::core::BlockHeader; use self::core::ser; @@ -25,6 +25,8 @@ use std::path::Path; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct TestElem(pub [u32; 4]); +impl DefaultHashable for TestElem {} + impl FixedLength for TestElem { const LEN: usize = 16; } diff --git a/servers/src/mining/stratumserver.rs b/servers/src/mining/stratumserver.rs index 4c91645692..be6b2b9cba 100644 --- a/servers/src/mining/stratumserver.rs +++ b/servers/src/mining/stratumserver.rs @@ -29,6 +29,7 @@ use std::{cmp, thread}; use crate::chain; use crate::common::stats::{StratumStats, WorkerStats}; use crate::common::types::{StratumServerConfig, SyncState}; +use crate::core::core::hash::Hashed; use crate::core::core::verifier_cache::VerifierCache; use crate::core::core::Block; use crate::core::{pow, ser}; diff --git a/store/tests/pmmr.rs b/store/tests/pmmr.rs index 26d75ec7f4..00abd7a5ff 100644 --- a/store/tests/pmmr.rs +++ b/store/tests/pmmr.rs @@ -21,6 +21,7 @@ use std::fs; use chrono::prelude::Utc; use croaring::Bitmap; +use crate::core::core::hash::DefaultHashable; use crate::core::core::pmmr::{Backend, PMMR}; use crate::core::ser::{ Error, FixedLength, PMMRIndexHashable, PMMRable, Readable, Reader, Writeable, Writer, @@ -903,6 +904,8 @@ fn load(pos: u64, elems: &[TestElem], backend: &mut store::pmmr::PMMRBackend