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. Part of #1434
This commit is contained in:
parent
5ad3205e58
commit
3cec9ee4a7
|
@ -26,7 +26,8 @@ funds to those addresses. See [ZIP 320](https://zips.z.cash/zip-0320) for detail
|
||||||
### Added
|
### Added
|
||||||
- `zcash_client_backend::data_api`:
|
- `zcash_client_backend::data_api`:
|
||||||
- `chain::BlockCache` trait, behind the `sync` feature flag.
|
- `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`:
|
- `zcash_client_backend::fees`:
|
||||||
- `EphemeralBalance`
|
- `EphemeralBalance`
|
||||||
- `ChangeValue::shielded, is_ephemeral`
|
- `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
|
- `error::Error` has new `Address` and (when the "transparent-inputs" feature
|
||||||
is enabled) `PaysEphemeralTransparentAddress` variants.
|
is enabled) `PaysEphemeralTransparentAddress` variants.
|
||||||
- `wallet::input_selection::InputSelectorError` has a new `Address` variant.
|
- `wallet::input_selection::InputSelectorError` has a new `Address` variant.
|
||||||
|
- `DecryptedTransaction::new` takes an additional `mined_height` argument.
|
||||||
- `zcash_client_backend::data_api::fees`
|
- `zcash_client_backend::data_api::fees`
|
||||||
- When the "transparent-inputs" feature is enabled, `ChangeValue` can also
|
- When the "transparent-inputs" feature is enabled, `ChangeValue` can also
|
||||||
represent an ephemeral transparent output in a proposal. Accordingly, the
|
represent an ephemeral transparent output in a proposal. Accordingly, the
|
||||||
|
|
|
@ -1263,6 +1263,7 @@ impl<A> ScannedBlock<A> {
|
||||||
/// The purpose of this struct is to permit atomic updates of the
|
/// The purpose of this struct is to permit atomic updates of the
|
||||||
/// wallet database when transactions are successfully decrypted.
|
/// wallet database when transactions are successfully decrypted.
|
||||||
pub struct DecryptedTransaction<'a, AccountId> {
|
pub struct DecryptedTransaction<'a, AccountId> {
|
||||||
|
mined_height: Option<BlockHeight>,
|
||||||
tx: &'a Transaction,
|
tx: &'a Transaction,
|
||||||
sapling_outputs: Vec<DecryptedOutput<sapling::Note, AccountId>>,
|
sapling_outputs: Vec<DecryptedOutput<sapling::Note, AccountId>>,
|
||||||
#[cfg(feature = "orchard")]
|
#[cfg(feature = "orchard")]
|
||||||
|
@ -1272,6 +1273,7 @@ pub struct DecryptedTransaction<'a, AccountId> {
|
||||||
impl<'a, AccountId> DecryptedTransaction<'a, AccountId> {
|
impl<'a, AccountId> DecryptedTransaction<'a, AccountId> {
|
||||||
/// Constructs a new [`DecryptedTransaction`] from its constituent parts.
|
/// Constructs a new [`DecryptedTransaction`] from its constituent parts.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
mined_height: Option<BlockHeight>,
|
||||||
tx: &'a Transaction,
|
tx: &'a Transaction,
|
||||||
sapling_outputs: Vec<DecryptedOutput<sapling::Note, AccountId>>,
|
sapling_outputs: Vec<DecryptedOutput<sapling::Note, AccountId>>,
|
||||||
#[cfg(feature = "orchard")] orchard_outputs: Vec<
|
#[cfg(feature = "orchard")] orchard_outputs: Vec<
|
||||||
|
@ -1279,6 +1281,7 @@ impl<'a, AccountId> DecryptedTransaction<'a, AccountId> {
|
||||||
>,
|
>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
mined_height,
|
||||||
tx,
|
tx,
|
||||||
sapling_outputs,
|
sapling_outputs,
|
||||||
#[cfg(feature = "orchard")]
|
#[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<BlockHeight> {
|
||||||
|
self.mined_height
|
||||||
|
}
|
||||||
/// Returns the raw transaction data.
|
/// Returns the raw transaction data.
|
||||||
pub fn tx(&self) -> &Transaction {
|
pub fn tx(&self) -> &Transaction {
|
||||||
self.tx
|
self.tx
|
||||||
|
|
|
@ -215,6 +215,7 @@ pub fn decrypt_transaction<'a, P: consensus::Parameters, AccountId: Copy>(
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
DecryptedTransaction::new(
|
DecryptedTransaction::new(
|
||||||
|
Some(height),
|
||||||
tx,
|
tx,
|
||||||
sapling_outputs,
|
sapling_outputs,
|
||||||
#[cfg(feature = "orchard")]
|
#[cfg(feature = "orchard")]
|
||||||
|
|
|
@ -124,6 +124,9 @@ use wallet::{
|
||||||
SubtreeScanProgress,
|
SubtreeScanProgress,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
use wallet::transparent::{find_account_for_transparent_address, put_transparent_output};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod testing;
|
mod testing;
|
||||||
|
|
||||||
|
@ -1320,6 +1323,24 @@ impl<P: consensus::Parameters> WalletWrite for WalletDb<rusqlite::Connection, P>
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
wallet::transparent::ephemeral::mark_ephemeral_address_as_seen(wdb, &address, tx_ref)?;
|
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
|
// 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
|
// store its transparent outputs in the same way they would be stored by
|
||||||
// create_spend_to_address.
|
// create_spend_to_address.
|
||||||
|
|
|
@ -582,6 +582,7 @@ pub(crate) fn send_multi_step_proposed_transfer<T: ShieldedPoolTester>() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let txid = build_result.transaction().txid();
|
let txid = build_result.transaction().txid();
|
||||||
let decrypted_tx = DecryptedTransaction::<AccountId>::new(
|
let decrypted_tx = DecryptedTransaction::<AccountId>::new(
|
||||||
|
None,
|
||||||
build_result.transaction(),
|
build_result.transaction(),
|
||||||
vec![],
|
vec![],
|
||||||
#[cfg(feature = "orchard")]
|
#[cfg(feature = "orchard")]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//! Support for legacy transparent addresses and scripts.
|
//! Support for legacy transparent addresses and scripts.
|
||||||
|
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||||
|
use zcash_address::TryFromRawAddress;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{self, Read, Write};
|
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<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"))]
|
#[cfg(any(test, feature = "test-dependencies"))]
|
||||||
pub mod testing {
|
pub mod testing {
|
||||||
use proptest::prelude::{any, prop_compose};
|
use proptest::prelude::{any, prop_compose};
|
||||||
|
|
Loading…
Reference in New Issue