zcash_client_backend: Update to use extracted `zip321` crate

This commit is contained in:
Kris Nuttycombe 2024-01-27 13:46:14 -07:00
parent d982d7826a
commit 3ea7d84183
13 changed files with 120 additions and 41 deletions

View File

@ -8,8 +8,8 @@ and this library adheres to Rust's notion of
## [Unreleased] ## [Unreleased]
### Added ### Added
- `zcash_address::ZcashAddress::can_receive_memo` - `zcash_address::ZcashAddress::{can_receive_memo, can_receive_as}`
- `zcash_address::unified::Address::can_receive_memo` - `zcash_address::unified::Address::{can_receive_memo, has_receiver}`
- Module `zcash_address::testing` under the `test-dependencies` feature. - Module `zcash_address::testing` under the `test-dependencies` feature.
- Module `zcash_address::unified::address::testing` under the - Module `zcash_address::unified::address::testing` under the
`test-dependencies` feature. `test-dependencies` feature.

View File

@ -1,3 +1,5 @@
use zcash_protocol::{PoolType, ShieldedProtocol};
use super::{private::SealedItem, ParseError, Typecode}; use super::{private::SealedItem, ParseError, Typecode};
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
@ -102,6 +104,17 @@ impl SealedItem for Receiver {
pub struct Address(pub(crate) Vec<Receiver>); pub struct Address(pub(crate) Vec<Receiver>);
impl Address { impl Address {
/// Returns whether this address has the ability to receive transfers of the given pool type.
pub fn has_receiver(&self, pool_type: PoolType) -> bool {
self.0.iter().any(|r| match r {
Receiver::Orchard(_) => pool_type == PoolType::Shielded(ShieldedProtocol::Orchard),
Receiver::Sapling(_) => pool_type == PoolType::Shielded(ShieldedProtocol::Sapling),
Receiver::P2pkh(_) => pool_type == PoolType::Transparent,
Receiver::P2sh(_) => pool_type == PoolType::Transparent,
Receiver::Unknown { .. } => false,
})
}
/// Returns whether this address can receive a memo. /// Returns whether this address can receive a memo.
pub fn can_receive_memo(&self) -> bool { pub fn can_receive_memo(&self) -> bool {
self.0 self.0

View File

@ -142,6 +142,7 @@ pub use convert::{
pub use encoding::ParseError; pub use encoding::ParseError;
pub use kind::unified; pub use kind::unified;
pub use zcash_protocol::consensus::NetworkType as Network; pub use zcash_protocol::consensus::NetworkType as Network;
use zcash_protocol::{PoolType, ShieldedProtocol};
/// A Zcash address. /// A Zcash address.
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
@ -267,6 +268,18 @@ impl ZcashAddress {
} }
} }
/// Returns whether this address has the ability to receive transfers of the given pool type.
pub fn can_receive_as(&self, pool_type: PoolType) -> bool {
match &self.kind {
AddressKind::Sprout(_) => false,
AddressKind::Sapling(_) => pool_type == PoolType::Shielded(ShieldedProtocol::Sapling),
AddressKind::Unified(addr) => addr.has_receiver(pool_type),
AddressKind::P2pkh(_) => pool_type == PoolType::Transparent,
AddressKind::P2sh(_) => pool_type == PoolType::Transparent,
AddressKind::Tex(_) => pool_type == PoolType::Transparent,
}
}
/// Returns whether this address can receive a memo. /// Returns whether this address can receive a memo.
pub fn can_receive_memo(&self) -> bool { pub fn can_receive_memo(&self) -> bool {
match &self.kind { match &self.kind {

View File

@ -19,6 +19,12 @@ and this library adheres to Rust's notion of
of the root module of the `zip321` crate. Several of the APIs of this module of the root module of the `zip321` crate. Several of the APIs of this module
have changed as a consequence of this extraction; please see the `zip321` have changed as a consequence of this extraction; please see the `zip321`
CHANGELOG for details. CHANGELOG for details.
- `zcash_client_backend::data_api`:
- `error::Error` has a new `Address` variant.
- `wallet::input_selection::InputSelectorError` has a new `Address` variant.
- `zcash_client_backend::proto::proposal::Proposal::{from_standard_proposal,
try_into_standard_proposal}` each no longer require a `consensus::Parameters`
argument.
## [0.12.1] - 2024-03-27 ## [0.12.1] - 2024-03-27

View File

@ -4,6 +4,7 @@ use std::error;
use std::fmt::{self, Debug, Display}; use std::fmt::{self, Debug, Display};
use shardtree::error::ShardTreeError; use shardtree::error::ShardTreeError;
use zcash_address::ConversionError;
use zcash_primitives::transaction::components::amount::NonNegativeAmount; use zcash_primitives::transaction::components::amount::NonNegativeAmount;
use zcash_primitives::transaction::{ use zcash_primitives::transaction::{
builder, builder,
@ -81,6 +82,9 @@ pub enum Error<DataSourceError, CommitmentTreeError, SelectionError, FeeError> {
/// full viewing key for an account. /// full viewing key for an account.
NoteMismatch(NoteId), NoteMismatch(NoteId),
/// An error occurred parsing the address from a payment request.
Address(ConversionError<&'static str>),
#[cfg(feature = "transparent-inputs")] #[cfg(feature = "transparent-inputs")]
AddressNotRecognized(TransparentAddress), AddressNotRecognized(TransparentAddress),
} }
@ -145,6 +149,9 @@ where
Error::NoSpendingKey(addr) => write!(f, "No spending key available for address: {}", addr), Error::NoSpendingKey(addr) => write!(f, "No spending key available for address: {}", addr),
Error::NoteMismatch(n) => write!(f, "A note being spent ({:?}) does not correspond to either the internal or external full viewing key for the provided spending key.", n), Error::NoteMismatch(n) => write!(f, "A note being spent ({:?}) does not correspond to either the internal or external full viewing key for the provided spending key.", n),
Error::Address(e) => {
write!(f, "An error occurred decoding the address from a payment request: {}.", e)
}
#[cfg(feature = "transparent-inputs")] #[cfg(feature = "transparent-inputs")]
Error::AddressNotRecognized(_) => { Error::AddressNotRecognized(_) => {
write!(f, "The specified transparent address was not recognized as belonging to the wallet.") write!(f, "The specified transparent address was not recognized as belonging to the wallet.")
@ -184,6 +191,12 @@ impl<DE, CE, SE, FE> From<BalanceError> for Error<DE, CE, SE, FE> {
} }
} }
impl<DE, CE, SE, FE> From<ConversionError<&'static str>> for Error<DE, CE, SE, FE> {
fn from(value: ConversionError<&'static str>) -> Self {
Error::Address(value)
}
}
impl<DE, CE, SE, FE> From<InputSelectorError<DE, SE>> for Error<DE, CE, SE, FE> { impl<DE, CE, SE, FE> From<InputSelectorError<DE, SE>> for Error<DE, CE, SE, FE> {
fn from(e: InputSelectorError<DE, SE>) -> Self { fn from(e: InputSelectorError<DE, SE>) -> Self {
match e { match e {
@ -198,6 +211,7 @@ impl<DE, CE, SE, FE> From<InputSelectorError<DE, SE>> for Error<DE, CE, SE, FE>
required, required,
}, },
InputSelectorError::SyncRequired => Error::ScanRequired, InputSelectorError::SyncRequired => Error::ScanRequired,
InputSelectorError::Address(e) => Error::Address(e),
} }
} }
} }

View File

@ -498,7 +498,7 @@ where
DbT::NoteRef: Copy + Eq + Ord, DbT::NoteRef: Copy + Eq + Ord,
{ {
let request = zip321::TransactionRequest::new(vec![Payment { let request = zip321::TransactionRequest::new(vec![Payment {
recipient_address: to.clone(), recipient_address: to.to_zcash_address(params),
amount, amount,
memo, memo,
label: None, label: None,
@ -848,13 +848,16 @@ where
// the transaction in payment index order, so we can use dead reckoning to // the transaction in payment index order, so we can use dead reckoning to
// figure out which output it ended up being. // figure out which output it ended up being.
let (prior_step, result) = &prior_step_results[input_ref.step_index()]; let (prior_step, result) = &prior_step_results[input_ref.step_index()];
let recipient_address = match &prior_step let recipient_address = &prior_step
.transaction_request() .transaction_request()
.payments() .payments()
.get(&i) .get(&i)
.expect("Payment step references are checked at construction") .expect("Payment step references are checked at construction")
.recipient_address .recipient_address
{ .clone()
.convert_if_network(params.network_type())?;
let recipient_taddr = match recipient_address {
Address::Transparent(t) => Some(t), Address::Transparent(t) => Some(t),
Address::Unified(uaddr) => uaddr.transparent(), Address::Unified(uaddr) => uaddr.transparent(),
_ => None, _ => None,
@ -879,7 +882,7 @@ where
.ok_or(Error::Proposal(ProposalError::ReferenceError(*input_ref)))? .ok_or(Error::Proposal(ProposalError::ReferenceError(*input_ref)))?
.vout[outpoint.n() as usize]; .vout[outpoint.n() as usize];
add_transparent_input(recipient_address, outpoint, utxo.clone())?; add_transparent_input(recipient_taddr, outpoint, utxo.clone())?;
} }
proposal::StepOutputIndex::Change(_) => unreachable!(), proposal::StepOutputIndex::Change(_) => unreachable!(),
} }
@ -953,7 +956,11 @@ where
(payment, output_pool) (payment, output_pool)
}) })
{ {
match &payment.recipient_address { let recipient_address = payment
.recipient_address
.clone()
.convert_if_network::<Address>(params.network_type())?;
match recipient_address {
Address::Unified(ua) => { Address::Unified(ua) => {
let memo = payment let memo = payment
.memo .memo
@ -1019,17 +1026,17 @@ where
.map_or_else(MemoBytes::empty, |m| m.clone()); .map_or_else(MemoBytes::empty, |m| m.clone());
builder.add_sapling_output( builder.add_sapling_output(
sapling_external_ovk, sapling_external_ovk,
*addr, addr,
payment.amount, payment.amount,
memo.clone(), memo.clone(),
)?; )?;
sapling_output_meta.push((Recipient::Sapling(*addr), payment.amount, Some(memo))); sapling_output_meta.push((Recipient::Sapling(addr), payment.amount, Some(memo)));
} }
Address::Transparent(to) => { Address::Transparent(to) => {
if payment.memo.is_some() { if payment.memo.is_some() {
return Err(Error::MemoForbidden); return Err(Error::MemoForbidden);
} else { } else {
builder.add_transparent_output(to, payment.amount)?; builder.add_transparent_output(&to, payment.amount)?;
} }
transparent_output_meta.push((to, payment.amount)); transparent_output_meta.push((to, payment.amount));
} }
@ -1167,7 +1174,7 @@ where
.map(|(index, _)| index) .map(|(index, _)| index)
.expect("An output should exist in the transaction for each transparent payment."); .expect("An output should exist in the transaction for each transparent payment.");
SentTransactionOutput::from_parts(output_index, Recipient::Transparent(*addr), value, None) SentTransactionOutput::from_parts(output_index, Recipient::Transparent(addr), value, None)
}); });
let mut outputs = vec![]; let mut outputs = vec![];

View File

@ -8,6 +8,7 @@ use std::{
}; };
use nonempty::NonEmpty; use nonempty::NonEmpty;
use zcash_address::ConversionError;
use zcash_primitives::{ use zcash_primitives::{
consensus::{self, BlockHeight}, consensus::{self, BlockHeight},
transaction::{ transaction::{
@ -48,6 +49,8 @@ pub enum InputSelectorError<DbErrT, SelectorErrT> {
Selection(SelectorErrT), Selection(SelectorErrT),
/// Input selection attempted to generate an invalid transaction proposal. /// Input selection attempted to generate an invalid transaction proposal.
Proposal(ProposalError), Proposal(ProposalError),
/// An error occurred parsing the address from a payment request.
Address(ConversionError<&'static str>),
/// Insufficient funds were available to satisfy the payment request that inputs were being /// Insufficient funds were available to satisfy the payment request that inputs were being
/// selected to attempt to satisfy. /// selected to attempt to satisfy.
InsufficientFunds { InsufficientFunds {
@ -59,6 +62,12 @@ pub enum InputSelectorError<DbErrT, SelectorErrT> {
SyncRequired, SyncRequired,
} }
impl<E, S> From<ConversionError<&'static str>> for InputSelectorError<E, S> {
fn from(value: ConversionError<&'static str>) -> Self {
InputSelectorError::Address(value)
}
}
impl<DE: fmt::Display, SE: fmt::Display> fmt::Display for InputSelectorError<DE, SE> { impl<DE: fmt::Display, SE: fmt::Display> fmt::Display for InputSelectorError<DE, SE> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self { match &self {
@ -79,6 +88,13 @@ impl<DE: fmt::Display, SE: fmt::Display> fmt::Display for InputSelectorError<DE,
e e
) )
} }
InputSelectorError::Address(e) => {
write!(
f,
"An error occurred decoding the address from a payment request: {}.",
e
)
}
InputSelectorError::InsufficientFunds { InputSelectorError::InsufficientFunds {
available, available,
required, required,
@ -344,7 +360,11 @@ where
let mut orchard_outputs = vec![]; let mut orchard_outputs = vec![];
let mut payment_pools = BTreeMap::new(); let mut payment_pools = BTreeMap::new();
for (idx, payment) in transaction_request.payments() { for (idx, payment) in transaction_request.payments() {
match &payment.recipient_address { let recipient_address = payment
.recipient_address
.clone()
.convert_if_network::<Address>(params.network_type())?;
match recipient_address {
Address::Transparent(addr) => { Address::Transparent(addr) => {
payment_pools.insert(*idx, PoolType::Transparent); payment_pools.insert(*idx, PoolType::Transparent);
transparent_outputs.push(TxOut { transparent_outputs.push(TxOut {
@ -380,7 +400,7 @@ where
} }
return Err(InputSelectorError::Selection( return Err(InputSelectorError::Selection(
GreedyInputSelectorError::UnsupportedAddress(Box::new(addr.clone())), GreedyInputSelectorError::UnsupportedAddress(Box::new(addr)),
)); ));
} }
} }

View File

@ -377,7 +377,7 @@ impl<NoteRef> Step<NoteRef> {
.payments() .payments()
.get(idx) .get(idx)
.iter() .iter()
.any(|payment| payment.recipient_address.has_receiver(*pool)) .any(|payment| payment.recipient_address.can_receive_as(*pool))
{ {
return Err(ProposalError::PaymentPoolsMismatch); return Err(ProposalError::PaymentPoolsMismatch);
} }

View File

@ -13,7 +13,7 @@ use sapling::{self, note::ExtractedNoteCommitment, Node};
use zcash_note_encryption::{EphemeralKeyBytes, COMPACT_NOTE_SIZE}; use zcash_note_encryption::{EphemeralKeyBytes, COMPACT_NOTE_SIZE};
use zcash_primitives::{ use zcash_primitives::{
block::{BlockHash, BlockHeader}, block::{BlockHash, BlockHeader},
consensus::{self, BlockHeight, Parameters}, consensus::BlockHeight,
memo::{self, MemoBytes}, memo::{self, MemoBytes},
merkle_tree::read_commitment_tree, merkle_tree::read_commitment_tree,
transaction::{components::amount::NonNegativeAmount, fees::StandardFeeRule, TxId}, transaction::{components::amount::NonNegativeAmount, fees::StandardFeeRule, TxId},
@ -485,17 +485,14 @@ impl From<ShieldedProtocol> for proposal::ValuePool {
impl proposal::Proposal { impl proposal::Proposal {
/// Serializes a [`Proposal`] based upon a supported [`StandardFeeRule`] to its protobuf /// Serializes a [`Proposal`] based upon a supported [`StandardFeeRule`] to its protobuf
/// representation. /// representation.
pub fn from_standard_proposal<P: Parameters, NoteRef>( pub fn from_standard_proposal<NoteRef>(value: &Proposal<StandardFeeRule, NoteRef>) -> Self {
params: &P,
value: &Proposal<StandardFeeRule, NoteRef>,
) -> Self {
use proposal::proposed_input; use proposal::proposed_input;
use proposal::{PriorStepChange, PriorStepOutput, ReceivedOutput}; use proposal::{PriorStepChange, PriorStepOutput, ReceivedOutput};
let steps = value let steps = value
.steps() .steps()
.iter() .iter()
.map(|step| { .map(|step| {
let transaction_request = step.transaction_request().to_uri(params); let transaction_request = step.transaction_request().to_uri();
let anchor_height = step let anchor_height = step
.shielded_inputs() .shielded_inputs()
@ -607,9 +604,8 @@ impl proposal::Proposal {
/// Attempts to parse a [`Proposal`] based upon a supported [`StandardFeeRule`] from its /// Attempts to parse a [`Proposal`] based upon a supported [`StandardFeeRule`] from its
/// protobuf representation. /// protobuf representation.
pub fn try_into_standard_proposal<P: consensus::Parameters, DbT, DbError>( pub fn try_into_standard_proposal<DbT, DbError>(
&self, &self,
params: &P,
wallet_db: &DbT, wallet_db: &DbT,
) -> Result<Proposal<StandardFeeRule, DbT::NoteRef>, ProposalDecodingError<DbError>> ) -> Result<Proposal<StandardFeeRule, DbT::NoteRef>, ProposalDecodingError<DbError>>
where where
@ -631,7 +627,7 @@ impl proposal::Proposal {
let mut steps = Vec::with_capacity(self.steps.len()); let mut steps = Vec::with_capacity(self.steps.len());
for step in &self.steps { for step in &self.steps {
let transaction_request = let transaction_request =
TransactionRequest::from_uri(params, &step.transaction_request)?; TransactionRequest::from_uri(&step.transaction_request)?;
let payment_pools = step let payment_pools = step
.payment_output_pools .payment_output_pools

View File

@ -1896,7 +1896,7 @@ fn check_proposal_serialization_roundtrip(
db_data: &WalletDb<rusqlite::Connection, LocalNetwork>, db_data: &WalletDb<rusqlite::Connection, LocalNetwork>,
proposal: &Proposal<StandardFeeRule, ReceivedNoteId>, proposal: &Proposal<StandardFeeRule, ReceivedNoteId>,
) { ) {
let proposal_proto = proposal::Proposal::from_standard_proposal(&db_data.params, proposal); let proposal_proto = proposal::Proposal::from_standard_proposal(proposal);
let deserialized_proposal = proposal_proto.try_into_standard_proposal(&db_data.params, db_data); let deserialized_proposal = proposal_proto.try_into_standard_proposal(db_data);
assert_matches!(deserialized_proposal, Ok(r) if &r == proposal); assert_matches!(deserialized_proposal, Ok(r) if &r == proposal);
} }

View File

@ -169,7 +169,7 @@ pub(crate) fn send_single_step_proposed_transfer<T: ShieldedPoolTester>() {
let to_extsk = T::sk(&[0xf5; 32]); let to_extsk = T::sk(&[0xf5; 32]);
let to: Address = T::sk_default_address(&to_extsk); let to: Address = T::sk_default_address(&to_extsk);
let request = zip321::TransactionRequest::new(vec![Payment { let request = zip321::TransactionRequest::new(vec![Payment {
recipient_address: to, recipient_address: to.to_zcash_address(&st.network()),
amount: NonNegativeAmount::const_from_u64(10000), amount: NonNegativeAmount::const_from_u64(10000),
memo: None, // this should result in the creation of an empty memo memo: None, // this should result in the creation of an empty memo
label: None, label: None,
@ -338,7 +338,7 @@ pub(crate) fn send_multi_step_proposed_transfer<T: ShieldedPoolTester>() {
// The first step will deshield to the wallet's default transparent address // The first step will deshield to the wallet's default transparent address
let to0 = Address::Transparent(account.usk().default_transparent_address().0); let to0 = Address::Transparent(account.usk().default_transparent_address().0);
let request0 = zip321::TransactionRequest::new(vec![Payment { let request0 = zip321::TransactionRequest::new(vec![Payment {
recipient_address: to0, recipient_address: to0.to_zcash_address(&st.network()),
amount: NonNegativeAmount::const_from_u64(50000), amount: NonNegativeAmount::const_from_u64(50000),
memo: None, memo: None,
label: None, label: None,
@ -383,7 +383,7 @@ pub(crate) fn send_multi_step_proposed_transfer<T: ShieldedPoolTester>() {
.0, .0,
); );
let request1 = zip321::TransactionRequest::new(vec![Payment { let request1 = zip321::TransactionRequest::new(vec![Payment {
recipient_address: to1, recipient_address: to1.to_zcash_address(&st.network()),
amount: NonNegativeAmount::const_from_u64(40000), amount: NonNegativeAmount::const_from_u64(40000),
memo: None, memo: None,
label: None, label: None,
@ -1043,7 +1043,7 @@ pub(crate) fn external_address_change_spends_detected_in_restore_from_seed<
let req = TransactionRequest::new(vec![ let req = TransactionRequest::new(vec![
// payment to an external recipient // payment to an external recipient
Payment { Payment {
recipient_address: addr2, recipient_address: addr2.to_zcash_address(&st.network()),
amount: amount_sent, amount: amount_sent,
memo: None, memo: None,
label: None, label: None,
@ -1052,7 +1052,7 @@ pub(crate) fn external_address_change_spends_detected_in_restore_from_seed<
}, },
// payment back to the originating wallet, simulating legacy change // payment back to the originating wallet, simulating legacy change
Payment { Payment {
recipient_address: addr, recipient_address: addr.to_zcash_address(&st.network()),
amount: amount_legacy_change, amount: amount_legacy_change,
memo: None, memo: None,
label: None, label: None,
@ -1152,7 +1152,7 @@ pub(crate) fn zip317_spend<T: ShieldedPoolTester>() {
// This first request will fail due to insufficient non-dust funds // This first request will fail due to insufficient non-dust funds
let req = TransactionRequest::new(vec![Payment { let req = TransactionRequest::new(vec![Payment {
recipient_address: T::fvk_default_address(&dfvk), recipient_address: T::fvk_default_address(&dfvk).to_zcash_address(&st.network()),
amount: NonNegativeAmount::const_from_u64(50000), amount: NonNegativeAmount::const_from_u64(50000),
memo: None, memo: None,
label: None, label: None,
@ -1177,7 +1177,7 @@ pub(crate) fn zip317_spend<T: ShieldedPoolTester>() {
// This request will succeed, spending a single dust input to pay the 10000 // This request will succeed, spending a single dust input to pay the 10000
// ZAT fee in addition to the 41000 ZAT output to the recipient // ZAT fee in addition to the 41000 ZAT output to the recipient
let req = TransactionRequest::new(vec![Payment { let req = TransactionRequest::new(vec![Payment {
recipient_address: T::fvk_default_address(&dfvk), recipient_address: T::fvk_default_address(&dfvk).to_zcash_address(&st.network()),
amount: NonNegativeAmount::const_from_u64(41000), amount: NonNegativeAmount::const_from_u64(41000),
memo: None, memo: None,
label: None, label: None,
@ -1480,7 +1480,7 @@ pub(crate) fn pool_crossing_required<P0: ShieldedPoolTester, P1: ShieldedPoolTes
let transfer_amount = NonNegativeAmount::const_from_u64(200000); let transfer_amount = NonNegativeAmount::const_from_u64(200000);
let p0_to_p1 = zip321::TransactionRequest::new(vec![Payment { let p0_to_p1 = zip321::TransactionRequest::new(vec![Payment {
recipient_address: p1_to, recipient_address: p1_to.to_zcash_address(&st.network()),
amount: transfer_amount, amount: transfer_amount,
memo: None, memo: None,
label: None, label: None,
@ -1571,7 +1571,7 @@ pub(crate) fn fully_funded_fully_private<P0: ShieldedPoolTester, P1: ShieldedPoo
let transfer_amount = NonNegativeAmount::const_from_u64(200000); let transfer_amount = NonNegativeAmount::const_from_u64(200000);
let p0_to_p1 = zip321::TransactionRequest::new(vec![Payment { let p0_to_p1 = zip321::TransactionRequest::new(vec![Payment {
recipient_address: p1_to, recipient_address: p1_to.to_zcash_address(&st.network()),
amount: transfer_amount, amount: transfer_amount,
memo: None, memo: None,
label: None, label: None,
@ -1662,7 +1662,7 @@ pub(crate) fn fully_funded_send_to_t<P0: ShieldedPoolTester, P1: ShieldedPoolTes
let transfer_amount = NonNegativeAmount::const_from_u64(200000); let transfer_amount = NonNegativeAmount::const_from_u64(200000);
let p0_to_p1 = zip321::TransactionRequest::new(vec![Payment { let p0_to_p1 = zip321::TransactionRequest::new(vec![Payment {
recipient_address: Address::Transparent(p1_to), recipient_address: Address::Transparent(p1_to).to_zcash_address(&st.network()),
amount: transfer_amount, amount: transfer_amount,
memo: None, memo: None,
label: None, label: None,
@ -1777,7 +1777,7 @@ pub(crate) fn multi_pool_checkpoint<P0: ShieldedPoolTester, P1: ShieldedPoolTest
// First, send funds just to P0 // First, send funds just to P0
let transfer_amount = NonNegativeAmount::const_from_u64(200000); let transfer_amount = NonNegativeAmount::const_from_u64(200000);
let p0_transfer = zip321::TransactionRequest::new(vec![Payment::without_memo( let p0_transfer = zip321::TransactionRequest::new(vec![Payment::without_memo(
P0::random_address(&mut st.rng), P0::random_address(&mut st.rng).to_zcash_address(&st.network()),
transfer_amount, transfer_amount,
)]) )])
.unwrap(); .unwrap();
@ -1802,8 +1802,14 @@ pub(crate) fn multi_pool_checkpoint<P0: ShieldedPoolTester, P1: ShieldedPoolTest
// In the next block, send funds to both P0 and P1 // In the next block, send funds to both P0 and P1
let both_transfer = zip321::TransactionRequest::new(vec![ let both_transfer = zip321::TransactionRequest::new(vec![
Payment::without_memo(P0::random_address(&mut st.rng), transfer_amount), Payment::without_memo(
Payment::without_memo(P1::random_address(&mut st.rng), transfer_amount), P0::random_address(&mut st.rng).to_zcash_address(&st.network()),
transfer_amount,
),
Payment::without_memo(
P1::random_address(&mut st.rng).to_zcash_address(&st.network()),
transfer_amount,
),
]) ])
.unwrap(); .unwrap();
let res = st let res = st
@ -2110,7 +2116,7 @@ pub(crate) fn scan_cached_blocks_allows_blocks_out_of_order<T: ShieldedPoolTeste
// We can spend the received notes // We can spend the received notes
let req = TransactionRequest::new(vec![Payment { let req = TransactionRequest::new(vec![Payment {
recipient_address: T::fvk_default_address(&dfvk), recipient_address: T::fvk_default_address(&dfvk).to_zcash_address(&st.network()),
amount: NonNegativeAmount::const_from_u64(110_000), amount: NonNegativeAmount::const_from_u64(110_000),
memo: None, memo: None,
label: None, label: None,

View File

@ -65,6 +65,7 @@ The entries below are relative to the `zcash_client_backend` crate as of
- `UnifiedAddressRequest` - `UnifiedAddressRequest`
- A new `orchard` feature flag has been added to make it possible to - A new `orchard` feature flag has been added to make it possible to
build client code without `orchard` dependendencies. build client code without `orchard` dependendencies.
- `zcash_keys::address::Address::to_zcash_address`
### Changed ### Changed
- The following methods and enum variants have been placed behind an `orchard` - The following methods and enum variants have been placed behind an `orchard`

View File

@ -295,7 +295,7 @@ impl Address {
addr.convert_if_network(params.network_type()).ok() addr.convert_if_network(params.network_type()).ok()
} }
pub fn encode<P: consensus::Parameters>(&self, params: &P) -> String { pub fn to_zcash_address<P: consensus::Parameters>(&self, params: &P) -> ZcashAddress {
let net = params.network_type(); let net = params.network_type();
match self { match self {
@ -311,7 +311,10 @@ impl Address {
}, },
Address::Unified(ua) => ua.to_address(net), Address::Unified(ua) => ua.to_address(net),
} }
.to_string() }
pub fn encode<P: consensus::Parameters>(&self, params: &P) -> String {
self.to_zcash_address(params).to_string()
} }
pub fn has_receiver(&self, pool_type: PoolType) -> bool { pub fn has_receiver(&self, pool_type: PoolType) -> bool {