From faccf56f04bf2c3ba67bd71c38cc93b4ab1363d4 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Mon, 26 Jun 2023 10:12:59 -0600 Subject: [PATCH] Split `PoolType` enum into `PoolType` and `ShieldedProtocol` There are cases where we wish to return informaiton that is relevant to a specific shielded protocol and `Transparent` is an invalid case. This is a minor preparatory refactoring that makes this distinction expressible. --- zcash_client_backend/CHANGELOG.md | 11 +++-- zcash_client_backend/src/data_api.rs | 13 ++++-- zcash_client_backend/src/data_api/wallet.rs | 40 +++++++++++-------- zcash_client_sqlite/src/lib.rs | 8 +++- zcash_client_sqlite/src/wallet.rs | 15 +++++-- .../wallet/init/migrations/ufvk_support.rs | 8 +++- .../init/migrations/v_transactions_net.rs | 5 ++- 7 files changed, 67 insertions(+), 33 deletions(-) diff --git a/zcash_client_backend/CHANGELOG.md b/zcash_client_backend/CHANGELOG.md index 999d91860..c76af3ce2 100644 --- a/zcash_client_backend/CHANGELOG.md +++ b/zcash_client_backend/CHANGELOG.md @@ -11,14 +11,15 @@ and this library adheres to Rust's notion of - `impl Eq for zcash_client_backend::zip321::{Payment, TransactionRequest}` - `impl Debug` for `zcash_client_backend::{data_api::wallet::input_selection::Proposal, wallet::ReceivedSaplingNote}` - `zcash_client_backend::data_api`: + - `BlockMetadata` + - `NullifierQuery` for use with `WalletRead::get_sapling_nullifiers` + - `ScannedBlock` + - `ShieldedProtocol` - `WalletRead::{block_metadata, block_fully_scanned, suggest_scan_ranges}` - `WalletWrite::put_block` - `WalletCommitmentTrees` - - `testing::MockWalletDb::new` - - `NullifierQuery` for use with `WalletRead::get_sapling_nullifiers` - - `BlockMetadata` - - `ScannedBlock` - `chain::CommitmentTreeRoot` + - `testing::MockWalletDb::new` - `wallet::input_sellection::Proposal::{min_target_height, min_anchor_height}`: - `zcash_client_backend::wallet::WalletSaplingOutput::note_commitment_tree_position` - `zcash_client_backend::scanning::ScanError` @@ -49,6 +50,8 @@ and this library adheres to Rust's notion of now take their respective `min_confirmations` arguments as `NonZeroU32` - 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 + 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. diff --git a/zcash_client_backend/src/data_api.rs b/zcash_client_backend/src/data_api.rs index 7cc945f18..bef383e2b 100644 --- a/zcash_client_backend/src/data_api.rs +++ b/zcash_client_backend/src/data_api.rs @@ -372,14 +372,21 @@ pub struct SentTransaction<'a> { pub utxos_spent: Vec, } +/// A shielded transfer protocol supported by the wallet. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ShieldedProtocol { + /// The Sapling protocol + Sapling, + // TODO: Orchard +} + /// A value pool to which the wallet supports sending transaction outputs. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum PoolType { /// The transparent value pool Transparent, - /// The Sapling value pool - Sapling, - // TODO: Orchard + /// A shielded value pool. + Shielded(ShieldedProtocol), } /// A type that represents the recipient of a transaction output; a recipient address (and, for diff --git a/zcash_client_backend/src/data_api/wallet.rs b/zcash_client_backend/src/data_api/wallet.rs index 7f3d4ce6a..60ef900ee 100644 --- a/zcash_client_backend/src/data_api/wallet.rs +++ b/zcash_client_backend/src/data_api/wallet.rs @@ -37,6 +37,8 @@ use crate::{ pub mod input_selection; use input_selection::{GreedyInputSelector, GreedyInputSelectorError, InputSelector}; +use super::ShieldedProtocol; + #[cfg(feature = "transparent-inputs")] use { crate::wallet::WalletTransparentOutput, @@ -550,7 +552,7 @@ where payment.memo.clone().unwrap_or_else(MemoBytes::empty), )?; sapling_output_meta.push(( - Recipient::Unified(ua.clone(), PoolType::Sapling), + Recipient::Unified(ua.clone(), PoolType::Shielded(ShieldedProtocol::Sapling)), payment.amount, payment.memo.clone(), )); @@ -589,7 +591,10 @@ where MemoBytes::empty(), )?; sapling_output_meta.push(( - Recipient::InternalAccount(account, PoolType::Sapling), + Recipient::InternalAccount( + account, + PoolType::Shielded(ShieldedProtocol::Sapling), + ), *amount, change_memo.clone(), )) @@ -610,20 +615,23 @@ where .output_index(i) .expect("An output should exist in the transaction for each shielded payment."); - let received_as = - if let Recipient::InternalAccount(account, PoolType::Sapling) = recipient { - tx.sapling_bundle().and_then(|bundle| { - try_sapling_note_decryption( - params, - proposal.min_target_height(), - &internal_ivk, - &bundle.shielded_outputs()[output_index], - ) - .map(|(note, _, _)| (account, note)) - }) - } else { - None - }; + let received_as = if let Recipient::InternalAccount( + account, + PoolType::Shielded(ShieldedProtocol::Sapling), + ) = recipient + { + tx.sapling_bundle().and_then(|bundle| { + try_sapling_note_decryption( + params, + proposal.min_target_height(), + &internal_ivk, + &bundle.shielded_outputs()[output_index], + ) + .map(|(note, _, _)| (account, note)) + }) + } else { + None + }; SentTransactionOutput::from_parts(output_index, recipient, value, memo, received_as) }); diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index 2f65053c4..c3d9b04bd 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -59,7 +59,8 @@ use zcash_client_backend::{ self, chain::{BlockSource, CommitmentTreeRoot}, BlockMetadata, DecryptedTransaction, NullifierQuery, PoolType, Recipient, ScannedBlock, - SentTransaction, WalletCommitmentTrees, WalletRead, WalletWrite, SAPLING_SHARD_HEIGHT, + SentTransaction, ShieldedProtocol, WalletCommitmentTrees, WalletRead, WalletWrite, + SAPLING_SHARD_HEIGHT, }, keys::{UnifiedFullViewingKey, UnifiedSpendingKey}, proto::compact_formats::CompactBlock, @@ -459,7 +460,10 @@ impl WalletWrite for WalletDb let recipient = if output.transfer_type == TransferType::Outgoing { Recipient::Sapling(output.note.recipient()) } else { - Recipient::InternalAccount(output.account, PoolType::Sapling) + Recipient::InternalAccount( + output.account, + PoolType::Shielded(ShieldedProtocol::Sapling) + ) }; wallet::put_sent_output( diff --git a/zcash_client_sqlite/src/wallet.rs b/zcash_client_sqlite/src/wallet.rs index 6b103cfc3..0e1458894 100644 --- a/zcash_client_sqlite/src/wallet.rs +++ b/zcash_client_sqlite/src/wallet.rs @@ -66,8 +66,11 @@ use rusqlite::{self, named_params, OptionalExtension, ToSql}; use std::convert::TryFrom; -use std::io::Cursor; -use std::{collections::HashMap, io}; +use std::{ + collections::HashMap, + io::{self, Cursor}, +}; +use zcash_client_backend::data_api::ShieldedProtocol; use zcash_primitives::{ block::BlockHash, @@ -116,7 +119,7 @@ pub(crate) fn pool_code(pool_type: PoolType) -> i64 { // implementation detail. match pool_type { PoolType::Transparent => 0i64, - PoolType::Sapling => 2i64, + PoolType::Shielded(ShieldedProtocol::Sapling) => 2i64, } } @@ -1119,7 +1122,11 @@ fn recipient_params( ) -> (Option, Option, PoolType) { match to { Recipient::Transparent(addr) => (Some(addr.encode(params)), None, PoolType::Transparent), - Recipient::Sapling(addr) => (Some(addr.encode(params)), None, PoolType::Sapling), + Recipient::Sapling(addr) => ( + Some(addr.encode(params)), + None, + PoolType::Shielded(ShieldedProtocol::Sapling), + ), Recipient::Unified(addr, pool) => (Some(addr.encode(params)), None, *pool), Recipient::InternalAccount(id, pool) => (None, Some(u32::from(*id)), *pool), } diff --git a/zcash_client_sqlite/src/wallet/init/migrations/ufvk_support.rs b/zcash_client_sqlite/src/wallet/init/migrations/ufvk_support.rs index def63a91d..656281b70 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/ufvk_support.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/ufvk_support.rs @@ -8,7 +8,9 @@ use secrecy::{ExposeSecret, SecretVec}; use uuid::Uuid; use zcash_client_backend::{ - address::RecipientAddress, data_api::PoolType, keys::UnifiedSpendingKey, + address::RecipientAddress, + data_api::{PoolType, ShieldedProtocol}, + keys::UnifiedSpendingKey, }; use zcash_primitives::{consensus, zip32::AccountId}; @@ -229,7 +231,9 @@ impl RusqliteMigration for Migration

{ )) })?; let output_pool = match decoded_address { - RecipientAddress::Shielded(_) => Ok(pool_code(PoolType::Sapling)), + RecipientAddress::Shielded(_) => { + Ok(pool_code(PoolType::Shielded(ShieldedProtocol::Sapling))) + } RecipientAddress::Transparent(_) => Ok(pool_code(PoolType::Transparent)), RecipientAddress::Unified(_) => Err(WalletMigrationError::CorruptedData( "Unified addresses should not yet appear in the sent_notes table." diff --git a/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_net.rs b/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_net.rs index fc3ab7378..7f82cea4a 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_net.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_net.rs @@ -6,9 +6,10 @@ use rusqlite::{self, named_params}; use schemer; use schemer_rusqlite::RusqliteMigration; use uuid::Uuid; +use zcash_client_backend::data_api::{PoolType, ShieldedProtocol}; use super::add_transaction_views; -use crate::wallet::{init::WalletMigrationError, pool_code, PoolType}; +use crate::wallet::{init::WalletMigrationError, pool_code}; pub(super) const MIGRATION_ID: Uuid = Uuid::from_fields( 0x2aa4d24f, @@ -48,7 +49,7 @@ impl RusqliteMigration for Migration { SELECT tx, :output_pool, output_index, from_account, from_account, value FROM sent_notes", named_params![ - ":output_pool": &pool_code(PoolType::Sapling) + ":output_pool": &pool_code(PoolType::Shielded(ShieldedProtocol::Sapling)) ] )?;