From bda640c3c5062ac025d6804c14c1cd4199458ffb Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Fri, 26 Jul 2024 08:47:01 -0600 Subject: [PATCH] zcash_client_sqlite: Store received UTXOs in `store_decrypted_tx`. This fixes an issue wherein transparent outputs of transactions added to the wallet via `decrypt_and_store_transaction` would not be properly recorded as UTXOs belonging to the wallet. Fixes #1434 --- zcash_client_backend/CHANGELOG.md | 4 +++- zcash_client_backend/src/data_api.rs | 7 +++++++ zcash_client_backend/src/decrypt.rs | 1 + zcash_client_sqlite/src/lib.rs | 20 ++++++++++++++++++++ zcash_client_sqlite/src/testing/pool.rs | 1 + zcash_primitives/src/legacy.rs | 19 +++++++++++++++++++ 6 files changed, 51 insertions(+), 1 deletion(-) diff --git a/zcash_client_backend/CHANGELOG.md b/zcash_client_backend/CHANGELOG.md index 6348182485..c4f90af6fe 100644 --- a/zcash_client_backend/CHANGELOG.md +++ b/zcash_client_backend/CHANGELOG.md @@ -26,7 +26,8 @@ funds to those addresses. See [ZIP 320](https://zips.z.cash/zip-0320) for detail ### Added - `zcash_client_backend::data_api`: - `chain::BlockCache` trait, behind the `sync` feature flag. - - `WalletRead::get_spendable_transparent_outputs`. + - `WalletRead::get_spendable_transparent_outputs` + - `DecryptedTransaction::mined_height` - `zcash_client_backend::fees`: - `EphemeralBalance` - `ChangeValue::shielded, is_ephemeral` @@ -68,6 +69,7 @@ funds to those addresses. See [ZIP 320](https://zips.z.cash/zip-0320) for detail - `error::Error` has new `Address` and (when the "transparent-inputs" feature is enabled) `PaysEphemeralTransparentAddress` variants. - `wallet::input_selection::InputSelectorError` has a new `Address` variant. + - `DecryptedTransaction::new` takes an additional `mined_height` argument. - `zcash_client_backend::data_api::fees` - When the "transparent-inputs" feature is enabled, `ChangeValue` can also represent an ephemeral transparent output in a proposal. Accordingly, the diff --git a/zcash_client_backend/src/data_api.rs b/zcash_client_backend/src/data_api.rs index 9c8e5a9326..cd80d169b6 100644 --- a/zcash_client_backend/src/data_api.rs +++ b/zcash_client_backend/src/data_api.rs @@ -1263,6 +1263,7 @@ impl ScannedBlock { /// The purpose of this struct is to permit atomic updates of the /// wallet database when transactions are successfully decrypted. pub struct DecryptedTransaction<'a, AccountId> { + mined_height: Option, tx: &'a Transaction, sapling_outputs: Vec>, #[cfg(feature = "orchard")] @@ -1272,6 +1273,7 @@ pub struct DecryptedTransaction<'a, AccountId> { impl<'a, AccountId> DecryptedTransaction<'a, AccountId> { /// Constructs a new [`DecryptedTransaction`] from its constituent parts. pub fn new( + mined_height: Option, tx: &'a Transaction, sapling_outputs: Vec>, #[cfg(feature = "orchard")] orchard_outputs: Vec< @@ -1279,6 +1281,7 @@ impl<'a, AccountId> DecryptedTransaction<'a, AccountId> { >, ) -> Self { Self { + mined_height, tx, sapling_outputs, #[cfg(feature = "orchard")] @@ -1286,6 +1289,10 @@ impl<'a, AccountId> DecryptedTransaction<'a, AccountId> { } } + /// Returns the height at which the transaction was mined, if known. + pub fn mined_height(&self) -> Option { + self.mined_height + } /// Returns the raw transaction data. pub fn tx(&self) -> &Transaction { self.tx diff --git a/zcash_client_backend/src/decrypt.rs b/zcash_client_backend/src/decrypt.rs index 51f9abcdbd..b48d077b53 100644 --- a/zcash_client_backend/src/decrypt.rs +++ b/zcash_client_backend/src/decrypt.rs @@ -215,6 +215,7 @@ pub fn decrypt_transaction<'a, P: consensus::Parameters, AccountId: Copy>( .collect(); DecryptedTransaction::new( + Some(height), tx, sapling_outputs, #[cfg(feature = "orchard")] diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index 69f8ebac8c..585779bc0a 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -124,6 +124,9 @@ use wallet::{ SubtreeScanProgress, }; +#[cfg(feature = "transparent-inputs")] +use wallet::transparent::{find_account_for_transparent_address, put_transparent_output}; + #[cfg(test)] mod testing; @@ -1351,6 +1354,23 @@ impl WalletWrite for WalletDb txout.value, None, )?; + } else { + #[cfg(feature = "transparent-inputs")] + if let Some(account_id) = find_account_for_transparent_address( + wdb.conn.0, + &wdb.params, + &address + )? { + put_transparent_output( + wdb.conn.0, + &wdb.params, + &OutPoint::new(d_tx.tx().txid().into(), u32::try_from(output_index).unwrap()), + txout, + d_tx.mined_height(), + &address, + account_id + )?; + } } } } diff --git a/zcash_client_sqlite/src/testing/pool.rs b/zcash_client_sqlite/src/testing/pool.rs index fbd06e6a61..ae6f37197a 100644 --- a/zcash_client_sqlite/src/testing/pool.rs +++ b/zcash_client_sqlite/src/testing/pool.rs @@ -582,6 +582,7 @@ pub(crate) fn send_multi_step_proposed_transfer() { .unwrap(); let txid = build_result.transaction().txid(); let decrypted_tx = DecryptedTransaction::::new( + None, build_result.transaction(), vec![], #[cfg(feature = "orchard")] diff --git a/zcash_primitives/src/legacy.rs b/zcash_primitives/src/legacy.rs index defe8e3760..c190ecbf5e 100644 --- a/zcash_primitives/src/legacy.rs +++ b/zcash_primitives/src/legacy.rs @@ -1,6 +1,7 @@ //! Support for legacy transparent addresses and scripts. use byteorder::{ReadBytesExt, WriteBytesExt}; +use zcash_address::TryFromAddress; use std::fmt; use std::io::{self, Read, Write}; @@ -407,6 +408,24 @@ impl TransparentAddress { } } +impl TryFromAddress for TransparentAddress { + type Error = (); + + fn try_from_transparent_p2pkh( + _net: zcash_address::Network, + data: [u8; 20], + ) -> Result> { + Ok(TransparentAddress::PublicKeyHash(data)) + } + + fn try_from_transparent_p2sh( + _net: zcash_address::Network, + data: [u8; 20], + ) -> Result> { + Ok(TransparentAddress::ScriptHash(data)) + } +} + #[cfg(any(test, feature = "test-dependencies"))] pub mod testing { use proptest::prelude::{any, prop_compose};