Skip to content

Commit

Permalink
Merge pull request #1343 from Oscar-Pepper/zingo_sync_scan_tx_with_ufvk
Browse files Browse the repository at this point in the history
Zingo sync scan tx with ufvk
  • Loading branch information
zancas authored Nov 15, 2024
2 parents 5fcc974 + a0764fe commit 0fed8b8
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 85 deletions.
46 changes: 9 additions & 37 deletions zingo-sync/src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ pub trait ScanningKeyOps<D: Domain, Nf> {
/// IVK-based implementations of this trait cannot successfully derive
/// nullifiers, in which this function will always return `None`.
fn nf(&self, note: &D::Note, note_position: Position) -> Option<Nf>;

/// Returns the outgtoing viewing key
fn ovk(&self) -> D::OutgoingViewingKey;
}
impl<D: Domain, Nf, K: ScanningKeyOps<D, Nf>> ScanningKeyOps<D, Nf> for &K {
fn prepare(&self) -> D::IncomingViewingKey {
Expand All @@ -76,21 +73,16 @@ impl<D: Domain, Nf, K: ScanningKeyOps<D, Nf>> ScanningKeyOps<D, Nf> for &K {
fn nf(&self, note: &D::Note, note_position: Position) -> Option<Nf> {
(*self).nf(note, note_position)
}

fn ovk(&self) -> D::OutgoingViewingKey {
(*self).ovk()
}
}

pub(crate) struct ScanningKey<Ivk, Nk, Ovk> {
pub(crate) struct ScanningKey<Ivk, Nk> {
key_id: KeyId,
ivk: Ivk,
nk: Option<Nk>,
ovk: Ovk,
}

impl ScanningKeyOps<SaplingDomain, sapling::Nullifier>
for ScanningKey<SaplingIvk, NullifierDerivingKey, sapling::keys::OutgoingViewingKey>
for ScanningKey<SaplingIvk, NullifierDerivingKey>
{
fn prepare(&self) -> sapling::note_encryption::PreparedIncomingViewingKey {
sapling_crypto::note_encryption::PreparedIncomingViewingKey::new(&self.ivk)
Expand All @@ -100,10 +92,6 @@ impl ScanningKeyOps<SaplingDomain, sapling::Nullifier>
self.nk.as_ref().map(|key| note.nf(key, position.into()))
}

fn ovk(&self) -> <SaplingDomain as Domain>::OutgoingViewingKey {
self.ovk
}

fn account_id(&self) -> &zcash_primitives::zip32::AccountId {
&self.key_id.account_id
}
Expand All @@ -114,7 +102,7 @@ impl ScanningKeyOps<SaplingDomain, sapling::Nullifier>
}

impl ScanningKeyOps<OrchardDomain, orchard::note::Nullifier>
for ScanningKey<IncomingViewingKey, FullViewingKey, orchard::keys::OutgoingViewingKey>
for ScanningKey<IncomingViewingKey, FullViewingKey>
{
fn prepare(&self) -> orchard::keys::PreparedIncomingViewingKey {
orchard::keys::PreparedIncomingViewingKey::new(&self.ivk)
Expand All @@ -128,10 +116,6 @@ impl ScanningKeyOps<OrchardDomain, orchard::note::Nullifier>
self.nk.as_ref().map(|key| note.nullifier(key))
}

fn ovk(&self) -> <OrchardDomain as Domain>::OutgoingViewingKey {
self.ovk.clone()
}

fn account_id(&self) -> &zcash_primitives::zip32::AccountId {
&self.key_id.account_id
}
Expand All @@ -145,14 +129,8 @@ impl ScanningKeyOps<OrchardDomain, orchard::note::Nullifier>
#[derive(Getters)]
#[getset(get = "pub(crate)")]
pub(crate) struct ScanningKeys {
sapling: HashMap<
KeyId,
ScanningKey<SaplingIvk, NullifierDerivingKey, sapling::keys::OutgoingViewingKey>,
>,
orchard: HashMap<
KeyId,
ScanningKey<IncomingViewingKey, FullViewingKey, orchard::keys::OutgoingViewingKey>,
>,
sapling: HashMap<KeyId, ScanningKey<SaplingIvk, NullifierDerivingKey>>,
orchard: HashMap<KeyId, ScanningKey<IncomingViewingKey, FullViewingKey>>,
}

impl ScanningKeys {
Expand All @@ -163,14 +141,10 @@ impl ScanningKeys {
) -> Self {
#![allow(clippy::type_complexity)]

let mut sapling: HashMap<
KeyId,
ScanningKey<SaplingIvk, NullifierDerivingKey, sapling::keys::OutgoingViewingKey>,
> = HashMap::new();
let mut orchard: HashMap<
KeyId,
ScanningKey<IncomingViewingKey, FullViewingKey, orchard::keys::OutgoingViewingKey>,
> = HashMap::new();
let mut sapling: HashMap<KeyId, ScanningKey<SaplingIvk, NullifierDerivingKey>> =
HashMap::new();
let mut orchard: HashMap<KeyId, ScanningKey<IncomingViewingKey, FullViewingKey>> =
HashMap::new();

for (account_id, ufvk) in ufvks {
if let Some(dfvk) = ufvk.sapling() {
Expand All @@ -182,7 +156,6 @@ impl ScanningKeys {
key_id,
ivk: dfvk.to_ivk(scope),
nk: Some(dfvk.to_nk(scope)),
ovk: dfvk.to_ovk(scope),
},
);
}
Expand All @@ -197,7 +170,6 @@ impl ScanningKeys {
key_id,
ivk: fvk.to_ivk(scope),
nk: Some(fvk.clone()),
ovk: fvk.to_ovk(scope),
},
);
}
Expand Down
9 changes: 5 additions & 4 deletions zingo-sync/src/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ use tokio::sync::mpsc;

use incrementalmerkletree::Position;
use zcash_client_backend::{data_api::scanning::ScanRange, proto::compact_formats::CompactBlock};
use zcash_keys::keys::UnifiedFullViewingKey;
use zcash_primitives::{
consensus::{BlockHeight, NetworkUpgrade, Parameters},
transaction::TxId,
zip32::AccountId,
};

use crate::{
client::{self, FetchRequest},
keys::ScanningKeys,
primitives::{NullifierMap, OutputId, WalletBlock, WalletTransaction},
witness::ShardTreeData,
};
Expand Down Expand Up @@ -140,7 +141,7 @@ impl DecryptedNoteData {
pub(crate) async fn scan<P>(
fetch_request_sender: mpsc::UnboundedSender<FetchRequest>,
parameters: &P,
scanning_keys: &ScanningKeys,
ufvks: &HashMap<AccountId, UnifiedFullViewingKey>,
scan_range: ScanRange,
previous_wallet_block: Option<WalletBlock>,
) -> Result<ScanResults, ()>
Expand All @@ -166,7 +167,7 @@ where
.unwrap();

let scan_data =
scan_compact_blocks(compact_blocks, parameters, scanning_keys, initial_scan_data).unwrap();
scan_compact_blocks(compact_blocks, parameters, ufvks, initial_scan_data).unwrap();

let ScanData {
nullifiers,
Expand All @@ -179,7 +180,7 @@ where
let wallet_transactions = scan_transactions(
fetch_request_sender,
parameters,
scanning_keys,
ufvks,
relevant_txids,
decrypted_note_data,
&wallet_blocks,
Expand Down
7 changes: 5 additions & 2 deletions zingo-sync/src/scan/compact_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ use sapling_crypto::{note_encryption::CompactOutputDescription, Node};
use zcash_client_backend::proto::compact_formats::{
CompactBlock, CompactOrchardAction, CompactSaplingOutput, CompactTx,
};
use zcash_keys::keys::UnifiedFullViewingKey;
use zcash_note_encryption::Domain;
use zcash_primitives::{
block::BlockHash,
consensus::{BlockHeight, Parameters},
transaction::TxId,
zip32::AccountId,
};

use crate::{
Expand All @@ -28,15 +30,16 @@ mod runners;
pub(crate) fn scan_compact_blocks<P>(
compact_blocks: Vec<CompactBlock>,
parameters: &P,
scanning_keys: &ScanningKeys,
ufvks: &HashMap<AccountId, UnifiedFullViewingKey>,
initial_scan_data: InitialScanData,
) -> Result<ScanData, ()>
where
P: Parameters + Sync + Send + 'static,
{
check_continuity(&compact_blocks, initial_scan_data.previous_block.as_ref()).unwrap();

let mut runners = trial_decrypt(parameters, scanning_keys, &compact_blocks).unwrap();
let scanning_keys = ScanningKeys::from_account_ufvks(ufvks.clone());
let mut runners = trial_decrypt(parameters, &scanning_keys, &compact_blocks).unwrap();

let mut wallet_blocks: BTreeMap<BlockHeight, WalletBlock> = BTreeMap::new();
let mut nullifiers = NullifierMap::new();
Expand Down
9 changes: 4 additions & 5 deletions zingo-sync/src/scan/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use zcash_client_backend::data_api::scanning::ScanRange;
use zcash_keys::keys::UnifiedFullViewingKey;
use zcash_primitives::{consensus::Parameters, zip32::AccountId};

use crate::{client::FetchRequest, keys::ScanningKeys, primitives::WalletBlock};
use crate::{client::FetchRequest, primitives::WalletBlock};

use super::{scan, ScanResults};

Expand Down Expand Up @@ -107,7 +107,7 @@ struct ScanWorker<P> {
scan_results_sender: mpsc::UnboundedSender<(ScanRange, ScanResults)>,
fetch_request_sender: mpsc::UnboundedSender<FetchRequest>,
parameters: P,
scanning_keys: ScanningKeys,
ufvks: HashMap<AccountId, UnifiedFullViewingKey>,
}

impl<P> ScanWorker<P>
Expand All @@ -121,14 +121,13 @@ where
parameters: P,
ufvks: HashMap<AccountId, UnifiedFullViewingKey>,
) -> Self {
let scanning_keys = ScanningKeys::from_account_ufvks(ufvks);
Self {
is_scanning: Arc::new(AtomicBool::new(false)),
scan_task_receiver,
scan_results_sender,
fetch_request_sender,
parameters,
scanning_keys,
ufvks,
}
}

Expand All @@ -139,7 +138,7 @@ where
let scan_results = scan(
self.fetch_request_sender.clone(),
&self.parameters.clone(),
&self.scanning_keys,
&self.ufvks,
scan_task.scan_range.clone(),
scan_task.previous_wallet_block,
)
Expand Down
65 changes: 39 additions & 26 deletions zingo-sync/src/scan/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::collections::{BTreeMap, HashMap, HashSet};

use incrementalmerkletree::Position;
use orchard::{
keys::Scope,
note_encryption::OrchardDomain,
primitives::redpallas::{Signature, SpendAuth},
Action,
Expand All @@ -12,18 +13,21 @@ use sapling_crypto::{
};
use tokio::sync::mpsc;

use zcash_keys::{address::UnifiedAddress, encoding::encode_payment_address};
use zcash_keys::{
address::UnifiedAddress, encoding::encode_payment_address, keys::UnifiedFullViewingKey,
};
use zcash_note_encryption::{BatchDomain, Domain, ShieldedOutput, ENC_CIPHERTEXT_SIZE};
use zcash_primitives::{
consensus::{BlockHeight, NetworkConstants, Parameters},
memo::Memo,
transaction::{Transaction, TxId},
zip32::AccountId,
};
use zingo_memo::ParsedMemo;

use crate::{
client::{self, FetchRequest},
keys::{KeyId, ScanningKeyOps as _, ScanningKeys},
keys::KeyId,
primitives::{
OrchardNote, OutgoingNote, OutgoingOrchardNote, OutgoingSaplingNote, OutputId, SaplingNote,
SyncOutgoingNotes, WalletBlock, WalletNote, WalletTransaction,
Expand Down Expand Up @@ -62,7 +66,7 @@ impl<Proof> ShieldedOutputExt<SaplingDomain> for OutputDescription<Proof> {
pub(crate) async fn scan_transactions<P: Parameters>(
fetch_request_sender: mpsc::UnboundedSender<FetchRequest>,
parameters: &P,
scanning_keys: &ScanningKeys,
ufvks: &HashMap<AccountId, UnifiedFullViewingKey>,
relevant_txids: HashSet<TxId>,
decrypted_note_data: DecryptedNoteData,
wallet_blocks: &BTreeMap<BlockHeight, WalletBlock>,
Expand Down Expand Up @@ -90,7 +94,7 @@ pub(crate) async fn scan_transactions<P: Parameters>(

let wallet_transaction = scan_transaction(
parameters,
scanning_keys,
ufvks,
transaction,
block_height,
&decrypted_note_data,
Expand All @@ -104,7 +108,7 @@ pub(crate) async fn scan_transactions<P: Parameters>(

fn scan_transaction<P: Parameters>(
parameters: &P,
scanning_keys: &ScanningKeys,
ufvks: &HashMap<AccountId, UnifiedFullViewingKey>,
transaction: Transaction,
block_height: BlockHeight,
decrypted_note_data: &DecryptedNoteData,
Expand All @@ -120,6 +124,36 @@ fn scan_transaction<P: Parameters>(
let mut outgoing_orchard_notes: Vec<OutgoingOrchardNote> = Vec::new();
let mut encoded_memos = Vec::new();

let mut sapling_ivks = Vec::new();
let mut sapling_ovks = Vec::new();
let mut orchard_ivks = Vec::new();
let mut orchard_ovks = Vec::new();
for (account_id, ufvk) in ufvks {
if let Some(dfvk) = ufvk.sapling() {
for scope in [Scope::External, Scope::Internal] {
let key_id = KeyId::from_parts(*account_id, scope);
sapling_ivks.push((
key_id,
sapling_crypto::note_encryption::PreparedIncomingViewingKey::new(
&dfvk.to_ivk(scope),
),
));
sapling_ovks.push((key_id, dfvk.to_ovk(scope)));
}
}

if let Some(fvk) = ufvk.orchard() {
for scope in [Scope::External, Scope::Internal] {
let key_id = KeyId::from_parts(*account_id, scope);
orchard_ivks.push((
key_id,
orchard::keys::PreparedIncomingViewingKey::new(&fvk.to_ivk(scope)),
));
orchard_ovks.push((key_id, fvk.to_ovk(scope)));
}
}
}

// TODO: scan transparent bundle

if let Some(bundle) = transaction.sapling_bundle() {
Expand All @@ -129,12 +163,6 @@ fn scan_transaction<P: Parameters>(
.map(|output| (SaplingDomain::new(zip212_enforcement), output.clone()))
.collect();

let sapling_ivks: Vec<(KeyId, sapling_crypto::keys::PreparedIncomingViewingKey)> =
scanning_keys
.sapling()
.iter()
.map(|(key_id, key)| (*key_id, key.prepare()))
.collect();
scan_incoming_notes::<
SaplingDomain,
OutputDescription<GrothProofBytes>,
Expand All @@ -149,11 +177,6 @@ fn scan_transaction<P: Parameters>(
)
.unwrap();

let sapling_ovks: Vec<(KeyId, sapling_crypto::keys::OutgoingViewingKey)> = scanning_keys
.sapling()
.iter()
.map(|(key_id, key)| (*key_id, key.ovk()))
.collect();
scan_outgoing_notes(
&mut outgoing_sapling_notes,
transaction.txid(),
Expand All @@ -172,11 +195,6 @@ fn scan_transaction<P: Parameters>(
.map(|action| (OrchardDomain::for_action(action), action.clone()))
.collect();

let orchard_ivks: Vec<(KeyId, orchard::keys::PreparedIncomingViewingKey)> = scanning_keys
.orchard()
.iter()
.map(|(key_id, key)| (*key_id, key.prepare()))
.collect();
scan_incoming_notes::<
OrchardDomain,
Action<Signature<SpendAuth>>,
Expand All @@ -191,11 +209,6 @@ fn scan_transaction<P: Parameters>(
)
.unwrap();

let orchard_ovks: Vec<(KeyId, orchard::keys::OutgoingViewingKey)> = scanning_keys
.orchard()
.iter()
.map(|(key_id, key)| (*key_id, key.ovk()))
.collect();
scan_outgoing_notes(
&mut outgoing_orchard_notes,
transaction.txid(),
Expand Down
Loading

0 comments on commit 0fed8b8

Please sign in to comment.