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 outgoing data #1336

Merged
merged 7 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
47 changes: 37 additions & 10 deletions zingo-sync/src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ 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 @@ -53,17 +56,21 @@ 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> {
pub(crate) struct ScanningKey<Ivk, Nk, Ovk> {
key_id: KeyId,
ivk: Ivk,
// TODO: Ovk
nk: Option<Nk>,
ovk: Ovk,
}

impl ScanningKeyOps<SaplingDomain, sapling::Nullifier>
for ScanningKey<SaplingIvk, NullifierDerivingKey>
for ScanningKey<SaplingIvk, NullifierDerivingKey, sapling::keys::OutgoingViewingKey>
{
fn prepare(&self) -> sapling::note_encryption::PreparedIncomingViewingKey {
sapling_crypto::note_encryption::PreparedIncomingViewingKey::new(&self.ivk)
Expand All @@ -73,6 +80,10 @@ 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.0
}
Expand All @@ -83,7 +94,7 @@ impl ScanningKeyOps<SaplingDomain, sapling::Nullifier>
}

impl ScanningKeyOps<OrchardDomain, orchard::note::Nullifier>
for ScanningKey<IncomingViewingKey, FullViewingKey>
for ScanningKey<IncomingViewingKey, FullViewingKey, orchard::keys::OutgoingViewingKey>
{
fn prepare(&self) -> orchard::keys::PreparedIncomingViewingKey {
orchard::keys::PreparedIncomingViewingKey::new(&self.ivk)
Expand All @@ -97,6 +108,10 @@ 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.0
}
Expand All @@ -110,8 +125,14 @@ impl ScanningKeyOps<OrchardDomain, orchard::note::Nullifier>
#[derive(Getters)]
#[getset(get = "pub(crate)")]
pub(crate) struct ScanningKeys {
sapling: HashMap<KeyId, ScanningKey<SaplingIvk, NullifierDerivingKey>>,
orchard: HashMap<KeyId, ScanningKey<IncomingViewingKey, FullViewingKey>>,
sapling: HashMap<
KeyId,
ScanningKey<SaplingIvk, NullifierDerivingKey, sapling::keys::OutgoingViewingKey>,
>,
orchard: HashMap<
KeyId,
ScanningKey<IncomingViewingKey, FullViewingKey, orchard::keys::OutgoingViewingKey>,
>,
}

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

let mut sapling: HashMap<KeyId, ScanningKey<SaplingIvk, NullifierDerivingKey>> =
HashMap::new();
let mut orchard: HashMap<KeyId, ScanningKey<IncomingViewingKey, FullViewingKey>> =
HashMap::new();
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();

for (account_id, ufvk) in ufvks {
if let Some(dfvk) = ufvk.sapling() {
Expand All @@ -136,6 +161,7 @@ impl ScanningKeys {
key_id: (account_id, scope),
ivk: dfvk.to_ivk(scope),
nk: Some(dfvk.to_nk(scope)),
ovk: dfvk.to_ovk(scope),
},
);
}
Expand All @@ -149,6 +175,7 @@ impl ScanningKeys {
key_id: (account_id, scope),
ivk: fvk.to_ivk(scope),
nk: Some(fvk.clone()),
ovk: fvk.to_ovk(scope),
},
);
}
Expand Down
1 change: 1 addition & 0 deletions zingo-sync/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ pub mod primitives;
pub(crate) mod scan;
pub mod sync;
pub mod traits;
pub(crate) mod utils;
pub mod witness;
85 changes: 68 additions & 17 deletions zingo-sync/src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,16 @@ use std::collections::BTreeMap;
use getset::{CopyGetters, Getters, MutGetters};

use incrementalmerkletree::Position;
use zcash_client_backend::{data_api::scanning::ScanRange, PoolType};
use zcash_keys::address::UnifiedAddress;
use zcash_primitives::{block::BlockHash, consensus::BlockHeight, memo::Memo, transaction::TxId};
use zcash_client_backend::data_api::scanning::ScanRange;
use zcash_keys::{address::UnifiedAddress, encoding::encode_payment_address};
use zcash_primitives::{
block::BlockHash,
consensus::{BlockHeight, NetworkConstants, Parameters},
memo::Memo,
transaction::TxId,
};

use crate::utils;

/// Encapsulates the current state of sync
#[derive(Debug, Getters, MutGetters)]
Expand Down Expand Up @@ -247,18 +254,62 @@ pub(crate) trait SyncNote {
fn memo(&self) -> &Self::Memo;
}

#[derive(Debug, Clone)]
pub struct OutgoingData {
/// ID of output sent from this capability to the recipient address
pub output_id: OutputId,
/// Pool of output sent from this capability to the recipient address
pub pool: PoolType, // TODO: consider moving pooltype back into output id
/// Recipient address that was sent to from this capability
pub recipient_address: String,
/// Full unified address encoded in change memo
pub recipient_ua: Option<UnifiedAddress>,
/// Amount of funds sent to recipient address
pub value: u64,
/// Memo sent to recipient address
pub memo: Memo,
/// Note sent from this capability to a recipient
#[derive(Debug, Clone, Getters, CopyGetters, MutGetters)]
pub struct OutgoingNote<N> {
/// Output ID
#[getset(get_copy = "pub")]
output_id: OutputId,
/// Decrypted note with recipient and value
#[getset(get = "pub")]
note: N,
/// Memo
#[getset(get = "pub")]
memo: Memo,
/// Recipient's full unified address from encoded memo
#[getset(get = "pub", get_mut = "pub")]
recipient_ua: Option<UnifiedAddress>,
}

impl<N> OutgoingNote<N> {
pub fn from_parts(
output_id: OutputId,
note: N,
memo: Memo,
recipient_ua: Option<UnifiedAddress>,
) -> Self {
Self {
output_id,
note,
memo,
recipient_ua,
}
}
}

impl SyncOutgoingNotes for OutgoingNote<sapling_crypto::Note> {
fn encoded_recipient<P>(&self, parameters: &P) -> String
where
P: Parameters + NetworkConstants,
{
encode_payment_address(
parameters.hrp_sapling_payment_address(),
&self.note().recipient(),
)
}
}

impl SyncOutgoingNotes for OutgoingNote<orchard::Note> {
fn encoded_recipient<P>(&self, parameters: &P) -> String
where
P: Parameters + NetworkConstants,
{
utils::encode_orchard_receiver(parameters, &self.note().recipient()).unwrap()
}
}

pub(crate) trait SyncOutgoingNotes {
fn encoded_recipient<P>(&self, parameters: &P) -> String
where
P: Parameters + NetworkConstants;
}
17 changes: 5 additions & 12 deletions zingo-sync/src/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,12 @@ impl InitialScanData {
}
}

#[allow(dead_code)]
struct ScanData {
pub(crate) nullifiers: NullifierMap,
pub(crate) wallet_blocks: BTreeMap<BlockHeight, WalletBlock>,
pub(crate) relevant_txids: HashSet<TxId>,
pub(crate) decrypted_note_data: DecryptedNoteData,
pub(crate) shard_tree_data: ShardTreeData,
nullifiers: NullifierMap,
wallet_blocks: BTreeMap<BlockHeight, WalletBlock>,
relevant_txids: HashSet<TxId>,
decrypted_note_data: DecryptedNoteData,
shard_tree_data: ShardTreeData,
}

pub(crate) struct ScanResults {
Expand All @@ -136,12 +135,6 @@ impl DecryptedNoteData {
}
}

impl Default for DecryptedNoteData {
fn default() -> Self {
Self::new()
}
}

// scans a given range and returns all data relevant to the specified keys
// `previous_wallet_block` is the wallet block with height [scan_range.start - 1]
pub(crate) async fn scan<P>(
Expand Down
Loading