Skip to content

Commit

Permalink
zcash_client_backend: Add propose_standard_transfer.
Browse files Browse the repository at this point in the history
  • Loading branch information
nuttycom committed Oct 25, 2023
1 parent cc0cc2d commit f1c0869
Show file tree
Hide file tree
Showing 3 changed files with 287 additions and 86 deletions.
104 changes: 89 additions & 15 deletions zcash_client_backend/src/data_api/wallet.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::num::NonZeroU32;

use shardtree::{error::ShardTreeError, store::ShardStore, ShardTree};

use zcash_primitives::{
consensus::{self, BlockHeight, NetworkUpgrade},
memo::MemoBytes,
Expand Down Expand Up @@ -212,29 +213,31 @@ where
DbT: WalletWrite + WalletCommitmentTrees,
DbT::NoteRef: Copy + Eq + Ord,
{
let req = zip321::TransactionRequest::new(vec![Payment {
recipient_address: to.clone(),
let account = wallet_db
.get_account_for_ufvk(&usk.to_unified_full_viewing_key())
.map_err(Error::DataSource)?
.ok_or(Error::KeyNotRecognized)?;

#[allow(deprecated)]
let proposal = propose_standard_transfer_to_address(
wallet_db,
params,
StandardFeeRule::PreZip313,
account,
min_confirmations,
to,
amount,
memo,
label: None,
message: None,
other_params: vec![],
}])
.expect(
"It should not be possible for this to violate ZIP 321 request construction invariants.",
);
change_memo,
)?;

#[allow(deprecated)]
let fee_rule = StandardFeeRule::PreZip313;
let change_strategy = fees::standard::SingleOutputChangeStrategy::new(fee_rule, change_memo);
spend(
create_proposed_transaction(
wallet_db,
params,
prover,
&GreedyInputSelector::<DbT, _>::new(change_strategy, DustOutputPolicy::default()),
usk,
req,
ovk_policy,
proposal,
min_confirmations,
)
}
Expand Down Expand Up @@ -373,6 +376,77 @@ where
.map_err(Error::from)
}

/// Proposes a transaction paying the specified address from the given account.
///
/// Returns the proposal, which may then be executed using [`create_proposed_transaction`]
///
/// Parameters:
/// * `wallet_db`: A read/write reference to the wallet database
/// * `params`: Consensus parameters
/// * `fee_rule`: The fee rule to use in creating the transaction.
/// * `spend_from_account`: The unified account that controls the funds that will be spent
/// in the resulting transaction. This procedure will return an error if the
/// account ID does not correspond to an account known to the wallet.
/// * `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
/// not supported.
/// * `to`: The address to which `amount` will be paid.
/// * `amount`: The amount to send.
/// * `memo`: A memo to be included in the output to the recipient.
/// * `change_memo`: A memo to be included in any change output that is created.
#[allow(clippy::too_many_arguments)]
#[allow(clippy::type_complexity)]
pub fn propose_standard_transfer_to_address<DbT, ParamsT, CommitmentTreeErrT>(
wallet_db: &mut DbT,
params: &ParamsT,
fee_rule: StandardFeeRule,
spend_from_account: AccountId,
min_confirmations: NonZeroU32,
to: &RecipientAddress,
amount: NonNegativeAmount,
memo: Option<MemoBytes>,
change_memo: Option<MemoBytes>,
) -> Result<
Proposal<StandardFeeRule, DbT::NoteRef>,
Error<
DbT::Error,
CommitmentTreeErrT,
GreedyInputSelectorError<Zip317FeeError, DbT::NoteRef>,
Zip317FeeError,
>,
>
where
ParamsT: consensus::Parameters + Clone,
DbT: WalletWrite,
DbT::NoteRef: Copy + Eq + Ord,
{
let request = zip321::TransactionRequest::new(vec![Payment {
recipient_address: to.clone(),
amount,
memo,
label: None,
message: None,
other_params: vec![],
}])
.expect(
"It should not be possible for this to violate ZIP 321 request construction invariants.",
);

let change_strategy = fees::standard::SingleOutputChangeStrategy::new(fee_rule, change_memo);
let input_selector =
GreedyInputSelector::<DbT, _>::new(change_strategy, DustOutputPolicy::default());

propose_transfer(
wallet_db,
params,
spend_from_account,
&input_selector,
request,
min_confirmations,
)
}

#[cfg(feature = "transparent-inputs")]
#[allow(clippy::too_many_arguments)]
#[allow(clippy::type_complexity)]
Expand Down
60 changes: 56 additions & 4 deletions zcash_client_sqlite/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use tempfile::NamedTempFile;
#[cfg(feature = "unstable")]
use tempfile::TempDir;

use zcash_client_backend::fees::{standard, DustOutputPolicy};
#[allow(deprecated)]
use zcash_client_backend::{
address::RecipientAddress,
Expand All @@ -22,8 +23,10 @@ use zcash_client_backend::{
chain::{scan_cached_blocks, BlockSource, ScanSummary},
wallet::{
create_proposed_transaction, create_spend_to_address,
input_selection::{GreedyInputSelectorError, InputSelector, Proposal},
propose_transfer, spend,
input_selection::{
GreedyInputSelector, GreedyInputSelectorError, InputSelector, Proposal,
},
propose_standard_transfer_to_address, propose_transfer, spend,
},
AccountBalance, AccountBirthday, WalletRead, WalletSummary, WalletWrite,
},
Expand All @@ -38,7 +41,7 @@ use zcash_note_encryption::Domain;
use zcash_primitives::{
block::BlockHash,
consensus::{self, BlockHeight, Network, NetworkUpgrade, Parameters},
memo::MemoBytes,
memo::{Memo, MemoBytes},
sapling::{
note_encryption::{sapling_note_encryption, SaplingDomain},
util::generate_random_rseed,
Expand All @@ -47,7 +50,7 @@ use zcash_primitives::{
},
transaction::{
components::amount::NonNegativeAmount,
fees::{zip317::FeeError as Zip317FeeError, FeeRule},
fees::{zip317::FeeError as Zip317FeeError, FeeRule, StandardFeeRule},
Transaction, TxId,
},
zip32::{sapling::DiversifiableFullViewingKey, DiversifierIndex},
Expand Down Expand Up @@ -524,6 +527,43 @@ impl<Cache> TestState<Cache> {
)
}

/// Invokes [`propose_standard_transfer`] with the given arguments.
#[allow(clippy::type_complexity)]
#[allow(clippy::too_many_arguments)]
pub(crate) fn propose_standard_transfer<CommitmentTreeErrT>(
&mut self,
spend_from_account: AccountId,
fee_rule: StandardFeeRule,
min_confirmations: NonZeroU32,
to: &RecipientAddress,
amount: NonNegativeAmount,
memo: Option<MemoBytes>,
change_memo: Option<MemoBytes>,
) -> Result<
Proposal<StandardFeeRule, ReceivedNoteId>,
data_api::error::Error<
SqliteClientError,
CommitmentTreeErrT,
GreedyInputSelectorError<Zip317FeeError, ReceivedNoteId>,
Zip317FeeError,
>,
> {
let params = self.network();
let result = propose_standard_transfer_to_address::<_, _, CommitmentTreeErrT>(
&mut self.db_data,
&params,
fee_rule,
spend_from_account,
min_confirmations,
to,
amount,
memo,
change_memo,
);

result

Check failure on line 564 in zcash_client_sqlite/src/testing.rs

View workflow job for this annotation

GitHub Actions / Clippy (MSRV)

returning the result of a `let` binding from a block

error: returning the result of a `let` binding from a block --> zcash_client_sqlite/src/testing.rs:564:9 | 552 | / let result = propose_standard_transfer_to_address::<_, _, CommitmentTreeErrT>( 553 | | &mut self.db_data, 554 | | &params, 555 | | fee_rule, ... | 561 | | change_memo, 562 | | ); | |__________- unnecessary `let` binding 563 | 564 | result | ^^^^^^ | = note: `-D clippy::let-and-return` implied by `-D warnings` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return help: return the expression directly | 552 ~ 553 | 554 ~ propose_standard_transfer_to_address::<_, _, CommitmentTreeErrT>( 555 + &mut self.db_data, 556 + &params, 557 + fee_rule, 558 + spend_from_account, 559 + min_confirmations, 560 + to, 561 + amount, 562 + memo, 563 + change_memo, 564 + ) |
}

/// Invokes [`propose_shielding`] with the given arguments.
#[cfg(feature = "transparent-inputs")]
#[allow(clippy::type_complexity)]
Expand Down Expand Up @@ -993,3 +1033,15 @@ impl TestCache for FsBlockCache {
meta
}
}

pub(crate) fn input_selector(
fee_rule: StandardFeeRule,
change_memo: Option<&str>,
) -> GreedyInputSelector<
WalletDb<rusqlite::Connection, Network>,
standard::SingleOutputChangeStrategy,
> {
let change_memo = change_memo.map(|m| MemoBytes::from(m.parse::<Memo>().unwrap()));
let change_strategy = standard::SingleOutputChangeStrategy::new(fee_rule, change_memo);
GreedyInputSelector::new(change_strategy, DustOutputPolicy::default())
}
Loading

0 comments on commit f1c0869

Please sign in to comment.