Skip to content

Commit

Permalink
zcash_client_backend: Add serialization & parsing for protobuf Propos…
Browse files Browse the repository at this point in the history
…al representation.

zcash_primitives
================

Added
-----
- `impl {Clone, PartialEq, Eq} for zcash_primitives::memo::Error`
- `impl {PartialEq, Eq} for zcash_primitives::sapling::note::Rseed`
- `impl From<TxId> for [u8; 32]`

zcash_client_backend
====================

Added
-----
- `zcash_client_backend::data_api::SaplingInputSource::get_spendable_sapling_note`
- `zcash_client_backend::data_api::TransparentInputSource::get_unspent_transparent_output`
- `zcash_client_backend::data_api::input_selection::Proposal::from_parts`
- `zcash_client_backend::data_api::input_selection::SaplingInputs::from_parts`
- `zcash_client_backend::zip321::TransactionRequest::total`
- `zcash_client_backend::proto::`
  - `PROPOSAL_SER_V1`
  - `ProposalError`
  - `proposal::Proposal::{from_standard_proposal, try_into_standard_proposal}`
  - `proposal::ProposedInput::parse_txid`
- `impl Clone for zcash_client_backend::{
     zip321::{Payment, TransactionRequest, Zip321Error, parse::Param, parse::IndexedParam},
     wallet::{ReceivedSaplingNote, WalletTransparentOutput},
     wallet::input_selection::{Proposal, SaplingInputs},
   }`
- `impl {PartialEq, Eq} for zcash_client_backend::{
     zip321::{Zip321Error, parse::Param, parse::IndexedParam},
     wallet::{ReceivedSaplingNote, WalletTransparentOutput},
     wallet::input_selection::{Proposal, SaplingInputs},
   }`
  • Loading branch information
nuttycom committed Nov 7, 2023
1 parent 1ce137e commit 9127158
Show file tree
Hide file tree
Showing 13 changed files with 492 additions and 50 deletions.
10 changes: 5 additions & 5 deletions zcash_client_backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ and this library adheres to Rust's notion of
backend-specific note identifier. The related `NoteRef` type parameter has
been removed from `error::Error`.
- A new variant `UnsupportedPoolType` has been added.
- `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::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
Expand Down
30 changes: 30 additions & 0 deletions zcash_client_backend/src/data_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,14 @@ pub trait SaplingInputSource {
/// or a UUID.
type NoteRef: Copy + Debug + Eq + Ord;

/// Returns a received Sapling note, or Ok(None) if the note is not known to belong to the
/// wallet or if the note is not spendable.
fn get_spendable_sapling_note(
&self,
txid: &TxId,
index: u32,
) -> Result<Option<ReceivedSaplingNote<Self::NoteRef>>, Self::Error>;

/// Returns a list of spendable Sapling notes sufficient to cover the specified target value,
/// if possible.
fn select_spendable_sapling_notes(
Expand All @@ -236,6 +244,13 @@ pub trait TransparentInputSource {
/// The type of errors produced by a wallet backend.
type Error;

/// Returns a received transparent UTXO, or Ok(None) if the UTXO is not known to belong to the
/// wallet or is not spendable.
fn get_unspent_transparent_output(
&self,
outpoint: &OutPoint,
) -> Result<Option<WalletTransparentOutput>, Self::Error>;

/// Returns a list of unspent transparent UTXOs that appear in the chain at heights up to and
/// including `max_height`.
fn get_unspent_transparent_outputs(
Expand Down Expand Up @@ -974,6 +989,14 @@ pub mod testing {
type Error = ();
type NoteRef = u32;

fn get_spendable_sapling_note(
&self,
_txid: &TxId,
_index: u32,
) -> Result<Option<ReceivedSaplingNote<Self::NoteRef>>, Self::Error> {
Ok(None)
}

fn select_spendable_sapling_notes(
&self,
_account: AccountId,
Expand All @@ -989,6 +1012,13 @@ pub mod testing {
impl TransparentInputSource for MockWalletDb {
type Error = ();

fn get_unspent_transparent_output(
&self,
_outpoint: &OutPoint,
) -> Result<Option<WalletTransparentOutput>, Self::Error> {
Ok(None)
}

fn get_unspent_transparent_outputs(
&self,
_address: &TransparentAddress,
Expand Down
51 changes: 51 additions & 0 deletions zcash_client_backend/src/data_api/wallet/input_selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ impl<DE: fmt::Display, SE: fmt::Display> fmt::Display for InputSelectorError<DE,
}

/// The inputs to be consumed and outputs to be produced in a proposed transaction.
#[derive(Clone, PartialEq, Eq)]
pub struct Proposal<FeeRuleT, NoteRef> {
transaction_request: TransactionRequest,
transparent_inputs: Vec<WalletTransparentOutput>,
Expand All @@ -90,6 +91,45 @@ pub struct Proposal<FeeRuleT, NoteRef> {
}

impl<FeeRuleT, NoteRef> Proposal<FeeRuleT, NoteRef> {
/// Constructs a [`Proposal`] from its constituent parts.
#[allow(clippy::too_many_arguments)]
pub(crate) fn from_parts(
transaction_request: TransactionRequest,
transparent_inputs: Vec<WalletTransparentOutput>,
sapling_inputs: Option<SaplingInputs<NoteRef>>,
balance: TransactionBalance,
fee_rule: FeeRuleT,
min_target_height: BlockHeight,
is_shielding: bool,
) -> Result<Self, ()> {
let transparent_total = transparent_inputs
.iter()
.map(|out| out.txout().value)
.fold(Ok(NonNegativeAmount::ZERO), |acc, a| (acc? + a).ok_or(()))?;
let sapling_total = sapling_inputs
.iter()
.flat_map(|s_in| s_in.notes().iter())
.map(|out| out.value())
.fold(Ok(NonNegativeAmount::ZERO), |acc, a| (acc? + a).ok_or(()))?;
let input_total = (transparent_total + sapling_total).ok_or(())?;

let output_total = (transaction_request.total()? + balance.total()).ok_or(())?;

if input_total == output_total {
Ok(Self {
transaction_request,
transparent_inputs,
sapling_inputs,
balance,
fee_rule,
min_target_height,
is_shielding,
})
} else {
Err(())
}
}

/// Returns the transaction request that describes the payments to be made.
pub fn transaction_request(&self) -> &TransactionRequest {
&self.transaction_request
Expand Down Expand Up @@ -147,12 +187,23 @@ impl<FeeRuleT, NoteRef> Debug for Proposal<FeeRuleT, NoteRef> {
}

/// The Sapling component of a proposed transaction.
#[derive(Clone, PartialEq, Eq)]
pub struct SaplingInputs<NoteRef> {
anchor_height: BlockHeight,
notes: NonEmpty<ReceivedSaplingNote<NoteRef>>,
}

impl<NoteRef> SaplingInputs<NoteRef> {
pub fn from_parts(
anchor_height: BlockHeight,
notes: NonEmpty<ReceivedSaplingNote<NoteRef>>,
) -> Self {
Self {
anchor_height,
notes,
}
}

pub fn anchor_height(&self) -> BlockHeight {
self.anchor_height
}
Expand Down
3 changes: 3 additions & 0 deletions zcash_client_backend/src/fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ impl ChangeValue {
pub struct TransactionBalance {
proposed_change: Vec<ChangeValue>,
fee_required: NonNegativeAmount,

// A cache for the sum of proposed change and fee; we compute it on construction anyway, so we
// cache the resulting value.
total: NonNegativeAmount,
}

Expand Down
Loading

0 comments on commit 9127158

Please sign in to comment.