Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions librustzcash/zcash_client_backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,37 @@ workspace.

## [Unreleased]

### Added - Zero fork
- `zcash_client_backend::data_api::wallet::ConfirmationsPolicy::bucketed_at_age`
- `zcash_client_backend::data_api::wallet::ConfirmationsPolicy::anchored_at`
- `zcash_client_backend::data_api::anchor_retention::CHECKPOINT_RETENTION_DEPTH`

### Changed - Zero fork
- `zcash_client_backend::data_api::wallet::propose_transfer` now draws a ZIP 318
anchor for EVERY proposal that spends Orchard notes, not only for a canonical
ZIP 318 crossing. The anchor is a boundary of the wallet's anchor bucket grid
at an age drawn from the ZIP 318 recency-weighted distribution when one is
admissible, and a uniformly drawn height between the newest note the proposal
spends and the target height when none is. When the drawn anchor is not
computable, or the wallet cannot fund the payment from notes old enough for
it, the proposal falls back to the ordinary anchor as before. The remaining
ZIP 318 crossing properties (canonical denomination, Ironwood bundle padding,
canonical fee) are unchanged and still apply only to a canonical crossing.
Callers should expect an Orchard-spending payment to require up to four grid
intervals of additional confirmations on its inputs.
- Any step proved against a bucket boundary now takes the ZIP 318 rolling
expiry, where previously only a canonical crossing did.
- `ConfirmationsPolicy::bucketed` now derives the most recent boundary from the
latest observed block rather than from the anchor its own confirmation
requirement implies, so that wallets with different confirmation requirements
agree on the grid.
- The note commitment trees now retain `CHECKPOINT_RETENTION_DEPTH` ordinary
checkpoints rather than as many as the backend's rewind bound allows, so that
a uniformly drawn fallback anchor remains witnessable.
- `zcash_client_backend::data_api::error::Error::ExpiryHeightConflictsWithCanonicalCrossing`
has been renamed to `ExpiryHeightConflictsWithBoundaryAnchor`, and is now
returned for any boundary-anchored step rather than only a canonical crossing.

### Added
- `zcash_client_backend::data_api::WalletWrite::import_standalone_transparent_address`
(requires the `transparent-key-import` feature): imports a transparent
Expand Down
17 changes: 17 additions & 0 deletions librustzcash/zcash_client_backend/src/data_api/anchor_retention.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,23 @@ use zcash_protocol::consensus::BlockHeight;
/// which is `AnchorBucketInterval::ZIP_318`.
pub use zcash_protocol::zip318::AnchorBucketInterval as AnchorRetentionInterval;

/// The number of ORDINARY checkpoints a wallet's note commitment trees retain, beyond which the
/// oldest are pruned. Checkpoints retained as durable anchors under an [`AnchorRetention`] policy
/// are exempt from this budget.
///
/// This answers a different question from a backend's rewind bound, which governs how far the
/// wallet may roll back and how far scanning re-verifies; this one governs which historical heights
/// a note can still be witnessed against, and is deeper. The [ZIP 318] FALLBACK anchor is drawn
/// uniformly from a window this depth must cover, and that window reaches back at most two anchor
/// bucket intervals: the fallback is taken only when the newest note a transaction spends postdates
/// the newest candidate boundary, which places it within one interval of the most recent boundary,
/// itself within one interval of the chain tip. At [`AnchorRetentionInterval::ZIP_318`] that is 288
/// blocks; an anchor drawn at a height whose checkpoint had been pruned could not be witnessed
/// against.
///
/// [ZIP 318]: https://zips.z.cash/zip-0318
pub const CHECKPOINT_RETENTION_DEPTH: u32 = 300;

/// The anchor-retention policy in force while a range of blocks is being added to the wallet: the
/// set of grids whose boundaries are retained, and the height from which retention applies.
///
Expand Down
21 changes: 11 additions & 10 deletions librustzcash/zcash_client_backend/src/data_api/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ pub enum Error<DataSourceError, CommitmentTreeError, SelectionError, FeeError, C
min_target_height: BlockHeight,
},

/// The caller requested an expiry height for a step that is a canonical ZIP 318 crossing.
/// The caller requested an expiry height for a step proved against an anchor bucket boundary.
///
/// Such a step takes its expiry from the ZIP 318 rolling window, which every crossing in the
/// same period shares; a caller-chosen expiry would single it out and undo the shape the
/// unpadded bundle and bucketed anchor were chosen to produce. Those are already fixed by the
/// time the transaction is built, so the conflict is reported rather than silently resolved.
/// Pass `None` to accept the canonical expiry.
ExpiryHeightConflictsWithCanonicalCrossing { requested: BlockHeight },
/// Such a step takes its expiry from the ZIP 318 rolling window, which every transaction in
/// the same period shares; a caller-chosen expiry would single it out and undo the anonymity
/// the bucketed anchor was chosen to produce. The anchor is already fixed by the time the
/// transaction is built, so the conflict is reported rather than silently resolved. Pass
/// `None` to accept the ZIP 318 rolling expiry.
ExpiryHeightConflictsWithBoundaryAnchor { requested: BlockHeight },
Comment thread
Copilot marked this conversation as resolved.

/// An error occurred while working with PCZTs.
#[cfg(feature = "pczt")]
Expand Down Expand Up @@ -326,10 +326,11 @@ where
"The specified transparent address was not recognized as belonging to the wallet."
)
}
Error::ExpiryHeightConflictsWithCanonicalCrossing { requested } => write!(
Error::ExpiryHeightConflictsWithBoundaryAnchor { requested } => write!(
f,
"An expiry height of {requested} was requested for a canonical ZIP 318 crossing, \
which takes the ZIP 318 rolling expiry; pass `None` to accept it."
"An expiry height of {requested} was requested for a transaction proved against \
an anchor bucket boundary, which takes the ZIP 318 rolling expiry; pass `None` \
to accept it."
),
Error::ExpiryHeightBelowTargetHeight {
expiry_height,
Expand Down
Loading
Loading