Implement `WalletRead::get_transparent_address_metadata` for

`zcash_client_sqlite` using direct database queries.

Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org>
This commit is contained in:
Daira-Emma Hopwood 2024-06-25 17:05:36 +01:00
parent 5a90fffed4
commit 7fb355739e
4 changed files with 76 additions and 1 deletions

View File

@ -1971,6 +1971,15 @@ pub mod testing {
Ok(HashMap::new())
}
#[cfg(feature = "transparent-inputs")]
fn get_transparent_address_metadata(
&self,
_account: Self::AccountId,
_address: &TransparentAddress,
) -> Result<Option<TransparentAddressMetadata>, Self::Error> {
Ok(None)
}
#[cfg(feature = "transparent-inputs")]
fn get_reserved_ephemeral_addresses(
&self,

View File

@ -534,6 +534,20 @@ impl<C: Borrow<rusqlite::Connection>, P: consensus::Parameters> WalletRead for W
)
}
#[cfg(feature = "transparent-inputs")]
fn get_transparent_address_metadata(
&self,
account: Self::AccountId,
address: &TransparentAddress,
) -> Result<Option<TransparentAddressMetadata>, Self::Error> {
wallet::transparent::get_transparent_address_metadata(
self.conn.borrow(),
&self.params,
account,
address,
)
}
#[cfg(feature = "transparent-inputs")]
fn get_reserved_ephemeral_addresses(
&self,

View File

@ -3,6 +3,7 @@ use std::collections::{HashMap, HashSet};
use rusqlite::OptionalExtension;
use rusqlite::{named_params, Connection, Row};
use zcash_keys::encoding::encode_transparent_address_p;
use zip32::{DiversifierIndex, Scope};
use zcash_address::unified::{Encoding, Ivk, Uivk};
@ -461,6 +462,57 @@ pub(crate) fn put_received_transparent_utxo<P: consensus::Parameters>(
}
}
pub(crate) fn get_transparent_address_metadata<P: consensus::Parameters>(
conn: &rusqlite::Connection,
params: &P,
account_id: AccountId,
address: &TransparentAddress,
) -> Result<Option<TransparentAddressMetadata>, SqliteClientError> {
let address_str = encode_transparent_address_p(params, address);
if let Some(di_vec) = conn
.query_row(
"SELECT diversifier_index_be FROM addresses
WHERE account_id = :account_id AND cached_transparent_receiver_address = :address",
named_params![":account_id": account_id.0, ":address": &address_str],
|row| row.get::<_, Vec<u8>>(0),
)
.optional()?
{
let address_index = address_index_from_diversifier_index_be(&di_vec)?;
let metadata = TransparentAddressMetadata::new(Scope::External.into(), address_index);
return Ok(Some(metadata));
}
if let Some((legacy_taddr, address_index)) =
get_legacy_transparent_address(params, conn, account_id)?
{
if &legacy_taddr == address {
let metadata = TransparentAddressMetadata::new(Scope::External.into(), address_index);
return Ok(Some(metadata));
}
}
// Search ephemeral addresses that have already been reserved.
if let Some(raw_index) = conn
.query_row(
"SELECT address_index FROM ephemeral_addresses
WHERE account_id = :account_id AND address = :address",
named_params![":account_id": account_id.0, ":address": &address_str],
|row| row.get::<_, u32>(0),
)
.optional()?
{
let address_index = NonHardenedChildIndex::from_index(raw_index).unwrap();
return Ok(Some(ephemeral::metadata(address_index)));
}
// We intentionally don't check for unreserved ephemeral addresses within the gap
// limit here. It's unnecessary to look up metadata for addresses from which we
// can spend.
Ok(None)
}
/// Attempts to determine the account that received the given transparent output.
///
/// The following three locations in the wallet's key tree are searched:

View File

@ -36,7 +36,7 @@ const EPHEMERAL_SCOPE: TransparentKeyScope = match TransparentKeyScope::custom(2
// Returns `TransparentAddressMetadata` in the ephemeral scope for the
// given address index.
fn metadata(address_index: NonHardenedChildIndex) -> TransparentAddressMetadata {
pub(crate) fn metadata(address_index: NonHardenedChildIndex) -> TransparentAddressMetadata {
TransparentAddressMetadata::new(EPHEMERAL_SCOPE, address_index)
}