diff --git a/zcash_client_backend/CHANGELOG.md b/zcash_client_backend/CHANGELOG.md index edd2ff396..7aa804d5f 100644 --- a/zcash_client_backend/CHANGELOG.md +++ b/zcash_client_backend/CHANGELOG.md @@ -51,9 +51,10 @@ and this library adheres to Rust's notion of - Arguments to `ScannedBlock::from_parts` have changed. - Changes to the `WalletRead` trait: - Added `Account` associated type. - - Added `get_orchard_nullifiers` + - Added `get_orchard_nullifiers` method. - `get_account_for_ufvk` now returns an `Self::Account` instead of a bare `AccountId` + - Added `get_seed_account` method. - Changes to the `InputSource` trait: - `select_spendable_notes` now takes its `target_value` argument as a `NonNegativeAmount`. Also, the values of the returned map are also diff --git a/zcash_client_backend/src/data_api.rs b/zcash_client_backend/src/data_api.rs index a6d06a427..da67ded3f 100644 --- a/zcash_client_backend/src/data_api.rs +++ b/zcash_client_backend/src/data_api.rs @@ -66,6 +66,7 @@ use std::{ use incrementalmerkletree::{frontier::Frontier, Retention}; use secrecy::SecretVec; use shardtree::{error::ShardTreeError, store::ShardStore, ShardTree}; +use zcash_keys::keys::HdSeedFingerprint; use self::{chain::CommitmentTreeRoot, scanning::ScanRange}; use crate::{ @@ -655,6 +656,14 @@ pub trait WalletRead { ufvk: &UnifiedFullViewingKey, ) -> Result, Self::Error>; + /// Returns the account corresponding to a given [`HdSeedFingerprint`] and + /// [`zip32::AccountId`], if any. + fn get_seed_account( + &self, + seed: &HdSeedFingerprint, + account_id: zip32::AccountId, + ) -> Result, Self::Error>; + /// Returns the wallet balances and sync status for an account given the specified minimum /// number of confirmations, or `Ok(None)` if the wallet has no balance data available. fn get_wallet_summary( @@ -1416,6 +1425,7 @@ pub mod testing { use secrecy::{ExposeSecret, SecretVec}; use shardtree::{error::ShardTreeError, store::memory::MemoryShardStore, ShardTree}; use std::{collections::HashMap, convert::Infallible, num::NonZeroU32}; + use zcash_keys::keys::HdSeedFingerprint; use zcash_primitives::{ block::BlockHash, @@ -1588,6 +1598,14 @@ pub mod testing { Ok(None) } + fn get_seed_account( + &self, + _seed: &HdSeedFingerprint, + _account_id: zip32::AccountId, + ) -> Result, Self::Error> { + Ok(None) + } + fn get_wallet_summary( &self, _min_confirmations: u32, diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index 80de58ea4..92c3753cd 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -405,6 +405,14 @@ impl, P: consensus::Parameters> WalletRead for W wallet::get_account_for_ufvk(self.conn.borrow(), &self.params, ufvk) } + fn get_seed_account( + &self, + seed: &HdSeedFingerprint, + account_id: zip32::AccountId, + ) -> Result, Self::Error> { + wallet::get_seed_account(self.conn.borrow(), &self.params, seed, account_id) + } + fn get_wallet_summary( &self, min_confirmations: u32, diff --git a/zcash_client_sqlite/src/wallet.rs b/zcash_client_sqlite/src/wallet.rs index 03664ba6e..59b5ddacd 100644 --- a/zcash_client_sqlite/src/wallet.rs +++ b/zcash_client_sqlite/src/wallet.rs @@ -779,6 +779,46 @@ pub(crate) fn get_account_for_ufvk( } } +/// Returns the account id corresponding to a given [`HdSeedFingerprint`] +/// and [`zip32::AccountId`], if any. +pub(crate) fn get_seed_account( + conn: &rusqlite::Connection, + params: &P, + seed: &HdSeedFingerprint, + account_id: zip32::AccountId, +) -> Result)>, SqliteClientError> { + let mut stmt = conn.prepare( + "SELECT id, ufvk + FROM accounts + WHERE hd_seed_fingerprint = :hd_seed_fingerprint + AND hd_account_index = :account_id", + )?; + + let mut accounts = stmt.query_and_then::<_, SqliteClientError, _, _>( + named_params![ + ":hd_seed_fingerprint": seed.as_bytes(), + ":hd_account_index": u32::from(account_id), + ], + |row| { + let account_id = row.get::<_, u32>(0).map(AccountId)?; + Ok(( + account_id, + row.get::<_, Option>(1)? + .map(|ufvk_str| UnifiedFullViewingKey::decode(params, &ufvk_str)) + .transpose() + .map_err(|e| { + SqliteClientError::CorruptedData(format!( + "Could not decode unified full viewing key for account {:?}: {}", + account_id, e + )) + })?, + )) + }, + )?; + + accounts.next().transpose() +} + pub(crate) trait ScanProgress { fn sapling_scan_progress( &self,