diff --git a/zcash_client_backend/CHANGELOG.md b/zcash_client_backend/CHANGELOG.md
index ee29ab2e48..bc7f3a4c5b 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..7496eb7c3c 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;
@@ -1320,6 +1323,24 @@ impl WalletWrite for WalletDb
#[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.
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..23ba7cf830 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::TryFromRawAddress;
use std::fmt;
use std::io::{self, Read, Write};
@@ -407,6 +408,22 @@ impl TransparentAddress {
}
}
+impl TryFromRawAddress for TransparentAddress {
+ type Error = ();
+
+ fn try_from_raw_transparent_p2pkh(
+ data: [u8; 20],
+ ) -> Result> {
+ Ok(TransparentAddress::PublicKeyHash(data))
+ }
+
+ fn try_from_raw_transparent_p2sh(
+ data: [u8; 20],
+ ) -> Result> {
+ Ok(TransparentAddress::ScriptHash(data))
+ }
+}
+
#[cfg(any(test, feature = "test-dependencies"))]
pub mod testing {
use proptest::prelude::{any, prop_compose};