Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zingo sync scan tx with ufvk #1343

Merged
merged 3 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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