zcash_client_backend: Fix `UnifiedFullViewingKey` Sapling item type

Per ZIP 316, the Sapling FVK Encoding only includes `(ak, nk, ovk, dk)`
which is a subset of the Sapling `ExtendedFullViewingKey`. We therefore
need to use `DiversifiableFullViewingKey` inside `UnifiedFullViewingKey`
in order to make it parseable from the UFVK string encoding.

`zcash_client_sqlite::wallet::get_extended_full_viewing_keys` has been
removed as a consequence of this change: we can no longer reconstruct
the correct `ExtendedFullViewingKey` from the `UnifiedFullViewingKey`.
This commit is contained in:
Jack Grigg 2022-06-14 02:27:55 +00:00
parent d8b860207d
commit 76d015ed11
11 changed files with 149 additions and 140 deletions

View File

@ -84,7 +84,6 @@ use zcash_primitives::{
consensus::{self, BlockHeight, NetworkUpgrade},
merkle_tree::CommitmentTree,
sapling::Nullifier,
zip32::{AccountId, ExtendedFullViewingKey},
};
use crate::{
@ -214,7 +213,7 @@ where
let ufvks = data.get_unified_full_viewing_keys()?;
// TODO: Change `scan_block` to also scan Orchard.
// https://github.com/zcash/librustzcash/issues/403
let extfvks: Vec<(&AccountId, &ExtendedFullViewingKey)> = ufvks
let dfvks: Vec<_> = ufvks
.iter()
.map(|(account, ufvk)| (account, ufvk.sapling().expect("TODO Add Orchard support")))
.collect();
@ -249,7 +248,7 @@ where
scan_block(
params,
block,
&extfvks,
&dfvks,
&nullifiers,
&mut tree,
&mut witness_refs[..],

View File

@ -46,9 +46,9 @@ pub fn decrypt_transaction<P: consensus::Parameters>(
if let Some(bundle) = tx.sapling_bundle() {
for (account, ufvk) in ufvks.iter() {
let extfvk = ufvk.sapling().expect("TODO: Add Orchard support");
let ivk = extfvk.fvk.vk.ivk();
let ovk = extfvk.fvk.ovk;
let dfvk = ufvk.sapling().expect("TODO: Add Orchard support");
let ivk = dfvk.fvk().vk.ivk();
let ovk = dfvk.fvk().ovk;
for (index, output) in bundle.shielded_outputs.iter().enumerate() {
let ((note, to, memo), outgoing) =

View File

@ -1,12 +1,12 @@
//! Helper functions for managing light client key material.
use zcash_primitives::{
consensus,
sapling::keys as sapling_keys,
zip32::{AccountId, DiversifierIndex},
};
use crate::address::UnifiedAddress;
#[cfg(feature = "transparent-inputs")]
use std::convert::TryInto;
#[cfg(feature = "transparent-inputs")]
@ -109,7 +109,7 @@ impl UnifiedSpendingKey {
UnifiedFullViewingKey {
#[cfg(feature = "transparent-inputs")]
transparent: Some(self.transparent.to_account_pubkey()),
sapling: Some(sapling::ExtendedFullViewingKey::from(&self.sapling)),
sapling: Some(sapling::ExtendedFullViewingKey::from(&self.sapling).into()),
}
}
@ -138,9 +138,7 @@ impl UnifiedSpendingKey {
pub struct UnifiedFullViewingKey {
#[cfg(feature = "transparent-inputs")]
transparent: Option<legacy::AccountPubKey>,
// TODO: This type is invalid for a UFVK; create a `sapling::DiversifiableFullViewingKey`
// to replace it.
sapling: Option<sapling::ExtendedFullViewingKey>,
sapling: Option<sapling_keys::DiversifiableFullViewingKey>,
}
#[doc(hidden)]
@ -148,7 +146,7 @@ impl UnifiedFullViewingKey {
/// Construct a new unified full viewing key, if the required components are present.
pub fn new(
#[cfg(feature = "transparent-inputs")] transparent: Option<legacy::AccountPubKey>,
sapling: Option<sapling::ExtendedFullViewingKey>,
sapling: Option<sapling_keys::DiversifiableFullViewingKey>,
) -> Option<UnifiedFullViewingKey> {
if sapling.is_none() {
None
@ -185,7 +183,12 @@ impl UnifiedFullViewingKey {
};
let sapling = if flag & 2 != 0 {
Some(sapling::ExtendedFullViewingKey::read(data).ok()?)
if data.len() != 128 {
return None;
}
Some(sapling_keys::DiversifiableFullViewingKey::from_bytes(
data.try_into().unwrap(),
)?)
} else {
None
};
@ -212,7 +215,7 @@ impl UnifiedFullViewingKey {
};
if let Some(sapling) = self.sapling.as_ref() {
sapling.write(&mut ufvk).unwrap();
ufvk.extend_from_slice(&sapling.to_bytes());
}
format!("DONOTUSEUFVK{}", hex::encode(&ufvk))
@ -225,9 +228,8 @@ impl UnifiedFullViewingKey {
self.transparent.as_ref()
}
/// Returns the Sapling extended full viewing key component of this
/// unified key.
pub fn sapling(&self) -> Option<&sapling::ExtendedFullViewingKey> {
/// Returns the Sapling diversifiable full viewing key component of this unified key.
pub fn sapling(&self) -> Option<&sapling_keys::DiversifiableFullViewingKey> {
self.sapling.as_ref()
}
@ -348,7 +350,7 @@ mod tests {
let sapling = {
let extsk = sapling::spending_key(&[0; 32], 0, account);
Some(ExtendedFullViewingKey::from(&extsk))
Some(ExtendedFullViewingKey::from(&extsk).into())
};
#[cfg(feature = "transparent-inputs")]
@ -368,6 +370,9 @@ mod tests {
decoded.transparent.map(|t| t.serialize()),
ufvk.transparent.map(|t| t.serialize()),
);
assert_eq!(decoded.sapling, ufvk.sapling);
assert_eq!(
decoded.sapling.map(|s| s.to_bytes()),
ufvk.sapling.map(|s| s.to_bytes()),
);
}
}

View File

@ -9,6 +9,7 @@ use zcash_primitives::{
consensus::{self, BlockHeight},
merkle_tree::{CommitmentTree, IncrementalWitness},
sapling::{
keys::DiversifiableFullViewingKey,
note_encryption::{try_sapling_compact_note_decryption, SaplingDomain},
Node, Note, Nullifier, PaymentAddress, SaplingIvk,
},
@ -127,6 +128,26 @@ pub trait ScanningKey {
fn nf(&self, note: &Note, witness: &IncrementalWitness<Node>) -> Self::Nf;
}
impl ScanningKey for DiversifiableFullViewingKey {
type Nf = Nullifier;
fn try_decryption<
P: consensus::Parameters,
Output: ShieldedOutput<SaplingDomain<P>, COMPACT_NOTE_SIZE>,
>(
&self,
params: &P,
height: BlockHeight,
output: &Output,
) -> Option<(Note, PaymentAddress)> {
try_sapling_compact_note_decryption(params, height, &self.fvk().vk.ivk(), output)
}
fn nf(&self, note: &Note, witness: &IncrementalWitness<Node>) -> Self::Nf {
note.nf(&self.fvk().vk, witness.position() as u64)
}
}
/// The [`ScanningKey`] implementation for [`ExtendedFullViewingKey`]s.
/// Nullifiers may be derived when scanning with these keys.
///

View File

@ -49,6 +49,12 @@ and this library adheres to Rust's notion of
constructed, rather than only in the case that a transaction has
been decrypted after being retrieved from the network.
### Removed
- `zcash_client_sqlite::wallet`:
- `get_extended_full_viewing_keys` (use
`zcash_client_backend::data_api::WalletRead::get_unified_full_viewing_keys`
instead).
### Deprecated
- A number of public API methods that are used internally to support the
`zcash_client_backend::data_api::{WalletRead, WalletWrite}` interfaces have

View File

@ -101,7 +101,7 @@ mod tests {
init_wallet_db(&db_data).unwrap();
// Add an account to the wallet
let (extfvk, _taddr) = init_test_accounts_table(&db_data);
let (dfvk, _taddr) = init_test_accounts_table(&db_data);
// Empty chain should be valid
validate_chain(
@ -115,7 +115,7 @@ mod tests {
let (cb, _) = fake_compact_block(
sapling_activation_height(),
BlockHash([0; 32]),
extfvk.clone(),
&dfvk,
Amount::from_u64(5).unwrap(),
);
insert_into_cache(&db_cache, &cb);
@ -144,7 +144,7 @@ mod tests {
let (cb2, _) = fake_compact_block(
sapling_activation_height() + 1,
cb.hash(),
extfvk,
&dfvk,
Amount::from_u64(7).unwrap(),
);
insert_into_cache(&db_cache, &cb2);
@ -180,19 +180,19 @@ mod tests {
init_wallet_db(&db_data).unwrap();
// Add an account to the wallet
let (extfvk, _taddr) = init_test_accounts_table(&db_data);
let (dfvk, _taddr) = init_test_accounts_table(&db_data);
// Create some fake CompactBlocks
let (cb, _) = fake_compact_block(
sapling_activation_height(),
BlockHash([0; 32]),
extfvk.clone(),
&dfvk,
Amount::from_u64(5).unwrap(),
);
let (cb2, _) = fake_compact_block(
sapling_activation_height() + 1,
cb.hash(),
extfvk.clone(),
&dfvk,
Amount::from_u64(7).unwrap(),
);
insert_into_cache(&db_cache, &cb);
@ -214,13 +214,13 @@ mod tests {
let (cb3, _) = fake_compact_block(
sapling_activation_height() + 2,
BlockHash([1; 32]),
extfvk.clone(),
&dfvk,
Amount::from_u64(8).unwrap(),
);
let (cb4, _) = fake_compact_block(
sapling_activation_height() + 3,
cb3.hash(),
extfvk,
&dfvk,
Amount::from_u64(3).unwrap(),
);
insert_into_cache(&db_cache, &cb3);
@ -250,19 +250,19 @@ mod tests {
init_wallet_db(&db_data).unwrap();
// Add an account to the wallet
let (extfvk, _taddr) = init_test_accounts_table(&db_data);
let (dfvk, _taddr) = init_test_accounts_table(&db_data);
// Create some fake CompactBlocks
let (cb, _) = fake_compact_block(
sapling_activation_height(),
BlockHash([0; 32]),
extfvk.clone(),
&dfvk,
Amount::from_u64(5).unwrap(),
);
let (cb2, _) = fake_compact_block(
sapling_activation_height() + 1,
cb.hash(),
extfvk.clone(),
&dfvk,
Amount::from_u64(7).unwrap(),
);
insert_into_cache(&db_cache, &cb);
@ -284,13 +284,13 @@ mod tests {
let (cb3, _) = fake_compact_block(
sapling_activation_height() + 2,
cb2.hash(),
extfvk.clone(),
&dfvk,
Amount::from_u64(8).unwrap(),
);
let (cb4, _) = fake_compact_block(
sapling_activation_height() + 3,
BlockHash([1; 32]),
extfvk,
&dfvk,
Amount::from_u64(3).unwrap(),
);
insert_into_cache(&db_cache, &cb3);
@ -320,7 +320,7 @@ mod tests {
init_wallet_db(&db_data).unwrap();
// Add an account to the wallet
let (extfvk, _taddr) = init_test_accounts_table(&db_data);
let (dfvk, _taddr) = init_test_accounts_table(&db_data);
// Account balance should be zero
assert_eq!(
@ -334,12 +334,12 @@ mod tests {
let (cb, _) = fake_compact_block(
sapling_activation_height(),
BlockHash([0; 32]),
extfvk.clone(),
&dfvk,
value,
);
let (cb2, _) =
fake_compact_block(sapling_activation_height() + 1, cb.hash(), extfvk, value2);
fake_compact_block(sapling_activation_height() + 1, cb.hash(), &dfvk, value2);
insert_into_cache(&db_cache, &cb);
insert_into_cache(&db_cache, &cb2);
@ -389,14 +389,14 @@ mod tests {
init_wallet_db(&db_data).unwrap();
// Add an account to the wallet
let (extfvk, _taddr) = init_test_accounts_table(&db_data);
let (dfvk, _taddr) = init_test_accounts_table(&db_data);
// Create a block with height SAPLING_ACTIVATION_HEIGHT
let value = Amount::from_u64(50000).unwrap();
let (cb1, _) = fake_compact_block(
sapling_activation_height(),
BlockHash([0; 32]),
extfvk.clone(),
&dfvk,
value,
);
insert_into_cache(&db_cache, &cb1);
@ -405,14 +405,10 @@ mod tests {
assert_eq!(get_balance(&db_data, AccountId::from(0)).unwrap(), value);
// We cannot scan a block of height SAPLING_ACTIVATION_HEIGHT + 2 next
let (cb2, _) = fake_compact_block(
sapling_activation_height() + 1,
cb1.hash(),
extfvk.clone(),
value,
);
let (cb2, _) =
fake_compact_block(sapling_activation_height() + 1, cb1.hash(), &dfvk, value);
let (cb3, _) =
fake_compact_block(sapling_activation_height() + 2, cb2.hash(), extfvk, value);
fake_compact_block(sapling_activation_height() + 2, cb2.hash(), &dfvk, value);
insert_into_cache(&db_cache, &cb3);
match scan_cached_blocks(&tests::network(), &db_cache, &mut db_write, None) {
Err(SqliteClientError::BackendError(e)) => {
@ -448,7 +444,7 @@ mod tests {
init_wallet_db(&db_data).unwrap();
// Add an account to the wallet
let (extfvk, _taddr) = init_test_accounts_table(&db_data);
let (dfvk, _taddr) = init_test_accounts_table(&db_data);
// Account balance should be zero
assert_eq!(
@ -461,7 +457,7 @@ mod tests {
let (cb, _) = fake_compact_block(
sapling_activation_height(),
BlockHash([0; 32]),
extfvk.clone(),
&dfvk,
value,
);
insert_into_cache(&db_cache, &cb);
@ -476,7 +472,7 @@ mod tests {
// Create a second fake CompactBlock sending more value to the address
let value2 = Amount::from_u64(7).unwrap();
let (cb2, _) =
fake_compact_block(sapling_activation_height() + 1, cb.hash(), extfvk, value2);
fake_compact_block(sapling_activation_height() + 1, cb.hash(), &dfvk, value2);
insert_into_cache(&db_cache, &cb2);
// Scan the cache again
@ -500,7 +496,7 @@ mod tests {
init_wallet_db(&db_data).unwrap();
// Add an account to the wallet
let (extfvk, _taddr) = init_test_accounts_table(&db_data);
let (dfvk, _taddr) = init_test_accounts_table(&db_data);
// Account balance should be zero
assert_eq!(
@ -513,7 +509,7 @@ mod tests {
let (cb, nf) = fake_compact_block(
sapling_activation_height(),
BlockHash([0; 32]),
extfvk.clone(),
&dfvk,
value,
);
insert_into_cache(&db_cache, &cb);
@ -535,7 +531,7 @@ mod tests {
sapling_activation_height() + 1,
cb.hash(),
(nf, value),
extfvk,
&dfvk,
to2,
value2,
),

View File

@ -745,8 +745,8 @@ mod tests {
legacy::TransparentAddress,
memo::MemoBytes,
sapling::{
note_encryption::sapling_note_encryption, util::generate_random_rseed, Note, Nullifier,
PaymentAddress,
keys::DiversifiableFullViewingKey, note_encryption::sapling_note_encryption,
util::generate_random_rseed, Note, Nullifier, PaymentAddress,
},
transaction::components::Amount,
zip32::ExtendedFullViewingKey,
@ -783,11 +783,11 @@ mod tests {
#[cfg(test)]
pub(crate) fn init_test_accounts_table(
db_data: &WalletDb<Network>,
) -> (ExtendedFullViewingKey, Option<TransparentAddress>) {
) -> (DiversifiableFullViewingKey, Option<TransparentAddress>) {
let seed = [0u8; 32];
let account = AccountId::from(0);
let extsk = sapling::spending_key(&seed, network().coin_type(), account);
let extfvk = ExtendedFullViewingKey::from(&extsk);
let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk));
#[cfg(feature = "transparent-inputs")]
let (tkey, taddr) = {
@ -804,13 +804,13 @@ mod tests {
let ufvk = UnifiedFullViewingKey::new(
#[cfg(feature = "transparent-inputs")]
tkey,
Some(extfvk.clone()),
Some(dfvk.clone()),
)
.unwrap();
init_accounts_table(db_data, &[ufvk]).unwrap();
(extfvk, taddr)
(dfvk, taddr)
}
/// Create a fake CompactBlock at the given height, containing a single output paying
@ -818,10 +818,10 @@ mod tests {
pub(crate) fn fake_compact_block(
height: BlockHeight,
prev_hash: BlockHash,
extfvk: ExtendedFullViewingKey,
dfvk: &DiversifiableFullViewingKey,
value: Amount,
) -> (CompactBlock, Nullifier) {
let to = extfvk.default_address().1;
let to = dfvk.default_address().1;
// Create a fake Note for the account
let mut rng = OsRng;
@ -833,7 +833,7 @@ mod tests {
rseed,
};
let encryptor = sapling_note_encryption::<_, Network>(
Some(extfvk.fvk.ovk),
Some(dfvk.fvk().ovk),
note.clone(),
to,
MemoBytes::empty(),
@ -859,7 +859,7 @@ mod tests {
rng.fill_bytes(&mut cb.hash);
cb.prevHash.extend_from_slice(&prev_hash.0);
cb.vtx.push(ctx);
(cb, note.nf(&extfvk.fvk.vk, 0))
(cb, note.nf(&dfvk.fvk().vk, 0))
}
/// Create a fake CompactBlock at the given height, spending a single note from the
@ -868,7 +868,7 @@ mod tests {
height: BlockHeight,
prev_hash: BlockHash,
(nf, in_value): (Nullifier, Amount),
extfvk: ExtendedFullViewingKey,
dfvk: &DiversifiableFullViewingKey,
to: PaymentAddress,
value: Amount,
) -> CompactBlock {
@ -893,7 +893,7 @@ mod tests {
rseed,
};
let encryptor = sapling_note_encryption::<_, Network>(
Some(extfvk.fvk.ovk),
Some(dfvk.fvk().ovk),
note.clone(),
to,
MemoBytes::empty(),
@ -912,7 +912,7 @@ mod tests {
// Create a fake Note for the change
ctx.outputs.push({
let change_addr = extfvk.default_address().1;
let change_addr = dfvk.default_address().1;
let rseed = generate_random_rseed(&network(), height, &mut rng);
let note = Note {
g_d: change_addr.diversifier().g_d().unwrap(),
@ -921,7 +921,7 @@ mod tests {
rseed,
};
let encryptor = sapling_note_encryption::<_, Network>(
Some(extfvk.fvk.ovk),
Some(dfvk.fvk().ovk),
note.clone(),
change_addr,
MemoBytes::empty(),

View File

@ -17,7 +17,7 @@ use zcash_primitives::{
consensus::{self, BlockHeight, BranchId, NetworkUpgrade, Parameters},
memo::{Memo, MemoBytes},
merkle_tree::{CommitmentTree, IncrementalWitness},
sapling::{Node, Note, Nullifier, PaymentAddress},
sapling::{keys::DiversifiableFullViewingKey, Node, Note, Nullifier, PaymentAddress},
transaction::{components::Amount, Transaction, TxId},
zip32::{AccountId, ExtendedFullViewingKey},
};
@ -172,28 +172,6 @@ pub fn get_address<P: consensus::Parameters>(
})
}
/// Returns the [`ExtendedFullViewingKey`]s for the wallet.
///
/// [`ExtendedFullViewingKey`]: zcash_primitives::zip32::ExtendedFullViewingKey
#[deprecated(
note = "This function will be removed in a future release. Use zcash_client_backend::data_api::WalletRead::get_unified_full_viewing_keys instead."
)]
pub fn get_extended_full_viewing_keys<P: consensus::Parameters>(
wdb: &WalletDb<P>,
) -> Result<HashMap<AccountId, ExtendedFullViewingKey>, SqliteClientError> {
get_unified_full_viewing_keys(wdb).map(|ufvks| {
ufvks
.into_iter()
.map(|(account, ufvk)| {
(
account,
ufvk.sapling().cloned().expect("TODO: Add Orchard support"),
)
})
.collect()
})
}
/// Returns the [`UnifiedFullViewingKey`]s for the wallet.
pub(crate) fn get_unified_full_viewing_keys<P: consensus::Parameters>(
wdb: &WalletDb<P>,
@ -248,7 +226,10 @@ pub fn is_valid_account_extfvk<P: consensus::Parameters>(
.map_err(SqliteClientError::from)
.and_then(|row| {
if let Some(ufvk) = row {
ufvk.map(|ufvk| ufvk.sapling() == Some(extfvk))
ufvk.map(|ufvk| {
ufvk.sapling().map(|dfvk| dfvk.to_bytes())
== Some(DiversifiableFullViewingKey::from(extfvk.clone()).to_bytes())
})
} else {
Ok(false)
}

View File

@ -179,8 +179,8 @@ pub fn init_wallet_db<P>(wdb: &WalletDb<P>) -> Result<(), rusqlite::Error> {
/// let seed = [0u8; 32]; // insecure; replace with a strong random seed
/// let account = AccountId::from(0);
/// let extsk = sapling::spending_key(&seed, Network::TestNetwork.coin_type(), account);
/// let extfvk = ExtendedFullViewingKey::from(&extsk);
/// let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk)).unwrap();
/// let dfvk = ExtendedFullViewingKey::from(&extsk).into();
/// let ufvk = UnifiedFullViewingKey::new(None, Some(dfvk)).unwrap();
/// init_accounts_table(&db_data, &[ufvk]).unwrap();
/// # }
/// ```
@ -293,6 +293,7 @@ mod tests {
use zcash_primitives::{
block::BlockHash,
consensus::{BlockHeight, Parameters},
sapling::keys::DiversifiableFullViewingKey,
zip32::ExtendedFullViewingKey,
};
@ -319,7 +320,7 @@ mod tests {
// First call with data should initialise the accounts table
let extsk = sapling::spending_key(&seed, network().coin_type(), account);
let extfvk = ExtendedFullViewingKey::from(&extsk);
let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk));
#[cfg(feature = "transparent-inputs")]
let ufvk = UnifiedFullViewingKey::new(
@ -328,12 +329,12 @@ mod tests {
.unwrap()
.to_account_pubkey(),
),
Some(extfvk),
Some(dfvk),
)
.unwrap();
#[cfg(not(feature = "transparent-inputs"))]
let ufvk = UnifiedFullViewingKey::new(Some(extfvk)).unwrap();
let ufvk = UnifiedFullViewingKey::new(Some(dfvk), None).unwrap();
init_accounts_table(&db_data, &[ufvk.clone()]).unwrap();

View File

@ -165,7 +165,10 @@ mod tests {
block::BlockHash,
consensus::{BlockHeight, BranchId, Parameters},
legacy::TransparentAddress,
sapling::{note_encryption::try_sapling_output_recovery, prover::TxProver},
sapling::{
keys::DiversifiableFullViewingKey, note_encryption::try_sapling_output_recovery,
prover::TxProver,
},
transaction::{components::Amount, Transaction},
zip32::{ExtendedFullViewingKey, ExtendedSpendingKey},
};
@ -207,8 +210,8 @@ mod tests {
// Add two accounts to the wallet
let extsk0 = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0));
let extsk1 = sapling::spending_key(&[1u8; 32], network().coin_type(), AccountId::from(1));
let extfvk0 = ExtendedFullViewingKey::from(&extsk0);
let extfvk1 = ExtendedFullViewingKey::from(&extsk1);
let dfvk0 = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk0));
let dfvk1 = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk1));
#[cfg(feature = "transparent-inputs")]
let ufvks = {
@ -219,14 +222,14 @@ mod tests {
transparent::AccountPrivKey::from_seed(&network(), &[1u8; 32], AccountId::from(1))
.unwrap();
[
UnifiedFullViewingKey::new(Some(tsk0.to_account_pubkey()), Some(extfvk0)).unwrap(),
UnifiedFullViewingKey::new(Some(tsk1.to_account_pubkey()), Some(extfvk1)).unwrap(),
UnifiedFullViewingKey::new(Some(tsk0.to_account_pubkey()), Some(dfvk0)).unwrap(),
UnifiedFullViewingKey::new(Some(tsk1.to_account_pubkey()), Some(dfvk1)).unwrap(),
]
};
#[cfg(not(feature = "transparent-inputs"))]
let ufvks = [
UnifiedFullViewingKey::new(Some(extfvk0)).unwrap(),
UnifiedFullViewingKey::new(Some(extfvk1)).unwrap(),
UnifiedFullViewingKey::new(Some(dfvk0), None).unwrap(),
UnifiedFullViewingKey::new(Some(dfvk1), None).unwrap(),
];
init_accounts_table(&db_data, &ufvks).unwrap();
@ -275,12 +278,12 @@ mod tests {
// Add an account to the wallet
let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0));
let extfvk = ExtendedFullViewingKey::from(&extsk);
let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk));
#[cfg(feature = "transparent-inputs")]
let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk)).unwrap();
let ufvk = UnifiedFullViewingKey::new(None, Some(dfvk)).unwrap();
#[cfg(not(feature = "transparent-inputs"))]
let ufvk = UnifiedFullViewingKey::new(Some(extfvk)).unwrap();
let ufvk = UnifiedFullViewingKey::new(Some(dfvk)).unwrap();
init_accounts_table(&db_data, &[ufvk]).unwrap();
let to = extsk.default_address().1.into();
@ -319,11 +322,11 @@ mod tests {
// Add an account to the wallet
let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0));
let extfvk = ExtendedFullViewingKey::from(&extsk);
let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk));
#[cfg(feature = "transparent-inputs")]
let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk)).unwrap();
let ufvk = UnifiedFullViewingKey::new(None, Some(dfvk)).unwrap();
#[cfg(not(feature = "transparent-inputs"))]
let ufvk = UnifiedFullViewingKey::new(Some(extfvk)).unwrap();
let ufvk = UnifiedFullViewingKey::new(Some(dfvk)).unwrap();
init_accounts_table(&db_data, &[ufvk]).unwrap();
let to = extsk.default_address().1.into();
@ -367,11 +370,11 @@ mod tests {
// Add an account to the wallet
let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0));
let extfvk = ExtendedFullViewingKey::from(&extsk);
let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk));
#[cfg(feature = "transparent-inputs")]
let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk.clone())).unwrap();
let ufvk = UnifiedFullViewingKey::new(None, Some(dfvk.clone())).unwrap();
#[cfg(not(feature = "transparent-inputs"))]
let ufvk = UnifiedFullViewingKey::new(Some(extfvk.clone())).unwrap();
let ufvk = UnifiedFullViewingKey::new(Some(dfvk.clone())).unwrap();
init_accounts_table(&db_data, &[ufvk]).unwrap();
// Add funds to the wallet in a single note
@ -379,7 +382,7 @@ mod tests {
let (cb, _) = fake_compact_block(
sapling_activation_height(),
BlockHash([0; 32]),
extfvk.clone(),
&dfvk,
value,
);
insert_into_cache(&db_cache, &cb);
@ -398,12 +401,7 @@ mod tests {
);
// Add more funds to the wallet in a second note
let (cb, _) = fake_compact_block(
sapling_activation_height() + 1,
cb.hash(),
extfvk.clone(),
value,
);
let (cb, _) = fake_compact_block(sapling_activation_height() + 1, cb.hash(), &dfvk, value);
insert_into_cache(&db_cache, &cb);
scan_cached_blocks(&tests::network(), &db_cache, &mut db_write, None).unwrap();
@ -446,12 +444,8 @@ mod tests {
// Mine blocks SAPLING_ACTIVATION_HEIGHT + 2 to 9 until just before the second
// note is verified
for i in 2..10 {
let (cb, _) = fake_compact_block(
sapling_activation_height() + i,
cb.hash(),
extfvk.clone(),
value,
);
let (cb, _) =
fake_compact_block(sapling_activation_height() + i, cb.hash(), &dfvk, value);
insert_into_cache(&db_cache, &cb);
}
scan_cached_blocks(&tests::network(), &db_cache, &mut db_write, None).unwrap();
@ -477,8 +471,7 @@ mod tests {
}
// Mine block 11 so that the second note becomes verified
let (cb, _) =
fake_compact_block(sapling_activation_height() + 10, cb.hash(), extfvk, value);
let (cb, _) = fake_compact_block(sapling_activation_height() + 10, cb.hash(), &dfvk, value);
insert_into_cache(&db_cache, &cb);
scan_cached_blocks(&tests::network(), &db_cache, &mut db_write, None).unwrap();
@ -510,11 +503,11 @@ mod tests {
// Add an account to the wallet
let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0));
let extfvk = ExtendedFullViewingKey::from(&extsk);
let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk));
#[cfg(feature = "transparent-inputs")]
let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk.clone())).unwrap();
let ufvk = UnifiedFullViewingKey::new(None, Some(dfvk.clone())).unwrap();
#[cfg(not(feature = "transparent-inputs"))]
let ufvk = UnifiedFullViewingKey::new(Some(extfvk.clone())).unwrap();
let ufvk = UnifiedFullViewingKey::new(Some(dfvk.clone())).unwrap();
init_accounts_table(&db_data, &[ufvk]).unwrap();
// Add funds to the wallet in a single note
@ -522,7 +515,7 @@ mod tests {
let (cb, _) = fake_compact_block(
sapling_activation_height(),
BlockHash([0; 32]),
extfvk,
&dfvk,
value,
);
insert_into_cache(&db_cache, &cb);
@ -573,7 +566,7 @@ mod tests {
let (cb, _) = fake_compact_block(
sapling_activation_height() + i,
cb.hash(),
ExtendedFullViewingKey::from(&ExtendedSpendingKey::master(&[i as u8])),
&ExtendedFullViewingKey::from(&ExtendedSpendingKey::master(&[i as u8])).into(),
value,
);
insert_into_cache(&db_cache, &cb);
@ -604,7 +597,7 @@ mod tests {
let (cb, _) = fake_compact_block(
sapling_activation_height() + 22,
cb.hash(),
ExtendedFullViewingKey::from(&ExtendedSpendingKey::master(&[22])),
&ExtendedFullViewingKey::from(&ExtendedSpendingKey::master(&[22])).into(),
value,
);
insert_into_cache(&db_cache, &cb);
@ -639,11 +632,11 @@ mod tests {
// Add an account to the wallet
let extsk = sapling::spending_key(&[0u8; 32], network.coin_type(), AccountId::from(0));
let extfvk = ExtendedFullViewingKey::from(&extsk);
let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk));
#[cfg(feature = "transparent-inputs")]
let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk.clone())).unwrap();
let ufvk = UnifiedFullViewingKey::new(None, Some(dfvk.clone())).unwrap();
#[cfg(not(feature = "transparent-inputs"))]
let ufvk = UnifiedFullViewingKey::new(Some(extfvk.clone())).unwrap();
let ufvk = UnifiedFullViewingKey::new(Some(dfvk.clone())).unwrap();
init_accounts_table(&db_data, &[ufvk]).unwrap();
// Add funds to the wallet in a single note
@ -651,7 +644,7 @@ mod tests {
let (cb, _) = fake_compact_block(
sapling_activation_height(),
BlockHash([0; 32]),
extfvk.clone(),
&dfvk,
value,
);
insert_into_cache(&db_cache, &cb);
@ -708,7 +701,7 @@ mod tests {
try_sapling_output_recovery(
&network,
sapling_activation_height(),
&extfvk.fvk.ovk,
&dfvk.fvk().ovk,
output,
)
};
@ -725,7 +718,7 @@ mod tests {
let (cb, _) = fake_compact_block(
sapling_activation_height() + i,
cb.hash(),
ExtendedFullViewingKey::from(&ExtendedSpendingKey::master(&[i as u8])),
&ExtendedFullViewingKey::from(&ExtendedSpendingKey::master(&[i as u8])).into(),
value,
);
insert_into_cache(&db_cache, &cb);
@ -749,11 +742,11 @@ mod tests {
// Add an account to the wallet
let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0));
let extfvk = ExtendedFullViewingKey::from(&extsk);
let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk));
#[cfg(feature = "transparent-inputs")]
let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk.clone())).unwrap();
let ufvk = UnifiedFullViewingKey::new(None, Some(dfvk.clone())).unwrap();
#[cfg(not(feature = "transparent-inputs"))]
let ufvk = UnifiedFullViewingKey::new(Some(extfvk.clone())).unwrap();
let ufvk = UnifiedFullViewingKey::new(Some(dfvk.clone())).unwrap();
init_accounts_table(&db_data, &[ufvk]).unwrap();
// Add funds to the wallet in a single note
@ -761,7 +754,7 @@ mod tests {
let (cb, _) = fake_compact_block(
sapling_activation_height(),
BlockHash([0; 32]),
extfvk,
&dfvk,
value,
);
insert_into_cache(&db_cache, &cb);

View File

@ -276,6 +276,13 @@ impl DiversifiableFullViewingKey {
zip32::sapling_find_address(&self.fvk, &self.dk, j)
}
/// Returns the payment address corresponding to the smallest valid diversifier index,
/// along with that index.
// TODO: See if this is only used in tests.
pub fn default_address(&self) -> (zip32::DiversifierIndex, PaymentAddress) {
zip32::sapling_default_address(&self.fvk, &self.dk)
}
/// Attempts to decrypt the given address's diversifier with this full viewing key.
///
/// This method extracts the diversifier from the given address and decrypts it as a