diff --git a/src/builder.rs b/src/builder.rs index ab37dda..341299b 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -137,7 +137,6 @@ impl TransactionBuilder { pub fn build(self, reason: Hash, rng: impl RngCore + CryptoRng) -> Result { let (tx, revealed_outputs) = self.revealed_tx.sign(rng)?; - let tx_hash = Hash::from(tx.hash()); let signed_spends: BTreeSet<_> = tx .inputs .iter() @@ -149,7 +148,7 @@ impl TransactionBuilder { .map(|i| { let spend = crate::Spend { dbc_id: input.dbc_id(), - tx_hash, + tx: tx.clone(), reason, blinded_amount: input.blinded_amount, }; diff --git a/src/dbc.rs b/src/dbc.rs index 09b3d8e..c837290 100644 --- a/src/dbc.rs +++ b/src/dbc.rs @@ -135,10 +135,9 @@ impl Dbc { } /// Generate the hash of this Dbc - pub fn hash(&self) -> [u8; 32] { + pub fn hash(&self) -> Hash { let mut sha3 = Sha3::v256(); - - sha3.update(&self.tx.hash()); + sha3.update(self.tx.hash().as_ref()); sha3.update(&self.ciphers.to_bytes()); for sp in self.signed_spends.iter() { @@ -146,10 +145,9 @@ impl Dbc { } sha3.update(self.reason().as_ref()); - let mut hash = [0u8; 32]; sha3.finalize(&mut hash); - hash + Hash::from(hash) } /// Verifies that this Dbc is valid. diff --git a/src/mock/mock_spentbook.rs b/src/mock/mock_spentbook.rs index a8f76a4..079d711 100644 --- a/src/mock/mock_spentbook.rs +++ b/src/mock/mock_spentbook.rs @@ -106,8 +106,8 @@ impl SpentbookNode { verify_tx: bool, ) -> Result<()> { let input_id = signed_spend.dbc_id(); - let spend_tx_hash = signed_spend.spend.tx_hash; - let tx_hash = Hash::from(tx.hash()); + let spend_tx_hash = signed_spend.tx_hash(); + let tx_hash = tx.hash(); if tx_hash != spend_tx_hash { return Err(Error::InvalidTransactionHash); diff --git a/src/signed_spend.rs b/src/signed_spend.rs index b19584b..0bf6f9d 100644 --- a/src/signed_spend.rs +++ b/src/signed_spend.rs @@ -6,7 +6,7 @@ // KIND, either express or implied. Please review the Licences for the specific language governing // permissions and limitations relating to use of the SAFE Network Software. -use crate::{BlindedAmount, DbcId, Error, Hash, Result, Signature}; +use crate::{BlindedAmount, DbcId, DbcTransaction, Error, Hash, Result, Signature}; use custom_debug::Debug; #[cfg(feature = "serde")] @@ -31,7 +31,7 @@ impl SignedSpend { /// Get transaction hash. pub fn tx_hash(&self) -> Hash { - self.spend.tx_hash + self.spend.tx.hash() } /// Get blinded amount. @@ -59,7 +59,7 @@ impl SignedSpend { /// valid for this SignedSpend. pub fn verify(&self, tx_hash: Hash) -> Result<()> { // Verify that input tx_hash matches our tx_hash which was signed by the DerivedKey of the input. - if tx_hash != self.spend.tx_hash { + if tx_hash != self.tx_hash() { return Err(Error::InvalidTransactionHash); } @@ -99,8 +99,8 @@ impl std::hash::Hash for SignedSpend { pub struct Spend { /// DbcId of input Dbc that this SignedSpend is proving to be spent. pub dbc_id: DbcId, - /// Hash of transaction that the input Dbc is being spent in. - pub tx_hash: Hash, + /// The transaction that the input Dbc is being spent in. + pub tx: DbcTransaction, /// Reason why this Dbc was spent. pub reason: Hash, #[debug(skip)] @@ -113,7 +113,7 @@ impl Spend { pub fn to_bytes(&self) -> Vec { let mut bytes: Vec = Default::default(); bytes.extend(self.dbc_id.to_bytes()); - bytes.extend(self.tx_hash.as_ref()); + bytes.extend(self.tx.hash().as_ref()); bytes.extend(self.reason.as_ref()); bytes.extend(self.blinded_amount.compress().to_bytes()); bytes diff --git a/src/spentbook.rs b/src/spentbook.rs index 82b8333..dedbf7a 100644 --- a/src/spentbook.rs +++ b/src/spentbook.rs @@ -285,7 +285,7 @@ mod tests { SignedSpend { spend: Spend { dbc_id: *signed_spend.dbc_id(), - tx_hash: signed_spend.tx_hash(), + tx: signed_spend.spend.tx.clone(), reason: Hash::default(), blinded_amount: *signed_spend.blinded_amount(), }, diff --git a/src/transaction/mod.rs b/src/transaction/mod.rs index e74829f..eda12a7 100644 --- a/src/transaction/mod.rs +++ b/src/transaction/mod.rs @@ -76,14 +76,12 @@ impl DbcTransaction { v } - pub fn hash(&self) -> [u8; 32] { + pub fn hash(&self) -> crate::Hash { let mut sha3 = Sha3::v256(); - sha3.update(&self.to_bytes()); - let mut hash = [0; 32]; sha3.finalize(&mut hash); - hash + crate::Hash::from(hash) } // note: must match message generated by RevealedTx::sign() diff --git a/src/verification.rs b/src/verification.rs index 51b8ff2..ab994cb 100644 --- a/src/verification.rs +++ b/src/verification.rs @@ -6,8 +6,11 @@ // KIND, either express or implied. Please review the Licences for the specific language governing // permissions and limitations relating to use of the SAFE Network Software. -use crate::transaction::{self, DbcTransaction}; -use crate::{BlindedAmount, DbcId, Error, Hash, Result, SignedSpend}; +use crate::{ + transaction::{self, DbcTransaction}, + BlindedAmount, DbcId, Error, Result, SignedSpend, +}; + use std::collections::BTreeSet; // Here we are putting transaction verification logic that is beyond @@ -26,37 +29,29 @@ impl TransactionVerifier { /// trustless/verified way. ie, the caller should not simply obtain keys /// from a SpentbookNode directly, but must somehow verify that the node is /// a valid authority. - pub fn verify( - transaction: &DbcTransaction, - signed_spends: &BTreeSet, - ) -> Result<(), Error> { + pub fn verify(tx: &DbcTransaction, signed_spends: &BTreeSet) -> Result<(), Error> { if signed_spends.is_empty() { return Err(transaction::Error::MissingTxInputs)?; } - if signed_spends.len() != transaction.inputs.len() { + if signed_spends.len() != tx.inputs.len() { return Err(Error::SignedSpendInputLenMismatch { current: signed_spends.len(), - expected: transaction.inputs.len(), + expected: tx.inputs.len(), }); } - let tx_hash = Hash::from(transaction.hash()); + let tx_hash = tx.hash(); // Verify that each pubkey is unique in this transaction. - let unique_dbc_ids: BTreeSet = - transaction.outputs.iter().map(|o| (*o.dbc_id())).collect(); - if unique_dbc_ids.len() != transaction.outputs.len() { + let unique_dbc_ids: BTreeSet = tx.outputs.iter().map(|o| (*o.dbc_id())).collect(); + if unique_dbc_ids.len() != tx.outputs.len() { return Err(Error::DbcIdNotUniqueAcrossOutputs); } // Verify that each input has a corresponding spent proof. for signed_spend in signed_spends.iter() { - if !transaction - .inputs - .iter() - .any(|m| m.dbc_id == *signed_spend.dbc_id()) - { + if !tx.inputs.iter().any(|m| m.dbc_id == *signed_spend.dbc_id()) { return Err(Error::SignedSpendInputIdMismatch); } } @@ -72,8 +67,7 @@ impl TransactionVerifier { let mut signed_spends_found: Vec<(usize, &SignedSpend)> = signed_spends .iter() .filter_map(|s| { - transaction - .inputs + tx.inputs .iter() .position(|m| m.dbc_id == *s.dbc_id()) .map(|idx| (idx, s)) @@ -89,7 +83,7 @@ impl TransactionVerifier { .map(|s| *s.blinded_amount()) .collect(); - transaction.verify(&blinded_amounts)?; + tx.verify(&blinded_amounts)?; Ok(()) } @@ -108,7 +102,7 @@ pub fn get_blinded_amounts_from_transaction( let mut referenced_spent_txs: Vec<&DbcTransaction> = vec![]; for spent_prf in signed_spends { for spent_tx in spent_transactions { - let tx_hash = Hash::from(spent_tx.hash()); + let tx_hash = spent_tx.hash(); if tx_hash == spent_prf.tx_hash() { referenced_spent_txs.push(spent_tx); }