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.

As part of this change, the role of backend-specific note identifiers
has been further reduced, using universal note identifiers for error
reporting instead.
  • Loading branch information
softminus authored and nuttycom committed Aug 16, 2023
1 parent 5e86d86 commit 65f4204
Show file tree
Hide file tree
Showing 20 changed files with 1,125 additions and 298 deletions.
61 changes: 43 additions & 18 deletions zcash_client_backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,55 @@ and this library adheres to Rust's notion of

## [Unreleased]
### Added
- `impl Eq for zcash_client_backend::address::RecipientAddress`
- `impl Eq for zcash_client_backend::zip321::{Payment, TransactionRequest}`
- `impl Debug` for `zcash_client_backend::{data_api::wallet::input_selection::Proposal, wallet::ReceivedSaplingNote}`
- `impl Clone for zcash_client_backend::{
zip321::{Payment, TransactionRequest, Zip321Error, parse::Param, parse::IndexedParam},
wallet::ReceivedSaplingNote,
}`
- `impl Debug` for `zcash_client_backend::{
data_api::wallet::input_selection::Proposal,
wallet::ReceivedSaplingNote
}`
- `impl Eq for zcash_client_backend::{
address::RecipientAddress,
zip321::{Payment, TransactionRequest, Zip321Error, parse::Param, parse::IndexedParam},
wallet::{ReceivedSaplingNote, WalletTransparentOutput},
}`
- `zcash_client_backend::data_api`:
- `BlockMetadata`
- `NoteId`
- `NullifierQuery` for use with `WalletRead::get_sapling_nullifiers`
- `ScannedBlock`
- `ShieldedProtocol`
- `WalletCommitmentTrees`
- `WalletRead::{block_metadata, block_fully_scanned, suggest_scan_ranges}`
- `WalletRead::{block_metadata, block_fully_scanned, suggest_scan_ranges,
get_spendable_sapling_note, get_unspent_transparent_output}`
- `WalletWrite::{put_blocks, update_chain_tip}`
- `chain::CommitmentTreeRoot`
- `scanning` A new module containing types required for `suggest_scan_ranges`
- `testing::MockWalletDb::new`
- `wallet::input_sellection::Proposal::{min_target_height, min_anchor_height}`:
- `wallet::input_selection::Proposal::{min_target_height, min_anchor_height}`:
- Added methods to `zcash_client_backend::wallet::ReceivedSaplingNote`:
`{from_parts, txid, output_index, diversifier, rseed, note_commitment_tree_position}`.
- `zcash_client_backend::wallet::WalletSaplingOutput::note_commitment_tree_position`
- `zcash_client_backend::wallet::input_selection::Proposal::new`
- `zcash_client_backend::scanning`:
- `ScanError`
- `impl<K: ScanningKey> ScanningKey for &K`
- `impl ScanningKey for (zip32::Scope, sapling::SaplingIvk, sapling::NullifierDerivingKey)`
- `zcash_client_backend::proto::`
- `PROPOSAL_SER_V1`
- `ProposalError`
- `proposal::Proposal`
- `zcash_client_backend::fees::standard`

### Changed
- MSRV is now 1.65.0.
- Bumped dependencies to `hdwallet 0.4`, `zcash_primitives 0.12`, `zcash_note_encryption 0.4`,
`incrementalmerkletree 0.4`, `orchard 0.5`, `bs58 0.5`
- `zcash_client_backend::data_api`:
- `WalletRead::TxRef` has been removed in favor of consistently using `TxId` instead.
- `WalletRead::TxRef` has been removed in favor of consistently using `TxId` instead.
- `WalletRead::get_transaction` now takes a `TxId` as its argument.
- `WalletWrite::{store_decrypted_tx, store_sent_tx}` now return `Result<(), Self::Error>`
- `WalletWrite::{store_decrypted_tx, store_sent_tx}` now return `Result<(), Self::Error>`
as the `WalletRead::TxRef` associated type has been removed. Use
`WalletRead::get_transaction` with the transaction's `TxId` instead.
- `WalletRead::get_memo` now takes a `NoteId` as its argument instead of `Self::NoteRef`
Expand All @@ -56,12 +75,18 @@ and this library adheres to Rust's notion of
- `wallet::{create_spend_to_address, create_proposed_transaction,
shield_transparent_funds}` all now require that `WalletCommitmentTrees` be
implemented for the type passed to them for the `wallet_db` parameter.
- The fields of `wallet::ReceivedSaplingNote` are now private. Use
`ReceivedSaplingNote::from_parts` for construction instead. Accessor
methods are provided for each previously-public field.
- The `NoteMismatch` variant of `data_api::error::Error` now wraps a `data_api::NoteId`
instead of a backend-specific note identifier. The related `NoteRef` type
parameter has been removed from `data_api::error::Error`.
- `wallet::create_spend_to_address` now takes an additional `change_memo` argument.
- `wallet::create_proposed_transaction` now takes an additional
`min_confirmations` argument.
- `wallet::{spend, create_spend_to_address, shield_transparent_funds,
propose_transfer, propose_shielding, create_proposed_transaction}` now take their
respective `min_confirmations` arguments as `NonZeroU32`
- `wallet::create_proposed_transaction` now takes its `proposal` argument
by reference instead of as an owned value.
- `wallet::{spend, create_spend_to_address, shield_transparent_funds,
propose_transfer, propose_shielding}` now take their respective
`min_confirmations` arguments as `NonZeroU32`
- `wallet::input_selection::InputSelector::{propose_transaction, propose_shielding}`
now take their respective `min_confirmations` arguments as `NonZeroU32`
- `data_api::wallet::shield_transparent_funds` no longer takes a `memo` argument;
Expand All @@ -73,13 +98,13 @@ and this library adheres to Rust's notion of
field of the `Proposal`'s `TransactionBalance`.
- A new `Scan` variant has been added to `data_api::chain::error::Error`.
- A new `SyncRequired` variant has been added to `data_api::wallet::input_selection::InputSelectorError`.
- The variants of the `PoolType` enum have changed; the `PoolType::Sapling` variant has been
- The variants of the `PoolType` enum have changed; the `PoolType::Sapling` variant has been
removed in favor of a `PoolType::Shielded` variant that wraps a `ShieldedProtocol` value.
- `zcash_client_backend::wallet`:
- `SpendableNote` has been renamed to `ReceivedSaplingNote`.
- Arguments to `WalletSaplingOutput::from_parts` have changed.
- `zcash_client_backend::data_api::wallet::input_selection::InputSelector`:
- Arguments to `{propose_transaction, propose_shielding}` have changed.
- Arguments to `{propose_transaction, propose_shielding}` have changed.
- `zcash_client_backend::data_api::wallet::{create_spend_to_address, spend,
create_proposed_transaction, shield_transparent_funds}` now return the `TxId`
for the newly created transaction instead an internal database identifier.
Expand All @@ -93,7 +118,7 @@ and this library adheres to Rust's notion of
tree and incremental witnesses for each previously-known note. In addition, the
return type has now been updated to return a `Result<ScannedBlock, ScanError>`.
- `proto/service.proto` has been updated to include the new GRPC endpoints
supported by lightwalletd v0.4.15
supported by lightwalletd v0.4.15
- `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.
Expand All @@ -104,18 +129,18 @@ and this library adheres to Rust's notion of
### Removed
- `zcash_client_backend::data_api`:
- `WalletRead::get_all_nullifiers`
- `WalletRead::{get_commitment_tree, get_witnesses}` have been removed
- `WalletRead::{get_commitment_tree, get_witnesses}` have been removed
without replacement. The utility of these methods is now subsumed
by those available from the `WalletCommitmentTrees` trait.
- `WalletWrite::advance_by_block` (use `WalletWrite::put_blocks` instead).
- `PrunedBlock` has been replaced by `ScannedBlock`
- `testing::MockWalletDb`, which is available under the `test-dependencies`
feature flag, has been modified by the addition of a `sapling_tree` property.
feature flag, has been modified by the addition of a `sapling_tree` property.
- `wallet::input_selection`:
- `Proposal::target_height` (use `Proposal::min_target_height` instead).
- `zcash_client_backend::data_api::chain::validate_chain` (logic merged into
`chain::scan_cached_blocks`.
- `zcash_client_backend::data_api::chain::error::{ChainError, Cause}` have been
- `zcash_client_backend::data_api::chain::error::{ChainError, Cause}` have been
replaced by `zcash_client_backend::scanning::ScanError`
- `zcash_client_backend::wallet::WalletSaplingOutput::{witness, witness_mut}`
have been removed as individual incremental witnesses are no longer tracked on a
Expand Down
17 changes: 13 additions & 4 deletions zcash_client_backend/proto/proposal.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,23 @@ message Proposal {
TransactionBalance balance = 4;
// The fee rule used in constructing this proposal
FeeRule feeRule = 6;
// The minimum number of confirmations required for transaction inputs to be selected.
// Each of the proposed inputs is know to have at least this many confirmations.
uint32 minConfirmations = 7;
// The target height for which the proposal was constructed
//
// The chain must contain at least this many blocks in order for the proposal to
// be executed.
uint32 minTargetHeight = 7;
uint32 minTargetHeight = 8;
// Returns the anchor height used in preparing the proposal.
//
// If, at the time that the proposal is executed, the anchor height
// required to satisfy / the minimum confirmation depth is less than this
// height, the proposal execution / API will return an error.
uint32 minAnchorHeight = 8;
uint32 minAnchorHeight = 9;
// A flag indicating whether the proposal is for a shielding transaction,
// used for determining which OVK to select for wallet-internal outputs.
bool isShielding = 9;
bool isShielding = 10;
}

// The value pool from which a particular proposed input is drawn
Expand Down Expand Up @@ -72,9 +75,15 @@ message ChangeValue {
}
}

// An object wrapper for memo bytes, to facilitate representing the
// `change_memo == None` case.
message MemoBytes {
bytes value = 1;
}

// The amount and memo for a proposed Sapling change output.
message SaplingChange {
int64 amount = 1;
bytes memo = 2;
MemoBytes memo = 2;
}

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 @@ -200,6 +200,14 @@ pub trait WalletRead {
query: NullifierQuery,
) -> Result<Vec<(AccountId, sapling::Nullifier)>, Self::Error>;

/// 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>;

/// Return all unspent Sapling notes, excluding the specified note IDs.
fn get_spendable_sapling_notes(
&self,
Expand Down Expand Up @@ -228,6 +236,13 @@ pub trait WalletRead {
account: AccountId,
) -> Result<HashMap<TransparentAddress, AddressMetadata>, Self::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 @@ -747,6 +762,14 @@ pub mod testing {
Ok(Vec::new())
}

fn get_spendable_sapling_note(

Check warning on line 765 in zcash_client_backend/src/data_api.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api.rs#L765

Added line #L765 was not covered by tests
&self,
_txid: &TxId,
_index: u32,
) -> Result<Option<ReceivedSaplingNote<Self::NoteRef>>, Self::Error> {
Ok(None)

Check warning on line 770 in zcash_client_backend/src/data_api.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api.rs#L770

Added line #L770 was not covered by tests
}

fn get_spendable_sapling_notes(
&self,
_account: AccountId,
Expand All @@ -773,6 +796,13 @@ pub mod testing {
Ok(HashMap::new())
}

fn get_unspent_transparent_output(

Check warning on line 799 in zcash_client_backend/src/data_api.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api.rs#L799

Added line #L799 was not covered by tests
&self,
_outpoint: &OutPoint,
) -> Result<Option<WalletTransparentOutput>, Self::Error> {
Ok(None)

Check warning on line 803 in zcash_client_backend/src/data_api.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api.rs#L803

Added line #L803 was not covered by tests
}

fn get_unspent_transparent_outputs(
&self,
_address: &TransparentAddress,
Expand Down
26 changes: 13 additions & 13 deletions zcash_client_backend/src/data_api/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ use crate::data_api::wallet::input_selection::InputSelectorError;
#[cfg(feature = "transparent-inputs")]
use zcash_primitives::{legacy::TransparentAddress, zip32::DiversifierIndex};

use super::NoteId;

/// Errors that can occur as a consequence of wallet operations.
#[derive(Debug)]
pub enum Error<DataSourceError, CommitmentTreeError, SelectionError, FeeError, NoteRef> {
pub enum Error<DataSourceError, CommitmentTreeError, SelectionError, FeeError> {
/// An error occurred retrieving data from the underlying data source
DataSource(DataSourceError),

Expand Down Expand Up @@ -56,7 +58,7 @@ pub enum Error<DataSourceError, CommitmentTreeError, SelectionError, FeeError, N

/// A note being spent does not correspond to either the internal or external
/// full viewing key for an account.
NoteMismatch(NoteRef),
NoteMismatch(NoteId),

#[cfg(feature = "transparent-inputs")]
AddressNotRecognized(TransparentAddress),
Expand All @@ -65,13 +67,12 @@ pub enum Error<DataSourceError, CommitmentTreeError, SelectionError, FeeError, N
ChildIndexOutOfRange(DiversifierIndex),
}

impl<DE, CE, SE, FE, N> fmt::Display for Error<DE, CE, SE, FE, N>
impl<DE, CE, SE, FE> fmt::Display for Error<DE, CE, SE, FE>
where
DE: fmt::Display,
CE: fmt::Display,
SE: fmt::Display,
FE: fmt::Display,
N: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
Expand Down Expand Up @@ -111,7 +112,7 @@ where
Error::ScanRequired => write!(f, "Must scan blocks first"),
Error::Builder(e) => write!(f, "An error occurred building the transaction: {}", e),
Error::MemoForbidden => write!(f, "It is not possible to send a memo to a transparent address."),
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),

Check warning on line 115 in zcash_client_backend/src/data_api/error.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api/error.rs#L115

Added line #L115 was not covered by tests

#[cfg(feature = "transparent-inputs")]
Error::AddressNotRecognized(_) => {
Expand All @@ -129,13 +130,12 @@ where
}
}

impl<DE, CE, SE, FE, N> error::Error for Error<DE, CE, SE, FE, N>
impl<DE, CE, SE, FE> error::Error for Error<DE, CE, SE, FE>
where
DE: Debug + Display + error::Error + 'static,
CE: Debug + Display + error::Error + 'static,
SE: Debug + Display + error::Error + 'static,
FE: Debug + Display + 'static,
N: Debug + Display,
{
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match &self {
Expand All @@ -148,19 +148,19 @@ where
}
}

impl<DE, CE, SE, FE, N> From<builder::Error<FE>> for Error<DE, CE, SE, FE, N> {
impl<DE, CE, SE, FE> From<builder::Error<FE>> for Error<DE, CE, SE, FE> {
fn from(e: builder::Error<FE>) -> Self {
Error::Builder(e)
}
}

impl<DE, CE, SE, FE, N> From<BalanceError> for Error<DE, CE, SE, FE, N> {
impl<DE, CE, SE, FE> From<BalanceError> for Error<DE, CE, SE, FE> {
fn from(e: BalanceError) -> Self {
Error::BalanceError(e)
}
}

impl<DE, CE, SE, FE, N> From<InputSelectorError<DE, SE>> for Error<DE, CE, SE, FE, N> {
impl<DE, CE, SE, FE> From<InputSelectorError<DE, SE>> for Error<DE, CE, SE, FE> {
fn from(e: InputSelectorError<DE, SE>) -> Self {
match e {
InputSelectorError::DataSource(e) => Error::DataSource(e),
Expand All @@ -177,19 +177,19 @@ impl<DE, CE, SE, FE, N> From<InputSelectorError<DE, SE>> for Error<DE, CE, SE, F
}
}

impl<DE, CE, SE, FE, N> From<sapling::builder::Error> for Error<DE, CE, SE, FE, N> {
impl<DE, CE, SE, FE> From<sapling::builder::Error> for Error<DE, CE, SE, FE> {
fn from(e: sapling::builder::Error) -> Self {
Error::Builder(builder::Error::SaplingBuild(e))
}
}

impl<DE, CE, SE, FE, N> From<transparent::builder::Error> for Error<DE, CE, SE, FE, N> {
impl<DE, CE, SE, FE> From<transparent::builder::Error> for Error<DE, CE, SE, FE> {
fn from(e: transparent::builder::Error) -> Self {
Error::Builder(builder::Error::TransparentBuild(e))
}
}

impl<DE, CE, SE, FE, N> From<ShardTreeError<CE>> for Error<DE, CE, SE, FE, N> {
impl<DE, CE, SE, FE> From<ShardTreeError<CE>> for Error<DE, CE, SE, FE> {
fn from(e: ShardTreeError<CE>) -> Self {
Error::CommitmentTree(e)
}
Expand Down
Loading

0 comments on commit 65f4204

Please sign in to comment.