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

Add UnifiedIncomingViewingKey struct #1245

Merged
merged 11 commits into from
Mar 18, 2024
50 changes: 17 additions & 33 deletions zcash_client_sqlite/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,10 @@
use std::num::NonZeroU32;
use std::ops::RangeInclusive;
use tracing::debug;
use zcash_address::unified::{Encoding, Ivk, Uivk};
use zcash_keys::keys::{AddressGenerationError, HdSeedFingerprint, UnifiedAddressRequest};
use zcash_address::unified::{Encoding, Uivk};
use zcash_keys::keys::{
AddressGenerationError, HdSeedFingerprint, UnifiedAddressRequest, UnifiedIncomingViewingKey,
};

use zcash_client_backend::{
address::{Address, UnifiedAddress},
Expand Down Expand Up @@ -118,6 +120,7 @@
crate::UtxoId,
rusqlite::Row,
std::collections::BTreeSet,
zcash_address::unified::Ivk,
zcash_client_backend::wallet::{TransparentAddressMetadata, WalletTransparentOutput},
zcash_primitives::{
legacy::{
Expand Down Expand Up @@ -182,7 +185,7 @@
///
/// Accounts that have this kind of viewing key cannot be used in wallet contexts,
/// because they are unable to maintain an accurate balance.
Incoming(Uivk),
Incoming(Box<UnifiedIncomingViewingKey>),
}

/// An account stored in a `zcash_client_sqlite` database.
Expand Down Expand Up @@ -232,10 +235,12 @@
}
}
AArnott marked this conversation as resolved.
Show resolved Hide resolved

fn uivk_str(&self, params: &impl Parameters) -> Result<String, SqliteClientError> {
fn uivk(&self) -> Result<UnifiedIncomingViewingKey, SqliteClientError> {
match self {
ViewingKey::Full(ufvk) => ufvk_to_uivk(ufvk, params),
ViewingKey::Incoming(uivk) => Ok(uivk.encode(&params.network_type())),
ViewingKey::Full(ufvk) => Ok(ufvk
.to_unified_incoming_viewing_key()
.map_err(|e| SqliteClientError::CorruptedData(e.to_string()))?),
ViewingKey::Incoming(uivk) => Ok((**uivk).to_owned()),

Check warning on line 243 in zcash_client_sqlite/src/wallet.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet.rs#L243

Added line #L243 was not covered by tests
}
}
}
Expand Down Expand Up @@ -295,31 +300,6 @@
)
}

pub(crate) fn ufvk_to_uivk<P: consensus::Parameters>(
ufvk: &UnifiedFullViewingKey,
params: &P,
) -> Result<String, SqliteClientError> {
let mut ivks: Vec<Ivk> = Vec::new();
if let Some(orchard) = ufvk.orchard() {
ivks.push(Ivk::Orchard(orchard.to_ivk(Scope::External).to_bytes()));
}
if let Some(sapling) = ufvk.sapling() {
let ivk = sapling.to_external_ivk();
ivks.push(Ivk::Sapling(ivk.to_bytes()));
}
#[cfg(feature = "transparent-inputs")]
if let Some(tfvk) = ufvk.transparent() {
let tivk = tfvk.derive_external_ivk()?;
ivks.push(Ivk::P2pkh(tivk.serialize().try_into().map_err(|_| {
SqliteClientError::BadAccountData("Unable to serialize transparent IVK.".to_string())
})?));
}

let uivk = zcash_address::unified::Uivk::try_from_items(ivks)
.map_err(|e| SqliteClientError::BadAccountData(format!("Unable to derive UIVK: {}", e)))?;
Ok(uivk.encode(&params.network_type()))
}

pub(crate) fn add_account<P: consensus::Parameters>(
conn: &rusqlite::Transaction,
params: &P,
Expand Down Expand Up @@ -369,7 +349,7 @@
":hd_seed_fingerprint": hd_seed_fingerprint.as_ref().map(|fp| fp.as_bytes()),
":hd_account_index": hd_account_index.map(u32::from),
":ufvk": viewing_key.ufvk().map(|ufvk| ufvk.encode(params)),
":uivk": viewing_key.uivk_str(params)?,
":uivk": viewing_key.uivk()?.to_uivk().encode(&params.network_type()),
":orchard_fvk_item_cache": orchard_item,
":sapling_fvk_item_cache": sapling_item,
":p2pkh_fvk_item_cache": transparent_item,
Expand Down Expand Up @@ -1533,7 +1513,11 @@
"UIVK network type does not match wallet network type".to_string(),
));
}
ViewingKey::Incoming(uivk)
ViewingKey::Incoming(Box::new(
UnifiedIncomingViewingKey::from_uivk(&uivk).map_err(|e| {
SqliteClientError::CorruptedData(format!("Failure to decode UIVK: {e}"))

Check warning on line 1518 in zcash_client_sqlite/src/wallet.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet.rs#L1516-L1518

Added lines #L1516 - L1518 were not covered by tests
})?,
))
};

Ok(Some(Account {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::{collections::HashSet, rc::Rc};

use crate::wallet::{account_kind_code, init::WalletMigrationError, ufvk_to_uivk};
use crate::wallet::{account_kind_code, init::WalletMigrationError};
use rusqlite::{named_params, Transaction};
use schemer_rusqlite::RusqliteMigration;
use secrecy::{ExposeSecret, SecretVec};
use uuid::Uuid;
use zcash_address::unified::Encoding;
use zcash_client_backend::{data_api::AccountKind, keys::UnifiedSpendingKey};
use zcash_keys::keys::{HdSeedFingerprint, UnifiedFullViewingKey};
use zcash_primitives::consensus;
Expand Down Expand Up @@ -119,8 +120,11 @@ impl<P: consensus::Parameters> RusqliteMigration for Migration<P> {
));
}

let uivk = ufvk_to_uivk(&ufvk_parsed, &self.params)
.map_err(|e| WalletMigrationError::CorruptedData(e.to_string()))?;
let uivk = ufvk_parsed
.to_unified_incoming_viewing_key()
.map_err(|e| WalletMigrationError::CorruptedData(e.to_string()))?
.to_uivk()
.encode(&self.params.network_type());

#[cfg(feature = "transparent-inputs")]
let transparent_item = ufvk_parsed.transparent().map(|k| k.serialize());
Expand Down
11 changes: 9 additions & 2 deletions zcash_keys/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,20 @@ and this library adheres to Rust's notion of
- `zcash_keys::address::Address::has_receiver`
- `impl Display for zcash_keys::keys::AddressGenerationError`
- `impl std::error::Error for zcash_keys::keys::AddressGenerationError`
- `zcash_keys::keys::DecodingError`
- `zcash_keys::keys::UnifiedFullViewingKey::from_ufvk`
- `zcash_keys::keys::UnifiedFullViewingKey::to_ufvk`
- `zcash_keys::keys::UnifiedFullViewingKey::to_unified_incoming_viewing_key`
- `zcash_keys::keys::UnifiedIncomingViewingKey`

### Changed
- `zcash_keys::keys::AddressGenerationError` has a new variant
`DiversifierSpaceExhausted`.
- `zcash_keys::keys::UnifiedFullViewingKey::{find_address, default_address}`
now return `Result<(UnifiedAddress, DiversifierIndex), AddressGenerationError>`
(instead of `Option<(UnifiedAddress, DiversifierIndex)>` for `find_address`).
- `zcash_keys::keys::AddressGenerationError`
- Dropped `Clone` trait
- Added `KeyDecoding` variant.
- Added `DiversifierSpaceExhausted` variant.

### Fixed
- `UnifiedFullViewingKey::find_address` can now find an address for a diversifier
Expand Down
Loading
Loading