Skip to content

Commit

Permalink
zcash_client_sqlite: Store received UTXOs in store_decrypted_tx.
Browse files Browse the repository at this point in the history
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.

Part of zcash#1434
  • Loading branch information
nuttycom committed Jul 26, 2024
1 parent 5ad3205 commit 3cec9ee
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 1 deletion.
4 changes: 3 additions & 1 deletion zcash_client_backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions zcash_client_backend/src/data_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,7 @@ impl<A> ScannedBlock<A> {
/// 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<BlockHeight>,
tx: &'a Transaction,
sapling_outputs: Vec<DecryptedOutput<sapling::Note, AccountId>>,
#[cfg(feature = "orchard")]
Expand All @@ -1272,20 +1273,26 @@ 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<BlockHeight>,
tx: &'a Transaction,
sapling_outputs: Vec<DecryptedOutput<sapling::Note, AccountId>>,
#[cfg(feature = "orchard")] orchard_outputs: Vec<
DecryptedOutput<orchard::note::Note, AccountId>,
>,
) -> Self {
Self {
mined_height,
tx,
sapling_outputs,
#[cfg(feature = "orchard")]
orchard_outputs,
}
}

/// Returns the height at which the transaction was mined, if known.
pub fn mined_height(&self) -> Option<BlockHeight> {
self.mined_height
}
/// Returns the raw transaction data.
pub fn tx(&self) -> &Transaction {
self.tx
Expand Down
1 change: 1 addition & 0 deletions zcash_client_backend/src/decrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
21 changes: 21 additions & 0 deletions zcash_client_sqlite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -1320,6 +1323,24 @@ impl<P: consensus::Parameters> WalletWrite for WalletDb<rusqlite::Connection, P>
#[cfg(feature = "transparent-inputs")]
wallet::transparent::ephemeral::mark_ephemeral_address_as_seen(wdb, &address, tx_ref)?;

// If the output belongs to the wallet, add it to `transparent_received_outputs`.
#[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
)?;
}

// If a transaction we observe contains spends from our wallet, we will
// store its transparent outputs in the same way they would be stored by
// create_spend_to_address.
Expand Down
1 change: 1 addition & 0 deletions zcash_client_sqlite/src/testing/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,7 @@ pub(crate) fn send_multi_step_proposed_transfer<T: ShieldedPoolTester>() {
.unwrap();
let txid = build_result.transaction().txid();
let decrypted_tx = DecryptedTransaction::<AccountId>::new(
None,
build_result.transaction(),
vec![],
#[cfg(feature = "orchard")]
Expand Down
17 changes: 17 additions & 0 deletions zcash_primitives/src/legacy.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Support for legacy transparent addresses and scripts.

use byteorder::{ReadBytesExt, WriteBytesExt};
use zcash_address::TryFromRawAddress;

use std::fmt;
use std::io::{self, Read, Write};
Expand Down Expand Up @@ -407,6 +408,22 @@ impl TransparentAddress {
}
}

impl TryFromRawAddress for TransparentAddress {
type Error = ();

fn try_from_raw_transparent_p2pkh(
data: [u8; 20],
) -> Result<Self, zcash_address::ConversionError<Self::Error>> {
Ok(TransparentAddress::PublicKeyHash(data))
}

fn try_from_raw_transparent_p2sh(
data: [u8; 20],
) -> Result<Self, zcash_address::ConversionError<Self::Error>> {
Ok(TransparentAddress::ScriptHash(data))
}
}

#[cfg(any(test, feature = "test-dependencies"))]
pub mod testing {
use proptest::prelude::{any, prop_compose};
Expand Down

0 comments on commit 3cec9ee

Please sign in to comment.