Refactor transparent address metadata lookups. This is correct as-is but

will be simplified and made more efficient in subsequent commmits.

Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org>
This commit is contained in:
Daira-Emma Hopwood 2024-06-25 12:04:35 +01:00
parent 6b465b702e
commit 4f43a01f83
4 changed files with 58 additions and 37 deletions

View File

@ -48,12 +48,13 @@ funds to those addresses. See [ZIP 320](https://zips.z.cash/zip-0320) for detail
`change_memo` is given, and defends against losing money by using
`DustAction::AddDustToFee` with a too-high dust threshold.
See [#1430](https://github.com/zcash/librustzcash/pull/1430) for details.
- `zcash_client_backend::zip321` has been extracted to, and is now a reexport
- `zcash_client_backend::zip321` has been extracted to, and is now a reexport
of the root module of the `zip321` crate. Several of the APIs of this module
have changed as a consequence of this extraction; please see the `zip321`
CHANGELOG for details.
- `zcash_client_backend::data_api`:
- `WalletRead` has a new `get_reserved_ephemeral_addresses` method.
- `WalletRead` has new `get_reserved_ephemeral_addresses` and
`get_transparent_address_metadata` methods.
- `WalletWrite` has a new `reserve_next_n_ephemeral_addresses` method.
- `error::Error` has a new `Address` variant.
- `wallet::input_selection::InputSelectorError` has a new `Address` variant.

View File

@ -921,6 +921,41 @@ pub trait WalletRead {
Ok(HashMap::new())
}
/// Returns the metadata associated with a given transparent receiver in an account
/// controlled by this wallet.
///
/// This is equivalent to (but may be implemented more efficiently than):
/// ```compile_fail
/// if let Some(result) = self.get_transparent_receivers(account)?.get(address) {
/// return Ok(result.clone());
/// }
/// if let Some(result) = self.get_reserved_ephemeral_addresses(account, false)?.get(address) {
/// return Ok(result.clone());
/// }
/// Ok(None)
/// ```
///
/// Returns `Ok(None)` if the address is not recognized, or we do not have metadata for it.
/// Returns `Ok(Some(metadata))` if we have the metadata.
#[cfg(feature = "transparent-inputs")]
fn get_transparent_address_metadata(
&self,
account: Self::AccountId,
address: &TransparentAddress,
) -> Result<Option<TransparentAddressMetadata>, Self::Error> {
// This should be overridden.
if let Some(result) = self.get_transparent_receivers(account)?.get(address) {
return Ok(result.clone());
}
if let Some(result) = self
.get_reserved_ephemeral_addresses(account, false)?
.get(address)
{
return Ok(result.clone());
}
Ok(None)
}
/// Returns the set of reserved ephemeral transparent addresses associated with the
/// given account controlled by this wallet.
///

View File

@ -81,7 +81,6 @@ use {
},
input_selection::ShieldingSelector,
std::collections::HashMap,
zcash_keys::encoding::AddressCodec,
zcash_primitives::transaction::components::TxOut,
};
@ -829,41 +828,32 @@ where
}
#[cfg(feature = "transparent-inputs")]
let mut known_addrs = wallet_db
.get_transparent_receivers(account_id)
.map_err(Error::DataSource)?;
#[cfg(feature = "transparent-inputs")]
let mut ephemeral_added = false;
let mut cache = HashMap::<TransparentAddress, TransparentAddressMetadata>::new();
#[cfg(feature = "transparent-inputs")]
let mut metadata_from_address = |addr: TransparentAddress| -> Result<
TransparentAddressMetadata,
ErrorT<DbT, InputsErrT, FeeRuleT>,
> {
match known_addrs.get(&addr) {
None if !ephemeral_added => {
// The ephemeral addresses are added lazily to avoid extra database operations
// in the common case. We don't need to include them in order to be able to
// construct ZIP 320 transactions, because in that case the ephemeral output
// is represented via a "change" reference to a previous step. However, we do
// need them in order to create a transaction from a proposal that explicitly
// spends an output from an ephemeral address. This need not set `for_detection`
// because we only need to be able to spend outputs already detected by this
// wallet instance.
ephemeral_added = true;
known_addrs.extend(
wallet_db
.get_reserved_ephemeral_addresses(account_id, false)
.map_err(Error::DataSource)?
.into_iter(),
);
known_addrs.get(&addr)
match cache.get(&addr) {
Some(result) => Ok(result.clone()),
None => {
// `wallet_db.get_transparent_address_metadata` includes reserved ephemeral
// addresses in its lookup. We don't need to include these in order to be
// able to construct ZIP 320 transactions, because in that case the ephemeral
// output is represented via a "change" reference to a previous step. However,
// we do need them in order to create a transaction from a proposal that
// explicitly spends an output from an ephemeral address (only for outputs
// already detected by this wallet instance).
let result = wallet_db
.get_transparent_address_metadata(account_id, &addr)
.map_err(InputSelectorError::DataSource)?
.ok_or(Error::AddressNotRecognized(addr))?;
cache.insert(addr, result.clone());
Ok(result)
}
result => result,
}
.ok_or(Error::AddressNotRecognized(addr))?
.clone()
.ok_or_else(|| Error::NoSpendingKey(addr.encode(params)))
};
#[cfg(feature = "transparent-inputs")]

View File

@ -112,13 +112,8 @@ pub(crate) fn get_transparent_receivers<P: consensus::Parameters>(
}
if let Some((taddr, address_index)) = get_legacy_transparent_address(params, conn, account)? {
ret.insert(
taddr,
Some(TransparentAddressMetadata::new(
Scope::External.into(),
address_index,
)),
);
let metadata = TransparentAddressMetadata::new(Scope::External.into(), address_index);
ret.insert(taddr, Some(metadata));
}
Ok(ret)