zcash_client_backend: Move `Recipient::EphemeralTransparent` behind the `transparent-inputs` feature flag.
This variant should not have been a part of the public API unless `tranpsarent-inputs` was enabled, as it's necessary for the wallet to be able to spend a transparent input in order for a ZIP 320 transaction to be properly constructed and authorized. In addition, this simplifies the `Recipient` API by removing its type parameters in favor of concrete types, made possible by using a separate type for the build process.
This commit is contained in:
parent
736bfd555b
commit
5290d13942
|
@ -9,6 +9,18 @@ and this library adheres to Rust's notion of
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Migrated to `nonempty 0.11`
|
- Migrated to `nonempty 0.11`
|
||||||
|
- `zcash_client_backend::wallet::Recipient` has changed:
|
||||||
|
- The `Recipient::External` variant is now a structured variant.
|
||||||
|
- The `Recipient::EphemeralTransparent` variant is now only available if
|
||||||
|
`zcash_client_backend` is built using the `transparent-inputs` feature flag.
|
||||||
|
- The `N` and `O` type pararameters to this type have been replaced by
|
||||||
|
concrete uses of `Box<Note>` and `Outpoint` instead. The
|
||||||
|
`map_internal_account_note` and `map_ephemeral_transparent_outpoint` and
|
||||||
|
`internal_account_note_transpose_option` methods have consequently been
|
||||||
|
removed.
|
||||||
|
- `zcash_client_backend::data_api::WalletRead::get_known_ephemeral_addresses`
|
||||||
|
now takes a `Range<zcash_transparent::keys::NonHardenedChildIndex>` as its
|
||||||
|
argument instead of a `Range<u32>`
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
- `zcash_client_backend::address` (use `zcash_keys::address` instead)
|
- `zcash_client_backend::address` (use `zcash_keys::address` instead)
|
||||||
|
|
|
@ -68,7 +68,6 @@ use std::{
|
||||||
use incrementalmerkletree::{frontier::Frontier, Retention};
|
use incrementalmerkletree::{frontier::Frontier, Retention};
|
||||||
use shardtree::{error::ShardTreeError, store::ShardStore, ShardTree};
|
use shardtree::{error::ShardTreeError, store::ShardStore, ShardTree};
|
||||||
|
|
||||||
use ::transparent::bundle::OutPoint;
|
|
||||||
use zcash_keys::{
|
use zcash_keys::{
|
||||||
address::UnifiedAddress,
|
address::UnifiedAddress,
|
||||||
keys::{
|
keys::{
|
||||||
|
@ -99,7 +98,8 @@ use crate::{
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
use {
|
use {
|
||||||
crate::wallet::TransparentAddressMetadata, ::transparent::address::TransparentAddress,
|
crate::wallet::TransparentAddressMetadata,
|
||||||
|
::transparent::{address::TransparentAddress, bundle::OutPoint},
|
||||||
std::ops::Range,
|
std::ops::Range,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1966,7 +1966,7 @@ impl<'a, AccountId> SentTransaction<'a, AccountId> {
|
||||||
/// This type is capable of representing both shielded and transparent outputs.
|
/// This type is capable of representing both shielded and transparent outputs.
|
||||||
pub struct SentTransactionOutput<AccountId> {
|
pub struct SentTransactionOutput<AccountId> {
|
||||||
output_index: usize,
|
output_index: usize,
|
||||||
recipient: Recipient<AccountId, Note, OutPoint>,
|
recipient: Recipient<AccountId>,
|
||||||
value: Zatoshis,
|
value: Zatoshis,
|
||||||
memo: Option<MemoBytes>,
|
memo: Option<MemoBytes>,
|
||||||
}
|
}
|
||||||
|
@ -1983,7 +1983,7 @@ impl<AccountId> SentTransactionOutput<AccountId> {
|
||||||
/// * `memo` - the memo that was sent with this output
|
/// * `memo` - the memo that was sent with this output
|
||||||
pub fn from_parts(
|
pub fn from_parts(
|
||||||
output_index: usize,
|
output_index: usize,
|
||||||
recipient: Recipient<AccountId, Note, OutPoint>,
|
recipient: Recipient<AccountId>,
|
||||||
value: Zatoshis,
|
value: Zatoshis,
|
||||||
memo: Option<MemoBytes>,
|
memo: Option<MemoBytes>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -2006,7 +2006,7 @@ impl<AccountId> SentTransactionOutput<AccountId> {
|
||||||
}
|
}
|
||||||
/// Returns the recipient address of the transaction, or the account id and
|
/// Returns the recipient address of the transaction, or the account id and
|
||||||
/// resulting note/outpoint for wallet-internal outputs.
|
/// resulting note/outpoint for wallet-internal outputs.
|
||||||
pub fn recipient(&self) -> &Recipient<AccountId, Note, OutPoint> {
|
pub fn recipient(&self) -> &Recipient<AccountId> {
|
||||||
&self.recipient
|
&self.recipient
|
||||||
}
|
}
|
||||||
/// Returns the value of the newly created output.
|
/// Returns the value of the newly created output.
|
||||||
|
|
|
@ -35,18 +35,9 @@ to a wallet-internal shielded address, as described in [ZIP 316](https://zips.z.
|
||||||
|
|
||||||
use nonempty::NonEmpty;
|
use nonempty::NonEmpty;
|
||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
use sapling::{
|
|
||||||
note_encryption::{try_sapling_note_decryption, PreparedIncomingViewingKey},
|
|
||||||
prover::{OutputProver, SpendProver},
|
|
||||||
};
|
|
||||||
use shardtree::error::{QueryError, ShardTreeError};
|
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
use zcash_keys::{
|
|
||||||
address::Address,
|
use shardtree::error::{QueryError, ShardTreeError};
|
||||||
keys::{UnifiedFullViewingKey, UnifiedSpendingKey},
|
|
||||||
};
|
|
||||||
use zcash_protocol::{PoolType, ShieldedProtocol};
|
|
||||||
use zip321::Payment;
|
|
||||||
|
|
||||||
use super::InputSource;
|
use super::InputSource;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -61,10 +52,18 @@ use crate::{
|
||||||
proposal::{Proposal, ProposalError, Step, StepOutputIndex},
|
proposal::{Proposal, ProposalError, Step, StepOutputIndex},
|
||||||
wallet::{Note, OvkPolicy, Recipient},
|
wallet::{Note, OvkPolicy, Recipient},
|
||||||
};
|
};
|
||||||
|
use ::sapling::{
|
||||||
|
note_encryption::{try_sapling_note_decryption, PreparedIncomingViewingKey},
|
||||||
|
prover::{OutputProver, SpendProver},
|
||||||
|
};
|
||||||
use ::transparent::{
|
use ::transparent::{
|
||||||
address::TransparentAddress, builder::TransparentSigningSet, bundle::OutPoint,
|
address::TransparentAddress, builder::TransparentSigningSet, bundle::OutPoint,
|
||||||
};
|
};
|
||||||
|
use zcash_address::ZcashAddress;
|
||||||
|
use zcash_keys::{
|
||||||
|
address::Address,
|
||||||
|
keys::{UnifiedFullViewingKey, UnifiedSpendingKey},
|
||||||
|
};
|
||||||
use zcash_primitives::transaction::{
|
use zcash_primitives::transaction::{
|
||||||
builder::{BuildConfig, BuildResult, Builder},
|
builder::{BuildConfig, BuildResult, Builder},
|
||||||
components::sapling::zip212_enforcement,
|
components::sapling::zip212_enforcement,
|
||||||
|
@ -75,8 +74,10 @@ use zcash_protocol::{
|
||||||
consensus::{self, BlockHeight, NetworkUpgrade},
|
consensus::{self, BlockHeight, NetworkUpgrade},
|
||||||
memo::MemoBytes,
|
memo::MemoBytes,
|
||||||
value::Zatoshis,
|
value::Zatoshis,
|
||||||
|
PoolType, ShieldedProtocol,
|
||||||
};
|
};
|
||||||
use zip32::Scope;
|
use zip32::Scope;
|
||||||
|
use zip321::Payment;
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
use {
|
use {
|
||||||
|
@ -100,7 +101,6 @@ use {
|
||||||
},
|
},
|
||||||
sapling::note_encryption::SaplingDomain,
|
sapling::note_encryption::SaplingDomain,
|
||||||
serde::{Deserialize, Serialize},
|
serde::{Deserialize, Serialize},
|
||||||
zcash_address::ZcashAddress,
|
|
||||||
zcash_note_encryption::try_output_recovery_with_pkd_esk,
|
zcash_note_encryption::try_output_recovery_with_pkd_esk,
|
||||||
zcash_protocol::{
|
zcash_protocol::{
|
||||||
consensus::NetworkConstants,
|
consensus::NetworkConstants,
|
||||||
|
@ -133,25 +133,32 @@ struct ProposalInfo<AccountId> {
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
enum PcztRecipient<AccountId> {
|
enum PcztRecipient<AccountId> {
|
||||||
External,
|
External,
|
||||||
EphemeralTransparent { receiving_account: AccountId },
|
#[cfg(feature = "transparent-inputs")]
|
||||||
InternalAccount { receiving_account: AccountId },
|
EphemeralTransparent {
|
||||||
|
receiving_account: AccountId,
|
||||||
|
},
|
||||||
|
InternalAccount {
|
||||||
|
receiving_account: AccountId,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "pczt")]
|
#[cfg(feature = "pczt")]
|
||||||
impl<AccountId: Copy> PcztRecipient<AccountId> {
|
impl<AccountId: Copy> PcztRecipient<AccountId> {
|
||||||
fn from_recipient<N, O>(recipient: Recipient<AccountId, N, O>) -> (Self, Option<ZcashAddress>) {
|
fn from_recipient(recipient: BuildRecipient<AccountId>) -> (Self, Option<ZcashAddress>) {
|
||||||
match recipient {
|
match recipient {
|
||||||
Recipient::External(addr, _) => (PcztRecipient::External, Some(addr)),
|
BuildRecipient::External {
|
||||||
Recipient::EphemeralTransparent {
|
recipient_address, ..
|
||||||
|
} => (PcztRecipient::External, Some(recipient_address)),
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
BuildRecipient::EphemeralTransparent {
|
||||||
receiving_account, ..
|
receiving_account, ..
|
||||||
} => (
|
} => (
|
||||||
PcztRecipient::EphemeralTransparent { receiving_account },
|
PcztRecipient::EphemeralTransparent { receiving_account },
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
Recipient::InternalAccount {
|
BuildRecipient::InternalAccount {
|
||||||
receiving_account,
|
receiving_account,
|
||||||
external_address,
|
external_address,
|
||||||
..
|
|
||||||
} => (
|
} => (
|
||||||
PcztRecipient::InternalAccount { receiving_account },
|
PcztRecipient::InternalAccount { receiving_account },
|
||||||
external_address,
|
external_address,
|
||||||
|
@ -536,6 +543,72 @@ where
|
||||||
Ok(NonEmpty::from_vec(txids).expect("proposal.steps is NonEmpty"))
|
Ok(NonEmpty::from_vec(txids).expect("proposal.steps is NonEmpty"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum BuildRecipient<AccountId> {
|
||||||
|
External {
|
||||||
|
recipient_address: ZcashAddress,
|
||||||
|
output_pool: PoolType,
|
||||||
|
},
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
EphemeralTransparent {
|
||||||
|
receiving_account: AccountId,
|
||||||
|
ephemeral_address: TransparentAddress,
|
||||||
|
},
|
||||||
|
InternalAccount {
|
||||||
|
receiving_account: AccountId,
|
||||||
|
external_address: Option<ZcashAddress>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<AccountId> BuildRecipient<AccountId> {
|
||||||
|
fn into_recipient_with_note(self, note: impl FnOnce() -> Note) -> Recipient<AccountId> {
|
||||||
|
match self {
|
||||||
|
BuildRecipient::External {
|
||||||
|
recipient_address,
|
||||||
|
output_pool,
|
||||||
|
} => Recipient::External {
|
||||||
|
recipient_address,
|
||||||
|
output_pool,
|
||||||
|
},
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
BuildRecipient::EphemeralTransparent { .. } => unreachable!(),
|
||||||
|
BuildRecipient::InternalAccount {
|
||||||
|
receiving_account,
|
||||||
|
external_address,
|
||||||
|
} => Recipient::InternalAccount {
|
||||||
|
receiving_account,
|
||||||
|
external_address,
|
||||||
|
note: Box::new(note()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_recipient_with_outpoint(
|
||||||
|
self,
|
||||||
|
#[cfg(feature = "transparent-inputs")] outpoint: OutPoint,
|
||||||
|
) -> Recipient<AccountId> {
|
||||||
|
match self {
|
||||||
|
BuildRecipient::External {
|
||||||
|
recipient_address,
|
||||||
|
output_pool,
|
||||||
|
} => Recipient::External {
|
||||||
|
recipient_address,
|
||||||
|
output_pool,
|
||||||
|
},
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
BuildRecipient::EphemeralTransparent {
|
||||||
|
receiving_account,
|
||||||
|
ephemeral_address,
|
||||||
|
} => Recipient::EphemeralTransparent {
|
||||||
|
receiving_account,
|
||||||
|
ephemeral_address,
|
||||||
|
outpoint,
|
||||||
|
},
|
||||||
|
BuildRecipient::InternalAccount { .. } => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
struct BuildState<'a, P, AccountId> {
|
struct BuildState<'a, P, AccountId> {
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
@ -544,18 +617,10 @@ struct BuildState<'a, P, AccountId> {
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
transparent_input_addresses: HashMap<TransparentAddress, TransparentAddressMetadata>,
|
transparent_input_addresses: HashMap<TransparentAddress, TransparentAddressMetadata>,
|
||||||
#[cfg(feature = "orchard")]
|
#[cfg(feature = "orchard")]
|
||||||
orchard_output_meta: Vec<(
|
orchard_output_meta: Vec<(BuildRecipient<AccountId>, Zatoshis, Option<MemoBytes>)>,
|
||||||
Recipient<AccountId, PoolType, OutPoint>,
|
sapling_output_meta: Vec<(BuildRecipient<AccountId>, Zatoshis, Option<MemoBytes>)>,
|
||||||
Zatoshis,
|
|
||||||
Option<MemoBytes>,
|
|
||||||
)>,
|
|
||||||
sapling_output_meta: Vec<(
|
|
||||||
Recipient<AccountId, PoolType, OutPoint>,
|
|
||||||
Zatoshis,
|
|
||||||
Option<MemoBytes>,
|
|
||||||
)>,
|
|
||||||
transparent_output_meta: Vec<(
|
transparent_output_meta: Vec<(
|
||||||
Recipient<AccountId, Note, ()>,
|
BuildRecipient<AccountId>,
|
||||||
TransparentAddress,
|
TransparentAddress,
|
||||||
Zatoshis,
|
Zatoshis,
|
||||||
StepOutputIndex,
|
StepOutputIndex,
|
||||||
|
@ -884,12 +949,10 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "orchard")]
|
#[cfg(feature = "orchard")]
|
||||||
let mut orchard_output_meta: Vec<(Recipient<_, PoolType, _>, Zatoshis, Option<MemoBytes>)> =
|
let mut orchard_output_meta: Vec<(BuildRecipient<_>, Zatoshis, Option<MemoBytes>)> = vec![];
|
||||||
vec![];
|
let mut sapling_output_meta: Vec<(BuildRecipient<_>, Zatoshis, Option<MemoBytes>)> = vec![];
|
||||||
let mut sapling_output_meta: Vec<(Recipient<_, PoolType, _>, Zatoshis, Option<MemoBytes>)> =
|
|
||||||
vec![];
|
|
||||||
let mut transparent_output_meta: Vec<(
|
let mut transparent_output_meta: Vec<(
|
||||||
Recipient<_, _, ()>,
|
BuildRecipient<_>,
|
||||||
TransparentAddress,
|
TransparentAddress,
|
||||||
Zatoshis,
|
Zatoshis,
|
||||||
StepOutputIndex,
|
StepOutputIndex,
|
||||||
|
@ -915,7 +978,10 @@ where
|
||||||
let memo = payment.memo().map_or_else(MemoBytes::empty, |m| m.clone());
|
let memo = payment.memo().map_or_else(MemoBytes::empty, |m| m.clone());
|
||||||
builder.add_sapling_output(sapling_external_ovk, to, payment.amount(), memo.clone())?;
|
builder.add_sapling_output(sapling_external_ovk, to, payment.amount(), memo.clone())?;
|
||||||
sapling_output_meta.push((
|
sapling_output_meta.push((
|
||||||
Recipient::External(recipient_address.clone(), PoolType::SAPLING),
|
BuildRecipient::External {
|
||||||
|
recipient_address: recipient_address.clone(),
|
||||||
|
output_pool: PoolType::SAPLING,
|
||||||
|
},
|
||||||
payment.amount(),
|
payment.amount(),
|
||||||
Some(memo),
|
Some(memo),
|
||||||
));
|
));
|
||||||
|
@ -936,7 +1002,10 @@ where
|
||||||
memo.clone(),
|
memo.clone(),
|
||||||
)?;
|
)?;
|
||||||
orchard_output_meta.push((
|
orchard_output_meta.push((
|
||||||
Recipient::External(recipient_address.clone(), PoolType::ORCHARD),
|
BuildRecipient::External {
|
||||||
|
recipient_address: recipient_address.clone(),
|
||||||
|
output_pool: PoolType::ORCHARD,
|
||||||
|
},
|
||||||
payment.amount(),
|
payment.amount(),
|
||||||
Some(memo),
|
Some(memo),
|
||||||
));
|
));
|
||||||
|
@ -962,7 +1031,10 @@ where
|
||||||
}
|
}
|
||||||
builder.add_transparent_output(&to, payment.amount())?;
|
builder.add_transparent_output(&to, payment.amount())?;
|
||||||
transparent_output_meta.push((
|
transparent_output_meta.push((
|
||||||
Recipient::External(recipient_address.clone(), PoolType::TRANSPARENT),
|
BuildRecipient::External {
|
||||||
|
recipient_address: recipient_address.clone(),
|
||||||
|
output_pool: PoolType::TRANSPARENT,
|
||||||
|
},
|
||||||
to,
|
to,
|
||||||
payment.amount(),
|
payment.amount(),
|
||||||
StepOutputIndex::Payment(payment_index),
|
StepOutputIndex::Payment(payment_index),
|
||||||
|
@ -1031,10 +1103,9 @@ where
|
||||||
memo.clone(),
|
memo.clone(),
|
||||||
)?;
|
)?;
|
||||||
sapling_output_meta.push((
|
sapling_output_meta.push((
|
||||||
Recipient::InternalAccount {
|
BuildRecipient::InternalAccount {
|
||||||
receiving_account: account_id,
|
receiving_account: account_id,
|
||||||
external_address: None,
|
external_address: None,
|
||||||
note: output_pool,
|
|
||||||
},
|
},
|
||||||
change_value.value(),
|
change_value.value(),
|
||||||
Some(memo),
|
Some(memo),
|
||||||
|
@ -1055,10 +1126,9 @@ where
|
||||||
memo.clone(),
|
memo.clone(),
|
||||||
)?;
|
)?;
|
||||||
orchard_output_meta.push((
|
orchard_output_meta.push((
|
||||||
Recipient::InternalAccount {
|
BuildRecipient::InternalAccount {
|
||||||
receiving_account: account_id,
|
receiving_account: account_id,
|
||||||
external_address: None,
|
external_address: None,
|
||||||
note: output_pool,
|
|
||||||
},
|
},
|
||||||
change_value.value(),
|
change_value.value(),
|
||||||
Some(memo),
|
Some(memo),
|
||||||
|
@ -1100,10 +1170,9 @@ where
|
||||||
// if a later step does not consume it.
|
// if a later step does not consume it.
|
||||||
builder.add_transparent_output(&ephemeral_address, change_value.value())?;
|
builder.add_transparent_output(&ephemeral_address, change_value.value())?;
|
||||||
transparent_output_meta.push((
|
transparent_output_meta.push((
|
||||||
Recipient::EphemeralTransparent {
|
BuildRecipient::EphemeralTransparent {
|
||||||
receiving_account: account_id,
|
receiving_account: account_id,
|
||||||
ephemeral_address,
|
ephemeral_address,
|
||||||
outpoint_metadata: (),
|
|
||||||
},
|
},
|
||||||
ephemeral_address,
|
ephemeral_address,
|
||||||
change_value.value(),
|
change_value.value(),
|
||||||
|
@ -1208,20 +1277,17 @@ where
|
||||||
.output_action_index(i)
|
.output_action_index(i)
|
||||||
.expect("An action should exist in the transaction for each Orchard output.");
|
.expect("An action should exist in the transaction for each Orchard output.");
|
||||||
|
|
||||||
let recipient = recipient
|
let recipient = recipient.into_recipient_with_note(|| {
|
||||||
.map_internal_account_note(|pool| {
|
build_result
|
||||||
assert!(pool == PoolType::ORCHARD);
|
.transaction()
|
||||||
build_result
|
.orchard_bundle()
|
||||||
.transaction()
|
.and_then(|bundle| {
|
||||||
.orchard_bundle()
|
bundle
|
||||||
.and_then(|bundle| {
|
.decrypt_output_with_key(output_index, &orchard_internal_ivk)
|
||||||
bundle
|
.map(|(note, _, _)| Note::Orchard(note))
|
||||||
.decrypt_output_with_key(output_index, &orchard_internal_ivk)
|
})
|
||||||
.map(|(note, _, _)| Note::Orchard(note))
|
.expect("Wallet-internal outputs must be decryptable with the wallet's IVK")
|
||||||
})
|
});
|
||||||
})
|
|
||||||
.internal_account_note_transpose_option()
|
|
||||||
.expect("Wallet-internal outputs must be decryptable with the wallet's IVK");
|
|
||||||
|
|
||||||
SentTransactionOutput::from_parts(output_index, recipient, value, memo)
|
SentTransactionOutput::from_parts(output_index, recipient, value, memo)
|
||||||
},
|
},
|
||||||
|
@ -1237,23 +1303,20 @@ where
|
||||||
.output_index(i)
|
.output_index(i)
|
||||||
.expect("An output should exist in the transaction for each Sapling payment.");
|
.expect("An output should exist in the transaction for each Sapling payment.");
|
||||||
|
|
||||||
let recipient = recipient
|
let recipient = recipient.into_recipient_with_note(|| {
|
||||||
.map_internal_account_note(|pool| {
|
build_result
|
||||||
assert!(pool == PoolType::SAPLING);
|
.transaction()
|
||||||
build_result
|
.sapling_bundle()
|
||||||
.transaction()
|
.and_then(|bundle| {
|
||||||
.sapling_bundle()
|
try_sapling_note_decryption(
|
||||||
.and_then(|bundle| {
|
&sapling_internal_ivk,
|
||||||
try_sapling_note_decryption(
|
&bundle.shielded_outputs()[output_index],
|
||||||
&sapling_internal_ivk,
|
zip212_enforcement(params, min_target_height),
|
||||||
&bundle.shielded_outputs()[output_index],
|
)
|
||||||
zip212_enforcement(params, min_target_height),
|
.map(|(note, _, _)| Note::Sapling(note))
|
||||||
)
|
})
|
||||||
.map(|(note, _, _)| Note::Sapling(note))
|
.expect("Wallet-internal outputs must be decryptable with the wallet's IVK")
|
||||||
})
|
});
|
||||||
})
|
|
||||||
.internal_account_note_transpose_option()
|
|
||||||
.expect("Wallet-internal outputs must be decryptable with the wallet's IVK");
|
|
||||||
|
|
||||||
SentTransactionOutput::from_parts(output_index, recipient, value, memo)
|
SentTransactionOutput::from_parts(output_index, recipient, value, memo)
|
||||||
},
|
},
|
||||||
|
@ -1280,7 +1343,11 @@ where
|
||||||
// would not usefully improve privacy.
|
// would not usefully improve privacy.
|
||||||
let outpoint = OutPoint::new(txid, n as u32);
|
let outpoint = OutPoint::new(txid, n as u32);
|
||||||
|
|
||||||
let recipient = recipient.map_ephemeral_transparent_outpoint(|()| outpoint.clone());
|
let recipient = recipient.into_recipient_with_outpoint(
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
outpoint.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
unused_transparent_outputs.insert(
|
unused_transparent_outputs.insert(
|
||||||
StepOutput::new(build_state.step_index, step_output_index),
|
StepOutput::new(build_state.step_index, step_output_index),
|
||||||
|
@ -1819,12 +1886,14 @@ where
|
||||||
|
|
||||||
let note_value = Zatoshis::try_from(note_value(¬e))?;
|
let note_value = Zatoshis::try_from(note_value(¬e))?;
|
||||||
let recipient = match (pczt_recipient, external_address) {
|
let recipient = match (pczt_recipient, external_address) {
|
||||||
(PcztRecipient::External, Some(addr)) => {
|
(PcztRecipient::External, Some(addr)) => Ok(Recipient::External {
|
||||||
Ok(Recipient::External(addr, PoolType::Shielded(output_pool)))
|
recipient_address: addr,
|
||||||
}
|
output_pool: PoolType::Shielded(output_pool),
|
||||||
|
}),
|
||||||
(PcztRecipient::External, None) => Err(PcztError::Invalid(
|
(PcztRecipient::External, None) => Err(PcztError::Invalid(
|
||||||
"external recipient needs to have its user_address field set".into(),
|
"external recipient needs to have its user_address field set".into(),
|
||||||
)),
|
)),
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
(PcztRecipient::EphemeralTransparent { .. }, _) => Err(PcztError::Invalid(
|
(PcztRecipient::EphemeralTransparent { .. }, _) => Err(PcztError::Invalid(
|
||||||
"shielded output cannot be EphemeralTransparent".into(),
|
"shielded output cannot be EphemeralTransparent".into(),
|
||||||
)),
|
)),
|
||||||
|
@ -1832,7 +1901,7 @@ where
|
||||||
Ok(Recipient::InternalAccount {
|
Ok(Recipient::InternalAccount {
|
||||||
receiving_account,
|
receiving_account,
|
||||||
external_address,
|
external_address,
|
||||||
note: wallet_note(note),
|
note: Box::new(wallet_note(note)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}?;
|
}?;
|
||||||
|
@ -1927,11 +1996,15 @@ where
|
||||||
|
|
||||||
let recipient = match (pczt_recipient, external_address) {
|
let recipient = match (pczt_recipient, external_address) {
|
||||||
(PcztRecipient::External, Some(addr)) => {
|
(PcztRecipient::External, Some(addr)) => {
|
||||||
Ok(Recipient::External(addr, PoolType::Transparent))
|
Ok(Recipient::External {
|
||||||
|
recipient_address: addr,
|
||||||
|
output_pool: PoolType::Transparent,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
(PcztRecipient::External, None) => Err(PcztError::Invalid(
|
(PcztRecipient::External, None) => Err(PcztError::Invalid(
|
||||||
"external recipient needs to have its user_address field set".into(),
|
"external recipient needs to have its user_address field set".into(),
|
||||||
)),
|
)),
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
(PcztRecipient::EphemeralTransparent { receiving_account }, _) => output
|
(PcztRecipient::EphemeralTransparent { receiving_account }, _) => output
|
||||||
.recipient_address()
|
.recipient_address()
|
||||||
.ok_or(PcztError::Invalid(
|
.ok_or(PcztError::Invalid(
|
||||||
|
@ -1941,7 +2014,7 @@ where
|
||||||
.map(|ephemeral_address| Recipient::EphemeralTransparent {
|
.map(|ephemeral_address| Recipient::EphemeralTransparent {
|
||||||
receiving_account,
|
receiving_account,
|
||||||
ephemeral_address,
|
ephemeral_address,
|
||||||
outpoint_metadata: outpoint,
|
outpoint,
|
||||||
}),
|
}),
|
||||||
(
|
(
|
||||||
PcztRecipient::InternalAccount {
|
PcztRecipient::InternalAccount {
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
//! Structs representing transaction data scanned from the block chain by a wallet or
|
//! Structs representing transaction data scanned from the block chain by a wallet or
|
||||||
//! light client.
|
//! light client.
|
||||||
|
|
||||||
|
use incrementalmerkletree::Position;
|
||||||
|
|
||||||
use ::transparent::{
|
use ::transparent::{
|
||||||
address::TransparentAddress,
|
address::TransparentAddress,
|
||||||
bundle::{OutPoint, TxOut},
|
bundle::{OutPoint, TxOut},
|
||||||
};
|
};
|
||||||
use incrementalmerkletree::Position;
|
|
||||||
use zcash_address::ZcashAddress;
|
use zcash_address::ZcashAddress;
|
||||||
use zcash_note_encryption::EphemeralKeyBytes;
|
use zcash_note_encryption::EphemeralKeyBytes;
|
||||||
use zcash_primitives::transaction::{fees::transparent as transparent_fees, TxId};
|
use zcash_primitives::transaction::{fees::transparent as transparent_fees, TxId};
|
||||||
|
@ -60,111 +61,31 @@ impl NoteId {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type that represents the recipient of a transaction output:
|
/// A type that represents the recipient of a transaction output:
|
||||||
|
///
|
||||||
/// * a recipient address;
|
/// * a recipient address;
|
||||||
/// * for external unified addresses, the pool to which the payment is sent;
|
/// * for external unified addresses, the pool to which the payment is sent;
|
||||||
/// * for ephemeral transparent addresses, the internal account ID and metadata about the outpoint;
|
|
||||||
/// * for wallet-internal outputs, the internal account ID and metadata about the note.
|
/// * for wallet-internal outputs, the internal account ID and metadata about the note.
|
||||||
|
/// * if the `transparent-inputs` feature is enabled, for ephemeral transparent outputs, the
|
||||||
|
/// internal account ID and metadata about the outpoint;
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Recipient<AccountId, N, O> {
|
pub enum Recipient<AccountId> {
|
||||||
External(ZcashAddress, PoolType),
|
External {
|
||||||
|
recipient_address: ZcashAddress,
|
||||||
|
output_pool: PoolType,
|
||||||
|
},
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
EphemeralTransparent {
|
EphemeralTransparent {
|
||||||
receiving_account: AccountId,
|
receiving_account: AccountId,
|
||||||
ephemeral_address: TransparentAddress,
|
ephemeral_address: TransparentAddress,
|
||||||
outpoint_metadata: O,
|
outpoint: OutPoint,
|
||||||
},
|
},
|
||||||
InternalAccount {
|
InternalAccount {
|
||||||
receiving_account: AccountId,
|
receiving_account: AccountId,
|
||||||
external_address: Option<ZcashAddress>,
|
external_address: Option<ZcashAddress>,
|
||||||
note: N,
|
note: Box<Note>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<AccountId, N, O> Recipient<AccountId, N, O> {
|
|
||||||
/// Return a copy of this `Recipient` with `f` applied to the note metadata, if any.
|
|
||||||
pub fn map_internal_account_note<B, F: FnOnce(N) -> B>(
|
|
||||||
self,
|
|
||||||
f: F,
|
|
||||||
) -> Recipient<AccountId, B, O> {
|
|
||||||
match self {
|
|
||||||
Recipient::External(addr, pool) => Recipient::External(addr, pool),
|
|
||||||
Recipient::EphemeralTransparent {
|
|
||||||
receiving_account,
|
|
||||||
ephemeral_address,
|
|
||||||
outpoint_metadata,
|
|
||||||
} => Recipient::EphemeralTransparent {
|
|
||||||
receiving_account,
|
|
||||||
ephemeral_address,
|
|
||||||
outpoint_metadata,
|
|
||||||
},
|
|
||||||
Recipient::InternalAccount {
|
|
||||||
receiving_account,
|
|
||||||
external_address,
|
|
||||||
note,
|
|
||||||
} => Recipient::InternalAccount {
|
|
||||||
receiving_account,
|
|
||||||
external_address,
|
|
||||||
note: f(note),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a copy of this `Recipient` with `f` applied to the output metadata, if any.
|
|
||||||
pub fn map_ephemeral_transparent_outpoint<B, F: FnOnce(O) -> B>(
|
|
||||||
self,
|
|
||||||
f: F,
|
|
||||||
) -> Recipient<AccountId, N, B> {
|
|
||||||
match self {
|
|
||||||
Recipient::External(addr, pool) => Recipient::External(addr, pool),
|
|
||||||
Recipient::EphemeralTransparent {
|
|
||||||
receiving_account,
|
|
||||||
ephemeral_address,
|
|
||||||
outpoint_metadata,
|
|
||||||
} => Recipient::EphemeralTransparent {
|
|
||||||
receiving_account,
|
|
||||||
ephemeral_address,
|
|
||||||
outpoint_metadata: f(outpoint_metadata),
|
|
||||||
},
|
|
||||||
Recipient::InternalAccount {
|
|
||||||
receiving_account,
|
|
||||||
external_address,
|
|
||||||
note,
|
|
||||||
} => Recipient::InternalAccount {
|
|
||||||
receiving_account,
|
|
||||||
external_address,
|
|
||||||
note,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<AccountId, N, O> Recipient<AccountId, Option<N>, O> {
|
|
||||||
/// Return a copy of this `Recipient` with optional note metadata transposed to
|
|
||||||
/// an optional result.
|
|
||||||
pub fn internal_account_note_transpose_option(self) -> Option<Recipient<AccountId, N, O>> {
|
|
||||||
match self {
|
|
||||||
Recipient::External(addr, pool) => Some(Recipient::External(addr, pool)),
|
|
||||||
Recipient::EphemeralTransparent {
|
|
||||||
receiving_account,
|
|
||||||
ephemeral_address,
|
|
||||||
outpoint_metadata,
|
|
||||||
} => Some(Recipient::EphemeralTransparent {
|
|
||||||
receiving_account,
|
|
||||||
ephemeral_address,
|
|
||||||
outpoint_metadata,
|
|
||||||
}),
|
|
||||||
Recipient::InternalAccount {
|
|
||||||
receiving_account,
|
|
||||||
external_address,
|
|
||||||
note,
|
|
||||||
} => note.map(|n0| Recipient::InternalAccount {
|
|
||||||
receiving_account,
|
|
||||||
external_address,
|
|
||||||
note: n0,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The shielded subset of a [`Transaction`]'s data that is relevant to a particular wallet.
|
/// The shielded subset of a [`Transaction`]'s data that is relevant to a particular wallet.
|
||||||
///
|
///
|
||||||
/// [`Transaction`]: zcash_primitives::transaction::Transaction
|
/// [`Transaction`]: zcash_primitives::transaction::Transaction
|
||||||
|
|
|
@ -84,7 +84,6 @@ use std::ops::RangeInclusive;
|
||||||
|
|
||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
use ::transparent::bundle::OutPoint;
|
|
||||||
use zcash_address::ZcashAddress;
|
use zcash_address::ZcashAddress;
|
||||||
use zcash_client_backend::{
|
use zcash_client_backend::{
|
||||||
data_api::{
|
data_api::{
|
||||||
|
@ -114,8 +113,9 @@ use zcash_protocol::{
|
||||||
value::{ZatBalance, Zatoshis},
|
value::{ZatBalance, Zatoshis},
|
||||||
PoolType, ShieldedProtocol,
|
PoolType, ShieldedProtocol,
|
||||||
};
|
};
|
||||||
use zip32::{self, DiversifierIndex, Scope};
|
use zip32::{DiversifierIndex, Scope};
|
||||||
|
|
||||||
|
use self::scanning::{parse_priority_code, priority_code, replace_queue_entries};
|
||||||
use crate::{
|
use crate::{
|
||||||
error::SqliteClientError,
|
error::SqliteClientError,
|
||||||
wallet::commitment_tree::{get_max_checkpointed_height, SqliteShardStore},
|
wallet::commitment_tree::{get_max_checkpointed_height, SqliteShardStore},
|
||||||
|
@ -125,9 +125,7 @@ use crate::{
|
||||||
use crate::{AccountUuid, TxRef, VERIFY_LOOKAHEAD};
|
use crate::{AccountUuid, TxRef, VERIFY_LOOKAHEAD};
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
use ::transparent::bundle::TxOut;
|
use ::transparent::bundle::{OutPoint, TxOut};
|
||||||
|
|
||||||
use self::scanning::{parse_priority_code, priority_code, replace_queue_entries};
|
|
||||||
|
|
||||||
#[cfg(feature = "orchard")]
|
#[cfg(feature = "orchard")]
|
||||||
use {crate::ORCHARD_TABLES_PREFIX, zcash_client_backend::data_api::ORCHARD_SHARD_HEIGHT};
|
use {crate::ORCHARD_TABLES_PREFIX, zcash_client_backend::data_api::ORCHARD_SHARD_HEIGHT};
|
||||||
|
@ -2269,55 +2267,53 @@ pub(crate) fn store_transaction_to_be_sent<P: consensus::Parameters>(
|
||||||
match output.recipient() {
|
match output.recipient() {
|
||||||
Recipient::InternalAccount {
|
Recipient::InternalAccount {
|
||||||
receiving_account,
|
receiving_account,
|
||||||
note: Note::Sapling(note),
|
note,
|
||||||
..
|
..
|
||||||
} => {
|
} => match note.as_ref() {
|
||||||
sapling::put_received_note(
|
Note::Sapling(note) => {
|
||||||
wdb.conn.0,
|
sapling::put_received_note(
|
||||||
&DecryptedOutput::new(
|
wdb.conn.0,
|
||||||
output.output_index(),
|
&DecryptedOutput::new(
|
||||||
note.clone(),
|
output.output_index(),
|
||||||
*receiving_account,
|
note.clone(),
|
||||||
output
|
*receiving_account,
|
||||||
.memo()
|
output
|
||||||
.map_or_else(MemoBytes::empty, |memo| memo.clone()),
|
.memo()
|
||||||
TransferType::WalletInternal,
|
.map_or_else(MemoBytes::empty, |memo| memo.clone()),
|
||||||
),
|
TransferType::WalletInternal,
|
||||||
tx_ref,
|
),
|
||||||
None,
|
tx_ref,
|
||||||
)?;
|
None,
|
||||||
}
|
)?;
|
||||||
#[cfg(feature = "orchard")]
|
}
|
||||||
Recipient::InternalAccount {
|
#[cfg(feature = "orchard")]
|
||||||
receiving_account,
|
Note::Orchard(note) => {
|
||||||
note: Note::Orchard(note),
|
orchard::put_received_note(
|
||||||
..
|
wdb.conn.0,
|
||||||
} => {
|
&DecryptedOutput::new(
|
||||||
orchard::put_received_note(
|
output.output_index(),
|
||||||
wdb.conn.0,
|
*note,
|
||||||
&DecryptedOutput::new(
|
*receiving_account,
|
||||||
output.output_index(),
|
output
|
||||||
*note,
|
.memo()
|
||||||
*receiving_account,
|
.map_or_else(MemoBytes::empty, |memo| memo.clone()),
|
||||||
output
|
TransferType::WalletInternal,
|
||||||
.memo()
|
),
|
||||||
.map_or_else(MemoBytes::empty, |memo| memo.clone()),
|
tx_ref,
|
||||||
TransferType::WalletInternal,
|
None,
|
||||||
),
|
)?;
|
||||||
tx_ref,
|
}
|
||||||
None,
|
},
|
||||||
)?;
|
|
||||||
}
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
Recipient::EphemeralTransparent {
|
Recipient::EphemeralTransparent {
|
||||||
receiving_account,
|
receiving_account,
|
||||||
ephemeral_address,
|
ephemeral_address,
|
||||||
outpoint_metadata,
|
outpoint,
|
||||||
} => {
|
} => {
|
||||||
transparent::put_transparent_output(
|
transparent::put_transparent_output(
|
||||||
wdb.conn.0,
|
wdb.conn.0,
|
||||||
&wdb.params,
|
&wdb.params,
|
||||||
outpoint_metadata,
|
outpoint,
|
||||||
&TxOut {
|
&TxOut {
|
||||||
value: output.value(),
|
value: output.value(),
|
||||||
script_pubkey: ephemeral_address.script(),
|
script_pubkey: ephemeral_address.script(),
|
||||||
|
@ -2733,11 +2729,14 @@ pub(crate) fn store_decrypted_tx<P: consensus::Parameters>(
|
||||||
TransferType::Outgoing => {
|
TransferType::Outgoing => {
|
||||||
let recipient = {
|
let recipient = {
|
||||||
let receiver = Receiver::Sapling(output.note().recipient());
|
let receiver = Receiver::Sapling(output.note().recipient());
|
||||||
let wallet_address =
|
let recipient_address =
|
||||||
select_receiving_address(params, conn, *output.account(), &receiver)?
|
select_receiving_address(params, conn, *output.account(), &receiver)?
|
||||||
.unwrap_or_else(|| receiver.to_zcash_address(params.network_type()));
|
.unwrap_or_else(|| receiver.to_zcash_address(params.network_type()));
|
||||||
|
|
||||||
Recipient::External(wallet_address, PoolType::SAPLING)
|
Recipient::External {
|
||||||
|
recipient_address,
|
||||||
|
output_pool: PoolType::SAPLING,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
put_sent_output(
|
put_sent_output(
|
||||||
|
@ -2757,7 +2756,7 @@ pub(crate) fn store_decrypted_tx<P: consensus::Parameters>(
|
||||||
let recipient = Recipient::InternalAccount {
|
let recipient = Recipient::InternalAccount {
|
||||||
receiving_account: *output.account(),
|
receiving_account: *output.account(),
|
||||||
external_address: None,
|
external_address: None,
|
||||||
note: Note::Sapling(output.note().clone()),
|
note: Box::new(Note::Sapling(output.note().clone())),
|
||||||
};
|
};
|
||||||
|
|
||||||
put_sent_output(
|
put_sent_output(
|
||||||
|
@ -2791,7 +2790,7 @@ pub(crate) fn store_decrypted_tx<P: consensus::Parameters>(
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
note: Note::Sapling(output.note().clone()),
|
note: Box::new(Note::Sapling(output.note().clone())),
|
||||||
};
|
};
|
||||||
|
|
||||||
put_sent_output(
|
put_sent_output(
|
||||||
|
@ -2819,11 +2818,14 @@ pub(crate) fn store_decrypted_tx<P: consensus::Parameters>(
|
||||||
TransferType::Outgoing => {
|
TransferType::Outgoing => {
|
||||||
let recipient = {
|
let recipient = {
|
||||||
let receiver = Receiver::Orchard(output.note().recipient());
|
let receiver = Receiver::Orchard(output.note().recipient());
|
||||||
let wallet_address =
|
let recipient_address =
|
||||||
select_receiving_address(params, conn, *output.account(), &receiver)?
|
select_receiving_address(params, conn, *output.account(), &receiver)?
|
||||||
.unwrap_or_else(|| receiver.to_zcash_address(params.network_type()));
|
.unwrap_or_else(|| receiver.to_zcash_address(params.network_type()));
|
||||||
|
|
||||||
Recipient::External(wallet_address, PoolType::ORCHARD)
|
Recipient::External {
|
||||||
|
recipient_address,
|
||||||
|
output_pool: PoolType::ORCHARD,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
put_sent_output(
|
put_sent_output(
|
||||||
|
@ -2843,7 +2845,7 @@ pub(crate) fn store_decrypted_tx<P: consensus::Parameters>(
|
||||||
let recipient = Recipient::InternalAccount {
|
let recipient = Recipient::InternalAccount {
|
||||||
receiving_account: *output.account(),
|
receiving_account: *output.account(),
|
||||||
external_address: None,
|
external_address: None,
|
||||||
note: Note::Orchard(*output.note()),
|
note: Box::new(Note::Orchard(*output.note())),
|
||||||
};
|
};
|
||||||
|
|
||||||
put_sent_output(
|
put_sent_output(
|
||||||
|
@ -2878,7 +2880,7 @@ pub(crate) fn store_decrypted_tx<P: consensus::Parameters>(
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
note: Note::Orchard(*output.note()),
|
note: Box::new(Note::Orchard(*output.note())),
|
||||||
};
|
};
|
||||||
|
|
||||||
put_sent_output(
|
put_sent_output(
|
||||||
|
@ -2989,14 +2991,17 @@ pub(crate) fn store_decrypted_tx<P: consensus::Parameters>(
|
||||||
let receiver = Receiver::Transparent(address);
|
let receiver = Receiver::Transparent(address);
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
let recipient_addr =
|
let recipient_address =
|
||||||
select_receiving_address(params, conn, account_uuid, &receiver)?
|
select_receiving_address(params, conn, account_uuid, &receiver)?
|
||||||
.unwrap_or_else(|| receiver.to_zcash_address(params.network_type()));
|
.unwrap_or_else(|| receiver.to_zcash_address(params.network_type()));
|
||||||
|
|
||||||
#[cfg(not(feature = "transparent-inputs"))]
|
#[cfg(not(feature = "transparent-inputs"))]
|
||||||
let recipient_addr = receiver.to_zcash_address(params.network_type());
|
let recipient_address = receiver.to_zcash_address(params.network_type());
|
||||||
|
|
||||||
let recipient = Recipient::External(recipient_addr, PoolType::TRANSPARENT);
|
let recipient = Recipient::External {
|
||||||
|
recipient_address,
|
||||||
|
output_pool: PoolType::TRANSPARENT,
|
||||||
|
};
|
||||||
|
|
||||||
put_sent_output(
|
put_sent_output(
|
||||||
conn,
|
conn,
|
||||||
|
@ -3295,13 +3300,23 @@ pub(crate) fn notify_tx_retrieved(
|
||||||
// and `put_sent_output`
|
// and `put_sent_output`
|
||||||
fn recipient_params<P: consensus::Parameters>(
|
fn recipient_params<P: consensus::Parameters>(
|
||||||
conn: &Connection,
|
conn: &Connection,
|
||||||
params: &P,
|
_params: &P,
|
||||||
from: AccountUuid,
|
from: AccountUuid,
|
||||||
to: &Recipient<AccountUuid, Note, OutPoint>,
|
to: &Recipient<AccountUuid>,
|
||||||
) -> Result<(AccountRef, Option<String>, Option<AccountRef>, PoolType), SqliteClientError> {
|
) -> Result<(AccountRef, Option<String>, Option<AccountRef>, PoolType), SqliteClientError> {
|
||||||
let from_account_id = get_account_ref(conn, from)?;
|
let from_account_id = get_account_ref(conn, from)?;
|
||||||
match to {
|
match to {
|
||||||
Recipient::External(addr, pool) => Ok((from_account_id, Some(addr.encode()), None, *pool)),
|
Recipient::External {
|
||||||
|
recipient_address,
|
||||||
|
output_pool,
|
||||||
|
..
|
||||||
|
} => Ok((
|
||||||
|
from_account_id,
|
||||||
|
Some(recipient_address.encode()),
|
||||||
|
None,
|
||||||
|
*output_pool,
|
||||||
|
)),
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
Recipient::EphemeralTransparent {
|
Recipient::EphemeralTransparent {
|
||||||
receiving_account,
|
receiving_account,
|
||||||
ephemeral_address,
|
ephemeral_address,
|
||||||
|
@ -3310,7 +3325,7 @@ fn recipient_params<P: consensus::Parameters>(
|
||||||
let to_account = get_account_ref(conn, *receiving_account)?;
|
let to_account = get_account_ref(conn, *receiving_account)?;
|
||||||
Ok((
|
Ok((
|
||||||
from_account_id,
|
from_account_id,
|
||||||
Some(ephemeral_address.encode(params)),
|
Some(ephemeral_address.encode(_params)),
|
||||||
Some(to_account),
|
Some(to_account),
|
||||||
PoolType::TRANSPARENT,
|
PoolType::TRANSPARENT,
|
||||||
))
|
))
|
||||||
|
@ -3414,7 +3429,7 @@ pub(crate) fn put_sent_output<P: consensus::Parameters>(
|
||||||
from_account_uuid: AccountUuid,
|
from_account_uuid: AccountUuid,
|
||||||
tx_ref: TxRef,
|
tx_ref: TxRef,
|
||||||
output_index: usize,
|
output_index: usize,
|
||||||
recipient: &Recipient<AccountUuid, Note, OutPoint>,
|
recipient: &Recipient<AccountUuid>,
|
||||||
value: Zatoshis,
|
value: Zatoshis,
|
||||||
memo: Option<&MemoBytes>,
|
memo: Option<&MemoBytes>,
|
||||||
) -> Result<(), SqliteClientError> {
|
) -> Result<(), SqliteClientError> {
|
||||||
|
|
Loading…
Reference in New Issue