mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-02-14 18:55:47 +00:00
Detect change notes while scanning blocks
This commit is contained in:
parent
9c51f3426b
commit
c1e6b1844c
@ -25,6 +25,7 @@ pub struct WalletTx {
|
|||||||
pub struct WalletShieldedSpend {
|
pub struct WalletShieldedSpend {
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
pub nf: Vec<u8>,
|
pub nf: Vec<u8>,
|
||||||
|
pub account: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A subset of an [`OutputDescription`] relevant to wallets and light clients.
|
/// A subset of an [`OutputDescription`] relevant to wallets and light clients.
|
||||||
@ -37,4 +38,5 @@ pub struct WalletShieldedOutput {
|
|||||||
pub account: usize,
|
pub account: usize,
|
||||||
pub note: Note<Bls12>,
|
pub note: Note<Bls12>,
|
||||||
pub to: PaymentAddress<Bls12>,
|
pub to: PaymentAddress<Bls12>,
|
||||||
|
pub is_change: bool,
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use ff::{PrimeField, PrimeFieldRepr};
|
use ff::{PrimeField, PrimeFieldRepr};
|
||||||
use pairing::bls12_381::{Bls12, Fr, FrRepr};
|
use pairing::bls12_381::{Bls12, Fr, FrRepr};
|
||||||
|
use std::collections::HashSet;
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
jubjub::{edwards, fs::Fs},
|
jubjub::{edwards, fs::Fs},
|
||||||
merkle_tree::{CommitmentTree, IncrementalWitness},
|
merkle_tree::{CommitmentTree, IncrementalWitness},
|
||||||
@ -25,6 +26,7 @@ use crate::wallet::{WalletShieldedOutput, WalletShieldedSpend, WalletTx};
|
|||||||
fn scan_output(
|
fn scan_output(
|
||||||
(index, output): (usize, CompactOutput),
|
(index, output): (usize, CompactOutput),
|
||||||
ivks: &[Fs],
|
ivks: &[Fs],
|
||||||
|
spent_from_accounts: &HashSet<usize>,
|
||||||
tree: &mut CommitmentTree<Node>,
|
tree: &mut CommitmentTree<Node>,
|
||||||
existing_witnesses: &mut [&mut IncrementalWitness<Node>],
|
existing_witnesses: &mut [&mut IncrementalWitness<Node>],
|
||||||
new_witnesses: &mut [IncrementalWitness<Node>],
|
new_witnesses: &mut [IncrementalWitness<Node>],
|
||||||
@ -64,6 +66,14 @@ fn scan_output(
|
|||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A note is marked as "change" if the account that received it
|
||||||
|
// also spent notes in the same transaction. This will catch,
|
||||||
|
// for instance:
|
||||||
|
// - Change created by spending fractions of notes.
|
||||||
|
// - Notes created by consolidation transactions.
|
||||||
|
// - Notes sent from one account to itself.
|
||||||
|
let is_change = spent_from_accounts.contains(&account);
|
||||||
|
|
||||||
return Some((
|
return Some((
|
||||||
WalletShieldedOutput {
|
WalletShieldedOutput {
|
||||||
index,
|
index,
|
||||||
@ -72,6 +82,7 @@ fn scan_output(
|
|||||||
account,
|
account,
|
||||||
note,
|
note,
|
||||||
to,
|
to,
|
||||||
|
is_change,
|
||||||
},
|
},
|
||||||
IncrementalWitness::from_tree(tree),
|
IncrementalWitness::from_tree(tree),
|
||||||
));
|
));
|
||||||
@ -89,7 +100,7 @@ fn scan_output(
|
|||||||
pub fn scan_block(
|
pub fn scan_block(
|
||||||
block: CompactBlock,
|
block: CompactBlock,
|
||||||
extfvks: &[ExtendedFullViewingKey],
|
extfvks: &[ExtendedFullViewingKey],
|
||||||
nullifiers: &[&[u8]],
|
nullifiers: &[(&[u8], usize)],
|
||||||
tree: &mut CommitmentTree<Node>,
|
tree: &mut CommitmentTree<Node>,
|
||||||
existing_witnesses: &mut [&mut IncrementalWitness<Node>],
|
existing_witnesses: &mut [&mut IncrementalWitness<Node>],
|
||||||
) -> Vec<(WalletTx, Vec<IncrementalWitness<Node>>)> {
|
) -> Vec<(WalletTx, Vec<IncrementalWitness<Node>>)> {
|
||||||
@ -101,29 +112,45 @@ pub fn scan_block(
|
|||||||
let num_outputs = tx.outputs.len();
|
let num_outputs = tx.outputs.len();
|
||||||
|
|
||||||
// Check for spent notes
|
// Check for spent notes
|
||||||
let shielded_spends: Vec<_> = tx
|
let shielded_spends: Vec<_> =
|
||||||
.spends
|
tx.spends
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(|(index, spend)| {
|
.filter_map(|(index, spend)| {
|
||||||
if nullifiers.contains(&&spend.nf[..]) {
|
if let Some(account) = nullifiers.iter().find_map(|&(nf, acc)| {
|
||||||
Some(WalletShieldedSpend {
|
if nf == &spend.nf[..] {
|
||||||
index,
|
Some(acc)
|
||||||
nf: spend.nf,
|
} else {
|
||||||
})
|
None
|
||||||
} else {
|
}
|
||||||
None
|
}) {
|
||||||
}
|
Some(WalletShieldedSpend {
|
||||||
})
|
index,
|
||||||
.collect();
|
nf: spend.nf,
|
||||||
|
account,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Collect the set of accounts that were spent from in this transaction
|
||||||
|
let spent_from_accounts: HashSet<_> =
|
||||||
|
shielded_spends.iter().map(|spend| spend.account).collect();
|
||||||
|
|
||||||
// Check for incoming notes while incrementing tree and witnesses
|
// Check for incoming notes while incrementing tree and witnesses
|
||||||
let mut shielded_outputs = vec![];
|
let mut shielded_outputs = vec![];
|
||||||
let mut new_witnesses = vec![];
|
let mut new_witnesses = vec![];
|
||||||
for to_scan in tx.outputs.into_iter().enumerate() {
|
for to_scan in tx.outputs.into_iter().enumerate() {
|
||||||
if let Some((output, new_witness)) =
|
if let Some((output, new_witness)) = scan_output(
|
||||||
scan_output(to_scan, &ivks, tree, existing_witnesses, &mut new_witnesses)
|
to_scan,
|
||||||
{
|
&ivks,
|
||||||
|
&spent_from_accounts,
|
||||||
|
tree,
|
||||||
|
existing_witnesses,
|
||||||
|
&mut new_witnesses,
|
||||||
|
) {
|
||||||
shielded_outputs.push(output);
|
shielded_outputs.push(output);
|
||||||
new_witnesses.push(new_witness);
|
new_witnesses.push(new_witness);
|
||||||
}
|
}
|
||||||
@ -292,12 +319,13 @@ mod tests {
|
|||||||
let extsk = ExtendedSpendingKey::master(&[]);
|
let extsk = ExtendedSpendingKey::master(&[]);
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
let nf = [7; 32];
|
let nf = [7; 32];
|
||||||
|
let account = 12;
|
||||||
|
|
||||||
let cb = fake_compact_block(1, nf, extfvk, Amount::from_u64(5).unwrap());
|
let cb = fake_compact_block(1, nf, extfvk, Amount::from_u64(5).unwrap());
|
||||||
assert_eq!(cb.vtx.len(), 2);
|
assert_eq!(cb.vtx.len(), 2);
|
||||||
|
|
||||||
let mut tree = CommitmentTree::new();
|
let mut tree = CommitmentTree::new();
|
||||||
let txs = scan_block(cb, &[], &[&nf], &mut tree, &mut []);
|
let txs = scan_block(cb, &[], &[(&nf, account)], &mut tree, &mut []);
|
||||||
assert_eq!(txs.len(), 1);
|
assert_eq!(txs.len(), 1);
|
||||||
|
|
||||||
let (tx, new_witnesses) = &txs[0];
|
let (tx, new_witnesses) = &txs[0];
|
||||||
@ -307,6 +335,7 @@ mod tests {
|
|||||||
assert_eq!(tx.shielded_outputs.len(), 0);
|
assert_eq!(tx.shielded_outputs.len(), 0);
|
||||||
assert_eq!(tx.shielded_spends[0].index, 0);
|
assert_eq!(tx.shielded_spends[0].index, 0);
|
||||||
assert_eq!(tx.shielded_spends[0].nf, nf);
|
assert_eq!(tx.shielded_spends[0].nf, nf);
|
||||||
|
assert_eq!(tx.shielded_spends[0].account, account);
|
||||||
assert_eq!(new_witnesses.len(), 0);
|
assert_eq!(new_witnesses.len(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user