// Magical Bitcoin Library // Written in 2020 by // Alekos Filini // // Copyright (c) 2020 Magical Bitcoin // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //! Descriptors //! //! This module contains generic utilities to work with descriptors, plus some re-exported types //! from [`miniscript`]. use std::collections::{BTreeMap, HashMap}; use std::fmt; use std::sync::Arc; use bitcoin::hashes::hash160; use bitcoin::secp256k1::Secp256k1; use bitcoin::util::bip32::{ChildNumber, DerivationPath, Fingerprint}; use bitcoin::util::psbt; use bitcoin::{PublicKey, Script, TxOut}; use miniscript::descriptor::{DescriptorPublicKey, DescriptorXKey, InnerXKey, KeyMap}; pub use miniscript::{ Descriptor, Legacy, Miniscript, MiniscriptKey, ScriptContext, Segwitv0, Terminal, ToPublicKey, }; pub mod checksum; mod dsl; pub mod error; pub mod policy; pub use self::checksum::get_checksum; use self::error::Error; pub use self::policy::Policy; use crate::wallet::signer::SignersContainer; /// Alias for a [`Descriptor`] that can contain extended keys using [`DescriptorPublicKey`] pub type ExtendedDescriptor = Descriptor; /// Alias for the type of maps that represent derivation paths in a [`psbt::Input`] or /// [`psbt::Output`] /// /// [`psbt::Input`]: bitcoin::util::psbt::Input /// [`psbt::Output`]: bitcoin::util::psbt::Output pub type HDKeyPaths = BTreeMap; /// Trait for types which can be converted into an [`ExtendedDescriptor`] and a [`KeyMap`] usable by a wallet pub trait ToWalletDescriptor { fn to_wallet_descriptor(self) -> Result<(ExtendedDescriptor, KeyMap), Error>; } impl ToWalletDescriptor for &str { fn to_wallet_descriptor(self) -> Result<(ExtendedDescriptor, KeyMap), Error> { Ok(ExtendedDescriptor::parse_secret(self)?) } } impl ToWalletDescriptor for &String { fn to_wallet_descriptor(self) -> Result<(ExtendedDescriptor, KeyMap), Error> { self.as_str().to_wallet_descriptor() } } impl ToWalletDescriptor for (ExtendedDescriptor, KeyMap) { fn to_wallet_descriptor(self) -> Result<(ExtendedDescriptor, KeyMap), Error> { Ok(self) } } impl ToWalletDescriptor for ExtendedDescriptor { fn to_wallet_descriptor(self) -> Result<(ExtendedDescriptor, KeyMap), Error> { (self, KeyMap::default()).to_wallet_descriptor() } } /// Trait implemented on [`Descriptor`]s to add a method to extract the spending [`policy`] pub trait ExtractPolicy { fn extract_policy( &self, signers: Arc>, ) -> Result, Error>; } pub(crate) trait XKeyUtils { fn full_path(&self, append: &[ChildNumber]) -> DerivationPath; fn root_fingerprint(&self) -> Fingerprint; } impl XKeyUtils for DescriptorXKey { fn full_path(&self, append: &[ChildNumber]) -> DerivationPath { let full_path = match &self.source { &Some((_, ref path)) => path .into_iter() .chain(self.derivation_path.into_iter()) .cloned() .collect(), &None => self.derivation_path.clone(), }; if self.is_wildcard { full_path .into_iter() .chain(append.into_iter()) .cloned() .collect() } else { full_path } } fn root_fingerprint(&self) -> Fingerprint { match &self.source { &Some((fingerprint, _)) => fingerprint.clone(), &None => self.xkey.xkey_fingerprint(), } } } pub(crate) trait DescriptorMeta: Sized { fn is_witness(&self) -> bool; fn get_hd_keypaths(&self, index: u32) -> Result; fn is_fixed(&self) -> bool; fn derive_from_hd_keypaths(&self, hd_keypaths: &HDKeyPaths) -> Option; fn derive_from_psbt_input(&self, psbt_input: &psbt::Input, utxo: Option) -> Option; } pub(crate) trait DescriptorScripts { fn psbt_redeem_script(&self) -> Option