Skip to content

Commit

Permalink
refactor(spend)!: include tx instead of only hash
Browse files Browse the repository at this point in the history
- This is necessary when sending the spend to close group, as they need
to call the close groups of parent spends to validate the current spend.
  • Loading branch information
oetyng committed Apr 9, 2023
1 parent f0d8744 commit 8b8089a
Show file tree
Hide file tree
Showing 7 changed files with 30 additions and 41 deletions.
3 changes: 1 addition & 2 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ impl TransactionBuilder {
pub fn build(self, reason: Hash, rng: impl RngCore + CryptoRng) -> Result<DbcBuilder> {
let (tx, revealed_outputs) = self.revealed_tx.sign(rng)?;

let tx_hash = Hash::from(tx.hash());
let signed_spends: BTreeSet<_> = tx
.inputs
.iter()
Expand All @@ -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,
};
Expand Down
8 changes: 3 additions & 5 deletions src/dbc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,21 +135,19 @@ 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() {
sha3.update(&sp.to_bytes());
}

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.
Expand Down
4 changes: 2 additions & 2 deletions src/mock/mock_spentbook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 6 additions & 6 deletions src/signed_spend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand All @@ -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.
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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)]
Expand All @@ -113,7 +113,7 @@ impl Spend {
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes: Vec<u8> = 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
Expand Down
2 changes: 1 addition & 1 deletion src/spentbook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
},
Expand Down
6 changes: 2 additions & 4 deletions src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
36 changes: 15 additions & 21 deletions src/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<SignedSpend>,
) -> Result<(), Error> {
pub fn verify(tx: &DbcTransaction, signed_spends: &BTreeSet<SignedSpend>) -> 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<DbcId> =
transaction.outputs.iter().map(|o| (*o.dbc_id())).collect();
if unique_dbc_ids.len() != transaction.outputs.len() {
let unique_dbc_ids: BTreeSet<DbcId> = 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);
}
}
Expand All @@ -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))
Expand All @@ -89,7 +83,7 @@ impl TransactionVerifier {
.map(|s| *s.blinded_amount())
.collect();

transaction.verify(&blinded_amounts)?;
tx.verify(&blinded_amounts)?;

Ok(())
}
Expand All @@ -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);
}
Expand Down

0 comments on commit 8b8089a

Please sign in to comment.