From bc7994b51521d96cc50d71b9158f371c3ea72aa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=97=E5=AE=87?= Date: Thu, 30 Jun 2022 18:44:40 +0800 Subject: [PATCH 01/16] Change `TxParams` for multi-descriptor context Store policy paths in a map with ExtendedDescriptor as key. This way we can re-use the TxParams struct in multi-descriptor/multi-wallet contexts. --- src/testutils/blockchain_tests.rs | 4 ++-- src/wallet/mod.rs | 33 ++++++++++++++----------------- src/wallet/tx_builder.rs | 25 ++++++++++++----------- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/testutils/blockchain_tests.rs b/src/testutils/blockchain_tests.rs index 7c08699c6..3084a7e06 100644 --- a/src/testutils/blockchain_tests.rs +++ b/src/testutils/blockchain_tests.rs @@ -1328,8 +1328,8 @@ macro_rules! bdk_blockchain_tests { let tx = { let mut builder = wallet.build_tx(); builder.add_recipient(test_client.get_node_address(None).script_pubkey(), 25_000) - .policy_path(ext_path, KeychainKind::External) - .policy_path(int_path, KeychainKind::Internal); + .policy_path(ext_path, wallet.get_descriptor_for_keychain(KeychainKind::External)) + .policy_path(int_path, wallet.get_descriptor_for_keychain(KeychainKind::Internal)); let (mut psbt, _details) = builder.finish().unwrap(); wallet.sign(&mut psbt, Default::default()).unwrap(); psbt.extract_tx() diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 9231c3b74..bbd2809e6 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -572,39 +572,36 @@ where }) .transpose()?; + let external_policy_path = params.descriptor_policy_paths.get(&self.descriptor); + let internal_policy_path = self + .change_descriptor + .as_ref() + .and_then(|desc| params.descriptor_policy_paths.get(desc)); + // The policy allows spending external outputs, but it requires a policy path that hasn't been // provided if params.change_policy != tx_builder::ChangeSpendPolicy::OnlyChange && external_policy.requires_path() - && params.external_policy_path.is_none() + && external_policy_path.is_none() { - return Err(Error::SpendingPolicyRequired(KeychainKind::External)); + return Err(Error::SpendingPolicyRequired(KeychainKind::External)); // TODO: Error should be of descriptor }; // Same for the internal_policy path, if present if let Some(internal_policy) = &internal_policy { if params.change_policy != tx_builder::ChangeSpendPolicy::ChangeForbidden && internal_policy.requires_path() - && params.internal_policy_path.is_none() + && internal_policy_path.is_none() { return Err(Error::SpendingPolicyRequired(KeychainKind::Internal)); }; } - let external_requirements = external_policy.get_condition( - params - .external_policy_path - .as_ref() - .unwrap_or(&BTreeMap::new()), - )?; + let external_requirements = + external_policy.get_condition(external_policy_path.unwrap_or(&BTreeMap::new()))?; let internal_requirements = internal_policy .map(|policy| { Ok::<_, Error>( - policy.get_condition( - params - .internal_policy_path - .as_ref() - .unwrap_or(&BTreeMap::new()), - )?, + policy.get_condition(internal_policy_path.unwrap_or(&BTreeMap::new()))?, ) }) .transpose()?; @@ -2738,7 +2735,7 @@ pub(crate) mod test { let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 30_000) - .policy_path(path, KeychainKind::External); + .policy_path(path, &wallet.descriptor); let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, 0xFFFFFFFF); @@ -2757,7 +2754,7 @@ pub(crate) mod test { let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 30_000) - .policy_path(path, KeychainKind::External); + .policy_path(path, &wallet.descriptor); let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, 144); @@ -4546,7 +4543,7 @@ pub(crate) mod test { let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) - .policy_path(path, KeychainKind::External); + .policy_path(path, &wallet.descriptor); let (psbt, _) = builder.finish().unwrap(); assert_eq!( diff --git a/src/wallet/tx_builder.rs b/src/wallet/tx_builder.rs index 0fee8aa9e..43045463b 100644 --- a/src/wallet/tx_builder.rs +++ b/src/wallet/tx_builder.rs @@ -47,6 +47,7 @@ use bitcoin::{OutPoint, Script, Transaction}; use miniscript::descriptor::DescriptorTrait; use super::coin_selection::{CoinSelectionAlgorithm, DefaultCoinSelectionAlgorithm}; +use crate::descriptor::ExtendedDescriptor; use crate::{database::BatchDatabase, Error, Utxo, Wallet}; use crate::{ types::{FeeRate, KeychainKind, LocalUtxo, WeightedUtxo}, @@ -119,7 +120,7 @@ impl TxBuilderContext for BumpFee {} #[derive(Debug)] pub struct TxBuilder<'a, D, Cs, Ctx> { pub(crate) wallet: &'a Wallet, - pub(crate) params: TxParams, + pub(crate) params: TxParams<'a>, pub(crate) coin_selection: Cs, pub(crate) phantom: PhantomData, } @@ -127,13 +128,13 @@ pub struct TxBuilder<'a, D, Cs, Ctx> { /// The parameters for transaction creation sans coin selection algorithm. //TODO: TxParams should eventually be exposed publicly. #[derive(Default, Debug, Clone)] -pub(crate) struct TxParams { +pub(crate) struct TxParams<'a> { pub(crate) recipients: Vec<(Script, u64)>, pub(crate) drain_wallet: bool, pub(crate) drain_to: Option