Provide PoolType to UnsupportedPoolType case; stylistic changes

This commit is contained in:
Matthew Watt 2023-10-08 19:05:50 -05:00
parent a9d18ec2ce
commit 94f2240e08
7 changed files with 49 additions and 21 deletions

View File

@ -7,6 +7,11 @@ and this library adheres to Rust's notion of
## [Unreleased] ## [Unreleased]
### Added
- `zcash_client_backend::data_api::ShieldedProtocol` has a new variant for `Orchard`, allowing for better reporting to callers trying to perform actions using `Orchard` before it is fully supported.
- `zcash_client_backend::data_api::error::Error` has new error variant:
- `Error::UnsupportedPoolType(zcash_client_backend::data_api::PoolType)`
### Changed ### Changed
- `zcash_client_backend::data_api::chain::scan_cached_blocks` now returns - `zcash_client_backend::data_api::chain::scan_cached_blocks` now returns
a `ScanSummary` containing metadata about the scanned blocks on success. a `ScanSummary` containing metadata about the scanned blocks on success.

View File

@ -556,7 +556,8 @@ pub struct SentTransaction<'a> {
pub enum ShieldedProtocol { pub enum ShieldedProtocol {
/// The Sapling protocol /// The Sapling protocol
Sapling, Sapling,
// TODO: Orchard /// The Orchard protocol
Orchard
} }
/// A unique identifier for a shielded transaction output /// A unique identifier for a shielded transaction output

View File

@ -22,7 +22,7 @@ use zcash_primitives::{legacy::TransparentAddress, zip32::DiversifierIndex};
/// Errors that can occur as a consequence of wallet operations. /// Errors that can occur as a consequence of wallet operations.
#[derive(Debug)] #[derive(Debug)]
pub enum Error<DataSourceError, CommitmentTreeError, SelectionError, FeeError, NoteRef> { pub enum Error<DataSourceError, CommitmentTreeError, SelectionError, FeeError, NoteRef, PoolType> {
/// An error occurred retrieving data from the underlying data source /// An error occurred retrieving data from the underlying data source
DataSource(DataSourceError), DataSource(DataSourceError),
@ -54,8 +54,8 @@ pub enum Error<DataSourceError, CommitmentTreeError, SelectionError, FeeError, N
/// It is forbidden to provide a memo when constructing a transparent output. /// It is forbidden to provide a memo when constructing a transparent output.
MemoForbidden, MemoForbidden,
/// Attempted to create a spend to an unsupported output type (i.e. Orchard) /// Attempted to create a spend to an unsupported pool type (currently, Orchard).
UnsupportedOutputType, UnsupportedPoolType(PoolType),
/// A note being spent does not correspond to either the internal or external /// A note being spent does not correspond to either the internal or external
/// full viewing key for an account. /// full viewing key for an account.
@ -68,13 +68,14 @@ pub enum Error<DataSourceError, CommitmentTreeError, SelectionError, FeeError, N
ChildIndexOutOfRange(DiversifierIndex), ChildIndexOutOfRange(DiversifierIndex),
} }
impl<DE, CE, SE, FE, N> fmt::Display for Error<DE, CE, SE, FE, N> impl<DE, CE, SE, FE, N, PT> fmt::Display for Error<DE, CE, SE, FE, N, PT>
where where
DE: fmt::Display, DE: fmt::Display,
CE: fmt::Display, CE: fmt::Display,
SE: fmt::Display, SE: fmt::Display,
FE: fmt::Display, FE: fmt::Display,
N: fmt::Display, N: fmt::Display,
PT: fmt::Display
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self { match &self {
@ -114,7 +115,7 @@ where
Error::ScanRequired => write!(f, "Must scan blocks first"), Error::ScanRequired => write!(f, "Must scan blocks first"),
Error::Builder(e) => write!(f, "An error occurred building the transaction: {}", e), 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::MemoForbidden => write!(f, "It is not possible to send a memo to a transparent address."),
Error::UnsupportedOutputType => write!(f, "Attempted to create spend to an unsupported output type"), Error::UnsupportedPoolType(t) => write!(f, "Attempted to create spend to an unsupported pool type: {}", t),
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),
#[cfg(feature = "transparent-inputs")] #[cfg(feature = "transparent-inputs")]
@ -133,13 +134,14 @@ where
} }
} }
impl<DE, CE, SE, FE, N> error::Error for Error<DE, CE, SE, FE, N> impl<DE, CE, SE, FE, N, PT> error::Error for Error<DE, CE, SE, FE, N, PT>
where where
DE: Debug + Display + error::Error + 'static, DE: Debug + Display + error::Error + 'static,
CE: Debug + Display + error::Error + 'static, CE: Debug + Display + error::Error + 'static,
SE: Debug + Display + error::Error + 'static, SE: Debug + Display + error::Error + 'static,
FE: Debug + Display + 'static, FE: Debug + Display + 'static,
N: Debug + Display, N: Debug + Display,
PT: Debug + Display
{ {
fn source(&self) -> Option<&(dyn error::Error + 'static)> { fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match &self { match &self {
@ -152,19 +154,19 @@ where
} }
} }
impl<DE, CE, SE, FE, N> From<builder::Error<FE>> for Error<DE, CE, SE, FE, N> { impl<DE, CE, SE, FE, N, PT> From<builder::Error<FE>> for Error<DE, CE, SE, FE, N, PT> {
fn from(e: builder::Error<FE>) -> Self { fn from(e: builder::Error<FE>) -> Self {
Error::Builder(e) Error::Builder(e)
} }
} }
impl<DE, CE, SE, FE, N> From<BalanceError> for Error<DE, CE, SE, FE, N> { impl<DE, CE, SE, FE, N, PT> From<BalanceError> for Error<DE, CE, SE, FE, N, PT> {
fn from(e: BalanceError) -> Self { fn from(e: BalanceError) -> Self {
Error::BalanceError(e) 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, N, PT> From<InputSelectorError<DE, SE>> for Error<DE, CE, SE, FE, N, PT> {
fn from(e: InputSelectorError<DE, SE>) -> Self { fn from(e: InputSelectorError<DE, SE>) -> Self {
match e { match e {
InputSelectorError::DataSource(e) => Error::DataSource(e), InputSelectorError::DataSource(e) => Error::DataSource(e),
@ -181,19 +183,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, N, PT> From<sapling::builder::Error> for Error<DE, CE, SE, FE, N, PT> {
fn from(e: sapling::builder::Error) -> Self { fn from(e: sapling::builder::Error) -> Self {
Error::Builder(builder::Error::SaplingBuild(e)) 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, N, PT> From<transparent::builder::Error> for Error<DE, CE, SE, FE, N, PT> {
fn from(e: transparent::builder::Error) -> Self { fn from(e: transparent::builder::Error) -> Self {
Error::Builder(builder::Error::TransparentBuild(e)) 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, N, PT> From<ShardTreeError<CE>> for Error<DE, CE, SE, FE, N, PT> {
fn from(e: ShardTreeError<CE>) -> Self { fn from(e: ShardTreeError<CE>) -> Self {
Error::CommitmentTree(e) Error::CommitmentTree(e)
} }

View File

@ -207,6 +207,7 @@ pub fn create_spend_to_address<DbT, ParamsT>(
GreedyInputSelectorError<BalanceError, DbT::NoteRef>, GreedyInputSelectorError<BalanceError, DbT::NoteRef>,
Infallible, Infallible,
DbT::NoteRef, DbT::NoteRef,
PoolType,
>, >,
> >
where where
@ -310,6 +311,7 @@ pub fn spend<DbT, ParamsT, InputsT>(
InputsT::Error, InputsT::Error,
<InputsT::FeeRule as FeeRule>::Error, <InputsT::FeeRule as FeeRule>::Error,
DbT::NoteRef, DbT::NoteRef,
PoolType,
>, >,
> >
where where
@ -364,6 +366,7 @@ pub fn propose_transfer<DbT, ParamsT, InputsT, CommitmentTreeErrT>(
InputsT::Error, InputsT::Error,
<InputsT::FeeRule as FeeRule>::Error, <InputsT::FeeRule as FeeRule>::Error,
DbT::NoteRef, DbT::NoteRef,
PoolType,
>, >,
> >
where where
@ -444,6 +447,7 @@ pub fn create_proposed_transaction<DbT, ParamsT, InputsErrT, FeeRuleT>(
InputsErrT, InputsErrT,
FeeRuleT::Error, FeeRuleT::Error,
DbT::NoteRef, DbT::NoteRef,
PoolType,
>, >,
> >
where where
@ -489,7 +493,7 @@ where
let checkpoint_depth = wallet_db.get_checkpoint_depth(min_confirmations)?; let checkpoint_depth = wallet_db.get_checkpoint_depth(min_confirmations)?;
wallet_db.with_sapling_tree_mut::<_, _, Error<_, _, _, _, _>>(|sapling_tree| { wallet_db.with_sapling_tree_mut::<_, _, Error<_, _, _, _, _, _>>(|sapling_tree| {
for selected in proposal.sapling_inputs() { for selected in proposal.sapling_inputs() {
let (note, key, merkle_path) = select_key_for_note( let (note, key, merkle_path) = select_key_for_note(
sapling_tree, sapling_tree,
@ -547,24 +551,24 @@ where
.as_ref() .as_ref()
.map_or_else(MemoBytes::empty, |m| m.clone()); .map_or_else(MemoBytes::empty, |m| m.clone());
if ua.sapling().is_some() { if let Some(sapling_receiver) = ua.sapling() {
builder.add_sapling_output( builder.add_sapling_output(
external_ovk, external_ovk,
*ua.sapling().unwrap(), *sapling_receiver,
payment.amount, payment.amount,
memo.clone(), memo.clone(),
)?; )?;
} else if ua.transparent().is_some() { } else if let Some(taddr) = ua.transparent() {
if payment.memo.is_some() { if payment.memo.is_some() {
return Err(Error::MemoForbidden); return Err(Error::MemoForbidden);
} else { } else {
builder.add_transparent_output( builder.add_transparent_output(
ua.transparent().unwrap(), taddr,
payment.amount payment.amount
)?; )?;
} }
} else { } else {
return Err(Error::UnsupportedOutputType); return Err(Error::UnsupportedPoolType(PoolType::Shielded(ShieldedProtocol::Orchard)));
} }
sapling_output_meta.push(( sapling_output_meta.push((
Recipient::Unified(ua.clone(), PoolType::Shielded(ShieldedProtocol::Sapling)), Recipient::Unified(ua.clone(), PoolType::Shielded(ShieldedProtocol::Sapling)),

View File

@ -7,6 +7,10 @@ and this library adheres to Rust's notion of
## [Unreleased] ## [Unreleased]
### Added
- `zcash_client_sqlite::error::SqliteClientError` has new error variant:
- `SqliteClientError::UnsupportedPoolType(zcash_client_backend::data_api::PoolType)`
## [0.8.0] - 2023-09-25 ## [0.8.0] - 2023-09-25
### Notable Changes ### Notable Changes

View File

@ -4,6 +4,7 @@ use std::error;
use std::fmt; use std::fmt;
use shardtree::error::ShardTreeError; use shardtree::error::ShardTreeError;
use zcash_client_backend::data_api::PoolType;
use zcash_client_backend::encoding::{Bech32DecodeError, TransparentCodecError}; use zcash_client_backend::encoding::{Bech32DecodeError, TransparentCodecError};
use zcash_primitives::{consensus::BlockHeight, zip32::AccountId}; use zcash_primitives::{consensus::BlockHeight, zip32::AccountId};
@ -98,6 +99,9 @@ pub enum SqliteClientError {
/// [`WalletWrite::update_chain_tip`]: /// [`WalletWrite::update_chain_tip`]:
/// zcash_client_backend::data_api::WalletWrite::update_chain_tip /// zcash_client_backend::data_api::WalletWrite::update_chain_tip
ChainHeightUnknown, ChainHeightUnknown,
/// Unsupported pool type
UnsupportedPoolType(PoolType)
} }
impl error::Error for SqliteClientError { impl error::Error for SqliteClientError {
@ -144,7 +148,8 @@ impl fmt::Display for SqliteClientError {
SqliteClientError::AddressNotRecognized(_) => write!(f, "The address associated with a received txo is not identifiable as belonging to the wallet."), SqliteClientError::AddressNotRecognized(_) => write!(f, "The address associated with a received txo is not identifiable as belonging to the wallet."),
SqliteClientError::CommitmentTree(err) => write!(f, "An error occurred accessing or updating note commitment tree data: {}.", err), SqliteClientError::CommitmentTree(err) => write!(f, "An error occurred accessing or updating note commitment tree data: {}.", err),
SqliteClientError::CacheMiss(height) => write!(f, "Requested height {} does not exist in the block cache.", height), SqliteClientError::CacheMiss(height) => write!(f, "Requested height {} does not exist in the block cache.", height),
SqliteClientError::ChainHeightUnknown => write!(f, "Chain height unknown; please call `update_chain_tip`") SqliteClientError::ChainHeightUnknown => write!(f, "Chain height unknown; please call `update_chain_tip`"),
SqliteClientError::UnsupportedPoolType(t) => write!(f, "Pool type is not currently supported: {:?}", t)
} }
} }
} }

View File

@ -136,6 +136,7 @@ pub(crate) fn pool_code(pool_type: PoolType) -> i64 {
match pool_type { match pool_type {
PoolType::Transparent => 0i64, PoolType::Transparent => 0i64,
PoolType::Shielded(ShieldedProtocol::Sapling) => 2i64, PoolType::Shielded(ShieldedProtocol::Sapling) => 2i64,
PoolType::Shielded(ShieldedProtocol::Orchard) => 4i64
} }
} }
@ -758,7 +759,12 @@ pub(crate) fn get_received_memo(
conn: &rusqlite::Connection, conn: &rusqlite::Connection,
note_id: NoteId, note_id: NoteId,
) -> Result<Option<Memo>, SqliteClientError> { ) -> Result<Option<Memo>, SqliteClientError> {
let memo_bytes: Option<Vec<_>> = match note_id.protocol() { let protocol = note_id.protocol();
if let ShieldedProtocol::Orchard = protocol {
return Err(SqliteClientError::UnsupportedPoolType(PoolType::Shielded(protocol)));
}
let memo_bytes: Option<Vec<_>> = match protocol {
ShieldedProtocol::Sapling => conn ShieldedProtocol::Sapling => conn
.query_row( .query_row(
"SELECT memo FROM sapling_received_notes "SELECT memo FROM sapling_received_notes
@ -773,6 +779,7 @@ pub(crate) fn get_received_memo(
) )
.optional()? .optional()?
.flatten(), .flatten(),
ShieldedProtocol::Orchard => None
}; };
memo_bytes memo_bytes