Skip to content

Commit

Permalink
zcash_client_sqlite: Add handling for the transparent address gap limit.
Browse files Browse the repository at this point in the history
This is a large change that unifies the handling of ephemeral
transparent addresses for ZIP 320 support with generalized "gap limit"
handling for transparent wallet recovery. The best way to understand
this commit is to start from the `transparent_gap_limit_handling`
database migration that drives the change in behavior.
  • Loading branch information
nuttycom committed Dec 28, 2024
1 parent 3e51560 commit 4b99663
Show file tree
Hide file tree
Showing 25 changed files with 2,096 additions and 1,003 deletions.
16 changes: 13 additions & 3 deletions zcash_client_backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,19 @@ and this library adheres to Rust's notion of
- The `Recipient::External` variant is now a structured variant.
- The `Recipient::EphemeralTransparent` variant is now only available if
`zcash_client_backend` is built using the `transparent-inputs` feature flag.
- `zcash_client_backend::data_api::WalletRead::get_known_ephemeral_addresses`
now takes a `Range<zcash_transparent::keys::NonHardenedChildIndex>` as its
argument instead of a `Range<u32>`
- `zcash_client_backend::data_api::WalletRead`:
- `get_transparent_receivers` now takes additional `include_change` and
`include_ephemeral` arguments.
- `get_known_ephemeral_addresses` now takes a
`Range<zcash_transparent::keys::NonHardenedChildIndex>` as its argument
instead of a `Range<u32>`
- `zcash_client_backend::data_api::WalletWrite` has an added method
`get_address_for_index`

### Removed
- `zcash_client_backend::data_api::GAP_LIMIT` gap limits are now configured
based upon the key scope that they're associated with; there is no longer a
globally applicable gap limit.

## [0.16.0] - 2024-12-16

Expand Down
40 changes: 30 additions & 10 deletions zcash_client_backend/src/data_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ use incrementalmerkletree::{frontier::Frontier, Retention};
use nonempty::NonEmpty;
use secrecy::SecretVec;
use shardtree::{error::ShardTreeError, store::ShardStore, ShardTree};
use zip32::fingerprint::SeedFingerprint;
use zip32::{fingerprint::SeedFingerprint, DiversifierIndex};

use self::{
chain::{ChainState, CommitmentTreeRoot},
Expand Down Expand Up @@ -131,10 +131,6 @@ pub const SAPLING_SHARD_HEIGHT: u8 = sapling::NOTE_COMMITMENT_TREE_DEPTH / 2;
#[cfg(feature = "orchard")]
pub const ORCHARD_SHARD_HEIGHT: u8 = { orchard::NOTE_COMMITMENT_TREE_DEPTH as u8 } / 2;

/// The number of ephemeral addresses that can be safely reserved without observing any
/// of them to be mined. This is the same as the gap limit in Bitcoin.
pub const GAP_LIMIT: u32 = 20;

/// An enumeration of constraints that can be applied when querying for nullifiers for notes
/// belonging to the wallet.
pub enum NullifierQuery {
Expand Down Expand Up @@ -1386,6 +1382,8 @@ pub trait WalletRead {
fn get_transparent_receivers(
&self,
_account: Self::AccountId,
_include_change: bool,
_include_ephemeral: bool,
) -> Result<HashMap<TransparentAddress, Option<TransparentAddressMetadata>>, Self::Error> {
Ok(HashMap::new())
}
Expand All @@ -1410,7 +1408,7 @@ pub trait WalletRead {
/// This is equivalent to (but may be implemented more efficiently than):
/// ```compile_fail
/// Ok(
/// if let Some(result) = self.get_transparent_receivers(account)?.get(address) {
/// if let Some(result) = self.get_transparent_receivers(account, true, true)?.get(address) {
/// result.clone()
/// } else {
/// self.get_known_ephemeral_addresses(account, None)?
Expand All @@ -1431,7 +1429,10 @@ pub trait WalletRead {
) -> Result<Option<TransparentAddressMetadata>, Self::Error> {
// This should be overridden.
Ok(
if let Some(result) = self.get_transparent_receivers(account)?.get(address) {
if let Some(result) = self
.get_transparent_receivers(account, true, true)?
.get(address)

Check warning on line 1434 in zcash_client_backend/src/data_api.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api.rs#L1432-L1434

Added lines #L1432 - L1434 were not covered by tests
{
result.clone()
} else {
self.get_known_ephemeral_addresses(account, None)?
Expand Down Expand Up @@ -2377,9 +2378,10 @@ pub trait WalletWrite: WalletRead {
key_source: Option<&str>,
) -> Result<Self::Account, Self::Error>;

/// Generates and persists the next available diversified address for the specified account,
/// given the current addresses known to the wallet. If the `request` parameter is `None`,
/// an address should be generated using all of the available receivers for the account's UFVK.
/// Generates, persists, and marks as exposed the next available diversified address for the
/// specified account, given the current addresses known to the wallet. If the `request`
/// parameter is `None`, an address should be generated using all of the available receivers
/// for the account's UFVK.
///
/// Returns `Ok(None)` if the account identifier does not correspond to a known
/// account.
Expand All @@ -2389,6 +2391,24 @@ pub trait WalletWrite: WalletRead {
request: Option<UnifiedAddressRequest>,
) -> Result<Option<UnifiedAddress>, Self::Error>;

/// Generates, persists, and marks as exposed a diversified address for the specified account
/// at the provided diversifier index. If the `request` parameter is `None`, an address should
/// be generated using all of the available receivers for the account's UFVK.
///
/// In the case that the diversifier index is outside of the range of valid transparent address
/// indexes, no transparent receiver should be generated in the resulting unified address. If a
/// transparent receiver is specifically requested for such a diversifier index,
/// implementations of this method should return an error.
///
/// Address generation should fail if a transparent receiver would be generated that violates
/// the backend's internally configured gap limit for HD-seed-based recovery.
fn get_address_for_index(
&mut self,
account: Self::AccountId,
diversifier_index: DiversifierIndex,
request: Option<UnifiedAddressRequest>,
) -> Result<Option<UnifiedAddress>, Self::Error>;

/// Updates the wallet's view of the blockchain.
///
/// This method is used to provide the wallet with information about the state of the
Expand Down
11 changes: 11 additions & 0 deletions zcash_client_backend/src/data_api/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2613,6 +2613,8 @@ impl WalletRead for MockWalletDb {
fn get_transparent_receivers(
&self,
_account: Self::AccountId,
_include_change: bool,
_include_ephemeral: bool,
) -> Result<HashMap<TransparentAddress, Option<TransparentAddressMetadata>>, Self::Error> {
Ok(HashMap::new())
}
Expand Down Expand Up @@ -2703,6 +2705,15 @@ impl WalletWrite for MockWalletDb {
Ok(None)
}

fn get_address_for_index(

Check warning on line 2708 in zcash_client_backend/src/data_api/testing.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api/testing.rs#L2708

Added line #L2708 was not covered by tests
&mut self,
_account: Self::AccountId,
_diversifier_index: DiversifierIndex,
_request: Option<UnifiedAddressRequest>,
) -> Result<Option<UnifiedAddress>, Self::Error> {
Ok(None)

Check warning on line 2714 in zcash_client_backend/src/data_api/testing.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api/testing.rs#L2714

Added line #L2714 was not covered by tests
}

#[allow(clippy::type_complexity)]
fn put_blocks(
&mut self,
Expand Down
Loading

0 comments on commit 4b99663

Please sign in to comment.