zcash_keys: Verify the ability to derive addresses at USK and UFVK construction.
This commit is contained in:
parent
9d6a8b6941
commit
4d9927b993
|
@ -235,12 +235,10 @@ impl ViewingKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uivk(&self) -> Result<UnifiedIncomingViewingKey, SqliteClientError> {
|
fn uivk(&self) -> UnifiedIncomingViewingKey {
|
||||||
match self {
|
match self {
|
||||||
ViewingKey::Full(ufvk) => Ok(ufvk
|
ViewingKey::Full(ufvk) => ufvk.as_ref().to_unified_incoming_viewing_key(),
|
||||||
.to_unified_incoming_viewing_key()
|
ViewingKey::Incoming(uivk) => uivk.as_ref().clone(),
|
||||||
.map_err(|e| SqliteClientError::CorruptedData(e.to_string()))?),
|
|
||||||
ViewingKey::Incoming(uivk) => Ok((**uivk).to_owned()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -349,7 +347,7 @@ pub(crate) fn add_account<P: consensus::Parameters>(
|
||||||
":hd_seed_fingerprint": hd_seed_fingerprint.as_ref().map(|fp| fp.as_bytes()),
|
":hd_seed_fingerprint": hd_seed_fingerprint.as_ref().map(|fp| fp.as_bytes()),
|
||||||
":hd_account_index": hd_account_index.map(u32::from),
|
":hd_account_index": hd_account_index.map(u32::from),
|
||||||
":ufvk": viewing_key.ufvk().map(|ufvk| ufvk.encode(params)),
|
":ufvk": viewing_key.ufvk().map(|ufvk| ufvk.encode(params)),
|
||||||
":uivk": viewing_key.uivk()?.to_uivk().encode(¶ms.network_type()),
|
":uivk": viewing_key.uivk().to_uivk().encode(¶ms.network_type()),
|
||||||
":orchard_fvk_item_cache": orchard_item,
|
":orchard_fvk_item_cache": orchard_item,
|
||||||
":sapling_fvk_item_cache": sapling_item,
|
":sapling_fvk_item_cache": sapling_item,
|
||||||
":p2pkh_fvk_item_cache": transparent_item,
|
":p2pkh_fvk_item_cache": transparent_item,
|
||||||
|
|
|
@ -122,7 +122,6 @@ impl<P: consensus::Parameters> RusqliteMigration for Migration<P> {
|
||||||
|
|
||||||
let uivk = ufvk_parsed
|
let uivk = ufvk_parsed
|
||||||
.to_unified_incoming_viewing_key()
|
.to_unified_incoming_viewing_key()
|
||||||
.map_err(|e| WalletMigrationError::CorruptedData(e.to_string()))?
|
|
||||||
.to_uivk()
|
.to_uivk()
|
||||||
.encode(&self.params.network_type());
|
.encode(&self.params.network_type());
|
||||||
|
|
||||||
|
|
|
@ -22,10 +22,13 @@ and this library adheres to Rust's notion of
|
||||||
now return `Result<(UnifiedAddress, DiversifierIndex), AddressGenerationError>`
|
now return `Result<(UnifiedAddress, DiversifierIndex), AddressGenerationError>`
|
||||||
(instead of `Option<(UnifiedAddress, DiversifierIndex)>` for `find_address`).
|
(instead of `Option<(UnifiedAddress, DiversifierIndex)>` for `find_address`).
|
||||||
- `zcash_keys::keys::AddressGenerationError`
|
- `zcash_keys::keys::AddressGenerationError`
|
||||||
- Dropped `Clone` trait
|
|
||||||
- Added `KeyDecoding` variant.
|
|
||||||
- Added `DiversifierSpaceExhausted` variant.
|
- Added `DiversifierSpaceExhausted` variant.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- `UnifiedFullViewingKey::new` has been placed behind the `test-dependencies`
|
||||||
|
feature flag. UFVKs should only be produced by derivation from the USK, or
|
||||||
|
parsed from their string representation.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- `UnifiedFullViewingKey::find_address` can now find an address for a diversifier
|
- `UnifiedFullViewingKey::find_address` can now find an address for a diversifier
|
||||||
index outside the valid transparent range if you aren't requesting a
|
index outside the valid transparent range if you aren't requesting a
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use zcash_address::unified::{self, Container, Encoding, Typecode, Ufvk, Uivk};
|
use zcash_address::unified::{self, Container, Encoding, Typecode, Ufvk, Uivk};
|
||||||
use zcash_protocol::consensus;
|
use zcash_protocol::consensus::{self, NetworkConstants};
|
||||||
use zip32::{AccountId, DiversifierIndex};
|
use zip32::{AccountId, DiversifierIndex};
|
||||||
|
|
||||||
use crate::address::UnifiedAddress;
|
use crate::address::UnifiedAddress;
|
||||||
|
@ -18,10 +18,6 @@ use {
|
||||||
zcash_primitives::legacy::keys::{self as legacy, IncomingViewingKey, NonHardenedChildIndex},
|
zcash_primitives::legacy::keys::{self as legacy, IncomingViewingKey, NonHardenedChildIndex},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(any(feature = "sapling", feature = "orchard"))]
|
|
||||||
// Your code here
|
|
||||||
use zcash_protocol::consensus::NetworkConstants;
|
|
||||||
|
|
||||||
#[cfg(all(
|
#[cfg(all(
|
||||||
feature = "transparent-inputs",
|
feature = "transparent-inputs",
|
||||||
any(test, feature = "test-dependencies")
|
any(test, feature = "test-dependencies")
|
||||||
|
@ -264,19 +260,37 @@ impl UnifiedSpendingKey {
|
||||||
panic!("ZIP 32 seeds MUST be at least 32 bytes");
|
panic!("ZIP 32 seeds MUST be at least 32 bytes");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(UnifiedSpendingKey {
|
UnifiedSpendingKey::from_checked_parts(
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
transparent: legacy::AccountPrivKey::from_seed(_params, seed, _account)
|
legacy::AccountPrivKey::from_seed(_params, seed, _account)
|
||||||
.map_err(DerivationError::Transparent)?,
|
.map_err(DerivationError::Transparent)?,
|
||||||
#[cfg(feature = "sapling")]
|
#[cfg(feature = "sapling")]
|
||||||
sapling: sapling::spending_key(seed, _params.coin_type(), _account),
|
sapling::spending_key(seed, _params.coin_type(), _account),
|
||||||
#[cfg(feature = "orchard")]
|
#[cfg(feature = "orchard")]
|
||||||
orchard: orchard::keys::SpendingKey::from_zip32_seed(
|
orchard::keys::SpendingKey::from_zip32_seed(seed, _params.coin_type(), _account)
|
||||||
seed,
|
.map_err(DerivationError::Orchard)?,
|
||||||
_params.coin_type(),
|
)
|
||||||
_account,
|
}
|
||||||
)
|
|
||||||
.map_err(DerivationError::Orchard)?,
|
/// Construct a USK from its constituent parts, after verifying that UIVK derivation can
|
||||||
|
/// succeed.
|
||||||
|
fn from_checked_parts(
|
||||||
|
#[cfg(feature = "transparent-inputs")] transparent: legacy::AccountPrivKey,
|
||||||
|
#[cfg(feature = "sapling")] sapling: sapling::ExtendedSpendingKey,
|
||||||
|
#[cfg(feature = "orchard")] orchard: orchard::keys::SpendingKey,
|
||||||
|
) -> Result<UnifiedSpendingKey, DerivationError> {
|
||||||
|
// Verify that FVK and IVK derivation succeed; we don't want to construct a USK
|
||||||
|
// that can't derive transparent addresses.
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
let _ = transparent.to_account_pubkey().derive_external_ivk()?;
|
||||||
|
|
||||||
|
Ok(UnifiedSpendingKey {
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
transparent,
|
||||||
|
#[cfg(feature = "sapling")]
|
||||||
|
sapling,
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
orchard,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,14 +480,15 @@ impl UnifiedSpendingKey {
|
||||||
let has_transparent = true;
|
let has_transparent = true;
|
||||||
|
|
||||||
if has_orchard && has_sapling && has_transparent {
|
if has_orchard && has_sapling && has_transparent {
|
||||||
return Ok(UnifiedSpendingKey {
|
return UnifiedSpendingKey::from_checked_parts(
|
||||||
#[cfg(feature = "orchard")]
|
|
||||||
orchard: orchard.unwrap(),
|
|
||||||
#[cfg(feature = "sapling")]
|
|
||||||
sapling: sapling.unwrap(),
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
transparent: transparent.unwrap(),
|
transparent.unwrap(),
|
||||||
});
|
#[cfg(feature = "sapling")]
|
||||||
|
sapling.unwrap(),
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
orchard.unwrap(),
|
||||||
|
)
|
||||||
|
.map_err(|_| DecodingError::KeyDataInvalid(Typecode::P2pkh));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -502,7 +517,7 @@ impl UnifiedSpendingKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors that can occur in the generation of unified addresses.
|
/// Errors that can occur in the generation of unified addresses.
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum AddressGenerationError {
|
pub enum AddressGenerationError {
|
||||||
/// The requested diversifier index was outside the range of valid transparent
|
/// The requested diversifier index was outside the range of valid transparent
|
||||||
/// child address indices.
|
/// child address indices.
|
||||||
|
@ -522,29 +537,6 @@ pub enum AddressGenerationError {
|
||||||
/// A Unified address cannot be generated without at least one shielded receiver being
|
/// A Unified address cannot be generated without at least one shielded receiver being
|
||||||
/// included.
|
/// included.
|
||||||
ShieldedReceiverRequired,
|
ShieldedReceiverRequired,
|
||||||
/// An error occurred while deriving a key or address from an HD wallet.
|
|
||||||
Derivation(DerivationError),
|
|
||||||
/// An error occurred while decoding a key from its encoded representation.
|
|
||||||
KeyDecoding(DecodingError),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
|
||||||
impl From<hdwallet::error::Error> for AddressGenerationError {
|
|
||||||
fn from(e: hdwallet::error::Error) -> Self {
|
|
||||||
AddressGenerationError::Derivation(DerivationError::Transparent(e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<DerivationError> for AddressGenerationError {
|
|
||||||
fn from(e: DerivationError) -> Self {
|
|
||||||
AddressGenerationError::Derivation(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<DecodingError> for AddressGenerationError {
|
|
||||||
fn from(e: DecodingError) -> Self {
|
|
||||||
AddressGenerationError::KeyDecoding(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for AddressGenerationError {
|
impl fmt::Display for AddressGenerationError {
|
||||||
|
@ -589,12 +581,6 @@ impl fmt::Display for AddressGenerationError {
|
||||||
AddressGenerationError::ShieldedReceiverRequired => {
|
AddressGenerationError::ShieldedReceiverRequired => {
|
||||||
write!(f, "A Unified Address requires at least one shielded (Sapling or Orchard) receiver.")
|
write!(f, "A Unified Address requires at least one shielded (Sapling or Orchard) receiver.")
|
||||||
}
|
}
|
||||||
AddressGenerationError::Derivation(e) => write!(f, "Error deriving address: {}", e),
|
|
||||||
AddressGenerationError::KeyDecoding(e) => write!(
|
|
||||||
f,
|
|
||||||
"Error decoding key from its serialized representation: {}.",
|
|
||||||
e
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -682,37 +668,56 @@ pub struct UnifiedFullViewingKey {
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
impl UnifiedFullViewingKey {
|
impl UnifiedFullViewingKey {
|
||||||
/// Construct a new unified full viewing key, if the required components are present.
|
/// Construct a new unified full viewing key.
|
||||||
|
///
|
||||||
|
/// This method is only available when the `test-dependencies` feature is enabled,
|
||||||
|
/// as derivation from the USK or deserialization from the serialized form should
|
||||||
|
/// be used instead.
|
||||||
|
#[cfg(any(test, feature = "test-dependencies"))]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
#[cfg(feature = "transparent-inputs")] transparent: Option<legacy::AccountPubKey>,
|
#[cfg(feature = "transparent-inputs")] transparent: Option<legacy::AccountPubKey>,
|
||||||
#[cfg(feature = "sapling")] sapling: Option<sapling::DiversifiableFullViewingKey>,
|
#[cfg(feature = "sapling")] sapling: Option<sapling::DiversifiableFullViewingKey>,
|
||||||
#[cfg(feature = "orchard")] orchard: Option<orchard::keys::FullViewingKey>,
|
#[cfg(feature = "orchard")] orchard: Option<orchard::keys::FullViewingKey>,
|
||||||
// TODO: Implement construction of UFVKs with metadata items.
|
// TODO: Implement construction of UFVKs with metadata items.
|
||||||
) -> Option<UnifiedFullViewingKey> {
|
) -> Result<UnifiedFullViewingKey, DerivationError> {
|
||||||
#[cfg(feature = "orchard")]
|
Self::from_checked_parts(
|
||||||
let has_orchard = orchard.is_some();
|
#[cfg(feature = "transparent-inputs")]
|
||||||
#[cfg(not(feature = "orchard"))]
|
transparent,
|
||||||
let has_orchard = false;
|
#[cfg(feature = "sapling")]
|
||||||
#[cfg(feature = "sapling")]
|
sapling,
|
||||||
let has_sapling = sapling.is_some();
|
#[cfg(feature = "orchard")]
|
||||||
#[cfg(not(feature = "sapling"))]
|
orchard,
|
||||||
let has_sapling = false;
|
// We don't currently allow constructing new UFVKs with unknown items, but we store
|
||||||
|
// this to allow parsing such UFVKs.
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if has_orchard || has_sapling {
|
/// Construct a UFVK from its constituent parts, after verifying that UIVK derivation can
|
||||||
Some(UnifiedFullViewingKey {
|
/// succeed.
|
||||||
#[cfg(feature = "transparent-inputs")]
|
fn from_checked_parts(
|
||||||
transparent,
|
#[cfg(feature = "transparent-inputs")] transparent: Option<legacy::AccountPubKey>,
|
||||||
#[cfg(feature = "sapling")]
|
#[cfg(feature = "sapling")] sapling: Option<sapling::DiversifiableFullViewingKey>,
|
||||||
sapling,
|
#[cfg(feature = "orchard")] orchard: Option<orchard::keys::FullViewingKey>,
|
||||||
#[cfg(feature = "orchard")]
|
unknown: Vec<(u32, Vec<u8>)>,
|
||||||
orchard,
|
) -> Result<UnifiedFullViewingKey, DerivationError> {
|
||||||
// We don't allow constructing new UFVKs with unknown items, but we store
|
// Verify that IVK derivation succeeds; we don't want to construct a UFVK
|
||||||
// this to allow parsing such UFVKs.
|
// that can't derive transparent addresses.
|
||||||
unknown: vec![],
|
#[cfg(feature = "transparent-inputs")]
|
||||||
})
|
let _ = transparent
|
||||||
} else {
|
.as_ref()
|
||||||
None
|
.map(|t| t.derive_external_ivk())
|
||||||
}
|
.transpose()?;
|
||||||
|
|
||||||
|
Ok(UnifiedFullViewingKey {
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
transparent,
|
||||||
|
#[cfg(feature = "sapling")]
|
||||||
|
sapling,
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
orchard,
|
||||||
|
unknown,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a `UnifiedFullViewingKey` from its [ZIP 316] string encoding.
|
/// Parses a `UnifiedFullViewingKey` from its [ZIP 316] string encoding.
|
||||||
|
@ -793,7 +798,7 @@ impl UnifiedFullViewingKey {
|
||||||
})
|
})
|
||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
Ok(Self {
|
Self::from_checked_parts(
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
transparent,
|
transparent,
|
||||||
#[cfg(feature = "sapling")]
|
#[cfg(feature = "sapling")]
|
||||||
|
@ -801,7 +806,8 @@ impl UnifiedFullViewingKey {
|
||||||
#[cfg(feature = "orchard")]
|
#[cfg(feature = "orchard")]
|
||||||
orchard,
|
orchard,
|
||||||
unknown,
|
unknown,
|
||||||
})
|
)
|
||||||
|
.map_err(|_| DecodingError::KeyDataInvalid(Typecode::P2pkh))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the string encoding of this `UnifiedFullViewingKey` for the given network.
|
/// Returns the string encoding of this `UnifiedFullViewingKey` for the given network.
|
||||||
|
@ -844,22 +850,19 @@ impl UnifiedFullViewingKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Derives a Unified Incoming Viewing Key from this Unified Full Viewing Key.
|
/// Derives a Unified Incoming Viewing Key from this Unified Full Viewing Key.
|
||||||
pub fn to_unified_incoming_viewing_key(
|
pub fn to_unified_incoming_viewing_key(&self) -> UnifiedIncomingViewingKey {
|
||||||
&self,
|
UnifiedIncomingViewingKey {
|
||||||
) -> Result<UnifiedIncomingViewingKey, DerivationError> {
|
|
||||||
Ok(UnifiedIncomingViewingKey {
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
transparent: self
|
transparent: self.transparent.as_ref().map(|t| {
|
||||||
.transparent
|
t.derive_external_ivk()
|
||||||
.as_ref()
|
.expect("Transparent IVK derivation was checked at construction.")
|
||||||
.map(|t| t.derive_external_ivk())
|
}),
|
||||||
.transpose()?,
|
|
||||||
#[cfg(feature = "sapling")]
|
#[cfg(feature = "sapling")]
|
||||||
sapling: self.sapling.as_ref().map(|s| s.to_external_ivk()),
|
sapling: self.sapling.as_ref().map(|s| s.to_external_ivk()),
|
||||||
#[cfg(feature = "orchard")]
|
#[cfg(feature = "orchard")]
|
||||||
orchard: self.orchard.as_ref().map(|o| o.to_ivk(Scope::External)),
|
orchard: self.orchard.as_ref().map(|o| o.to_ivk(Scope::External)),
|
||||||
unknown: Vec::new(),
|
unknown: Vec::new(),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the transparent component of the unified key at the
|
/// Returns the transparent component of the unified key at the
|
||||||
|
@ -890,7 +893,7 @@ impl UnifiedFullViewingKey {
|
||||||
j: DiversifierIndex,
|
j: DiversifierIndex,
|
||||||
request: UnifiedAddressRequest,
|
request: UnifiedAddressRequest,
|
||||||
) -> Result<UnifiedAddress, AddressGenerationError> {
|
) -> Result<UnifiedAddress, AddressGenerationError> {
|
||||||
self.to_unified_incoming_viewing_key()?.address(j, request)
|
self.to_unified_incoming_viewing_key().address(j, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Searches the diversifier space starting at diversifier index `j` for one which will
|
/// Searches the diversifier space starting at diversifier index `j` for one which will
|
||||||
|
@ -905,7 +908,7 @@ impl UnifiedFullViewingKey {
|
||||||
mut j: DiversifierIndex,
|
mut j: DiversifierIndex,
|
||||||
request: UnifiedAddressRequest,
|
request: UnifiedAddressRequest,
|
||||||
) -> Result<(UnifiedAddress, DiversifierIndex), AddressGenerationError> {
|
) -> Result<(UnifiedAddress, DiversifierIndex), AddressGenerationError> {
|
||||||
self.to_unified_incoming_viewing_key()?
|
self.to_unified_incoming_viewing_key()
|
||||||
.find_address(j, request)
|
.find_address(j, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -936,7 +939,12 @@ pub struct UnifiedIncomingViewingKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnifiedIncomingViewingKey {
|
impl UnifiedIncomingViewingKey {
|
||||||
/// Construct a new unified incoming viewing key, if the required components are present.
|
/// Construct a new unified incoming viewing key.
|
||||||
|
///
|
||||||
|
/// This method is only available when the `test-dependencies` feature is enabled,
|
||||||
|
/// as derivation from the UFVK or deserialization from the serialized form should
|
||||||
|
/// be used instead.
|
||||||
|
#[cfg(any(test, feature = "test-dependencies"))]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
#[cfg(feature = "transparent-inputs")] transparent: Option<
|
#[cfg(feature = "transparent-inputs")] transparent: Option<
|
||||||
zcash_primitives::legacy::keys::ExternalIvk,
|
zcash_primitives::legacy::keys::ExternalIvk,
|
||||||
|
@ -944,30 +952,17 @@ impl UnifiedIncomingViewingKey {
|
||||||
#[cfg(feature = "sapling")] sapling: Option<::sapling::zip32::IncomingViewingKey>,
|
#[cfg(feature = "sapling")] sapling: Option<::sapling::zip32::IncomingViewingKey>,
|
||||||
#[cfg(feature = "orchard")] orchard: Option<orchard::keys::IncomingViewingKey>,
|
#[cfg(feature = "orchard")] orchard: Option<orchard::keys::IncomingViewingKey>,
|
||||||
// TODO: Implement construction of UIVKs with metadata items.
|
// TODO: Implement construction of UIVKs with metadata items.
|
||||||
) -> Option<UnifiedIncomingViewingKey> {
|
) -> UnifiedIncomingViewingKey {
|
||||||
#[cfg(feature = "orchard")]
|
UnifiedIncomingViewingKey {
|
||||||
let has_orchard = orchard.is_some();
|
#[cfg(feature = "transparent-inputs")]
|
||||||
#[cfg(not(feature = "orchard"))]
|
transparent,
|
||||||
let has_orchard = false;
|
#[cfg(feature = "sapling")]
|
||||||
#[cfg(feature = "sapling")]
|
sapling,
|
||||||
let has_sapling = sapling.is_some();
|
#[cfg(feature = "orchard")]
|
||||||
#[cfg(not(feature = "sapling"))]
|
orchard,
|
||||||
let has_sapling = false;
|
// We don't allow constructing new UFVKs with unknown items, but we store
|
||||||
|
// this to allow parsing such UFVKs.
|
||||||
if has_orchard || has_sapling {
|
unknown: vec![],
|
||||||
Some(UnifiedIncomingViewingKey {
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
|
||||||
transparent,
|
|
||||||
#[cfg(feature = "sapling")]
|
|
||||||
sapling,
|
|
||||||
#[cfg(feature = "orchard")]
|
|
||||||
orchard,
|
|
||||||
// We don't allow constructing new UFVKs with unknown items, but we store
|
|
||||||
// this to allow parsing such UFVKs.
|
|
||||||
unknown: vec![],
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1543,7 +1538,6 @@ mod tests {
|
||||||
|
|
||||||
#[cfg(any(feature = "orchard", feature = "sapling"))]
|
#[cfg(any(feature = "orchard", feature = "sapling"))]
|
||||||
{
|
{
|
||||||
let uivk = uivk.expect("Orchard or Sapling ivk is present.");
|
|
||||||
let encoded = uivk.to_uivk().encode(&NetworkType::Main);
|
let encoded = uivk.to_uivk().encode(&NetworkType::Main);
|
||||||
|
|
||||||
// Test encoded form against known values; these test vectors contain Orchard receivers
|
// Test encoded form against known values; these test vectors contain Orchard receivers
|
||||||
|
@ -1654,8 +1648,7 @@ mod tests {
|
||||||
let d_idx = DiversifierIndex::from(tv.diversifier_index);
|
let d_idx = DiversifierIndex::from(tv.diversifier_index);
|
||||||
let uivk = usk
|
let uivk = usk
|
||||||
.to_unified_full_viewing_key()
|
.to_unified_full_viewing_key()
|
||||||
.to_unified_incoming_viewing_key()
|
.to_unified_incoming_viewing_key();
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// The test vectors contain some diversifier indices that do not generate
|
// The test vectors contain some diversifier indices that do not generate
|
||||||
// valid Sapling addresses, so skip those.
|
// valid Sapling addresses, so skip those.
|
||||||
|
|
Loading…
Reference in New Issue