miniscript/
plan.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! A spending plan or *plan* for short is a representation of a particular spending path on a
4//! descriptor. This allows us to analayze a choice of spending path without producing any
5//! signatures or other witness data for it.
6//!
7//! To make a plan you provide the descriptor with "assets" like which keys you are able to use, hash
8//! pre-images you have access to, absolute/relative timelock constraints etc.
9//!
10//! Once you've got a plan it can tell you its expected satisfaction weight which can be useful for
11//! doing coin selection. Furthermore it provides which subset of those keys and hash pre-images you
12//! will actually need as well as what locktime or sequence number you need to set.
13//!
14//! Once you've obtained signatures, hash pre-images etc required by the plan, it can create a
15//! witness/script_sig for the input.
16
17use core::iter::FromIterator;
18
19use bitcoin::hashes::{hash160, ripemd160, sha256};
20use bitcoin::key::XOnlyPublicKey;
21use bitcoin::script::PushBytesBuf;
22use bitcoin::taproot::{ControlBlock, LeafVersion, TapLeafHash};
23use bitcoin::{absolute, bip32, psbt, relative, ScriptBuf, WitnessVersion};
24
25use crate::descriptor::{self, Descriptor, DescriptorType, KeyMap};
26use crate::miniscript::hash256;
27use crate::miniscript::satisfy::{Placeholder, Satisfier, SchnorrSigType};
28use crate::prelude::*;
29use crate::util::witness_size;
30use crate::{DefiniteDescriptorKey, DescriptorPublicKey, Error, MiniscriptKey, ToPublicKey};
31
32/// Trait describing a present/missing lookup table for constructing witness templates
33///
34/// This trait mirrors the [`Satisfier`] trait, with the difference that most methods just return a
35/// boolean indicating the item presence. The methods looking up keys return the key
36/// length, the methods looking up public key hashes return the public key, and a few other methods
37/// need to return the item itself.
38///
39/// This trait is automatically implemented for every type that is also a satisfier, and simply
40/// proxies the queries to the satisfier and returns whether an item is available or not.
41///
42/// All the methods have a default implementation that returns `false` or `None`.
43pub trait AssetProvider<Pk: MiniscriptKey> {
44    /// Given a public key, look up an ECDSA signature with that key, return whether we found it
45    fn provider_lookup_ecdsa_sig(&self, _: &Pk) -> bool { false }
46
47    /// Lookup the tap key spend sig and return its size
48    fn provider_lookup_tap_key_spend_sig(&self, _: &Pk) -> Option<usize> { None }
49
50    /// Given a public key and a associated leaf hash, look up a schnorr signature with that key
51    /// and return its size
52    fn provider_lookup_tap_leaf_script_sig(&self, _: &Pk, _: &TapLeafHash) -> Option<usize> { None }
53
54    /// Obtain a reference to the control block for a ver and script
55    fn provider_lookup_tap_control_block_map(
56        &self,
57    ) -> Option<&BTreeMap<ControlBlock, (bitcoin::ScriptBuf, LeafVersion)>> {
58        None
59    }
60
61    /// Given a raw `Pkh`, lookup corresponding [`bitcoin::PublicKey`]
62    fn provider_lookup_raw_pkh_pk(&self, _: &hash160::Hash) -> Option<bitcoin::PublicKey> { None }
63
64    /// Given a raw `Pkh`, lookup corresponding [`bitcoin::secp256k1::XOnlyPublicKey`]
65    fn provider_lookup_raw_pkh_x_only_pk(&self, _: &hash160::Hash) -> Option<XOnlyPublicKey> {
66        None
67    }
68
69    /// Given a keyhash, look up the EC signature and the associated key.
70    /// Returns the key if a signature is found.
71    /// Even if signatures for public key Hashes are not available, the users
72    /// can use this map to provide pkh -> pk mapping which can be useful
73    /// for dissatisfying pkh.
74    fn provider_lookup_raw_pkh_ecdsa_sig(&self, _: &hash160::Hash) -> Option<bitcoin::PublicKey> {
75        None
76    }
77
78    /// Given a keyhash, look up the schnorr signature and the associated key.
79    /// Returns the key and sig len if a signature is found.
80    /// Even if signatures for public key Hashes are not available, the users
81    /// can use this map to provide pkh -> pk mapping which can be useful
82    /// for dissatisfying pkh.
83    fn provider_lookup_raw_pkh_tap_leaf_script_sig(
84        &self,
85        _: &(hash160::Hash, TapLeafHash),
86    ) -> Option<(XOnlyPublicKey, usize)> {
87        None
88    }
89
90    /// Given a SHA256 hash, look up its preimage, return whether we found it
91    fn provider_lookup_sha256(&self, _: &Pk::Sha256) -> bool { false }
92
93    /// Given a HASH256 hash, look up its preimage, return whether we found it
94    fn provider_lookup_hash256(&self, _: &Pk::Hash256) -> bool { false }
95
96    /// Given a RIPEMD160 hash, look up its preimage, return whether we found it
97    fn provider_lookup_ripemd160(&self, _: &Pk::Ripemd160) -> bool { false }
98
99    /// Given a HASH160 hash, look up its preimage, return whether we found it
100    fn provider_lookup_hash160(&self, _: &Pk::Hash160) -> bool { false }
101
102    /// Assert whether a relative locktime is satisfied
103    fn check_older(&self, _: relative::LockTime) -> bool { false }
104
105    /// Assert whether an absolute locktime is satisfied
106    fn check_after(&self, _: absolute::LockTime) -> bool { false }
107}
108
109/// Wrapper around [`Assets`] that logs every query and value returned
110#[cfg(feature = "std")]
111pub struct LoggerAssetProvider<'a>(pub &'a Assets);
112
113#[cfg(feature = "std")]
114macro_rules! impl_log_method {
115    ( $name:ident, $( <$ctx:ident: ScriptContext > )? $( $arg:ident : $ty:ty, )* -> $ret_ty:ty ) => {
116        fn $name $( <$ctx: ScriptContext> )? ( &self, $( $arg:$ty ),* ) -> $ret_ty {
117            let ret = (self.0).$name $( ::<$ctx> )*( $( $arg ),* );
118            dbg!(stringify!( $name ), ( $( $arg ),* ), &ret);
119
120            ret
121        }
122    }
123}
124
125#[cfg(feature = "std")]
126impl<'a> AssetProvider<DefiniteDescriptorKey> for LoggerAssetProvider<'a> {
127    impl_log_method!(provider_lookup_ecdsa_sig, pk: &DefiniteDescriptorKey, -> bool);
128    impl_log_method!(provider_lookup_tap_key_spend_sig, pk: &DefiniteDescriptorKey, -> Option<usize>);
129    impl_log_method!(provider_lookup_tap_leaf_script_sig, pk: &DefiniteDescriptorKey, leaf_hash: &TapLeafHash, -> Option<usize>);
130    impl_log_method!(provider_lookup_tap_control_block_map, -> Option<&BTreeMap<ControlBlock, (bitcoin::ScriptBuf, LeafVersion)>>);
131    impl_log_method!(provider_lookup_raw_pkh_pk, hash: &hash160::Hash, -> Option<bitcoin::PublicKey>);
132    impl_log_method!(provider_lookup_raw_pkh_x_only_pk, hash: &hash160::Hash, -> Option<XOnlyPublicKey>);
133    impl_log_method!(provider_lookup_raw_pkh_ecdsa_sig, hash: &hash160::Hash, -> Option<bitcoin::PublicKey>);
134    impl_log_method!(provider_lookup_raw_pkh_tap_leaf_script_sig, hash: &(hash160::Hash, TapLeafHash), -> Option<(XOnlyPublicKey, usize)>);
135    impl_log_method!(provider_lookup_sha256, hash: &sha256::Hash, -> bool);
136    impl_log_method!(provider_lookup_hash256, hash: &hash256::Hash, -> bool);
137    impl_log_method!(provider_lookup_ripemd160, hash: &ripemd160::Hash, -> bool);
138    impl_log_method!(provider_lookup_hash160, hash: &hash160::Hash, -> bool);
139    impl_log_method!(check_older, s: relative::LockTime, -> bool);
140    impl_log_method!(check_after, t: absolute::LockTime, -> bool);
141}
142
143impl<T, Pk> AssetProvider<Pk> for T
144where
145    T: Satisfier<Pk>,
146    Pk: MiniscriptKey + ToPublicKey,
147{
148    fn provider_lookup_ecdsa_sig(&self, pk: &Pk) -> bool {
149        Satisfier::lookup_ecdsa_sig(self, pk).is_some()
150    }
151
152    fn provider_lookup_tap_key_spend_sig(&self, _: &Pk) -> Option<usize> {
153        Satisfier::lookup_tap_key_spend_sig(self).map(|s| s.to_vec().len())
154    }
155
156    fn provider_lookup_tap_leaf_script_sig(
157        &self,
158        pk: &Pk,
159        leaf_hash: &TapLeafHash,
160    ) -> Option<usize> {
161        Satisfier::lookup_tap_leaf_script_sig(self, pk, leaf_hash).map(|s| s.to_vec().len())
162    }
163
164    fn provider_lookup_tap_control_block_map(
165        &self,
166    ) -> Option<&BTreeMap<ControlBlock, (bitcoin::ScriptBuf, LeafVersion)>> {
167        Satisfier::lookup_tap_control_block_map(self)
168    }
169
170    fn provider_lookup_raw_pkh_pk(&self, hash: &hash160::Hash) -> Option<bitcoin::PublicKey> {
171        Satisfier::lookup_raw_pkh_pk(self, hash)
172    }
173
174    fn provider_lookup_raw_pkh_x_only_pk(&self, hash: &hash160::Hash) -> Option<XOnlyPublicKey> {
175        Satisfier::lookup_raw_pkh_x_only_pk(self, hash)
176    }
177
178    fn provider_lookup_raw_pkh_ecdsa_sig(
179        &self,
180        hash: &hash160::Hash,
181    ) -> Option<bitcoin::PublicKey> {
182        Satisfier::lookup_raw_pkh_ecdsa_sig(self, hash).map(|(pk, _)| pk)
183    }
184
185    fn provider_lookup_raw_pkh_tap_leaf_script_sig(
186        &self,
187        hash: &(hash160::Hash, TapLeafHash),
188    ) -> Option<(XOnlyPublicKey, usize)> {
189        Satisfier::lookup_raw_pkh_tap_leaf_script_sig(self, hash)
190            .map(|(pk, sig)| (pk, sig.to_vec().len()))
191    }
192
193    fn provider_lookup_sha256(&self, hash: &Pk::Sha256) -> bool {
194        Satisfier::lookup_sha256(self, hash).is_some()
195    }
196
197    fn provider_lookup_hash256(&self, hash: &Pk::Hash256) -> bool {
198        Satisfier::lookup_hash256(self, hash).is_some()
199    }
200
201    fn provider_lookup_ripemd160(&self, hash: &Pk::Ripemd160) -> bool {
202        Satisfier::lookup_ripemd160(self, hash).is_some()
203    }
204
205    fn provider_lookup_hash160(&self, hash: &Pk::Hash160) -> bool {
206        Satisfier::lookup_hash160(self, hash).is_some()
207    }
208
209    fn check_older(&self, s: relative::LockTime) -> bool { Satisfier::check_older(self, s) }
210
211    fn check_after(&self, l: absolute::LockTime) -> bool { Satisfier::check_after(self, l) }
212}
213
214/// Representation of a particular spending path on a descriptor. Contains the witness template
215/// and the timelocks needed for satisfying the plan.
216/// Calling `plan` on a Descriptor will return this structure,
217/// containing the cheapest spending path possible (considering the `Assets` given)
218#[derive(Debug, Clone)]
219pub struct Plan {
220    /// This plan's witness template
221    pub(crate) template: Vec<Placeholder<DefiniteDescriptorKey>>,
222    /// The absolute timelock this plan uses
223    pub absolute_timelock: Option<absolute::LockTime>,
224    /// The relative timelock this plan uses
225    pub relative_timelock: Option<relative::LockTime>,
226
227    pub(crate) descriptor: Descriptor<DefiniteDescriptorKey>,
228}
229
230impl Plan {
231    /// Returns the witness template
232    pub fn witness_template(&self) -> &Vec<Placeholder<DefiniteDescriptorKey>> { &self.template }
233
234    /// Returns the witness version
235    pub fn witness_version(&self) -> Option<WitnessVersion> {
236        self.descriptor.desc_type().segwit_version()
237    }
238
239    /// The weight, in witness units, needed for satisfying this plan (includes both
240    /// the script sig weight and the witness weight)
241    pub fn satisfaction_weight(&self) -> usize { self.witness_size() + self.scriptsig_size() * 4 }
242
243    /// The size in bytes of the script sig that satisfies this plan
244    pub fn scriptsig_size(&self) -> usize {
245        match (self.descriptor.desc_type().segwit_version(), self.descriptor.desc_type()) {
246            // Entire witness goes in the script_sig
247            (None, _) => witness_size(self.template.as_ref()),
248            // Taproot doesn't have a "wrapped" version (scriptSig len (1))
249            (Some(WitnessVersion::V1), _) => 1,
250            // scriptSig len (1) + OP_0 (1) + OP_PUSHBYTES_20 (1) + <pk hash> (20)
251            (_, DescriptorType::ShWpkh) => 1 + 1 + 1 + 20,
252            // scriptSig len (1) + OP_0 (1) + OP_PUSHBYTES_32 (1) + <script hash> (32)
253            (_, DescriptorType::ShWsh) | (_, DescriptorType::ShWshSortedMulti) => 1 + 1 + 1 + 32,
254            // Native Segwit v0 (scriptSig len (1))
255            _ => 1,
256        }
257    }
258
259    /// The size in bytes of the witness that satisfies this plan
260    pub fn witness_size(&self) -> usize {
261        if self.descriptor.desc_type().segwit_version().is_some() {
262            witness_size(self.template.as_ref())
263        } else {
264            0 // should be 1 if there's at least one segwit input in the tx, but that's out of
265              // scope as we can't possibly know that just by looking at the descriptor
266        }
267    }
268
269    /// Try creating the final script_sig and witness using a [`Satisfier`]
270    pub fn satisfy<Sat: Satisfier<DefiniteDescriptorKey>>(
271        &self,
272        stfr: &Sat,
273    ) -> Result<(Vec<Vec<u8>>, ScriptBuf), Error> {
274        use bitcoin::blockdata::script::Builder;
275
276        let stack = self
277            .template
278            .iter()
279            .map(|placeholder| placeholder.satisfy_self(stfr))
280            .collect::<Option<Vec<Vec<u8>>>>()
281            .ok_or(Error::CouldNotSatisfy)?;
282
283        Ok(match self.descriptor.desc_type() {
284            DescriptorType::Bare
285            | DescriptorType::Sh
286            | DescriptorType::Pkh
287            | DescriptorType::ShSortedMulti => (
288                vec![],
289                stack
290                    .into_iter()
291                    .fold(Builder::new(), |builder, item| {
292                        use core::convert::TryFrom;
293                        let bytes = PushBytesBuf::try_from(item)
294                            .expect("All the possible placeholders can be made into PushBytesBuf");
295                        builder.push_slice(bytes)
296                    })
297                    .into_script(),
298            ),
299            DescriptorType::Wpkh
300            | DescriptorType::Wsh
301            | DescriptorType::WshSortedMulti
302            | DescriptorType::Tr => (stack, ScriptBuf::new()),
303            DescriptorType::ShWsh | DescriptorType::ShWshSortedMulti | DescriptorType::ShWpkh => {
304                (stack, self.descriptor.unsigned_script_sig())
305            }
306        })
307    }
308
309    /// Update a PSBT input with the metadata required to complete this plan
310    ///
311    /// This will only add the metadata for items required to complete this plan. For example, if
312    /// there are multiple keys present in the descriptor, only the few used by this plan will be
313    /// added to the PSBT.
314    pub fn update_psbt_input(&self, input: &mut psbt::Input) {
315        if let Descriptor::Tr(tr) = &self.descriptor {
316            enum SpendType {
317                KeySpend { internal_key: XOnlyPublicKey },
318                ScriptSpend { leaf_hash: TapLeafHash },
319            }
320
321            #[derive(Default)]
322            struct TrDescriptorData {
323                tap_script: Option<ScriptBuf>,
324                control_block: Option<ControlBlock>,
325                spend_type: Option<SpendType>,
326                key_origins: BTreeMap<XOnlyPublicKey, bip32::KeySource>,
327            }
328
329            let spend_info = tr.spend_info();
330            input.tap_merkle_root = spend_info.merkle_root();
331
332            let data = self
333                .template
334                .iter()
335                .fold(TrDescriptorData::default(), |mut data, item| {
336                    match item {
337                        Placeholder::TapScript(script) => data.tap_script = Some(script.clone()),
338                        Placeholder::TapControlBlock(cb) => data.control_block = Some(cb.clone()),
339                        Placeholder::SchnorrSigPk(pk, sig_type, _) => {
340                            let raw_pk = pk.to_x_only_pubkey();
341
342                            match (&data.spend_type, sig_type) {
343                                // First encountered schnorr sig, update the `TrDescriptorData` accordingly
344                                (None, SchnorrSigType::KeySpend { .. }) => data.spend_type = Some(SpendType::KeySpend { internal_key: raw_pk }),
345                                (None, SchnorrSigType::ScriptSpend { leaf_hash }) => data.spend_type = Some(SpendType::ScriptSpend { leaf_hash: *leaf_hash }),
346
347                                // Inconsistent placeholders (should be unreachable with the
348                                // current implementation)
349                                (Some(SpendType::KeySpend {..}), SchnorrSigType::ScriptSpend { .. }) | (Some(SpendType::ScriptSpend {..}), SchnorrSigType::KeySpend{..}) => unreachable!("Mixed taproot key-spend and script-spend placeholders in the same plan"),
350
351                                _ => {},
352                            }
353
354                            for path in pk.full_derivation_paths() {
355                                data.key_origins.insert(raw_pk, (pk.master_fingerprint(), path));
356                            }
357                        }
358                        Placeholder::SchnorrSigPkHash(_, tap_leaf_hash, _) => {
359                            data.spend_type = Some(SpendType::ScriptSpend { leaf_hash: *tap_leaf_hash });
360                        }
361                        _ => {}
362                    }
363
364                    data
365                });
366
367            // TODO: TapTree. we need to re-traverse the tree to build it, sigh
368
369            let leaf_hash = match data.spend_type {
370                Some(SpendType::KeySpend { internal_key }) => {
371                    input.tap_internal_key = Some(internal_key);
372                    None
373                }
374                Some(SpendType::ScriptSpend { leaf_hash }) => Some(leaf_hash),
375                _ => None,
376            };
377            for (pk, key_source) in data.key_origins {
378                input
379                    .tap_key_origins
380                    .entry(pk)
381                    .and_modify(|(leaf_hashes, _)| {
382                        if let Some(lh) = leaf_hash {
383                            if leaf_hashes.iter().all(|&i| i != lh) {
384                                leaf_hashes.push(lh);
385                            }
386                        }
387                    })
388                    .or_insert_with(|| (vec![], key_source));
389            }
390            if let (Some(tap_script), Some(control_block)) = (data.tap_script, data.control_block) {
391                input
392                    .tap_scripts
393                    .insert(control_block, (tap_script, LeafVersion::TapScript));
394            }
395        } else {
396            for item in &self.template {
397                if let Placeholder::EcdsaSigPk(pk) = item {
398                    let public_key = pk.to_public_key().inner;
399                    let master_fingerprint = pk.master_fingerprint();
400                    for derivation_path in pk.full_derivation_paths() {
401                        input
402                            .bip32_derivation
403                            .insert(public_key, (master_fingerprint, derivation_path));
404                    }
405                }
406            }
407
408            match &self.descriptor {
409                Descriptor::Bare(_) | Descriptor::Pkh(_) | Descriptor::Wpkh(_) => {}
410                Descriptor::Sh(sh) => match sh.as_inner() {
411                    descriptor::ShInner::Wsh(wsh) => {
412                        input.witness_script = Some(wsh.inner_script());
413                        input.redeem_script = Some(wsh.inner_script().to_p2wsh());
414                    }
415                    descriptor::ShInner::Wpkh(..) => input.redeem_script = Some(sh.inner_script()),
416                    descriptor::ShInner::SortedMulti(_) | descriptor::ShInner::Ms(_) => {
417                        input.redeem_script = Some(sh.inner_script())
418                    }
419                },
420                Descriptor::Wsh(wsh) => input.witness_script = Some(wsh.inner_script()),
421                Descriptor::Tr(_) => unreachable!("Tr is dealt with separately"),
422            }
423        }
424    }
425}
426
427#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
428/// Signatures which a key can produce
429///
430/// Defaults to `ecdsa=true` and `taproot=TaprootCanSign::default()`
431pub struct CanSign {
432    /// Whether the key can produce ECDSA signatures
433    pub ecdsa: bool,
434    /// Whether the key can produce taproot (Schnorr) signatures
435    pub taproot: TaprootCanSign,
436}
437
438impl Default for CanSign {
439    fn default() -> Self { CanSign { ecdsa: true, taproot: TaprootCanSign::default() } }
440}
441
442#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
443/// Signatures which a taproot key can produce
444///
445/// Defaults to `key_spend=true`, `script_spend=Any` and `sighash_default=true`
446pub struct TaprootCanSign {
447    /// Can produce key spend signatures
448    pub key_spend: bool,
449    /// Can produce script spend signatures
450    pub script_spend: TaprootAvailableLeaves,
451    /// Whether `SIGHASH_DEFAULT` will be used to sign
452    pub sighash_default: bool,
453}
454
455impl TaprootCanSign {
456    fn sig_len(&self) -> usize {
457        match self.sighash_default {
458            true => 64,
459            false => 65,
460        }
461    }
462}
463
464impl Default for TaprootCanSign {
465    fn default() -> Self {
466        TaprootCanSign {
467            key_spend: true,
468            script_spend: TaprootAvailableLeaves::Any,
469            sighash_default: true,
470        }
471    }
472}
473
474#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
475/// Which taproot leaves the key can sign for
476pub enum TaprootAvailableLeaves {
477    /// Cannot sign for any leaf
478    None,
479    /// Can sign for any leaf
480    Any,
481    /// Can sign only for a specific leaf
482    Single(TapLeafHash),
483    /// Can sign for multiple leaves
484    Many(Vec<TapLeafHash>),
485}
486
487impl TaprootAvailableLeaves {
488    fn is_available(&self, lh: &TapLeafHash) -> bool {
489        use TaprootAvailableLeaves::*;
490
491        match self {
492            None => false,
493            Any => true,
494            Single(v) => v == lh,
495            Many(list) => list.contains(lh),
496        }
497    }
498}
499
500/// The Assets we can use to satisfy a particular spending path
501#[derive(Debug, Default)]
502pub struct Assets {
503    /// Keys the user can sign for, and how. A pair `(fingerprint, derivation_path)` is
504    /// provided, meaning that the user can sign using the key with `fingerprint`,
505    /// derived with either `derivation_path` or a derivation path that extends `derivation_path`
506    /// by exactly one child number. For example, if the derivation path `m/0/1` is provided, the
507    /// user can sign with either `m/0/1` or `m/0/1/*`.
508    pub keys: BTreeSet<(bip32::KeySource, CanSign)>,
509    /// Set of available sha256 preimages
510    pub sha256_preimages: BTreeSet<sha256::Hash>,
511    /// Set of available hash256 preimages
512    pub hash256_preimages: BTreeSet<hash256::Hash>,
513    /// Set of available ripemd160 preimages
514    pub ripemd160_preimages: BTreeSet<ripemd160::Hash>,
515    /// Set of available hash160 preimages
516    pub hash160_preimages: BTreeSet<hash160::Hash>,
517    /// Maximum absolute timelock allowed
518    pub absolute_timelock: Option<absolute::LockTime>,
519    /// Maximum relative timelock allowed
520    pub relative_timelock: Option<relative::LockTime>,
521}
522
523// Checks if the `pk` is a "direct child" of the `derivation_path` provided.
524// Direct child means that the key derivation path is either the same as the
525// `derivation_path`, or the same extened by exactly one child number.
526// For example, `pk/0/1/2` is a direct child of `m/0/1` and of `m/0/1/2`,
527// but not of `m/0`.
528fn is_key_direct_child_of(
529    pk: &DefiniteDescriptorKey,
530    derivation_path: &bip32::DerivationPath,
531) -> bool {
532    for pk_derivation_path in pk.full_derivation_paths() {
533        if &pk_derivation_path == derivation_path {
534            return true;
535        }
536
537        let definite_path_len = pk_derivation_path.len();
538        if derivation_path.as_ref() == &pk_derivation_path[..(definite_path_len - 1)] {
539            return true;
540        }
541    }
542
543    false
544}
545
546impl Assets {
547    pub(crate) fn has_ecdsa_key(&self, pk: &DefiniteDescriptorKey) -> bool {
548        self.keys.iter().any(|(keysource, can_sign)| {
549            can_sign.ecdsa
550                && pk.master_fingerprint() == keysource.0
551                && is_key_direct_child_of(pk, &keysource.1)
552        })
553    }
554
555    pub(crate) fn has_taproot_internal_key(&self, pk: &DefiniteDescriptorKey) -> Option<usize> {
556        self.keys.iter().find_map(|(keysource, can_sign)| {
557            if !can_sign.taproot.key_spend
558                || pk.master_fingerprint() != keysource.0
559                || !is_key_direct_child_of(pk, &keysource.1)
560            {
561                None
562            } else {
563                Some(can_sign.taproot.sig_len())
564            }
565        })
566    }
567
568    pub(crate) fn has_taproot_script_key(
569        &self,
570        pk: &DefiniteDescriptorKey,
571        tap_leaf_hash: &TapLeafHash,
572    ) -> Option<usize> {
573        self.keys.iter().find_map(|(keysource, can_sign)| {
574            if !can_sign.taproot.script_spend.is_available(tap_leaf_hash)
575                || pk.master_fingerprint() != keysource.0
576                || !is_key_direct_child_of(pk, &keysource.1)
577            {
578                None
579            } else {
580                Some(can_sign.taproot.sig_len())
581            }
582        })
583    }
584}
585
586impl AssetProvider<DefiniteDescriptorKey> for Assets {
587    fn provider_lookup_ecdsa_sig(&self, pk: &DefiniteDescriptorKey) -> bool {
588        self.has_ecdsa_key(pk)
589    }
590
591    fn provider_lookup_tap_key_spend_sig(&self, pk: &DefiniteDescriptorKey) -> Option<usize> {
592        self.has_taproot_internal_key(pk)
593    }
594
595    fn provider_lookup_tap_leaf_script_sig(
596        &self,
597        pk: &DefiniteDescriptorKey,
598        tap_leaf_hash: &TapLeafHash,
599    ) -> Option<usize> {
600        self.has_taproot_script_key(pk, tap_leaf_hash)
601    }
602
603    fn provider_lookup_sha256(&self, hash: &sha256::Hash) -> bool {
604        self.sha256_preimages.contains(hash)
605    }
606
607    fn provider_lookup_hash256(&self, hash: &hash256::Hash) -> bool {
608        self.hash256_preimages.contains(hash)
609    }
610
611    fn provider_lookup_ripemd160(&self, hash: &ripemd160::Hash) -> bool {
612        self.ripemd160_preimages.contains(hash)
613    }
614
615    fn provider_lookup_hash160(&self, hash: &hash160::Hash) -> bool {
616        self.hash160_preimages.contains(hash)
617    }
618
619    fn check_older(&self, s: relative::LockTime) -> bool {
620        if let Some(timelock) = self.relative_timelock {
621            s.is_implied_by(timelock)
622        } else {
623            false
624        }
625    }
626
627    fn check_after(&self, l: absolute::LockTime) -> bool {
628        if let Some(timelock) = self.absolute_timelock {
629            l.is_implied_by(timelock)
630        } else {
631            false
632        }
633    }
634}
635
636impl FromIterator<DescriptorPublicKey> for Assets {
637    fn from_iter<I: IntoIterator<Item = DescriptorPublicKey>>(iter: I) -> Self {
638        let mut keys = BTreeSet::new();
639        for pk in iter {
640            for deriv_path in pk.full_derivation_paths() {
641                keys.insert(((pk.master_fingerprint(), deriv_path), CanSign::default()));
642            }
643        }
644        Assets { keys, ..Default::default() }
645    }
646}
647
648/// Conversion into a `Assets`
649pub trait IntoAssets {
650    /// Convert `self` into a `Assets` struct
651    fn into_assets(self) -> Assets;
652}
653
654impl IntoAssets for KeyMap {
655    fn into_assets(self) -> Assets { Assets::from_iter(self.into_iter().map(|(k, _)| k)) }
656}
657
658impl IntoAssets for DescriptorPublicKey {
659    fn into_assets(self) -> Assets { vec![self].into_assets() }
660}
661
662impl IntoAssets for Vec<DescriptorPublicKey> {
663    fn into_assets(self) -> Assets { Assets::from_iter(self) }
664}
665
666impl IntoAssets for sha256::Hash {
667    fn into_assets(self) -> Assets {
668        Assets { sha256_preimages: vec![self].into_iter().collect(), ..Default::default() }
669    }
670}
671
672impl IntoAssets for hash256::Hash {
673    fn into_assets(self) -> Assets {
674        Assets { hash256_preimages: vec![self].into_iter().collect(), ..Default::default() }
675    }
676}
677
678impl IntoAssets for ripemd160::Hash {
679    fn into_assets(self) -> Assets {
680        Assets { ripemd160_preimages: vec![self].into_iter().collect(), ..Default::default() }
681    }
682}
683
684impl IntoAssets for hash160::Hash {
685    fn into_assets(self) -> Assets {
686        Assets { hash160_preimages: vec![self].into_iter().collect(), ..Default::default() }
687    }
688}
689
690impl IntoAssets for Assets {
691    fn into_assets(self) -> Assets { self }
692}
693
694impl Assets {
695    /// Contruct an empty instance
696    pub fn new() -> Self { Self::default() }
697
698    /// Add some assets
699    #[allow(clippy::should_implement_trait)] // looks like the `ops::Add` trait
700    pub fn add<A: IntoAssets>(mut self, asset: A) -> Self {
701        self.append(asset.into_assets());
702        self
703    }
704
705    /// Set the maximum relative timelock allowed
706    pub fn older(mut self, seq: relative::LockTime) -> Self {
707        self.relative_timelock = Some(seq);
708        self
709    }
710
711    /// Set the maximum absolute timelock allowed
712    pub fn after(mut self, lt: absolute::LockTime) -> Self {
713        self.absolute_timelock = Some(lt);
714        self
715    }
716
717    fn append(&mut self, b: Self) {
718        self.keys.extend(b.keys);
719        self.sha256_preimages.extend(b.sha256_preimages);
720        self.hash256_preimages.extend(b.hash256_preimages);
721        self.ripemd160_preimages.extend(b.ripemd160_preimages);
722        self.hash160_preimages.extend(b.hash160_preimages);
723
724        self.relative_timelock = b.relative_timelock.or(self.relative_timelock);
725        self.absolute_timelock = b.absolute_timelock.or(self.absolute_timelock);
726    }
727}
728
729#[cfg(test)]
730mod test {
731    use std::str::FromStr;
732
733    use bitcoin::bip32::Xpub;
734
735    use super::*;
736    use crate::*;
737
738    #[allow(clippy::type_complexity)]
739    fn test_inner(
740        desc: &str,
741        keys: Vec<DescriptorPublicKey>,
742        hashes: Vec<hash160::Hash>,
743        // [ (key_indexes, hash_indexes, older, after, expected) ]
744        tests: Vec<(
745            Vec<usize>,
746            Vec<usize>,
747            Option<relative::LockTime>,
748            Option<absolute::LockTime>,
749            Option<usize>,
750        )>,
751    ) {
752        let desc = Descriptor::<DefiniteDescriptorKey>::from_str(desc).unwrap();
753
754        for (key_indexes, hash_indexes, older, after, expected) in tests {
755            let mut assets = Assets::new();
756            if let Some(seq) = older {
757                assets = assets.older(seq);
758            }
759            if let Some(locktime) = after {
760                assets = assets.after(locktime);
761            }
762            for ki in key_indexes {
763                assets = assets.add(keys[ki].clone());
764            }
765            for hi in hash_indexes {
766                assets = assets.add(hashes[hi]);
767            }
768
769            let result = desc.clone().plan(&assets);
770            assert_eq!(
771                result.as_ref().ok().map(|plan| plan.satisfaction_weight()),
772                expected,
773                "{:#?}",
774                result
775            );
776        }
777    }
778
779    #[test]
780    fn test_or() {
781        let keys = vec![
782            DescriptorPublicKey::from_str(
783                "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
784            )
785            .unwrap(),
786            DescriptorPublicKey::from_str(
787                "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a",
788            )
789            .unwrap(),
790        ];
791        let hashes = vec![];
792        let desc = format!("wsh(t:or_c(pk({}),v:pkh({})))", keys[0], keys[1]);
793
794        // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig)
795        let tests = vec![
796            (vec![], vec![], None, None, None),
797            (vec![0], vec![], None, None, Some(4 + 1 + 73)),
798            (vec![0, 1], vec![], None, None, Some(4 + 1 + 73)),
799        ];
800
801        test_inner(&desc, keys, hashes, tests);
802    }
803
804    #[test]
805    fn test_and() {
806        let keys = vec![
807            DescriptorPublicKey::from_str(
808                "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
809            )
810            .unwrap(),
811            DescriptorPublicKey::from_str(
812                "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a",
813            )
814            .unwrap(),
815        ];
816        let hashes = vec![];
817        let desc = format!("wsh(and_v(v:pk({}),pk({})))", keys[0], keys[1]);
818
819        // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) * 2
820        let tests = vec![
821            (vec![], vec![], None, None, None),
822            (vec![0], vec![], None, None, None),
823            (vec![0, 1], vec![], None, None, Some(4 + 1 + 73 * 2)),
824        ];
825
826        test_inner(&desc, keys, hashes, tests);
827    }
828
829    #[test]
830    fn test_multi() {
831        let keys = vec![
832            DescriptorPublicKey::from_str(
833                "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
834            )
835            .unwrap(),
836            DescriptorPublicKey::from_str(
837                "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a",
838            )
839            .unwrap(),
840            DescriptorPublicKey::from_str(
841                "03500a2b48b0f66c8183cc0d6645ab21cc19c7fad8a33ff04d41c3ece54b0bc1c5",
842            )
843            .unwrap(),
844            DescriptorPublicKey::from_str(
845                "033ad2d191da4f39512adbaac320cae1f12f298386a4e9d43fd98dec7cf5db2ac9",
846            )
847            .unwrap(),
848        ];
849        let hashes = vec![];
850        let desc = format!("wsh(multi(3,{},{},{},{}))", keys[0], keys[1], keys[2], keys[3]);
851
852        let tests = vec![
853            (vec![], vec![], None, None, None),
854            (vec![0, 1], vec![], None, None, None),
855            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) * 3 + 1 (dummy push)
856            (vec![0, 1, 3], vec![], None, None, Some(4 + 1 + 73 * 3 + 1)),
857        ];
858
859        test_inner(&desc, keys, hashes, tests);
860    }
861
862    #[test]
863    fn test_thresh() {
864        // relative::LockTime has no constructors except by going through Sequence
865        use bitcoin::Sequence;
866        let keys = vec![
867            DescriptorPublicKey::from_str(
868                "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
869            )
870            .unwrap(),
871            DescriptorPublicKey::from_str(
872                "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a",
873            )
874            .unwrap(),
875        ];
876        let hashes = vec![];
877        let desc = format!("wsh(thresh(2,pk({}),s:pk({}),snl:older(144)))", keys[0], keys[1]);
878
879        let tests = vec![
880            (vec![], vec![], None, None, None),
881            (
882                vec![],
883                vec![],
884                Some(Sequence(1000).to_relative_lock_time().unwrap()),
885                None,
886                None,
887            ),
888            (vec![0], vec![], None, None, None),
889            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) + 1 (OP_0) + 1 (OP_ZERO)
890            (
891                vec![0],
892                vec![],
893                Some(Sequence(1000).to_relative_lock_time().unwrap()),
894                None,
895                Some(80),
896            ),
897            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) * 2 + 2 (OP_PUSHBYTE_1 0x01)
898            (vec![0, 1], vec![], None, None, Some(153)),
899            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) + 1 (OP_0) + 1 (OP_ZERO)
900            (
901                vec![0, 1],
902                vec![],
903                Some(Sequence(1000).to_relative_lock_time().unwrap()),
904                None,
905                Some(80),
906            ),
907            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) * 2 + 2 (OP_PUSHBYTE_1 0x01)
908            (
909                vec![0, 1],
910                vec![],
911                Some(
912                    Sequence::from_512_second_intervals(10)
913                        .to_relative_lock_time()
914                        .unwrap(),
915                ),
916                None,
917                Some(153),
918            ), // incompatible timelock
919        ];
920
921        test_inner(&desc, keys.clone(), hashes.clone(), tests);
922
923        let desc = format!("wsh(thresh(2,pk({}),s:pk({}),snl:after(144)))", keys[0], keys[1]);
924
925        let tests = vec![
926            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) + 1 (OP_0) + 1 (OP_ZERO)
927            (
928                vec![0],
929                vec![],
930                None,
931                Some(absolute::LockTime::from_height(1000).unwrap()),
932                Some(80),
933            ),
934            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) * 2 + 2 (OP_PUSHBYTE_1 0x01)
935            (
936                vec![0, 1],
937                vec![],
938                None,
939                Some(absolute::LockTime::from_time(500_001_000).unwrap()),
940                Some(153),
941            ), // incompatible timelock
942        ];
943
944        test_inner(&desc, keys, hashes, tests);
945    }
946
947    #[test]
948    fn test_taproot() {
949        let keys = vec![
950            DescriptorPublicKey::from_str(
951                "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
952            )
953            .unwrap(),
954            DescriptorPublicKey::from_str(
955                "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a",
956            )
957            .unwrap(),
958            DescriptorPublicKey::from_str(
959                "03500a2b48b0f66c8183cc0d6645ab21cc19c7fad8a33ff04d41c3ece54b0bc1c5",
960            )
961            .unwrap(),
962            DescriptorPublicKey::from_str(
963                "033ad2d191da4f39512adbaac320cae1f12f298386a4e9d43fd98dec7cf5db2ac9",
964            )
965            .unwrap(),
966            DescriptorPublicKey::from_str(
967                "023fc33527afab09fa97135f2180bcd22ce637b1d2fbcb2db748b1f2c33f45b2b4",
968            )
969            .unwrap(),
970        ];
971        let hashes = vec![];
972        //    .
973        //   / \
974        //  .   .
975        //  A  / \
976        //    .   .
977        //    B   C
978        //  where A = pk(key1)
979        //        B = multi(1, key2, key3)
980        //        C = and(key4, after(10))
981        let desc = format!(
982            "tr({},{{pk({}),{{multi_a(1,{},{}),and_v(v:pk({}),after(10))}}}})",
983            keys[0], keys[1], keys[2], keys[3], keys[4]
984        );
985
986        // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 64 (sig)
987        let internal_key_sat_weight = Some(70);
988        // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 64 (sig)
989        // + 34 [script: 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIG)]
990        // + 65 [control block: 1 (control byte) + 32 (internal key) + 32 (hash BC)]
991        let first_leaf_sat_weight = Some(169);
992        // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 64 (sig)
993        // + 1 (OP_ZERO)
994        // + 70 [script: 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIG)
995        //       + 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIGADD)
996        //       + 1 (OP_PUSHNUM1) + 1 (OP_NUMEQUAL)]
997        // + 97 [control block: 1 (control byte) + 32 (internal key) + 32 (hash C) + 32 (hash
998        //       A)]
999        let second_leaf_sat_weight = Some(238);
1000        // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 64 (sig)
1001        // + 36 [script: 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIGVERIFY)
1002        //       + 1 (OP_PUSHNUM_10) + 1 (OP_CLTV)]
1003        // + 97 [control block: 1 (control byte) + 32 (internal key) + 32 (hash B) + 32 (hash
1004        //       A)]
1005        let third_leaf_sat_weight = Some(203);
1006
1007        let tests = vec![
1008            // Don't give assets
1009            (vec![], vec![], None, None, None),
1010            // Spend with internal key
1011            (vec![0], vec![], None, None, internal_key_sat_weight),
1012            // Spend with first leaf (single pk)
1013            (vec![1], vec![], None, None, first_leaf_sat_weight),
1014            // Spend with second leaf (1of2)
1015            (vec![2], vec![], None, None, second_leaf_sat_weight),
1016            // Spend with second leaf (1of2)
1017            (vec![2, 3], vec![], None, None, second_leaf_sat_weight),
1018            // Spend with third leaf (key + timelock)
1019            (
1020                vec![4],
1021                vec![],
1022                None,
1023                Some(absolute::LockTime::from_height(10).unwrap()),
1024                third_leaf_sat_weight,
1025            ),
1026            // Spend with third leaf (key + timelock),
1027            // but timelock is too low (=impossible)
1028            (vec![4], vec![], None, Some(absolute::LockTime::from_height(9).unwrap()), None),
1029            // Spend with third leaf (key + timelock),
1030            // but timelock is in the wrong unit (=impossible)
1031            (
1032                vec![4],
1033                vec![],
1034                None,
1035                Some(absolute::LockTime::from_time(1296000000).unwrap()),
1036                None,
1037            ),
1038            // Spend with third leaf (key + timelock),
1039            // but don't give the timelock (=impossible)
1040            (vec![4], vec![], None, None, None),
1041            // Give all the keys (internal key will be used, as it's cheaper)
1042            (vec![0, 1, 2, 3, 4], vec![], None, None, internal_key_sat_weight),
1043            // Give all the leaf keys (uses 1st leaf)
1044            (vec![1, 2, 3, 4], vec![], None, None, first_leaf_sat_weight),
1045            // Give 2nd+3rd leaf without timelock (uses 2nd leaf)
1046            (vec![2, 3, 4], vec![], None, None, second_leaf_sat_weight),
1047            // Give 2nd+3rd leaf with timelock (uses 3rd leaf)
1048            (
1049                vec![2, 3, 4],
1050                vec![],
1051                None,
1052                Some(absolute::LockTime::from_consensus(11)),
1053                third_leaf_sat_weight,
1054            ),
1055        ];
1056
1057        test_inner(&desc, keys, hashes, tests);
1058    }
1059
1060    #[test]
1061    fn test_hash() {
1062        let keys = vec![DescriptorPublicKey::from_str(
1063            "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
1064        )
1065        .unwrap()];
1066        let hashes = vec![hash160::Hash::from_slice(&[0; 20]).unwrap()];
1067        let desc = format!("wsh(and_v(v:pk({}),hash160({})))", keys[0], hashes[0]);
1068
1069        let tests = vec![
1070            // No assets, impossible
1071            (vec![], vec![], None, None, None),
1072            // Only key, impossible
1073            (vec![0], vec![], None, None, None),
1074            // Only hash, impossible
1075            (vec![], vec![0], None, None, None),
1076            // Key + hash
1077            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) + 1 (OP_PUSH) + 32 (preimage)
1078            (vec![0], vec![0], None, None, Some(111)),
1079        ];
1080
1081        test_inner(&desc, keys, hashes, tests);
1082    }
1083
1084    #[test]
1085    fn test_plan_update_psbt_tr() {
1086        // keys taken from: https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki#Specifications
1087        let root_xpub = Xpub::from_str("xpub661MyMwAqRbcFkPHucMnrGNzDwb6teAX1RbKQmqtEF8kK3Z7LZ59qafCjB9eCRLiTVG3uxBxgKvRgbubRhqSKXnGGb1aoaqLrpMBDrVxga8").unwrap();
1088        let fingerprint = root_xpub.fingerprint();
1089        let xpub = format!("[{}/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ", fingerprint);
1090        let desc =
1091            format!("tr({}/0/0,{{pkh({}/0/1),multi_a(2,{}/1/0,{}/1/1)}})", xpub, xpub, xpub, xpub);
1092
1093        let desc = Descriptor::from_str(&desc).unwrap();
1094
1095        let internal_key = DescriptorPublicKey::from_str(&format!("{}/0/0", xpub)).unwrap();
1096        let first_branch = DescriptorPublicKey::from_str(&format!("{}/0/1", xpub)).unwrap();
1097        let second_branch = DescriptorPublicKey::from_str(&format!("{}/1/*", xpub)).unwrap(); // Note this is a wildcard key, so it can sign for the whole multi_a
1098
1099        let mut psbt_input = bitcoin::psbt::Input::default();
1100        let assets = Assets::new().add(internal_key);
1101        desc.clone()
1102            .plan(&assets)
1103            .unwrap()
1104            .update_psbt_input(&mut psbt_input);
1105        assert!(psbt_input.tap_internal_key.is_some(), "Internal key is missing");
1106        assert!(psbt_input.tap_merkle_root.is_some(), "Merkle root is missing");
1107        assert_eq!(psbt_input.tap_key_origins.len(), 1, "Unexpected number of tap_key_origins");
1108        assert_eq!(psbt_input.tap_scripts.len(), 0, "Unexpected number of tap_scripts");
1109
1110        let mut psbt_input = bitcoin::psbt::Input::default();
1111        let assets = Assets::new().add(first_branch);
1112        desc.clone()
1113            .plan(&assets)
1114            .unwrap()
1115            .update_psbt_input(&mut psbt_input);
1116        assert!(psbt_input.tap_internal_key.is_none(), "Internal key is present");
1117        assert!(psbt_input.tap_merkle_root.is_some(), "Merkle root is missing");
1118        assert_eq!(psbt_input.tap_key_origins.len(), 1, "Unexpected number of tap_key_origins");
1119        assert_eq!(psbt_input.tap_scripts.len(), 1, "Unexpected number of tap_scripts");
1120
1121        let mut psbt_input = bitcoin::psbt::Input::default();
1122        let assets = Assets::new().add(second_branch);
1123        desc.plan(&assets)
1124            .unwrap()
1125            .update_psbt_input(&mut psbt_input);
1126        assert!(psbt_input.tap_internal_key.is_none(), "Internal key is present");
1127        assert!(psbt_input.tap_merkle_root.is_some(), "Merkle root is missing");
1128        assert_eq!(psbt_input.tap_key_origins.len(), 2, "Unexpected number of tap_key_origins");
1129        assert_eq!(psbt_input.tap_scripts.len(), 1, "Unexpected number of tap_scripts");
1130    }
1131
1132    #[test]
1133    fn test_plan_update_psbt_segwit() {
1134        // keys taken from: https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki#Specifications
1135        let root_xpub = Xpub::from_str("xpub661MyMwAqRbcFkPHucMnrGNzDwb6teAX1RbKQmqtEF8kK3Z7LZ59qafCjB9eCRLiTVG3uxBxgKvRgbubRhqSKXnGGb1aoaqLrpMBDrVxga8").unwrap();
1136        let fingerprint = root_xpub.fingerprint();
1137        let xpub = format!("[{}/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ", fingerprint);
1138        let desc = format!("wsh(multi(2,{}/1/0,{}/1/1))", xpub, xpub);
1139
1140        let desc = Descriptor::from_str(&desc).unwrap();
1141
1142        let asset_key = DescriptorPublicKey::from_str(&format!("{}/1/*", xpub)).unwrap(); // Note this is a wildcard key, so it can sign for the whole multi
1143
1144        let mut psbt_input = bitcoin::psbt::Input::default();
1145        let assets = Assets::new().add(asset_key);
1146        desc.plan(&assets)
1147            .unwrap()
1148            .update_psbt_input(&mut psbt_input);
1149        assert!(psbt_input.witness_script.is_some(), "Witness script missing");
1150        assert!(psbt_input.redeem_script.is_none(), "Redeem script present");
1151        assert_eq!(psbt_input.bip32_derivation.len(), 2, "Unexpected number of bip32_derivation");
1152    }
1153}