diff --git a/core/src/core/block.rs b/core/src/core/block.rs index 568859c32..e059fa87e 100644 --- a/core/src/core/block.rs +++ b/core/src/core/block.rs @@ -293,7 +293,7 @@ impl Block { // build vectors with all inputs and all outputs, ordering them by hash // needs to be a fold so we don't end up with a vector of vectors and we // want to fully own the refs (not just a pointer like flat_map). - let inputs = txs.iter().fold(vec![], |mut acc, ref tx| { + let mut inputs = txs.iter().fold(vec![], |mut acc, ref tx| { let mut inputs = tx.inputs.clone(); acc.append(&mut inputs); acc @@ -305,6 +305,10 @@ impl Block { }); outputs.push(reward_out); + inputs.sort(); + outputs.sort(); + kernels.sort(); + // calculate the overall Merkle tree and fees Ok( diff --git a/core/src/core/transaction.rs b/core/src/core/transaction.rs index 47796b0ee..bcf5c6452 100644 --- a/core/src/core/transaction.rs +++ b/core/src/core/transaction.rs @@ -16,11 +16,13 @@ use byteorder::{BigEndian, ByteOrder}; use blake2::blake2b::blake2b; -use util::secp::{self, Secp256k1, Message, Signature}; -use util::secp::pedersen::{RangeProof, Commitment}; +use util::secp::{self, Message, Secp256k1, Signature}; +use util::secp::pedersen::{Commitment, RangeProof}; +use std::cmp::Ordering; use std::ops; use core::Committed; +use core::hash::Hashed; use core::pmmr::Summable; use keychain::{Identifier, Keychain}; use ser::{self, read_and_verify_sorted, Readable, Reader, Writeable, WriteableSorted, Writer}; @@ -39,6 +41,29 @@ bitflags! { } } +// don't seem to be able to define an Ord implementation for Hash due to +// Ord being defined on all pointers, resorting to a macro instead +macro_rules! hashable_ord { + ($hashable: ident) => { + impl Ord for $hashable { + fn cmp(&self, other: &$hashable) -> Ordering { + self.hash().cmp(&other.hash()) + } + } + impl PartialOrd for $hashable { + fn partial_cmp(&self, other: &$hashable) -> Option { + Some(self.hash().cmp(&other.hash())) + } + } + impl PartialEq for $hashable { + fn eq(&self, other: &$hashable) -> bool { + self.hash() == other.hash() + } + } + impl Eq for $hashable {} + } +} + /// Errors thrown by Block validation #[derive(Debug, PartialEq)] pub enum Error { @@ -68,7 +93,7 @@ pub fn kernel_sig_msg(fee: u64, lock_height: u64) -> [u8; 32] { /// amount to zero. /// The signature signs the fee and the lock_height, which are retained for /// signature validation. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone)] pub struct TxKernel { /// Options for a kernel's structure or use pub features: KernelFeatures, @@ -86,6 +111,8 @@ pub struct TxKernel { pub excess_sig: Vec, } +hashable_ord!(TxKernel); + impl Writeable for TxKernel { fn write(&self, writer: &mut W) -> Result<(), ser::Error> { ser_multiwrite!( @@ -169,7 +196,6 @@ impl Writeable for Transaction { } } - /// Implementation of Readable for a transaction, defines how to read a full /// transaction from a binary stream. impl Readable for Transaction { @@ -327,9 +353,11 @@ impl Transaction { /// A transaction input, mostly a reference to an output being spent by the /// transaction. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone)] pub struct Input(pub Commitment); +hashable_ord!(Input); + /// Implementation of Writeable for a transaction Input, defines how to write /// an Input as binary. impl Writeable for Input { @@ -423,7 +451,7 @@ impl SwitchCommitHash { /// The hash of an output only covers its features, lock_height, commitment, /// and switch commitment. The range proof is expected to have its own hash /// and is stored and committed to separately. -#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, Serialize, Deserialize)] pub struct Output { /// Options for an output's structure or use pub features: OutputFeatures, @@ -435,6 +463,8 @@ pub struct Output { pub proof: RangeProof, } +hashable_ord!(Output); + /// Implementation of Writeable for a transaction Output, defines how to write /// an Output as binary. impl Writeable for Output { @@ -672,8 +702,8 @@ mod test { } #[test] - fn commit_consistency(){ - let keychain = Keychain::from_seed(&[0;32]).unwrap(); + fn commit_consistency() { + let keychain = Keychain::from_seed(&[0; 32]).unwrap(); let key_id = keychain.derive_key_id(1).unwrap(); let commit = keychain.commit(1003, &key_id).unwrap(); @@ -687,7 +717,7 @@ mod test { println!("Switch commit 2: {:?}", switch_commit_2); println!("commit2 : {:?}", commit_2); - assert!(commit==commit_2); - assert!(switch_commit==switch_commit_2); + assert!(commit == commit_2); + assert!(switch_commit == switch_commit_2); } }