diff --git a/zcash_client_backend/CHANGELOG.md b/zcash_client_backend/CHANGELOG.md index 68f07ad39b..1c8e544d8c 100644 --- a/zcash_client_backend/CHANGELOG.md +++ b/zcash_client_backend/CHANGELOG.md @@ -30,6 +30,8 @@ and this library adheres to Rust's notion of - The return type of `ChangeValue::output_pool`, and the type of the `output_pool` argument to `ChangeValue::new`, have changed from `ShieldedProtocol` to `zcash_protocol::PoolType`. +- `zcash_client_backend::input_selection::GreedyInputSelectorError` has a + new variant `UnsupportedTexAddress`. - `zcash_client_backend::wallet::Recipient` variants have changed. Instead of wrapping protocol-address types, the `Recipient` type now wraps a `zcash_address::ZcashAddress`. This simplifies the process of tracking the diff --git a/zcash_client_backend/src/data_api/wallet.rs b/zcash_client_backend/src/data_api/wallet.rs index e0e6918f02..deea7e9057 100644 --- a/zcash_client_backend/src/data_api/wallet.rs +++ b/zcash_client_backend/src/data_api/wallet.rs @@ -1044,6 +1044,9 @@ where payment.amount(), )); } + Address::Tex(_) => { + return Err(Error::ProposalNotSupported); + } } } diff --git a/zcash_client_backend/src/data_api/wallet/input_selection.rs b/zcash_client_backend/src/data_api/wallet/input_selection.rs index ddcba7304a..8ac49c92e3 100644 --- a/zcash_client_backend/src/data_api/wallet/input_selection.rs +++ b/zcash_client_backend/src/data_api/wallet/input_selection.rs @@ -222,6 +222,8 @@ pub enum GreedyInputSelectorError { Balance(BalanceError), /// A unified address did not contain a supported receiver. UnsupportedAddress(Box), + /// Support for transparent-source-only (TEX) addresses requires the transparent-inputs feature. + UnsupportedTexAddress, /// An error was encountered in change selection. Change(ChangeError), } @@ -239,6 +241,9 @@ impl fmt::Display for GreedyInputSelectorErro // don't have network parameters here write!(f, "Unified address contains no supported receivers.") } + GreedyInputSelectorError::UnsupportedTexAddress => { + write!(f, "Support for transparent-source-only (TEX) addresses requires the transparent-inputs feature.") + } GreedyInputSelectorError::Change(err) => { write!(f, "An error occurred computing change and fees: {}", err) } @@ -373,6 +378,11 @@ where script_pubkey: addr.script(), }); } + Address::Tex(_) => { + return Err(InputSelectorError::Selection( + GreedyInputSelectorError::UnsupportedTexAddress, + )); + } Address::Sapling(_) => { payment_pools.insert(*idx, PoolType::SAPLING); sapling_outputs.push(SaplingPayment(payment.amount())); diff --git a/zcash_client_sqlite/src/testing.rs b/zcash_client_sqlite/src/testing.rs index 89bde533bf..2773b9458f 100644 --- a/zcash_client_sqlite/src/testing.rs +++ b/zcash_client_sqlite/src/testing.rs @@ -1689,7 +1689,9 @@ fn fake_compact_block_spending( ) .0, ), - Address::Transparent(_) => panic!("transparent addresses not supported in compact blocks"), + Address::Transparent(_) | Address::Tex(_) => { + panic!("transparent addresses not supported in compact blocks") + } Address::Unified(ua) => { // This is annoying to implement, because the protocol-aware UA type has no // concept of ZIP 316 preference order. diff --git a/zcash_client_sqlite/src/wallet/init/migrations/ufvk_support.rs b/zcash_client_sqlite/src/wallet/init/migrations/ufvk_support.rs index b014b8f9ab..2d88745deb 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/ufvk_support.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/ufvk_support.rs @@ -131,7 +131,7 @@ impl RusqliteMigration for Migration

{ }); } } - Address::Transparent(_) => { + Address::Transparent(_) | Address::Tex(_) => { return Err(WalletMigrationError::CorruptedData( "Address field value decoded to a transparent address; should have been Sapling or unified.".to_string())); } @@ -263,7 +263,9 @@ impl RusqliteMigration for Migration

{ })?; let output_pool = match decoded_address { Address::Sapling(_) => Ok(pool_code(PoolType::SAPLING)), - Address::Transparent(_) => Ok(pool_code(PoolType::TRANSPARENT)), + Address::Transparent(_) | Address::Tex(_) => { + Ok(pool_code(PoolType::TRANSPARENT)) + } Address::Unified(_) => Err(WalletMigrationError::CorruptedData( "Unified addresses should not yet appear in the sent_notes table." .to_string(), diff --git a/zcash_keys/CHANGELOG.md b/zcash_keys/CHANGELOG.md index 4e8da9e526..d363f35bf8 100644 --- a/zcash_keys/CHANGELOG.md +++ b/zcash_keys/CHANGELOG.md @@ -5,11 +5,16 @@ and this library adheres to Rust's notion of [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Notable changes +- `zcash_keys` now supports TEX (transparent-source-only) addresses as specified + in [ZIP 320](https://zips.z.cash/zip-0320). + ### Added -- `zcash_keys::address::Address::try_from_zcash_address` +- `zcash_keys::address::Address::{try_from_zcash_address, try_from_raw_tex}` - `zcash_keys::address::Receiver` ### Changed +- `zcash_keys::Address` has a new variant `Tex`. - MSRV is now 1.66.0. ## [0.2.0] - 2024-03-25 diff --git a/zcash_keys/src/address.rs b/zcash_keys/src/address.rs index 8d3e0e4609..440a40cf87 100644 --- a/zcash_keys/src/address.rs +++ b/zcash_keys/src/address.rs @@ -293,10 +293,22 @@ impl Receiver { /// An address that funds can be sent to. #[derive(Debug, PartialEq, Eq, Clone)] pub enum Address { + /// A Sapling payment address. #[cfg(feature = "sapling")] Sapling(PaymentAddress), + + /// A transparent address corresponding to either a public key or a `Script`. Transparent(TransparentAddress), + + /// A [ZIP 316] Unified Address. + /// + /// [ZIP 316]: https://zips.z.cash/zip-0316 Unified(UnifiedAddress), + + /// A [ZIP 320] transparent-source-only P2PKH address, or "TEX address". + /// + /// [ZIP 320]: https://zips.z.cash/zip-0320 + Tex([u8; 20]), } #[cfg(feature = "sapling")] @@ -344,6 +356,10 @@ impl TryFromRawAddress for Address { fn try_from_raw_transparent_p2sh(data: [u8; 20]) -> Result> { Ok(TransparentAddress::ScriptHash(data).into()) } + + fn try_from_raw_tex(data: [u8; 20]) -> Result> { + Ok(Address::Tex(data)) + } } impl Address { @@ -379,6 +395,7 @@ impl Address { } }, Address::Unified(ua) => ua.to_address(net), + Address::Tex(data) => ZcashAddress::from_tex(net, *data), } } @@ -394,7 +411,9 @@ impl Address { Address::Sapling(_) => { matches!(pool_type, PoolType::Shielded(ShieldedProtocol::Sapling)) } - Address::Transparent(_) => matches!(pool_type, PoolType::Transparent), + Address::Transparent(_) | Address::Tex(_) => { + matches!(pool_type, PoolType::Transparent) + } Address::Unified(ua) => match pool_type { PoolType::Transparent => ua.transparent().is_some(), PoolType::Shielded(ShieldedProtocol::Sapling) => { @@ -449,6 +468,7 @@ pub mod testing { arb_payment_address().prop_map(Address::Sapling), arb_transparent_addr().prop_map(Address::Transparent), arb_unified_addr(Network::TestNetwork, request).prop_map(Address::Unified), + proptest::array::uniform20(any::()).prop_map(Address::Tex), ] } @@ -457,6 +477,7 @@ pub mod testing { return prop_oneof![ arb_transparent_addr().prop_map(Address::Transparent), arb_unified_addr(Network::TestNetwork, request).prop_map(Address::Unified), + proptest::array::uniform20(any::()).prop_map(Address::Tex), ]; } }