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:
parent
6b465b702e
commit
4f43a01f83
|
@ -53,7 +53,8 @@ funds to those addresses. See [ZIP 320](https://zips.z.cash/zip-0320) for detail
|
|||
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.
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue