Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zcash_client_backend: Introduce an "orchard" feature flag. #1080

Merged
merged 3 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
30 changes: 24 additions & 6 deletions zcash_client_backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ and this library adheres to Rust's notion of

### Added
- `zcash_client_backend::data_api`:
- `BlockMetadata::orchard_tree_size`.
- `BlockMetadata::orchard_tree_size` (when the `orchard` feature is enabled).
- `TransparentInputSource`
- `SaplingInputSource`
- `ScannedBlock::{
sapling_tree_size, orchard_tree_size, orchard_nullifier_map,
orchard_commitments, into_commitments
}`
- `ScannedBlock::{into_commitments, sapling}`
- `ScannedBlock::orchard` (when the `orchard` feature is enabled.)
- `ScannedBlockSapling`
- `ScannedBlockOrchard` (when the `orchard` feature is enabled.)
- `ScannedBlockCommitments`
- `Balance::{add_spendable_value, add_pending_change_value, add_pending_spendable_value}`
- `AccountBalance::{
with_sapling_balance_mut,
Expand Down Expand Up @@ -49,12 +50,17 @@ and this library adheres to Rust's notion of
wallet::{ReceivedSaplingNote, WalletTransparentOutput},
wallet::input_selection::{Proposal, SaplingInputs},
}`
- A new `orchard` feature flag has been added to make it possible to
build client code without `orchard` dependendencies.

### Moved
- `zcash_client_backend::data_api::{PoolType, ShieldedProtocol}` have
been moved into the `zcash_client_backend` root module.
- `zcash_client_backend::data_api::{NoteId, Recipient}` have
been moved into the `zcash_client_backend::wallet` module.
- `ScannedBlock::{sapling_tree_size, sapling_nullifier_map, sapling_commitments}`
have been moved to `ScannedBlockSapling` and in that context are now
named `{tree_size, nullifier_map, commitments}` respectively.

### Changed
- `zcash_client_backend::data_api`:
Expand All @@ -68,7 +74,6 @@ and this library adheres to Rust's notion of
`WalletShieldedOutput` change.
- `ScannedBlock` has an additional type parameter as a consequence of the
`WalletTx` change.
- Arguments to `ScannedBlock::from_parts` have changed.
- `ScannedBlock::metadata` has been renamed to `to_block_metadata` and now
returns an owned value rather than a reference.
- `ShieldedProtocol` has a new variant for `Orchard`, allowing for better
Expand Down Expand Up @@ -184,6 +189,18 @@ and this library adheres to Rust's notion of
- `zcash_client_backend::address`:
- `RecipientAddress` has been renamed to `Address`
- `Address::Shielded` has been renamed to `Address::Sapling`
- `UnifiedAddress::from_receivers` no longer takes an Orchard receiver
argument uless the `orchard` feature is enabled.
nuttycom marked this conversation as resolved.
Show resolved Hide resolved
- `UnifiedAddress::orchard` is now only available when the `orchard` feature
is enabled.

- `zcash_client_backend::keys`:
- `DerivationError::Orchard` is now only available when the `orchard` feature
is enabled.
- `UnifiedSpendingKey::orchard` is now only available when the `orchard`
feature is enabled.
- `UnifiedFullViewingKey::new` no longer takes an Orchard full viewing key
argument uless the `orchard` feature is enabled.
nuttycom marked this conversation as resolved.
Show resolved Hide resolved

### Removed
- `zcash_client_backend::wallet::ReceivedSaplingNote` has been replaced by
Expand All @@ -195,6 +212,7 @@ and this library adheres to Rust's notion of
removed without replacement as it was unused, and its functionality will be
fully reproduced by `SaplingInputSource::select_spendable_sapling_notes` in a future
change.
- `zcash_client_backend::data_api::ScannedBlock::from_parts` has been made crate-private.
- `zcash_client_backend::data_api::ScannedBlock::into_sapling_commitments` has been
replaced by `into_commitments` which returns both Sapling and Orchard note commitments
and associated note commitment retention information for the block.
Expand Down
7 changes: 5 additions & 2 deletions zcash_client_backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ subtle.workspace = true
# - Shielded protocols
bls12_381.workspace = true
group.workspace = true
orchard.workspace = true
orchard = { workspace = true, optional = true }
sapling.workspace = true

# - Note commitment trees
Expand Down Expand Up @@ -109,10 +109,13 @@ lightwalletd-tonic = ["dep:tonic"]
## Enables receiving transparent funds and shielding them.
transparent-inputs = ["dep:hdwallet", "zcash_primitives/transparent-inputs"]

## Enables receiving and spending Orchard funds.
orchard = ["dep:orchard"]

## Exposes APIs that are useful for testing, such as `proptest` strategies.
test-dependencies = [
"dep:proptest",
"orchard/test-dependencies",
"orchard?/test-dependencies",
"zcash_primitives/test-dependencies",
"incrementalmerkletree/test-dependencies",
]
Expand Down
41 changes: 33 additions & 8 deletions zcash_client_backend/src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ impl AddressMetadata {
/// A Unified Address.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnifiedAddress {
#[cfg(feature = "orchard")]
orchard: Option<orchard::Address>,
sapling: Option<PaymentAddress>,
transparent: Option<TransparentAddress>,
Expand All @@ -48,6 +49,7 @@ impl TryFrom<unified::Address> for UnifiedAddress {
type Error = &'static str;

fn try_from(ua: unified::Address) -> Result<Self, Self::Error> {
#[cfg(feature = "orchard")]
let mut orchard = None;
let mut sapling = None;
let mut transparent = None;
Expand All @@ -58,6 +60,7 @@ impl TryFrom<unified::Address> for UnifiedAddress {
.items_as_parsed()
.iter()
.filter_map(|receiver| match receiver {
#[cfg(feature = "orchard")]
unified::Receiver::Orchard(data) => {
Option::from(orchard::Address::from_raw_address_bytes(data))
.ok_or("Invalid Orchard receiver in Unified Address")
Expand All @@ -67,6 +70,10 @@ impl TryFrom<unified::Address> for UnifiedAddress {
})
.transpose()
}
#[cfg(not(feature = "orchard"))]
unified::Receiver::Orchard(data) => {
Some(Ok((unified::Typecode::Orchard.into(), data.to_vec())))
}
unified::Receiver::Sapling(data) => PaymentAddress::from_bytes(data)
.ok_or("Invalid Sapling receiver in Unified Address")
.map(|pa| {
Expand All @@ -89,6 +96,7 @@ impl TryFrom<unified::Address> for UnifiedAddress {
.collect::<Result<_, _>>()?;

Ok(Self {
#[cfg(feature = "orchard")]
orchard,
sapling,
transparent,
Expand All @@ -103,12 +111,18 @@ impl UnifiedAddress {
/// Returns `None` if the receivers would produce an invalid Unified Address (namely,
/// if no shielded receiver is provided).
pub fn from_receivers(
orchard: Option<orchard::Address>,
#[cfg(feature = "orchard")] orchard: Option<orchard::Address>,
str4d marked this conversation as resolved.
Show resolved Hide resolved
sapling: Option<PaymentAddress>,
transparent: Option<TransparentAddress>,
) -> Option<Self> {
if orchard.is_some() || sapling.is_some() {
#[cfg(feature = "orchard")]
let has_orchard = orchard.is_some();
#[cfg(not(feature = "orchard"))]
let has_orchard = false;

if has_orchard || sapling.is_some() {
Some(Self {
#[cfg(feature = "orchard")]
orchard,
sapling,
transparent,
Expand All @@ -121,6 +135,7 @@ impl UnifiedAddress {
}

/// Returns the Orchard receiver within this Unified Address, if any.
#[cfg(feature = "orchard")]
pub fn orchard(&self) -> Option<&orchard::Address> {
self.orchard.as_ref()
}
Expand All @@ -136,6 +151,15 @@ impl UnifiedAddress {
}

fn to_address(&self, net: Network) -> ZcashAddress {
#[cfg(feature = "orchard")]
let orchard_receiver = self
.orchard
.as_ref()
.map(|addr| addr.to_raw_address_bytes())
.map(unified::Receiver::Orchard);
#[cfg(not(feature = "orchard"))]
let orchard_receiver = None;

let ua = unified::Address::try_from_items(
self.unknown
.iter()
Expand All @@ -153,12 +177,7 @@ impl UnifiedAddress {
.map(|pa| pa.to_bytes())
.map(unified::Receiver::Sapling),
)
.chain(
self.orchard
.as_ref()
.map(|addr| addr.to_raw_address_bytes())
.map(unified::Receiver::Orchard),
)
.chain(orchard_receiver)
.collect(),
)
.expect("UnifiedAddress should only be constructed safely");
Expand Down Expand Up @@ -259,6 +278,7 @@ mod tests {

#[test]
fn ua_round_trip() {
#[cfg(feature = "orchard")]
let orchard = {
let sk = orchard::keys::SpendingKey::from_zip32_seed(&[0; 32], 0, 0).unwrap();
let fvk = orchard::keys::FullViewingKey::from(&sk);
Expand All @@ -273,8 +293,12 @@ mod tests {

let transparent = { None };

#[cfg(feature = "orchard")]
let ua = UnifiedAddress::from_receivers(orchard, sapling, transparent).unwrap();

#[cfg(not(feature = "orchard"))]
let ua = UnifiedAddress::from_receivers(sapling, transparent).unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could just be

let ua = UnifiedAddress::from_receivers(
    #[cfg(feature = "orchard")] orchard,
    sapling,
    transparent,
).unwrap();

(which will be simpler once we add the "sapling" feature).


let addr = Address::Unified(ua);
let addr_str = addr.encode(&MAIN_NETWORK);
assert_eq!(Address::decode(&MAIN_NETWORK, &addr_str), Some(addr));
Expand All @@ -290,6 +314,7 @@ mod tests {
tv.p2pkh_bytes.is_some() || tv.p2sh_bytes.is_some()
);
assert_eq!(ua.sapling().is_some(), tv.sapling_raw_addr.is_some());
#[cfg(feature = "orchard")]
assert_eq!(ua.orchard().is_some(), tv.orchard_raw_addr.is_some());
}
Some(_) => {
Expand Down
Loading
Loading