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
|
||||
- `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
|
||||
|
|
|
@ -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")]
|
||||
|
@ -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<BlockHeight>,
|
||||
tx: &'a Transaction,
|
||||
sapling_outputs: Vec<DecryptedOutput<sapling::Note, AccountId>>,
|
||||
#[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<BlockHeight> {
|
||||
self.mined_height
|
||||
}
|
||||
/// Returns the raw transaction data.
|
||||
pub fn tx(&self) -> &Transaction {
|
||||
self.tx
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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<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.
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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<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};
|
||||
|
|
Loading…
Reference in New Issue