1use core::iter::FromIterator;
20
21use bitcoin::hashes::{hash160, ripemd160, sha256};
22use bitcoin::key::XOnlyPublicKey;
23use bitcoin::script::PushBytesBuf;
24use bitcoin::taproot::{ControlBlock, LeafVersion, TapLeafHash};
25use bitcoin::{absolute, bip32, psbt, relative, ScriptBuf, WitnessVersion};
26
27use crate::descriptor::{self, Descriptor, DescriptorType, KeyMap};
28use crate::miniscript::hash256;
29use crate::miniscript::satisfy::{Placeholder, Satisfier, SchnorrSigType};
30use crate::prelude::*;
31use crate::util::witness_size;
32use crate::{DefiniteDescriptorKey, DescriptorPublicKey, Error, MiniscriptKey, ToPublicKey};
33
34pub trait AssetProvider<Pk: MiniscriptKey> {
46 fn provider_lookup_ecdsa_sig(&self, _: &Pk) -> bool { false }
48
49 fn provider_lookup_tap_key_spend_sig(&self, _: &Pk) -> Option<usize> { None }
51
52 fn provider_lookup_tap_leaf_script_sig(&self, _: &Pk, _: &TapLeafHash) -> Option<usize> { None }
55
56 fn provider_lookup_raw_pkh_pk(&self, _: &hash160::Hash) -> Option<bitcoin::PublicKey> { None }
58
59 fn provider_lookup_raw_pkh_x_only_pk(&self, _: &hash160::Hash) -> Option<XOnlyPublicKey> {
61 None
62 }
63
64 fn provider_lookup_raw_pkh_ecdsa_sig(&self, _: &hash160::Hash) -> Option<bitcoin::PublicKey> {
72 None
73 }
74
75 fn provider_lookup_raw_pkh_tap_leaf_script_sig(
83 &self,
84 _: &(hash160::Hash, TapLeafHash),
85 ) -> Option<(XOnlyPublicKey, usize)> {
86 None
87 }
88
89 fn provider_lookup_sha256(&self, _: &Pk::Sha256) -> bool { false }
91
92 fn provider_lookup_hash256(&self, _: &Pk::Hash256) -> bool { false }
94
95 fn provider_lookup_ripemd160(&self, _: &Pk::Ripemd160) -> bool { false }
97
98 fn provider_lookup_hash160(&self, _: &Pk::Hash160) -> bool { false }
100
101 fn check_older(&self, _: relative::LockTime) -> bool { false }
103
104 fn check_after(&self, _: absolute::LockTime) -> bool { false }
106}
107
108#[cfg(feature = "std")]
110pub struct LoggerAssetProvider<'a>(pub &'a Assets);
111
112#[cfg(feature = "std")]
113macro_rules! impl_log_method {
114 ( $name:ident, $( <$ctx:ident: ScriptContext > )? $( $arg:ident : $ty:ty, )* -> $ret_ty:ty ) => {
115 fn $name $( <$ctx: ScriptContext> )? ( &self, $( $arg:$ty ),* ) -> $ret_ty {
116 let ret = (self.0).$name $( ::<$ctx> )*( $( $arg ),* );
117 dbg!(stringify!( $name ), ( $( $arg ),* ), &ret);
118
119 ret
120 }
121 }
122}
123
124#[cfg(feature = "std")]
125impl AssetProvider<DefiniteDescriptorKey> for LoggerAssetProvider<'_> {
126 impl_log_method!(provider_lookup_ecdsa_sig, pk: &DefiniteDescriptorKey, -> bool);
127 impl_log_method!(provider_lookup_tap_key_spend_sig, pk: &DefiniteDescriptorKey, -> Option<usize>);
128 impl_log_method!(provider_lookup_tap_leaf_script_sig, pk: &DefiniteDescriptorKey, leaf_hash: &TapLeafHash, -> Option<usize>);
129 impl_log_method!(provider_lookup_raw_pkh_pk, hash: &hash160::Hash, -> Option<bitcoin::PublicKey>);
130 impl_log_method!(provider_lookup_raw_pkh_x_only_pk, hash: &hash160::Hash, -> Option<XOnlyPublicKey>);
131 impl_log_method!(provider_lookup_raw_pkh_ecdsa_sig, hash: &hash160::Hash, -> Option<bitcoin::PublicKey>);
132 impl_log_method!(provider_lookup_raw_pkh_tap_leaf_script_sig, hash: &(hash160::Hash, TapLeafHash), -> Option<(XOnlyPublicKey, usize)>);
133 impl_log_method!(provider_lookup_sha256, hash: &sha256::Hash, -> bool);
134 impl_log_method!(provider_lookup_hash256, hash: &hash256::Hash, -> bool);
135 impl_log_method!(provider_lookup_ripemd160, hash: &ripemd160::Hash, -> bool);
136 impl_log_method!(provider_lookup_hash160, hash: &hash160::Hash, -> bool);
137 impl_log_method!(check_older, s: relative::LockTime, -> bool);
138 impl_log_method!(check_after, t: absolute::LockTime, -> bool);
139}
140
141impl<T, Pk> AssetProvider<Pk> for T
142where
143 T: Satisfier<Pk>,
144 Pk: MiniscriptKey + ToPublicKey,
145{
146 fn provider_lookup_ecdsa_sig(&self, pk: &Pk) -> bool {
147 Satisfier::lookup_ecdsa_sig(self, pk).is_some()
148 }
149
150 fn provider_lookup_tap_key_spend_sig(&self, pk: &Pk) -> Option<usize> {
151 Satisfier::lookup_tap_key_spend_sig(self, pk).map(|s| s.to_vec().len())
152 }
153
154 fn provider_lookup_tap_leaf_script_sig(
155 &self,
156 pk: &Pk,
157 leaf_hash: &TapLeafHash,
158 ) -> Option<usize> {
159 Satisfier::lookup_tap_leaf_script_sig(self, pk, leaf_hash).map(|s| s.to_vec().len())
160 }
161
162 fn provider_lookup_raw_pkh_pk(&self, hash: &hash160::Hash) -> Option<bitcoin::PublicKey> {
163 Satisfier::lookup_raw_pkh_pk(self, hash)
164 }
165
166 fn provider_lookup_raw_pkh_x_only_pk(&self, hash: &hash160::Hash) -> Option<XOnlyPublicKey> {
167 Satisfier::lookup_raw_pkh_x_only_pk(self, hash)
168 }
169
170 fn provider_lookup_raw_pkh_ecdsa_sig(
171 &self,
172 hash: &hash160::Hash,
173 ) -> Option<bitcoin::PublicKey> {
174 Satisfier::lookup_raw_pkh_ecdsa_sig(self, hash).map(|(pk, _)| pk)
175 }
176
177 fn provider_lookup_raw_pkh_tap_leaf_script_sig(
178 &self,
179 hash: &(hash160::Hash, TapLeafHash),
180 ) -> Option<(XOnlyPublicKey, usize)> {
181 Satisfier::lookup_raw_pkh_tap_leaf_script_sig(self, hash)
182 .map(|(pk, sig)| (pk, sig.to_vec().len()))
183 }
184
185 fn provider_lookup_sha256(&self, hash: &Pk::Sha256) -> bool {
186 Satisfier::lookup_sha256(self, hash).is_some()
187 }
188
189 fn provider_lookup_hash256(&self, hash: &Pk::Hash256) -> bool {
190 Satisfier::lookup_hash256(self, hash).is_some()
191 }
192
193 fn provider_lookup_ripemd160(&self, hash: &Pk::Ripemd160) -> bool {
194 Satisfier::lookup_ripemd160(self, hash).is_some()
195 }
196
197 fn provider_lookup_hash160(&self, hash: &Pk::Hash160) -> bool {
198 Satisfier::lookup_hash160(self, hash).is_some()
199 }
200
201 fn check_older(&self, s: relative::LockTime) -> bool { Satisfier::check_older(self, s) }
202
203 fn check_after(&self, l: absolute::LockTime) -> bool { Satisfier::check_after(self, l) }
204}
205
206#[derive(Debug, Clone)]
213pub struct Plan {
214 pub(crate) template: Vec<Placeholder<DefiniteDescriptorKey>>,
216 pub absolute_timelock: Option<absolute::LockTime>,
218 pub relative_timelock: Option<relative::LockTime>,
220 pub descriptor: Descriptor<DefiniteDescriptorKey>,
222}
223
224impl Plan {
225 pub fn witness_template(&self) -> &Vec<Placeholder<DefiniteDescriptorKey>> { &self.template }
227
228 pub fn witness_version(&self) -> Option<WitnessVersion> {
230 self.descriptor.desc_type().segwit_version()
231 }
232
233 pub fn satisfaction_weight(&self) -> usize { self.witness_size() + self.scriptsig_size() * 4 }
236
237 pub fn scriptsig_size(&self) -> usize {
240 match (self.descriptor.desc_type().segwit_version(), self.descriptor.desc_type()) {
241 (None, _) => witness_size(self.template.as_ref()),
243 (Some(WitnessVersion::V1), _) => 1,
245 (_, DescriptorType::ShWpkh) => 1 + 1 + 1 + 20,
247 (_, DescriptorType::ShWsh) | (_, DescriptorType::ShWshSortedMulti) => 1 + 1 + 1 + 32,
249 _ => 1,
251 }
252 }
253
254 pub fn witness_size(&self) -> usize {
259 if self.descriptor.desc_type().segwit_version().is_some() {
260 witness_size(self.template.as_ref())
261 } else {
262 0
263 }
264 }
265
266 pub fn satisfy<Sat: Satisfier<DefiniteDescriptorKey>>(
268 &self,
269 stfr: &Sat,
270 ) -> Result<(Vec<Vec<u8>>, ScriptBuf), Error> {
271 use bitcoin::blockdata::script::Builder;
272
273 let stack = self
274 .template
275 .iter()
276 .map(|placeholder| placeholder.satisfy_self(stfr))
277 .collect::<Option<Vec<Vec<u8>>>>()
278 .ok_or(Error::CouldNotSatisfy)?;
279
280 Ok(match self.descriptor.desc_type() {
281 DescriptorType::Bare
282 | DescriptorType::Sh
283 | DescriptorType::Pkh
284 | DescriptorType::ShSortedMulti => (
285 vec![],
286 stack
287 .into_iter()
288 .fold(Builder::new(), |builder, item| {
289 let bytes = PushBytesBuf::try_from(item)
290 .expect("All the possible placeholders can be made into PushBytesBuf");
291 builder.push_slice(bytes)
292 })
293 .into_script(),
294 ),
295 DescriptorType::Wpkh
296 | DescriptorType::Wsh
297 | DescriptorType::WshSortedMulti
298 | DescriptorType::Tr => (stack, ScriptBuf::new()),
299 DescriptorType::ShWsh | DescriptorType::ShWshSortedMulti | DescriptorType::ShWpkh => {
300 (stack, self.descriptor.unsigned_script_sig())
301 }
302 })
303 }
304
305 pub fn update_psbt_input(&self, input: &mut psbt::Input) {
311 if let Descriptor::Tr(tr) = &self.descriptor {
312 enum SpendType {
313 KeySpend { internal_key: XOnlyPublicKey },
314 ScriptSpend { leaf_hash: TapLeafHash },
315 }
316
317 #[derive(Default)]
318 struct TrDescriptorData {
319 tap_script: Option<ScriptBuf>,
320 control_block: Option<ControlBlock>,
321 spend_type: Option<SpendType>,
322 key_origins: BTreeMap<XOnlyPublicKey, bip32::KeySource>,
323 }
324
325 let spend_info = tr.spend_info();
326 input.tap_merkle_root = spend_info.merkle_root();
327
328 let data = self
329 .template
330 .iter()
331 .fold(TrDescriptorData::default(), |mut data, item| {
332 match item {
333 Placeholder::TapScript(script) => data.tap_script = Some(script.clone()),
334 Placeholder::TapControlBlock(cb) => data.control_block = Some(cb.clone()),
335 Placeholder::SchnorrSigPk(pk, sig_type, _) => {
336 let raw_pk = pk.to_x_only_pubkey();
337
338 match (&data.spend_type, sig_type) {
339 (None, SchnorrSigType::KeySpend { .. }) => data.spend_type = Some(SpendType::KeySpend { internal_key: raw_pk }),
341 (None, SchnorrSigType::ScriptSpend { leaf_hash }) => data.spend_type = Some(SpendType::ScriptSpend { leaf_hash: *leaf_hash }),
342
343 (Some(SpendType::KeySpend {..}), SchnorrSigType::ScriptSpend { .. }) | (Some(SpendType::ScriptSpend {..}), SchnorrSigType::KeySpend{..}) => unreachable!("Mixed taproot key-spend and script-spend placeholders in the same plan"),
346
347 _ => {},
348 }
349
350 for path in pk.full_derivation_paths() {
351 data.key_origins.insert(raw_pk, (pk.master_fingerprint(), path));
352 }
353 }
354 Placeholder::SchnorrSigPkHash(_, tap_leaf_hash, _) => {
355 data.spend_type = Some(SpendType::ScriptSpend { leaf_hash: *tap_leaf_hash });
356 }
357 _ => {}
358 }
359
360 data
361 });
362
363 let leaf_hash = match data.spend_type {
364 Some(SpendType::KeySpend { internal_key }) => {
365 input.tap_internal_key = Some(internal_key);
366 None
367 }
368 Some(SpendType::ScriptSpend { leaf_hash }) => Some(leaf_hash),
369 _ => None,
370 };
371 for (pk, key_source) in data.key_origins {
372 input
373 .tap_key_origins
374 .entry(pk)
375 .and_modify(|(leaf_hashes, _)| {
376 if let Some(lh) = leaf_hash {
377 if leaf_hashes.iter().all(|&i| i != lh) {
378 leaf_hashes.push(lh);
379 }
380 }
381 })
382 .or_insert_with(|| (vec![], key_source));
383 }
384 if let (Some(tap_script), Some(control_block)) = (data.tap_script, data.control_block) {
385 input
386 .tap_scripts
387 .insert(control_block, (tap_script, LeafVersion::TapScript));
388 }
389 } else {
390 for item in &self.template {
391 if let Placeholder::EcdsaSigPk(pk) = item {
392 let public_key = pk.to_public_key().inner;
393 let master_fingerprint = pk.master_fingerprint();
394 for derivation_path in pk.full_derivation_paths() {
395 input
396 .bip32_derivation
397 .insert(public_key, (master_fingerprint, derivation_path));
398 }
399 }
400 }
401
402 match &self.descriptor {
403 Descriptor::Bare(_) | Descriptor::Pkh(_) | Descriptor::Wpkh(_) => {}
404 Descriptor::Sh(sh) => match sh.as_inner() {
405 descriptor::ShInner::Wsh(wsh) => {
406 input.witness_script = Some(wsh.inner_script());
407 input.redeem_script = Some(wsh.inner_script().to_p2wsh());
408 }
409 descriptor::ShInner::Wpkh(..) => input.redeem_script = Some(sh.inner_script()),
410 descriptor::ShInner::SortedMulti(_) | descriptor::ShInner::Ms(_) => {
411 input.redeem_script = Some(sh.inner_script())
412 }
413 },
414 Descriptor::Wsh(wsh) => input.witness_script = Some(wsh.inner_script()),
415 Descriptor::Tr(_) => unreachable!("Tr is dealt with separately"),
416 }
417 }
418 }
419}
420
421#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
422pub struct CanSign {
426 pub ecdsa: bool,
428 pub taproot: TaprootCanSign,
430}
431
432impl Default for CanSign {
433 fn default() -> Self { CanSign { ecdsa: true, taproot: TaprootCanSign::default() } }
434}
435
436#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
437pub struct TaprootCanSign {
441 pub key_spend: bool,
443 pub script_spend: TaprootAvailableLeaves,
445 pub sighash_default: bool,
447}
448
449impl TaprootCanSign {
450 fn sig_len(&self) -> usize {
451 match self.sighash_default {
452 true => 64,
453 false => 65,
454 }
455 }
456}
457
458impl Default for TaprootCanSign {
459 fn default() -> Self {
460 TaprootCanSign {
461 key_spend: true,
462 script_spend: TaprootAvailableLeaves::Any,
463 sighash_default: true,
464 }
465 }
466}
467
468#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
469pub enum TaprootAvailableLeaves {
471 None,
473 Any,
475 Single(TapLeafHash),
477 Many(Vec<TapLeafHash>),
479}
480
481impl TaprootAvailableLeaves {
482 fn is_available(&self, lh: &TapLeafHash) -> bool {
483 use TaprootAvailableLeaves::*;
484
485 match self {
486 None => false,
487 Any => true,
488 Single(v) => v == lh,
489 Many(list) => list.contains(lh),
490 }
491 }
492}
493
494#[derive(Debug, Default)]
496pub struct Assets {
497 pub keys: BTreeSet<(bip32::KeySource, CanSign)>,
505 pub sha256_preimages: BTreeSet<sha256::Hash>,
507 pub hash256_preimages: BTreeSet<hash256::Hash>,
509 pub ripemd160_preimages: BTreeSet<ripemd160::Hash>,
511 pub hash160_preimages: BTreeSet<hash160::Hash>,
513 pub absolute_timelock: Option<absolute::LockTime>,
515 pub relative_timelock: Option<relative::LockTime>,
517}
518
519fn is_key_direct_child_of(
525 pk: &DefiniteDescriptorKey,
526 derivation_path: &bip32::DerivationPath,
527) -> bool {
528 for pk_derivation_path in pk.full_derivation_paths() {
529 if &pk_derivation_path == derivation_path {
530 return true;
531 }
532
533 let definite_path_len = pk_derivation_path.len();
534 if derivation_path.as_ref() == &pk_derivation_path[..(definite_path_len - 1)] {
535 return true;
536 }
537 }
538
539 false
540}
541
542impl Assets {
543 pub(crate) fn has_ecdsa_key(&self, pk: &DefiniteDescriptorKey) -> bool {
544 self.keys.iter().any(|(keysource, can_sign)| {
545 can_sign.ecdsa
546 && pk.master_fingerprint() == keysource.0
547 && is_key_direct_child_of(pk, &keysource.1)
548 })
549 }
550
551 pub(crate) fn has_taproot_internal_key(&self, pk: &DefiniteDescriptorKey) -> Option<usize> {
552 self.keys.iter().find_map(|(keysource, can_sign)| {
553 if !can_sign.taproot.key_spend
554 || pk.master_fingerprint() != keysource.0
555 || !is_key_direct_child_of(pk, &keysource.1)
556 {
557 None
558 } else {
559 Some(can_sign.taproot.sig_len())
560 }
561 })
562 }
563
564 pub(crate) fn has_taproot_script_key(
565 &self,
566 pk: &DefiniteDescriptorKey,
567 tap_leaf_hash: &TapLeafHash,
568 ) -> Option<usize> {
569 self.keys.iter().find_map(|(keysource, can_sign)| {
570 if !can_sign.taproot.script_spend.is_available(tap_leaf_hash)
571 || pk.master_fingerprint() != keysource.0
572 || !is_key_direct_child_of(pk, &keysource.1)
573 {
574 None
575 } else {
576 Some(can_sign.taproot.sig_len())
577 }
578 })
579 }
580}
581
582impl AssetProvider<DefiniteDescriptorKey> for Assets {
583 fn provider_lookup_ecdsa_sig(&self, pk: &DefiniteDescriptorKey) -> bool {
584 self.has_ecdsa_key(pk)
585 }
586
587 fn provider_lookup_tap_key_spend_sig(&self, pk: &DefiniteDescriptorKey) -> Option<usize> {
588 self.has_taproot_internal_key(pk)
589 }
590
591 fn provider_lookup_tap_leaf_script_sig(
592 &self,
593 pk: &DefiniteDescriptorKey,
594 tap_leaf_hash: &TapLeafHash,
595 ) -> Option<usize> {
596 self.has_taproot_script_key(pk, tap_leaf_hash)
597 }
598
599 fn provider_lookup_sha256(&self, hash: &sha256::Hash) -> bool {
600 self.sha256_preimages.contains(hash)
601 }
602
603 fn provider_lookup_hash256(&self, hash: &hash256::Hash) -> bool {
604 self.hash256_preimages.contains(hash)
605 }
606
607 fn provider_lookup_ripemd160(&self, hash: &ripemd160::Hash) -> bool {
608 self.ripemd160_preimages.contains(hash)
609 }
610
611 fn provider_lookup_hash160(&self, hash: &hash160::Hash) -> bool {
612 self.hash160_preimages.contains(hash)
613 }
614
615 fn check_older(&self, s: relative::LockTime) -> bool {
616 if let Some(timelock) = self.relative_timelock {
617 s.is_implied_by(timelock)
618 } else {
619 false
620 }
621 }
622
623 fn check_after(&self, l: absolute::LockTime) -> bool {
624 if let Some(timelock) = self.absolute_timelock {
625 l.is_implied_by(timelock)
626 } else {
627 false
628 }
629 }
630}
631
632impl FromIterator<DescriptorPublicKey> for Assets {
633 fn from_iter<I: IntoIterator<Item = DescriptorPublicKey>>(iter: I) -> Self {
634 let mut keys = BTreeSet::new();
635 for pk in iter {
636 for deriv_path in pk.full_derivation_paths() {
637 keys.insert(((pk.master_fingerprint(), deriv_path), CanSign::default()));
638 }
639 }
640 Assets { keys, ..Default::default() }
641 }
642}
643
644pub trait IntoAssets {
646 fn into_assets(self) -> Assets;
648}
649
650impl IntoAssets for KeyMap {
651 fn into_assets(self) -> Assets { Assets::from_iter(self.into_iter().map(|(k, _)| k)) }
652}
653
654impl IntoAssets for DescriptorPublicKey {
655 fn into_assets(self) -> Assets { vec![self].into_assets() }
656}
657
658impl IntoAssets for Vec<DescriptorPublicKey> {
659 fn into_assets(self) -> Assets { Assets::from_iter(self) }
660}
661
662impl IntoAssets for sha256::Hash {
663 fn into_assets(self) -> Assets {
664 Assets { sha256_preimages: vec![self].into_iter().collect(), ..Default::default() }
665 }
666}
667
668impl IntoAssets for hash256::Hash {
669 fn into_assets(self) -> Assets {
670 Assets { hash256_preimages: vec![self].into_iter().collect(), ..Default::default() }
671 }
672}
673
674impl IntoAssets for ripemd160::Hash {
675 fn into_assets(self) -> Assets {
676 Assets { ripemd160_preimages: vec![self].into_iter().collect(), ..Default::default() }
677 }
678}
679
680impl IntoAssets for hash160::Hash {
681 fn into_assets(self) -> Assets {
682 Assets { hash160_preimages: vec![self].into_iter().collect(), ..Default::default() }
683 }
684}
685
686impl IntoAssets for Assets {
687 fn into_assets(self) -> Assets { self }
688}
689
690impl Assets {
691 pub fn new() -> Self { Self::default() }
693
694 #[allow(clippy::should_implement_trait)] pub fn add<A: IntoAssets>(mut self, asset: A) -> Self {
697 self.append(asset.into_assets());
698 self
699 }
700
701 pub fn older(mut self, seq: relative::LockTime) -> Self {
703 self.relative_timelock = Some(seq);
704 self
705 }
706
707 pub fn after(mut self, lt: absolute::LockTime) -> Self {
709 self.absolute_timelock = Some(lt);
710 self
711 }
712
713 fn append(&mut self, b: Self) {
714 self.keys.extend(b.keys);
715 self.sha256_preimages.extend(b.sha256_preimages);
716 self.hash256_preimages.extend(b.hash256_preimages);
717 self.ripemd160_preimages.extend(b.ripemd160_preimages);
718 self.hash160_preimages.extend(b.hash160_preimages);
719
720 self.relative_timelock = b.relative_timelock.or(self.relative_timelock);
721 self.absolute_timelock = b.absolute_timelock.or(self.absolute_timelock);
722 }
723}
724
725#[cfg(test)]
726mod test {
727 use std::str::FromStr;
728
729 use bitcoin::bip32::Xpub;
730
731 use super::*;
732 use crate::*;
733
734 #[allow(clippy::type_complexity)]
735 fn test_inner(
736 desc: &str,
737 keys: Vec<DescriptorPublicKey>,
738 hashes: Vec<hash160::Hash>,
739 tests: Vec<(
741 Vec<usize>,
742 Vec<usize>,
743 Option<relative::LockTime>,
744 Option<absolute::LockTime>,
745 Option<usize>,
746 )>,
747 ) {
748 let desc = Descriptor::<DefiniteDescriptorKey>::from_str(desc).unwrap();
749
750 for (key_indexes, hash_indexes, older, after, expected) in tests {
751 let mut assets = Assets::new();
752 if let Some(seq) = older {
753 assets = assets.older(seq);
754 }
755 if let Some(locktime) = after {
756 assets = assets.after(locktime);
757 }
758 for ki in key_indexes {
759 assets = assets.add(keys[ki].clone());
760 }
761 for hi in hash_indexes {
762 assets = assets.add(hashes[hi]);
763 }
764
765 let result = desc.clone().plan(&assets);
766 assert_eq!(
767 result.as_ref().ok().map(|plan| plan.satisfaction_weight()),
768 expected,
769 "{:#?}",
770 result
771 );
772 }
773 }
774
775 #[test]
776 fn test_or() {
777 let keys = vec![
778 DescriptorPublicKey::from_str(
779 "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
780 )
781 .unwrap(),
782 DescriptorPublicKey::from_str(
783 "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a",
784 )
785 .unwrap(),
786 ];
787 let hashes = vec![];
788 let desc = format!("wsh(t:or_c(pk({}),v:pkh({})))", keys[0], keys[1]);
789
790 let tests = vec![
792 (vec![], vec![], None, None, None),
793 (vec![0], vec![], None, None, Some(4 + 1 + 73)),
794 (vec![0, 1], vec![], None, None, Some(4 + 1 + 73)),
795 ];
796
797 test_inner(&desc, keys, hashes, tests);
798 }
799
800 #[test]
801 fn test_and() {
802 let keys = vec![
803 DescriptorPublicKey::from_str(
804 "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
805 )
806 .unwrap(),
807 DescriptorPublicKey::from_str(
808 "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a",
809 )
810 .unwrap(),
811 ];
812 let hashes = vec![];
813 let desc = format!("wsh(and_v(v:pk({}),pk({})))", keys[0], keys[1]);
814
815 let tests = vec![
817 (vec![], vec![], None, None, None),
818 (vec![0], vec![], None, None, None),
819 (vec![0, 1], vec![], None, None, Some(4 + 1 + 73 * 2)),
820 ];
821
822 test_inner(&desc, keys, hashes, tests);
823 }
824
825 #[test]
826 fn test_multi() {
827 let keys = vec![
828 DescriptorPublicKey::from_str(
829 "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
830 )
831 .unwrap(),
832 DescriptorPublicKey::from_str(
833 "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a",
834 )
835 .unwrap(),
836 DescriptorPublicKey::from_str(
837 "03500a2b48b0f66c8183cc0d6645ab21cc19c7fad8a33ff04d41c3ece54b0bc1c5",
838 )
839 .unwrap(),
840 DescriptorPublicKey::from_str(
841 "033ad2d191da4f39512adbaac320cae1f12f298386a4e9d43fd98dec7cf5db2ac9",
842 )
843 .unwrap(),
844 ];
845 let hashes = vec![];
846 let desc = format!("wsh(multi(3,{},{},{},{}))", keys[0], keys[1], keys[2], keys[3]);
847
848 let tests = vec![
849 (vec![], vec![], None, None, None),
850 (vec![0, 1], vec![], None, None, None),
851 (vec![0, 1, 3], vec![], None, None, Some(4 + 1 + 73 * 3 + 1)),
853 ];
854
855 test_inner(&desc, keys, hashes, tests);
856 }
857
858 #[test]
859 fn test_thresh() {
860 use bitcoin::Sequence;
862 let keys = vec![
863 DescriptorPublicKey::from_str(
864 "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
865 )
866 .unwrap(),
867 DescriptorPublicKey::from_str(
868 "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a",
869 )
870 .unwrap(),
871 ];
872 let hashes = vec![];
873 let desc = format!("wsh(thresh(2,pk({}),s:pk({}),snl:older(144)))", keys[0], keys[1]);
874
875 let tests = vec![
876 (vec![], vec![], None, None, None),
877 (
878 vec![],
879 vec![],
880 Some(Sequence(1000).to_relative_lock_time().unwrap()),
881 None,
882 None,
883 ),
884 (vec![0], vec![], None, None, None),
885 (
887 vec![0],
888 vec![],
889 Some(Sequence(1000).to_relative_lock_time().unwrap()),
890 None,
891 Some(80),
892 ),
893 (vec![0, 1], vec![], None, None, Some(153)),
895 (
897 vec![0, 1],
898 vec![],
899 Some(Sequence(1000).to_relative_lock_time().unwrap()),
900 None,
901 Some(80),
902 ),
903 (
905 vec![0, 1],
906 vec![],
907 Some(
908 Sequence::from_512_second_intervals(10)
909 .to_relative_lock_time()
910 .unwrap(),
911 ),
912 None,
913 Some(153),
914 ), ];
916
917 test_inner(&desc, keys.clone(), hashes.clone(), tests);
918
919 let desc = format!("wsh(thresh(2,pk({}),s:pk({}),snl:after(144)))", keys[0], keys[1]);
920
921 let tests = vec![
922 (
924 vec![0],
925 vec![],
926 None,
927 Some(absolute::LockTime::from_height(1000).unwrap()),
928 Some(80),
929 ),
930 (
932 vec![0, 1],
933 vec![],
934 None,
935 Some(absolute::LockTime::from_time(500_001_000).unwrap()),
936 Some(153),
937 ), ];
939
940 test_inner(&desc, keys, hashes, tests);
941 }
942
943 #[test]
944 fn test_taproot() {
945 let keys = vec![
946 DescriptorPublicKey::from_str(
947 "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
948 )
949 .unwrap(),
950 DescriptorPublicKey::from_str(
951 "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a",
952 )
953 .unwrap(),
954 DescriptorPublicKey::from_str(
955 "03500a2b48b0f66c8183cc0d6645ab21cc19c7fad8a33ff04d41c3ece54b0bc1c5",
956 )
957 .unwrap(),
958 DescriptorPublicKey::from_str(
959 "033ad2d191da4f39512adbaac320cae1f12f298386a4e9d43fd98dec7cf5db2ac9",
960 )
961 .unwrap(),
962 DescriptorPublicKey::from_str(
963 "023fc33527afab09fa97135f2180bcd22ce637b1d2fbcb2db748b1f2c33f45b2b4",
964 )
965 .unwrap(),
966 ];
967 let hashes = vec![];
968 let desc = format!(
978 "tr({},{{pk({}),{{multi_a(1,{},{}),and_v(v:pk({}),after(10))}}}})",
979 keys[0], keys[1], keys[2], keys[3], keys[4]
980 );
981
982 let internal_key_sat_weight = Some(70);
984 let first_leaf_sat_weight = Some(171);
990 let second_leaf_sat_weight = Some(240);
1000 let third_leaf_sat_weight = Some(205);
1008
1009 let tests = vec![
1010 (vec![], vec![], None, None, None),
1012 (vec![0], vec![], None, None, internal_key_sat_weight),
1014 (vec![1], vec![], None, None, first_leaf_sat_weight),
1016 (vec![2], vec![], None, None, second_leaf_sat_weight),
1018 (vec![2, 3], vec![], None, None, second_leaf_sat_weight),
1020 (
1022 vec![4],
1023 vec![],
1024 None,
1025 Some(absolute::LockTime::from_height(10).unwrap()),
1026 third_leaf_sat_weight,
1027 ),
1028 (vec![4], vec![], None, Some(absolute::LockTime::from_height(9).unwrap()), None),
1031 (
1034 vec![4],
1035 vec![],
1036 None,
1037 Some(absolute::LockTime::from_time(1296000000).unwrap()),
1038 None,
1039 ),
1040 (vec![4], vec![], None, None, None),
1043 (vec![0, 1, 2, 3, 4], vec![], None, None, internal_key_sat_weight),
1045 (vec![1, 2, 3, 4], vec![], None, None, first_leaf_sat_weight),
1047 (vec![2, 3, 4], vec![], None, None, second_leaf_sat_weight),
1049 (
1051 vec![2, 3, 4],
1052 vec![],
1053 None,
1054 Some(absolute::LockTime::from_consensus(11)),
1055 third_leaf_sat_weight,
1056 ),
1057 ];
1058
1059 test_inner(&desc, keys, hashes, tests);
1060 }
1061
1062 #[test]
1063 fn test_hash() {
1064 let keys = vec![DescriptorPublicKey::from_str(
1065 "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
1066 )
1067 .unwrap()];
1068 let hashes = vec![hash160::Hash::from_slice(&[0; 20]).unwrap()];
1069 let desc = format!("wsh(and_v(v:pk({}),hash160({})))", keys[0], hashes[0]);
1070
1071 let tests = vec![
1072 (vec![], vec![], None, None, None),
1074 (vec![0], vec![], None, None, None),
1076 (vec![], vec![0], None, None, None),
1078 (vec![0], vec![0], None, None, Some(111)),
1081 ];
1082
1083 test_inner(&desc, keys, hashes, tests);
1084 }
1085
1086 #[test]
1087 fn test_plan_update_psbt_tr() {
1088 let root_xpub = Xpub::from_str("xpub661MyMwAqRbcFkPHucMnrGNzDwb6teAX1RbKQmqtEF8kK3Z7LZ59qafCjB9eCRLiTVG3uxBxgKvRgbubRhqSKXnGGb1aoaqLrpMBDrVxga8").unwrap();
1090 let fingerprint = root_xpub.fingerprint();
1091 let xpub = format!("[{}/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ", fingerprint);
1092 let desc =
1093 format!("tr({}/0/0,{{pkh({}/0/1),multi_a(2,{}/1/0,{}/1/1)}})", xpub, xpub, xpub, xpub);
1094
1095 let desc = Descriptor::from_str(&desc).unwrap();
1096
1097 let internal_key = DescriptorPublicKey::from_str(&format!("{}/0/0", xpub)).unwrap();
1098 let first_branch = DescriptorPublicKey::from_str(&format!("{}/0/1", xpub)).unwrap();
1099 let second_branch = DescriptorPublicKey::from_str(&format!("{}/1/*", xpub)).unwrap(); let mut psbt_input = bitcoin::psbt::Input::default();
1102 let assets = Assets::new().add(internal_key);
1103 desc.clone()
1104 .plan(&assets)
1105 .unwrap()
1106 .update_psbt_input(&mut psbt_input);
1107 assert!(psbt_input.tap_internal_key.is_some(), "Internal key is missing");
1108 assert!(psbt_input.tap_merkle_root.is_some(), "Merkle root is missing");
1109 assert_eq!(psbt_input.tap_key_origins.len(), 1, "Unexpected number of tap_key_origins");
1110 assert_eq!(psbt_input.tap_scripts.len(), 0, "Unexpected number of tap_scripts");
1111
1112 let mut psbt_input = bitcoin::psbt::Input::default();
1113 let assets = Assets::new().add(first_branch);
1114 desc.clone()
1115 .plan(&assets)
1116 .unwrap()
1117 .update_psbt_input(&mut psbt_input);
1118 assert!(psbt_input.tap_internal_key.is_none(), "Internal key is present");
1119 assert!(psbt_input.tap_merkle_root.is_some(), "Merkle root is missing");
1120 assert_eq!(psbt_input.tap_key_origins.len(), 1, "Unexpected number of tap_key_origins");
1121 assert_eq!(psbt_input.tap_scripts.len(), 1, "Unexpected number of tap_scripts");
1122
1123 let mut psbt_input = bitcoin::psbt::Input::default();
1124 let assets = Assets::new().add(second_branch);
1125 desc.plan(&assets)
1126 .unwrap()
1127 .update_psbt_input(&mut psbt_input);
1128 assert!(psbt_input.tap_internal_key.is_none(), "Internal key is present");
1129 assert!(psbt_input.tap_merkle_root.is_some(), "Merkle root is missing");
1130 assert_eq!(psbt_input.tap_key_origins.len(), 2, "Unexpected number of tap_key_origins");
1131 assert_eq!(psbt_input.tap_scripts.len(), 1, "Unexpected number of tap_scripts");
1132 }
1133
1134 #[test]
1135 fn test_plan_update_psbt_segwit() {
1136 let root_xpub = Xpub::from_str("xpub661MyMwAqRbcFkPHucMnrGNzDwb6teAX1RbKQmqtEF8kK3Z7LZ59qafCjB9eCRLiTVG3uxBxgKvRgbubRhqSKXnGGb1aoaqLrpMBDrVxga8").unwrap();
1138 let fingerprint = root_xpub.fingerprint();
1139 let xpub = format!("[{}/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ", fingerprint);
1140 let desc = format!("wsh(multi(2,{}/1/0,{}/1/1))", xpub, xpub);
1141
1142 let desc = Descriptor::from_str(&desc).unwrap();
1143
1144 let asset_key = DescriptorPublicKey::from_str(&format!("{}/1/*", xpub)).unwrap(); let mut psbt_input = bitcoin::psbt::Input::default();
1147 let assets = Assets::new().add(asset_key);
1148 desc.plan(&assets)
1149 .unwrap()
1150 .update_psbt_input(&mut psbt_input);
1151 assert!(psbt_input.witness_script.is_some(), "Witness script missing");
1152 assert!(psbt_input.redeem_script.is_none(), "Redeem script present");
1153 assert_eq!(psbt_input.bip32_derivation.len(), 2, "Unexpected number of bip32_derivation");
1154 }
1155}