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: Move change memos into the ChangeValue components of Proposals #1012

Merged
merged 2 commits into from
Oct 12, 2023
Merged
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
17 changes: 17 additions & 0 deletions zcash_client_backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,23 @@ and this library adheres to Rust's notion of
an `Amount`.
- All uses of `Amount` in `data_api::wallet::input_selection` have been replaced
with `NonNegativeAmount`.
- `wallet::shield_transparent_funds` no longer
takes a `memo` argument; instead, memos to be associated with the shielded
outputs should be specified in the construction of the value of the
`input_selector` argument, which is used to construct the proposed shielded
values as internal "change" outputs.
- `wallet::create_proposed_transaction` no longer takes a
`change_memo` argument; instead, change memos are represented in the
individual values of the `proposed_change` field of the `Proposal`'s
`TransactionBalance`.
- `wallet::create_spend_to_address` now takes an additional
`change_memo` argument.
- `zcash_client_backend::fees::ChangeValue::Sapling` is now a structured variant.
In addition to the existing change value, it now also carries an optional memo
to be associated with the change output.
- `zcash_client_backend::fees::fixed::SingleOutputChangeStrategy::new` and
`zcash_client_backend::fees::zip317::SingleOutputChangeStrategy::new` each now
accept an additional `change_memo` argument.
- All uses of `Amount` in `zcash_client_backend::fees` have been replaced
with `NonNegativeAmount`.

Expand Down
25 changes: 9 additions & 16 deletions zcash_client_backend/src/data_api/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ where
/// received note must have in the blockchain in order to be considered for being
/// spent. A value of 10 confirmations is recommended and 0-conf transactions are
/// not supported.
/// * `change_memo`: A memo to be included in the change output
///
/// # Examples
///
Expand Down Expand Up @@ -174,7 +175,8 @@ where
/// Amount::from_u64(1).unwrap(),
/// None,
/// OvkPolicy::Sender,
/// 10
/// 10,
/// None
/// )
///
/// # }
Expand All @@ -196,6 +198,7 @@ pub fn create_spend_to_address<DbT, ParamsT>(
memo: Option<MemoBytes>,
ovk_policy: OvkPolicy,
min_confirmations: NonZeroU32,
change_memo: Option<MemoBytes>,
nuttycom marked this conversation as resolved.
Show resolved Hide resolved
) -> Result<
TxId,
Error<
Expand Down Expand Up @@ -224,7 +227,7 @@ where

#[allow(deprecated)]
let fee_rule = fixed::FeeRule::standard();
let change_strategy = fees::fixed::SingleOutputChangeStrategy::new(fee_rule);
let change_strategy = fees::fixed::SingleOutputChangeStrategy::new(fee_rule, change_memo);
spend(
wallet_db,
params,
Expand Down Expand Up @@ -335,7 +338,6 @@ where
ovk_policy,
proposal,
min_confirmations,
None,
)
}

Expand Down Expand Up @@ -418,7 +420,6 @@ pub fn create_proposed_transaction<DbT, ParamsT, InputsErrT, FeeRuleT>(
ovk_policy: OvkPolicy,
proposal: Proposal<FeeRuleT, DbT::NoteRef>,
min_confirmations: NonZeroU32,
change_memo: Option<MemoBytes>,
) -> Result<
TxId,
Error<
Expand Down Expand Up @@ -566,22 +567,20 @@ where

for change_value in proposal.balance().proposed_change() {
match change_value {
ChangeValue::Sapling(amount) => {
let memo = change_memo
.as_ref()
.map_or_else(MemoBytes::empty, |m| m.clone());
ChangeValue::Sapling { value, memo } => {
let memo = memo.as_ref().map_or_else(MemoBytes::empty, |m| m.clone());
builder.add_sapling_output(
internal_ovk(),
dfvk.change_address().1,
amount.into(),
value.into(),
memo.clone(),
)?;
sapling_output_meta.push((
Recipient::InternalAccount(
account,
PoolType::Shielded(ShieldedProtocol::Sapling),
),
amount.into(),
value.into(),
Some(memo),
))
}
Expand Down Expand Up @@ -682,10 +681,6 @@ where
/// * `from_addrs`: The list of transparent addresses that will be used to filter transaparent
/// UTXOs received by the wallet. Only UTXOs received at one of the provided addresses will
/// be selected to be shielded.
/// * `memo`: A memo to be included in the output to the (internal) recipient.
/// This can be used to take notes about auto-shielding operations internal
/// to the wallet that the wallet can use to improve how it represents those
/// shielding transactions to the user.
/// * `min_confirmations`: The minimum number of confirmations that a previously
/// received note must have in the blockchain in order to be considered for being
/// spent. A value of 10 confirmations is recommended and 0-conf transactions are
Expand All @@ -703,7 +698,6 @@ pub fn shield_transparent_funds<DbT, ParamsT, InputsT>(
shielding_threshold: NonNegativeAmount,
usk: &UnifiedSpendingKey,
from_addrs: &[TransparentAddress],
memo: &MemoBytes,
min_confirmations: NonZeroU32,
) -> Result<
TxId,
Expand Down Expand Up @@ -737,7 +731,6 @@ where
OvkPolicy::Sender,
proposal,
min_confirmations,
Some(memo.clone()),
)
}

Expand Down
22 changes: 19 additions & 3 deletions zcash_client_backend/src/fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use zcash_primitives::{
consensus::{self, BlockHeight},
memo::MemoBytes,
transaction::{
components::{
amount::{Amount, BalanceError, NonNegativeAmount},
Expand All @@ -19,13 +20,28 @@
/// A proposed change amount and output pool.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ChangeValue {
Sapling(NonNegativeAmount),
Sapling {
value: NonNegativeAmount,
memo: Option<MemoBytes>,
},
}

impl ChangeValue {
pub fn sapling(value: NonNegativeAmount, memo: Option<MemoBytes>) -> Self {
Self::Sapling { value, memo }
}

/// Returns the value of the change output to be created, in zatoshis.
pub fn value(&self) -> NonNegativeAmount {
match self {
ChangeValue::Sapling(value) => *value,
ChangeValue::Sapling { value, .. } => *value,
}
}

/// Returns the memo to be associated with the change output.
pub fn memo(&self) -> Option<&MemoBytes> {
match self {
ChangeValue::Sapling { memo, .. } => memo.as_ref(),

Check warning on line 44 in zcash_client_backend/src/fees.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/fees.rs#L42-L44

Added lines #L42 - L44 were not covered by tests
}
}
}
nuttycom marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -60,7 +76,7 @@
})
}

/// The change values proposed by the [`ChangeStrategy`] that computed this balance.
/// The change values proposed by the [`ChangeStrategy`] that computed this balance.
pub fn proposed_change(&self) -> &[ChangeValue] {
&self.proposed_change
}
Expand Down
31 changes: 22 additions & 9 deletions zcash_client_backend/src/fees/fixed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use zcash_primitives::{
consensus::{self, BlockHeight},
memo::MemoBytes,
transaction::{
components::{
amount::{Amount, BalanceError, NonNegativeAmount},
Expand All @@ -21,12 +22,17 @@
/// shielded pool and delegates fee calculation to the provided fee rule.
pub struct SingleOutputChangeStrategy {
fee_rule: FixedFeeRule,
change_memo: Option<MemoBytes>,
}

impl SingleOutputChangeStrategy {
/// Constructs a new [`SingleOutputChangeStrategy`] with the specified fee rule.
pub fn new(fee_rule: FixedFeeRule) -> Self {
Self { fee_rule }
/// Constructs a new [`SingleOutputChangeStrategy`] with the specified fee rule
/// and change memo.
pub fn new(fee_rule: FixedFeeRule, change_memo: Option<MemoBytes>) -> Self {
Self {
fee_rule,
change_memo,
}
}
}

Expand Down Expand Up @@ -136,7 +142,10 @@
})
}
DustAction::AllowDustChange => TransactionBalance::new(
vec![ChangeValue::Sapling(proposed_change)],
vec![ChangeValue::sapling(
proposed_change,
self.change_memo.clone(),

Check warning on line 147 in zcash_client_backend/src/fees/fixed.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/fees/fixed.rs#L145-L147

Added lines #L145 - L147 were not covered by tests
)],
fee_amount,
)
.map_err(overflow),
Expand All @@ -148,7 +157,10 @@
}
} else {
TransactionBalance::new(
vec![ChangeValue::Sapling(proposed_change)],
vec![ChangeValue::sapling(
proposed_change,
self.change_memo.clone(),
)],
fee_amount,
)
.map_err(overflow)
Expand Down Expand Up @@ -185,7 +197,7 @@
fn change_without_dust() {
#[allow(deprecated)]
let fee_rule = FixedFeeRule::standard();
let change_strategy = SingleOutputChangeStrategy::new(fee_rule);
let change_strategy = SingleOutputChangeStrategy::new(fee_rule, None);

// spend a single Sapling note that is sufficient to pay the fee
let result = change_strategy.compute_balance(
Expand All @@ -205,16 +217,17 @@

assert_matches!(
result,
Ok(balance) if balance.proposed_change() == [ChangeValue::Sapling(NonNegativeAmount::const_from_u64(10000))]
&& balance.fee_required() == NonNegativeAmount::const_from_u64(10000)
Ok(balance) if
balance.proposed_change() == [ChangeValue::sapling(NonNegativeAmount::const_from_u64(10000), None)] &&
balance.fee_required() == NonNegativeAmount::const_from_u64(10000)
);
}

#[test]
fn dust_change() {
#[allow(deprecated)]
let fee_rule = FixedFeeRule::standard();
let change_strategy = SingleOutputChangeStrategy::new(fee_rule);
let change_strategy = SingleOutputChangeStrategy::new(fee_rule, None);

// spend a single Sapling note that is sufficient to pay the fee
let result = change_strategy.compute_balance(
Expand Down
39 changes: 27 additions & 12 deletions zcash_client_backend/src/fees/zip317.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

use zcash_primitives::{
consensus::{self, BlockHeight},
memo::MemoBytes,
transaction::{
components::{
amount::{Amount, BalanceError, NonNegativeAmount},
Expand All @@ -28,13 +29,17 @@
/// shielded pool and delegates fee calculation to the provided fee rule.
pub struct SingleOutputChangeStrategy {
fee_rule: Zip317FeeRule,
change_memo: Option<MemoBytes>,
}

impl SingleOutputChangeStrategy {
/// Constructs a new [`SingleOutputChangeStrategy`] with the specified ZIP 317
/// fee parameters.
pub fn new(fee_rule: Zip317FeeRule) -> Self {
Self { fee_rule }
/// fee parameters and change memo.
pub fn new(fee_rule: Zip317FeeRule, change_memo: Option<MemoBytes>) -> Self {
Self {
fee_rule,
change_memo,
}
}
nuttycom marked this conversation as resolved.
Show resolved Hide resolved
}

Expand Down Expand Up @@ -204,7 +209,10 @@
})
}
DustAction::AllowDustChange => TransactionBalance::new(
vec![ChangeValue::Sapling(proposed_change)],
vec![ChangeValue::sapling(
proposed_change,
self.change_memo.clone(),

Check warning on line 214 in zcash_client_backend/src/fees/zip317.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/fees/zip317.rs#L212-L214

Added lines #L212 - L214 were not covered by tests
)],
fee_amount,
)
.map_err(|_| overflow()),
Expand All @@ -215,8 +223,14 @@
.map_err(|_| overflow()),
}
} else {
TransactionBalance::new(vec![ChangeValue::Sapling(proposed_change)], fee_amount)
.map_err(|_| overflow())
TransactionBalance::new(
vec![ChangeValue::sapling(
proposed_change,
self.change_memo.clone(),
)],
fee_amount,
)
.map_err(|_| overflow())
}
}
}
Expand Down Expand Up @@ -249,7 +263,7 @@

#[test]
fn change_without_dust() {
let change_strategy = SingleOutputChangeStrategy::new(Zip317FeeRule::standard());
let change_strategy = SingleOutputChangeStrategy::new(Zip317FeeRule::standard(), None);

// spend a single Sapling note that is sufficient to pay the fee
let result = change_strategy.compute_balance(
Expand All @@ -269,14 +283,15 @@

assert_matches!(
result,
Ok(balance) if balance.proposed_change() == [ChangeValue::Sapling(NonNegativeAmount::const_from_u64(5000))]
&& balance.fee_required() == NonNegativeAmount::const_from_u64(10000)
Ok(balance) if
balance.proposed_change() == [ChangeValue::sapling(NonNegativeAmount::const_from_u64(5000), None)] &&
balance.fee_required() == NonNegativeAmount::const_from_u64(10000)
);
}

#[test]
fn change_with_transparent_payments() {
let change_strategy = SingleOutputChangeStrategy::new(Zip317FeeRule::standard());
let change_strategy = SingleOutputChangeStrategy::new(Zip317FeeRule::standard(), None);

// spend a single Sapling note that is sufficient to pay the fee
let result = change_strategy.compute_balance(
Expand Down Expand Up @@ -306,7 +321,7 @@

#[test]
fn change_with_allowable_dust() {
let change_strategy = SingleOutputChangeStrategy::new(Zip317FeeRule::standard());
let change_strategy = SingleOutputChangeStrategy::new(Zip317FeeRule::standard(), None);

// spend a single Sapling note that is sufficient to pay the fee
let result = change_strategy.compute_balance(
Expand Down Expand Up @@ -339,7 +354,7 @@

#[test]
fn change_with_disallowed_dust() {
let change_strategy = SingleOutputChangeStrategy::new(Zip317FeeRule::standard());
let change_strategy = SingleOutputChangeStrategy::new(Zip317FeeRule::standard(), None);

// spend a single Sapling note that is sufficient to pay the fee
let result = change_strategy.compute_balance(
Expand Down
2 changes: 1 addition & 1 deletion zcash_client_sqlite/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ mod tests {
}])
.unwrap();
let input_selector = GreedyInputSelector::new(
SingleOutputChangeStrategy::new(FeeRule::standard()),
SingleOutputChangeStrategy::new(FeeRule::standard(), None),
DustOutputPolicy::default(),
);
assert_matches!(
Expand Down
Loading
Loading