Merge commit 'refs/pull/264/head' of github.com:bitcoindevkit/bdk

This commit is contained in:
Alekos Filini 2021-01-12 14:02:41 +01:00
commit 6955a7776d
No known key found for this signature in database
GPG Key ID: 431401E4A4530061
9 changed files with 190 additions and 106 deletions

View File

@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
### Descriptor
#### Changed
- Added an alias `DescriptorError` for `descriptor::error::Error`
- Changed the error returned by `descriptor!()` and `fragment!()` to `DescriptorError`
- Changed the error type in `ToWalletDescriptor` to `DescriptorError`
- Improved checks on descriptors built using the macros
### Blockchain ### Blockchain
#### Changed #### Changed
- Remove `BlockchainMarker`, `OfflineClient` and `OfflineWallet` in favor of just using the unit - Remove `BlockchainMarker`, `OfflineClient` and `OfflineWallet` in favor of just using the unit

View File

@ -36,14 +36,12 @@
//! # use bdk::database::{AnyDatabase, MemoryDatabase}; //! # use bdk::database::{AnyDatabase, MemoryDatabase};
//! # use bdk::{Wallet}; //! # use bdk::{Wallet};
//! let memory = MemoryDatabase::default(); //! let memory = MemoryDatabase::default();
//! let wallet_memory = //! let wallet_memory = Wallet::new_offline("...", None, Network::Testnet, memory)?;
//! Wallet::new_offline("...", None, Network::Testnet, memory)?;
//! //!
//! # #[cfg(feature = "key-value-db")] //! # #[cfg(feature = "key-value-db")]
//! # { //! # {
//! let sled = sled::open("my-database")?.open_tree("default_tree")?; //! let sled = sled::open("my-database")?.open_tree("default_tree")?;
//! let wallet_sled = //! let wallet_sled = Wallet::new_offline("...", None, Network::Testnet, sled)?;
//! Wallet::new_offline("...", None, Network::Testnet, sled)?;
//! # } //! # }
//! # Ok::<(), bdk::Error>(()) //! # Ok::<(), bdk::Error>(())
//! ``` //! ```

View File

@ -29,7 +29,7 @@
use std::iter::FromIterator; use std::iter::FromIterator;
use crate::descriptor::Error; use crate::descriptor::DescriptorError;
const INPUT_CHARSET: &str = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ "; const INPUT_CHARSET: &str = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ ";
const CHECKSUM_CHARSET: &str = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; const CHECKSUM_CHARSET: &str = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
@ -57,14 +57,14 @@ fn poly_mod(mut c: u64, val: u64) -> u64 {
} }
/// Compute the checksum of a descriptor /// Compute the checksum of a descriptor
pub fn get_checksum(desc: &str) -> Result<String, Error> { pub fn get_checksum(desc: &str) -> Result<String, DescriptorError> {
let mut c = 1; let mut c = 1;
let mut cls = 0; let mut cls = 0;
let mut clscount = 0; let mut clscount = 0;
for ch in desc.chars() { for ch in desc.chars() {
let pos = INPUT_CHARSET let pos = INPUT_CHARSET
.find(ch) .find(ch)
.ok_or(Error::InvalidDescriptorCharacter(ch))? as u64; .ok_or(DescriptorError::InvalidDescriptorCharacter(ch))? as u64;
c = poly_mod(c, pos & 31); c = poly_mod(c, pos & 31);
cls = cls * 3 + (pos >> 5); cls = cls * 3 + (pos >> 5);
clscount += 1; clscount += 1;
@ -120,7 +120,7 @@ mod test {
assert!(matches!( assert!(matches!(
get_checksum(&invalid_desc).err(), get_checksum(&invalid_desc).err(),
Some(Error::InvalidDescriptorCharacter(invalid_char)) if invalid_char == sparkle_heart Some(DescriptorError::InvalidDescriptorCharacter(invalid_char)) if invalid_char == sparkle_heart
)); ));
} }
} }

View File

@ -60,6 +60,7 @@ macro_rules! impl_top_level_pk {
$key.to_descriptor_key() $key.to_descriptor_key()
.and_then(|key: DescriptorKey<$ctx>| key.extract(&secp)) .and_then(|key: DescriptorKey<$ctx>| key.extract(&secp))
.map_err($crate::descriptor::DescriptorError::Key)
.map(|(pk, key_map, valid_networks)| { .map(|(pk, key_map, valid_networks)| {
( (
$crate::miniscript::Descriptor::< $crate::miniscript::Descriptor::<
@ -75,11 +76,17 @@ macro_rules! impl_top_level_pk {
#[doc(hidden)] #[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! impl_leaf_opcode { macro_rules! impl_leaf_opcode {
( $terminal_variant:ident ) => { ( $terminal_variant:ident ) => {{
use $crate::descriptor::CheckMiniscript;
$crate::miniscript::Miniscript::from_ast( $crate::miniscript::Miniscript::from_ast(
$crate::miniscript::miniscript::decode::Terminal::$terminal_variant, $crate::miniscript::miniscript::decode::Terminal::$terminal_variant,
) )
.map_err($crate::Error::Miniscript) .map_err($crate::descriptor::DescriptorError::Miniscript)
.and_then(|minisc| {
minisc.check_minsicript()?;
Ok(minisc)
})
.map(|minisc| { .map(|minisc| {
( (
minisc, minisc,
@ -87,17 +94,23 @@ macro_rules! impl_leaf_opcode {
$crate::keys::any_network(), $crate::keys::any_network(),
) )
}) })
}; }};
} }
#[doc(hidden)] #[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! impl_leaf_opcode_value { macro_rules! impl_leaf_opcode_value {
( $terminal_variant:ident, $value:expr ) => { ( $terminal_variant:ident, $value:expr ) => {{
use $crate::descriptor::CheckMiniscript;
$crate::miniscript::Miniscript::from_ast( $crate::miniscript::Miniscript::from_ast(
$crate::miniscript::miniscript::decode::Terminal::$terminal_variant($value), $crate::miniscript::miniscript::decode::Terminal::$terminal_variant($value),
) )
.map_err($crate::Error::Miniscript) .map_err($crate::descriptor::DescriptorError::Miniscript)
.and_then(|minisc| {
minisc.check_minsicript()?;
Ok(minisc)
})
.map(|minisc| { .map(|minisc| {
( (
minisc, minisc,
@ -105,17 +118,23 @@ macro_rules! impl_leaf_opcode_value {
$crate::keys::any_network(), $crate::keys::any_network(),
) )
}) })
}; }};
} }
#[doc(hidden)] #[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! impl_leaf_opcode_value_two { macro_rules! impl_leaf_opcode_value_two {
( $terminal_variant:ident, $one:expr, $two:expr ) => { ( $terminal_variant:ident, $one:expr, $two:expr ) => {{
use $crate::descriptor::CheckMiniscript;
$crate::miniscript::Miniscript::from_ast( $crate::miniscript::Miniscript::from_ast(
$crate::miniscript::miniscript::decode::Terminal::$terminal_variant($one, $two), $crate::miniscript::miniscript::decode::Terminal::$terminal_variant($one, $two),
) )
.map_err($crate::Error::Miniscript) .map_err($crate::descriptor::DescriptorError::Miniscript)
.and_then(|minisc| {
minisc.check_minsicript()?;
Ok(minisc)
})
.map(|minisc| { .map(|minisc| {
( (
minisc, minisc,
@ -123,13 +142,15 @@ macro_rules! impl_leaf_opcode_value_two {
$crate::keys::any_network(), $crate::keys::any_network(),
) )
}) })
}; }};
} }
#[doc(hidden)] #[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! impl_node_opcode_two { macro_rules! impl_node_opcode_two {
( $terminal_variant:ident, $( $inner:tt )* ) => ({ ( $terminal_variant:ident, $( $inner:tt )* ) => ({
use $crate::descriptor::CheckMiniscript;
let inner = $crate::fragment_internal!( @t $( $inner )* ); let inner = $crate::fragment_internal!( @t $( $inner )* );
let (a, b) = $crate::descriptor::dsl::TupleTwo::from(inner).flattened(); let (a, b) = $crate::descriptor::dsl::TupleTwo::from(inner).flattened();
@ -139,10 +160,14 @@ macro_rules! impl_node_opcode_two {
// join key_maps // join key_maps
a_keymap.extend(b_keymap.into_iter()); a_keymap.extend(b_keymap.into_iter());
Ok(($crate::miniscript::Miniscript::from_ast($crate::miniscript::miniscript::decode::Terminal::$terminal_variant( let minisc = $crate::miniscript::Miniscript::from_ast($crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
std::sync::Arc::new(a_minisc), std::sync::Arc::new(a_minisc),
std::sync::Arc::new(b_minisc), std::sync::Arc::new(b_minisc),
))?, a_keymap, $crate::keys::merge_networks(&a_networks, &b_networks))) ))?;
minisc.check_minsicript()?;
Ok((minisc, a_keymap, $crate::keys::merge_networks(&a_networks, &b_networks)))
}) })
}); });
} }
@ -151,6 +176,8 @@ macro_rules! impl_node_opcode_two {
#[macro_export] #[macro_export]
macro_rules! impl_node_opcode_three { macro_rules! impl_node_opcode_three {
( $terminal_variant:ident, $( $inner:tt )* ) => { ( $terminal_variant:ident, $( $inner:tt )* ) => {
use $crate::descriptor::CheckMiniscript;
let inner = $crate::fragment_internal!( @t $( $inner )* ); let inner = $crate::fragment_internal!( @t $( $inner )* );
let (a, b, c) = $crate::descriptor::dsl::TupleThree::from(inner).flattened(); let (a, b, c) = $crate::descriptor::dsl::TupleThree::from(inner).flattened();
@ -164,11 +191,15 @@ macro_rules! impl_node_opcode_three {
let networks = $crate::keys::merge_networks(&a_networks, &b_networks); let networks = $crate::keys::merge_networks(&a_networks, &b_networks);
let networks = $crate::keys::merge_networks(&networks, &c_networks); let networks = $crate::keys::merge_networks(&networks, &c_networks);
Ok(($crate::miniscript::Miniscript::from_ast($crate::miniscript::miniscript::decode::Terminal::$terminal_variant( let minisc = $crate::miniscript::Miniscript::from_ast($crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
std::sync::Arc::new(a_minisc), std::sync::Arc::new(a_minisc),
std::sync::Arc::new(b_minisc), std::sync::Arc::new(b_minisc),
std::sync::Arc::new(c_minisc), std::sync::Arc::new(c_minisc),
))?, a_keymap, networks)) ))?;
minisc.check_minsicript()?;
Ok((minisc, a_keymap, networks))
}) })
}; };
} }
@ -190,6 +221,7 @@ macro_rules! impl_sortedmulti {
)* )*
keys.into_iter().collect::<Result<Vec<_>, _>>() keys.into_iter().collect::<Result<Vec<_>, _>>()
.map_err($crate::descriptor::DescriptorError::Key)
.and_then(|keys| $crate::keys::make_sortedmulti_inner($thresh, keys, &secp)) .and_then(|keys| $crate::keys::make_sortedmulti_inner($thresh, keys, &secp))
}); });
@ -199,18 +231,20 @@ macro_rules! impl_sortedmulti {
#[macro_export] #[macro_export]
macro_rules! apply_modifier { macro_rules! apply_modifier {
( $terminal_variant:ident, $inner:expr ) => {{ ( $terminal_variant:ident, $inner:expr ) => {{
use $crate::descriptor::CheckMiniscript;
$inner $inner
.map_err(|e| -> $crate::Error { e.into() }) .map_err(|e| -> $crate::descriptor::DescriptorError { e.into() })
.and_then(|(minisc, keymap, networks)| { .and_then(|(minisc, keymap, networks)| {
Ok(( let minisc = $crate::miniscript::Miniscript::from_ast(
$crate::miniscript::Miniscript::from_ast( $crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
$crate::miniscript::miniscript::decode::Terminal::$terminal_variant( std::sync::Arc::new(minisc),
std::sync::Arc::new(minisc), ),
), )?;
)?,
keymap, minisc.check_minsicript()?;
networks,
)) Ok((minisc, keymap, networks))
}) })
}}; }};
@ -272,7 +306,7 @@ macro_rules! apply_modifier {
/// Macro to write full descriptors with code /// Macro to write full descriptors with code
/// ///
/// This macro expands to a `Result` of /// This macro expands to a `Result` of
/// [`DescriptorTemplateOut`](super::template::DescriptorTemplateOut) and [`Error`](crate::Error) /// [`DescriptorTemplateOut`](super::template::DescriptorTemplateOut) and [`DescriptorError`](crate::descriptor::DescriptorError)
/// ///
/// The syntax is very similar to the normal descriptor syntax, with the exception that modifiers /// The syntax is very similar to the normal descriptor syntax, with the exception that modifiers
/// cannot be grouped together. For instance, a descriptor fragment like `sdv:older(144)` has to be /// cannot be grouped together. For instance, a descriptor fragment like `sdv:older(144)` has to be
@ -305,8 +339,11 @@ macro_rules! apply_modifier {
/// ///
/// ``` /// ```
/// # use std::str::FromStr; /// # use std::str::FromStr;
/// let my_key_1 = bitcoin::PublicKey::from_str("02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c")?; /// let my_key_1 = bitcoin::PublicKey::from_str(
/// let my_key_2 = bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?; /// "02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c",
/// )?;
/// let my_key_2 =
/// bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
/// let my_timelock = 50; /// let my_timelock = 50;
/// ///
/// let (descriptor_a, key_map_a, networks) = bdk::descriptor! { /// let (descriptor_a, key_map_a, networks) = bdk::descriptor! {
@ -315,12 +352,13 @@ macro_rules! apply_modifier {
/// ) /// )
/// }?; /// }?;
/// ///
/// #[rustfmt::skip]
/// let b_items = vec![ /// let b_items = vec![
/// bdk::fragment!(pk(my_key_1))?, /// bdk::fragment!(pk(my_key_1))?,
/// bdk::fragment!(s:pk(my_key_2))?, /// bdk::fragment!(s:pk(my_key_2))?,
/// bdk::fragment!(s:d:v:older(my_timelock))?, /// bdk::fragment!(s:d:v:older(my_timelock))?,
/// ]; /// ];
/// let (descriptor_b, mut key_map_b, networks) = bdk::descriptor!(wsh(thresh_vec(2,b_items)))?; /// let (descriptor_b, mut key_map_b, networks) = bdk::descriptor!(wsh(thresh_vec(2, b_items)))?;
/// ///
/// assert_eq!(descriptor_a, descriptor_b); /// assert_eq!(descriptor_a, descriptor_b);
/// assert_eq!(key_map_a.len(), key_map_b.len()); /// assert_eq!(key_map_a.len(), key_map_b.len());
@ -496,7 +534,7 @@ macro_rules! fragment_internal {
/// Macro to write descriptor fragments with code /// Macro to write descriptor fragments with code
/// ///
/// This macro will be expanded to an object of type `Result<(Miniscript<DescriptorPublicKey, _>, KeyMap, ValidNetworks), Error>`. It allows writing /// This macro will be expanded to an object of type `Result<(Miniscript<DescriptorPublicKey, _>, KeyMap, ValidNetworks), DescriptorError>`. It allows writing
/// fragments of larger descriptors that can be pieced together using `fragment!(thresh_vec(m, ...))`. /// fragments of larger descriptors that can be pieced together using `fragment!(thresh_vec(m, ...))`.
/// ///
/// The syntax to write macro fragment is the same as documented for the [`descriptor`] macro. /// The syntax to write macro fragment is the same as documented for the [`descriptor`] macro.
@ -599,6 +637,7 @@ macro_rules! fragment {
)* )*
keys.into_iter().collect::<Result<Vec<_>, _>>() keys.into_iter().collect::<Result<Vec<_>, _>>()
.map_err($crate::descriptor::DescriptorError::Key)
.and_then(|keys| $crate::keys::make_multi($thresh, keys, &secp)) .and_then(|keys| $crate::keys::make_multi($thresh, keys, &secp))
}); });
@ -620,8 +659,8 @@ mod test {
use std::str::FromStr; use std::str::FromStr;
use crate::descriptor::DescriptorMeta; use crate::descriptor::{DescriptorError, DescriptorMeta};
use crate::keys::{DescriptorKey, KeyError, ToDescriptorKey, ValidNetworks}; use crate::keys::{DescriptorKey, ToDescriptorKey, ValidNetworks};
use bitcoin::network::constants::Network::{Bitcoin, Regtest, Testnet}; use bitcoin::network::constants::Network::{Bitcoin, Regtest, Testnet};
use bitcoin::util::bip32; use bitcoin::util::bip32;
use bitcoin::util::bip32::ChildNumber; use bitcoin::util::bip32::ChildNumber;
@ -631,7 +670,7 @@ mod test {
// verify descriptor generates expected script(s) (if bare or pk) or address(es) // verify descriptor generates expected script(s) (if bare or pk) or address(es)
fn check( fn check(
desc: Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), KeyError>, desc: Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), DescriptorError>,
is_witness: bool, is_witness: bool,
is_fixed: bool, is_fixed: bool,
expected: &[&str], expected: &[&str],
@ -978,4 +1017,15 @@ mod test {
assert_eq!(descriptor.to_string(), "wsh(thresh(2,dv:older(1),s:pk(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c),s:pk(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c)))") assert_eq!(descriptor.to_string(), "wsh(thresh(2,dv:older(1),s:pk(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c),s:pk(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c)))")
} }
// TODO: uncomment once https://github.com/rust-bitcoin/rust-miniscript/pull/221 is released
//
// #[test]
// #[should_panic(expected = "Miniscript(ContextError(CompressedOnly))")]
// fn test_dsl_miniscript_checks() {
// let mut uncompressed_pk = PrivateKey::from_wif("L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6").unwrap();
// uncompressed_pk.compressed = false;
// descriptor!(wsh(v:pk(uncompressed_pk))).unwrap();
// }
} }

View File

@ -27,26 +27,19 @@
/// Errors related to the parsing and usage of descriptors /// Errors related to the parsing and usage of descriptors
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
//InternalError,
//InvalidPrefix(Vec<u8>),
//HardenedDerivationOnXpub,
//MalformedInput,
/// Invalid HD Key path, such as having a wildcard but a length != 1 /// Invalid HD Key path, such as having a wildcard but a length != 1
InvalidHDKeyPath, InvalidHDKeyPath,
/// The provided descriptor doesn't match its checksum
InvalidDescriptorChecksum,
//KeyParsingError(String),
/// Error thrown while working with [`keys`](crate::keys) /// Error thrown while working with [`keys`](crate::keys)
Key(crate::keys::KeyError), Key(crate::keys::KeyError),
/// Error while extracting and manipulating policies /// Error while extracting and manipulating policies
Policy(crate::descriptor::policy::PolicyError), Policy(crate::descriptor::policy::PolicyError),
//InputIndexDoesntExist,
//MissingPublicKey,
//MissingDetails,
/// Invalid character found in the descriptor checksum /// Invalid character found in the descriptor checksum
InvalidDescriptorCharacter(char), InvalidDescriptorCharacter(char),
//CantDeriveWithMiniscript,
/// BIP32 error /// BIP32 error
BIP32(bitcoin::util::bip32::Error), BIP32(bitcoin::util::bip32::Error),
/// Error during base58 decoding /// Error during base58 decoding

View File

@ -49,7 +49,7 @@ pub mod policy;
pub mod template; pub mod template;
pub use self::checksum::get_checksum; pub use self::checksum::get_checksum;
use self::error::Error; pub use self::error::Error as DescriptorError;
pub use self::policy::Policy; pub use self::policy::Policy;
use self::template::DescriptorTemplateOut; use self::template::DescriptorTemplateOut;
use crate::keys::{KeyError, ToDescriptorKey}; use crate::keys::{KeyError, ToDescriptorKey};
@ -72,14 +72,14 @@ pub trait ToWalletDescriptor {
fn to_wallet_descriptor( fn to_wallet_descriptor(
self, self,
network: Network, network: Network,
) -> Result<(ExtendedDescriptor, KeyMap), KeyError>; ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError>;
} }
impl ToWalletDescriptor for &str { impl ToWalletDescriptor for &str {
fn to_wallet_descriptor( fn to_wallet_descriptor(
self, self,
network: Network, network: Network,
) -> Result<(ExtendedDescriptor, KeyMap), KeyError> { ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
let descriptor = if self.contains('#') { let descriptor = if self.contains('#') {
let parts: Vec<&str> = self.splitn(2, '#').collect(); let parts: Vec<&str> = self.splitn(2, '#').collect();
if !get_checksum(parts[0]) if !get_checksum(parts[0])
@ -87,7 +87,7 @@ impl ToWalletDescriptor for &str {
.map(|computed| computed == parts[1]) .map(|computed| computed == parts[1])
.unwrap_or(false) .unwrap_or(false)
{ {
return Err(KeyError::InvalidChecksum); return Err(DescriptorError::InvalidDescriptorChecksum);
} }
parts[0] parts[0]
@ -103,7 +103,7 @@ impl ToWalletDescriptor for &String {
fn to_wallet_descriptor( fn to_wallet_descriptor(
self, self,
network: Network, network: Network,
) -> Result<(ExtendedDescriptor, KeyMap), KeyError> { ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
self.as_str().to_wallet_descriptor(network) self.as_str().to_wallet_descriptor(network)
} }
} }
@ -112,7 +112,7 @@ impl ToWalletDescriptor for ExtendedDescriptor {
fn to_wallet_descriptor( fn to_wallet_descriptor(
self, self,
network: Network, network: Network,
) -> Result<(ExtendedDescriptor, KeyMap), KeyError> { ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
(self, KeyMap::default()).to_wallet_descriptor(network) (self, KeyMap::default()).to_wallet_descriptor(network)
} }
} }
@ -121,7 +121,7 @@ impl ToWalletDescriptor for (ExtendedDescriptor, KeyMap) {
fn to_wallet_descriptor( fn to_wallet_descriptor(
self, self,
network: Network, network: Network,
) -> Result<(ExtendedDescriptor, KeyMap), KeyError> { ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
use crate::keys::DescriptorKey; use crate::keys::DescriptorKey;
let secp = Secp256k1::new(); let secp = Secp256k1::new();
@ -140,7 +140,7 @@ impl ToWalletDescriptor for (ExtendedDescriptor, KeyMap) {
if networks.contains(&network) { if networks.contains(&network) {
Ok(pk) Ok(pk)
} else { } else {
Err(KeyError::InvalidNetwork) Err(DescriptorError::Key(KeyError::InvalidNetwork))
} }
}; };
@ -155,7 +155,7 @@ impl ToWalletDescriptor for DescriptorTemplateOut {
fn to_wallet_descriptor( fn to_wallet_descriptor(
self, self,
network: Network, network: Network,
) -> Result<(ExtendedDescriptor, KeyMap), KeyError> { ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
let valid_networks = &self.2; let valid_networks = &self.2;
let fix_key = |pk: &DescriptorPublicKey| { let fix_key = |pk: &DescriptorPublicKey| {
@ -177,7 +177,7 @@ impl ToWalletDescriptor for DescriptorTemplateOut {
Ok(pk) Ok(pk)
} else { } else {
Err(KeyError::InvalidNetwork) Err(DescriptorError::Key(KeyError::InvalidNetwork))
} }
}; };
@ -188,6 +188,22 @@ impl ToWalletDescriptor for DescriptorTemplateOut {
} }
} }
#[doc(hidden)]
/// Used internally mainly by the `descriptor!()` and `fragment!()` macros
pub trait CheckMiniscript<Ctx: miniscript::ScriptContext> {
fn check_minsicript(&self) -> Result<(), miniscript::Error>;
}
impl<Ctx: miniscript::ScriptContext, Pk: miniscript::MiniscriptKey> CheckMiniscript<Ctx>
for miniscript::Miniscript<Pk, Ctx>
{
fn check_minsicript(&self) -> Result<(), miniscript::Error> {
Ctx::check_global_validity(self)?;
Ok(())
}
}
/// Trait implemented on [`Descriptor`]s to add a method to extract the spending [`policy`] /// Trait implemented on [`Descriptor`]s to add a method to extract the spending [`policy`]
pub trait ExtractPolicy { pub trait ExtractPolicy {
/// Extract the spending [`policy`] /// Extract the spending [`policy`]
@ -195,7 +211,7 @@ pub trait ExtractPolicy {
&self, &self,
signers: &SignersContainer, signers: &SignersContainer,
secp: &SecpCtx, secp: &SecpCtx,
) -> Result<Option<Policy>, Error>; ) -> Result<Option<Policy>, DescriptorError>;
} }
pub(crate) trait XKeyUtils { pub(crate) trait XKeyUtils {
@ -235,8 +251,8 @@ impl<K: InnerXKey> XKeyUtils for DescriptorXKey<K> {
pub(crate) trait DescriptorMeta: Sized { pub(crate) trait DescriptorMeta: Sized {
fn is_witness(&self) -> bool; fn is_witness(&self) -> bool;
fn get_hd_keypaths(&self, index: u32, secp: &SecpCtx) -> Result<HDKeyPaths, Error>; fn get_hd_keypaths(&self, index: u32, secp: &SecpCtx) -> Result<HDKeyPaths, DescriptorError>;
fn get_extended_keys(&self) -> Result<Vec<DescriptorXKey<ExtendedPubKey>>, Error>; fn get_extended_keys(&self) -> Result<Vec<DescriptorXKey<ExtendedPubKey>>, DescriptorError>;
fn is_fixed(&self) -> bool; fn is_fixed(&self) -> bool;
fn derive_from_hd_keypaths(&self, hd_keypaths: &HDKeyPaths, secp: &SecpCtx) -> Option<Self>; fn derive_from_hd_keypaths(&self, hd_keypaths: &HDKeyPaths, secp: &SecpCtx) -> Option<Self>;
fn derive_from_psbt_input( fn derive_from_psbt_input(
@ -297,11 +313,11 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
} }
} }
fn get_hd_keypaths(&self, index: u32, secp: &SecpCtx) -> Result<HDKeyPaths, Error> { fn get_hd_keypaths(&self, index: u32, secp: &SecpCtx) -> Result<HDKeyPaths, DescriptorError> {
let translate_key = |key: &DescriptorPublicKey, let translate_key = |key: &DescriptorPublicKey,
index: u32, index: u32,
paths: &mut HDKeyPaths| paths: &mut HDKeyPaths|
-> Result<DummyKey, Error> { -> Result<DummyKey, DescriptorError> {
match key { match key {
DescriptorPublicKey::SinglePub(_) => {} DescriptorPublicKey::SinglePub(_) => {}
DescriptorPublicKey::XPub(xpub) => { DescriptorPublicKey::XPub(xpub) => {
@ -344,10 +360,10 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
Ok(answer_pk) Ok(answer_pk)
} }
fn get_extended_keys(&self) -> Result<Vec<DescriptorXKey<ExtendedPubKey>>, Error> { fn get_extended_keys(&self) -> Result<Vec<DescriptorXKey<ExtendedPubKey>>, DescriptorError> {
let get_key = |key: &DescriptorPublicKey, let get_key = |key: &DescriptorPublicKey,
keys: &mut Vec<DescriptorXKey<ExtendedPubKey>>| keys: &mut Vec<DescriptorXKey<ExtendedPubKey>>|
-> Result<DummyKey, Error> { -> Result<DummyKey, DescriptorError> {
if let DescriptorPublicKey::XPub(xpub) = key { if let DescriptorPublicKey::XPub(xpub) = key {
keys.push(xpub.clone()) keys.push(xpub.clone())
} }
@ -369,7 +385,10 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
} }
fn is_fixed(&self) -> bool { fn is_fixed(&self) -> bool {
fn check_key(key: &DescriptorPublicKey, flag: &mut bool) -> Result<DummyKey, Error> { fn check_key(
key: &DescriptorPublicKey,
flag: &mut bool,
) -> Result<DummyKey, DescriptorError> {
match key { match key {
DescriptorPublicKey::SinglePub(_) => {} DescriptorPublicKey::SinglePub(_) => {}
DescriptorPublicKey::XPub(xpub) => { DescriptorPublicKey::XPub(xpub) => {
@ -398,7 +417,7 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
let try_key = |key: &DescriptorPublicKey, let try_key = |key: &DescriptorPublicKey,
index: &HashMap<Fingerprint, DerivationPath>, index: &HashMap<Fingerprint, DerivationPath>,
found_path: &mut Option<ChildNumber>| found_path: &mut Option<ChildNumber>|
-> Result<DummyKey, Error> { -> Result<DummyKey, DescriptorError> {
if found_path.is_some() { if found_path.is_some() {
// already found a matching path, we are done // already found a matching path, we are done
return Ok(DummyKey::default()); return Ok(DummyKey::default());
@ -432,7 +451,7 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
Some(path) if !xpub.is_wildcard && path.is_empty() => { Some(path) if !xpub.is_wildcard && path.is_empty() => {
*found_path = Some(ChildNumber::Normal { index: 0 }) *found_path = Some(ChildNumber::Normal { index: 0 })
} }
Some(_) => return Err(Error::InvalidHDKeyPath), Some(_) => return Err(DescriptorError::InvalidHDKeyPath),
_ => {} _ => {}
} }
} }
@ -713,11 +732,17 @@ mod test {
let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)#67ju93jw" let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)#67ju93jw"
.to_wallet_descriptor(Network::Testnet); .to_wallet_descriptor(Network::Testnet);
assert!(matches!(desc.err(), Some(KeyError::InvalidChecksum))); assert!(matches!(
desc.err(),
Some(DescriptorError::InvalidDescriptorChecksum)
));
let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)#67ju93jw" let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)#67ju93jw"
.to_wallet_descriptor(Network::Testnet); .to_wallet_descriptor(Network::Testnet);
assert!(matches!(desc.err(), Some(KeyError::InvalidChecksum))); assert!(matches!(
desc.err(),
Some(DescriptorError::InvalidDescriptorChecksum)
));
} }
// test ToWalletDescriptor trait from &str with keys from right and wrong network // test ToWalletDescriptor trait from &str with keys from right and wrong network
@ -749,11 +774,17 @@ mod test {
let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)" let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"
.to_wallet_descriptor(Network::Bitcoin); .to_wallet_descriptor(Network::Bitcoin);
assert!(matches!(desc.err(), Some(KeyError::InvalidNetwork))); assert!(matches!(
desc.err(),
Some(DescriptorError::Key(KeyError::InvalidNetwork))
));
let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)" let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)"
.to_wallet_descriptor(Network::Bitcoin); .to_wallet_descriptor(Network::Bitcoin);
assert!(matches!(desc.err(), Some(KeyError::InvalidNetwork))); assert!(matches!(
desc.err(),
Some(DescriptorError::Key(KeyError::InvalidNetwork))
));
} }
// test ToWalletDescriptor trait from the output of the descriptor!() macro // test ToWalletDescriptor trait from the output of the descriptor!() macro

View File

@ -1145,11 +1145,12 @@ mod test {
let (prvkey0, _pubkey0, _fingerprint0) = setup_keys(TPRV0_STR); let (prvkey0, _pubkey0, _fingerprint0) = setup_keys(TPRV0_STR);
let (_prvkey1, pubkey1, _fingerprint1) = setup_keys(TPRV1_STR); let (_prvkey1, pubkey1, _fingerprint1) = setup_keys(TPRV1_STR);
let sequence = 50; let sequence = 50;
#[rustfmt::skip]
let desc = descriptor!(wsh(thresh( let desc = descriptor!(wsh(thresh(
2, 2,
pk(prvkey0), pk(prvkey0),
s: pk(pubkey1), s:pk(pubkey1),
s: d: v: older(sequence) s:d:v:older(sequence)
))) )))
.unwrap(); .unwrap();

View File

@ -33,7 +33,8 @@ use bitcoin::Network;
use miniscript::{Legacy, Segwitv0}; use miniscript::{Legacy, Segwitv0};
use super::{ExtendedDescriptor, KeyMap, ToWalletDescriptor}; use super::{ExtendedDescriptor, KeyMap, ToWalletDescriptor};
use crate::keys::{DerivableKey, KeyError, ToDescriptorKey, ValidNetworks}; use crate::descriptor::DescriptorError;
use crate::keys::{DerivableKey, ToDescriptorKey, ValidNetworks};
use crate::{descriptor, KeychainKind}; use crate::{descriptor, KeychainKind};
/// Type alias for the return type of [`DescriptorTemplate`], [`descriptor!`](crate::descriptor!) and others /// Type alias for the return type of [`DescriptorTemplate`], [`descriptor!`](crate::descriptor!) and others
@ -47,6 +48,7 @@ pub type DescriptorTemplateOut = (ExtendedDescriptor, KeyMap, ValidNetworks);
/// ## Example /// ## Example
/// ///
/// ``` /// ```
/// use bdk::descriptor::error::Error as DescriptorError;
/// use bdk::keys::{KeyError, ToDescriptorKey}; /// use bdk::keys::{KeyError, ToDescriptorKey};
/// use bdk::miniscript::Legacy; /// use bdk::miniscript::Legacy;
/// use bdk::template::{DescriptorTemplate, DescriptorTemplateOut}; /// use bdk::template::{DescriptorTemplate, DescriptorTemplateOut};
@ -54,14 +56,14 @@ pub type DescriptorTemplateOut = (ExtendedDescriptor, KeyMap, ValidNetworks);
/// struct MyP2PKH<K: ToDescriptorKey<Legacy>>(K); /// struct MyP2PKH<K: ToDescriptorKey<Legacy>>(K);
/// ///
/// impl<K: ToDescriptorKey<Legacy>> DescriptorTemplate for MyP2PKH<K> { /// impl<K: ToDescriptorKey<Legacy>> DescriptorTemplate for MyP2PKH<K> {
/// fn build(self) -> Result<DescriptorTemplateOut, KeyError> { /// fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
/// Ok(bdk::descriptor!(pkh(self.0))?) /// Ok(bdk::descriptor!(pkh(self.0))?)
/// } /// }
/// } /// }
/// ``` /// ```
pub trait DescriptorTemplate { pub trait DescriptorTemplate {
/// Build the complete descriptor /// Build the complete descriptor
fn build(self) -> Result<DescriptorTemplateOut, KeyError>; fn build(self) -> Result<DescriptorTemplateOut, DescriptorError>;
} }
/// Turns a [`DescriptorTemplate`] into a valid wallet descriptor by calling its /// Turns a [`DescriptorTemplate`] into a valid wallet descriptor by calling its
@ -70,7 +72,7 @@ impl<T: DescriptorTemplate> ToWalletDescriptor for T {
fn to_wallet_descriptor( fn to_wallet_descriptor(
self, self,
network: Network, network: Network,
) -> Result<(ExtendedDescriptor, KeyMap), KeyError> { ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
Ok(self.build()?.to_wallet_descriptor(network)?) Ok(self.build()?.to_wallet_descriptor(network)?)
} }
} }
@ -103,7 +105,7 @@ impl<T: DescriptorTemplate> ToWalletDescriptor for T {
pub struct P2PKH<K: ToDescriptorKey<Legacy>>(pub K); pub struct P2PKH<K: ToDescriptorKey<Legacy>>(pub K);
impl<K: ToDescriptorKey<Legacy>> DescriptorTemplate for P2PKH<K> { impl<K: ToDescriptorKey<Legacy>> DescriptorTemplate for P2PKH<K> {
fn build(self) -> Result<DescriptorTemplateOut, KeyError> { fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
Ok(descriptor!(pkh(self.0))?) Ok(descriptor!(pkh(self.0))?)
} }
} }
@ -137,7 +139,7 @@ impl<K: ToDescriptorKey<Legacy>> DescriptorTemplate for P2PKH<K> {
pub struct P2WPKH_P2SH<K: ToDescriptorKey<Segwitv0>>(pub K); pub struct P2WPKH_P2SH<K: ToDescriptorKey<Segwitv0>>(pub K);
impl<K: ToDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH_P2SH<K> { impl<K: ToDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH_P2SH<K> {
fn build(self) -> Result<DescriptorTemplateOut, KeyError> { fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
Ok(descriptor!(sh(wpkh(self.0)))?) Ok(descriptor!(sh(wpkh(self.0)))?)
} }
} }
@ -170,7 +172,7 @@ impl<K: ToDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH_P2SH<K> {
pub struct P2WPKH<K: ToDescriptorKey<Segwitv0>>(pub K); pub struct P2WPKH<K: ToDescriptorKey<Segwitv0>>(pub K);
impl<K: ToDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH<K> { impl<K: ToDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH<K> {
fn build(self) -> Result<DescriptorTemplateOut, KeyError> { fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
Ok(descriptor!(wpkh(self.0))?) Ok(descriptor!(wpkh(self.0))?)
} }
} }
@ -205,7 +207,7 @@ impl<K: ToDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH<K> {
pub struct BIP44<K: DerivableKey<Legacy>>(pub K, pub KeychainKind); pub struct BIP44<K: DerivableKey<Legacy>>(pub K, pub KeychainKind);
impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44<K> { impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44<K> {
fn build(self) -> Result<DescriptorTemplateOut, KeyError> { fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
Ok(P2PKH(legacy::make_bipxx_private(44, self.0, self.1)?).build()?) Ok(P2PKH(legacy::make_bipxx_private(44, self.0, self.1)?).build()?)
} }
} }
@ -244,7 +246,7 @@ impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44<K> {
pub struct BIP44Public<K: DerivableKey<Legacy>>(pub K, pub bip32::Fingerprint, pub KeychainKind); pub struct BIP44Public<K: DerivableKey<Legacy>>(pub K, pub bip32::Fingerprint, pub KeychainKind);
impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44Public<K> { impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44Public<K> {
fn build(self) -> Result<DescriptorTemplateOut, KeyError> { fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
Ok(P2PKH(legacy::make_bipxx_public(44, self.0, self.1, self.2)?).build()?) Ok(P2PKH(legacy::make_bipxx_public(44, self.0, self.1, self.2)?).build()?)
} }
} }
@ -279,7 +281,7 @@ impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44Public<K> {
pub struct BIP49<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind); pub struct BIP49<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind);
impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49<K> { impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49<K> {
fn build(self) -> Result<DescriptorTemplateOut, KeyError> { fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
Ok(P2WPKH_P2SH(segwit_v0::make_bipxx_private(49, self.0, self.1)?).build()?) Ok(P2WPKH_P2SH(segwit_v0::make_bipxx_private(49, self.0, self.1)?).build()?)
} }
} }
@ -318,7 +320,7 @@ impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49<K> {
pub struct BIP49Public<K: DerivableKey<Segwitv0>>(pub K, pub bip32::Fingerprint, pub KeychainKind); pub struct BIP49Public<K: DerivableKey<Segwitv0>>(pub K, pub bip32::Fingerprint, pub KeychainKind);
impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49Public<K> { impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49Public<K> {
fn build(self) -> Result<DescriptorTemplateOut, KeyError> { fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
Ok(P2WPKH_P2SH(segwit_v0::make_bipxx_public(49, self.0, self.1, self.2)?).build()?) Ok(P2WPKH_P2SH(segwit_v0::make_bipxx_public(49, self.0, self.1, self.2)?).build()?)
} }
} }
@ -353,7 +355,7 @@ impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49Public<K> {
pub struct BIP84<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind); pub struct BIP84<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind);
impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP84<K> { impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP84<K> {
fn build(self) -> Result<DescriptorTemplateOut, KeyError> { fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
Ok(P2WPKH(segwit_v0::make_bipxx_private(84, self.0, self.1)?).build()?) Ok(P2WPKH(segwit_v0::make_bipxx_private(84, self.0, self.1)?).build()?)
} }
} }
@ -392,7 +394,7 @@ impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP84<K> {
pub struct BIP84Public<K: DerivableKey<Segwitv0>>(pub K, pub bip32::Fingerprint, pub KeychainKind); pub struct BIP84Public<K: DerivableKey<Segwitv0>>(pub K, pub bip32::Fingerprint, pub KeychainKind);
impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP84Public<K> { impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP84Public<K> {
fn build(self) -> Result<DescriptorTemplateOut, KeyError> { fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
Ok(P2WPKH(segwit_v0::make_bipxx_public(84, self.0, self.1, self.2)?).build()?) Ok(P2WPKH(segwit_v0::make_bipxx_public(84, self.0, self.1, self.2)?).build()?)
} }
} }
@ -406,7 +408,7 @@ macro_rules! expand_make_bipxx {
bip: u32, bip: u32,
key: K, key: K,
keychain: KeychainKind, keychain: KeychainKind,
) -> Result<impl ToDescriptorKey<$ctx>, KeyError> { ) -> Result<impl ToDescriptorKey<$ctx>, DescriptorError> {
let mut derivation_path = Vec::with_capacity(4); let mut derivation_path = Vec::with_capacity(4);
derivation_path.push(bip32::ChildNumber::from_hardened_idx(bip)?); derivation_path.push(bip32::ChildNumber::from_hardened_idx(bip)?);
derivation_path.push(bip32::ChildNumber::from_hardened_idx(0)?); derivation_path.push(bip32::ChildNumber::from_hardened_idx(0)?);
@ -430,7 +432,7 @@ macro_rules! expand_make_bipxx {
key: K, key: K,
parent_fingerprint: bip32::Fingerprint, parent_fingerprint: bip32::Fingerprint,
keychain: KeychainKind, keychain: KeychainKind,
) -> Result<impl ToDescriptorKey<$ctx>, KeyError> { ) -> Result<impl ToDescriptorKey<$ctx>, DescriptorError> {
let derivation_path: bip32::DerivationPath = match keychain { let derivation_path: bip32::DerivationPath = match keychain {
KeychainKind::External => vec![bip32::ChildNumber::from_normal_idx(0)?].into(), KeychainKind::External => vec![bip32::ChildNumber::from_normal_idx(0)?].into(),
KeychainKind::Internal => vec![bip32::ChildNumber::from_normal_idx(1)?].into(), KeychainKind::Internal => vec![bip32::ChildNumber::from_normal_idx(1)?].into(),
@ -456,8 +458,8 @@ mod test {
// test existing descriptor templates, make sure they are expanded to the right descriptors // test existing descriptor templates, make sure they are expanded to the right descriptors
use super::*; use super::*;
use crate::descriptor::DescriptorMeta; use crate::descriptor::{DescriptorError, DescriptorMeta};
use crate::keys::{KeyError, ValidNetworks}; use crate::keys::ValidNetworks;
use bitcoin::hashes::core::str::FromStr; use bitcoin::hashes::core::str::FromStr;
use bitcoin::network::constants::Network::Regtest; use bitcoin::network::constants::Network::Regtest;
use bitcoin::secp256k1::Secp256k1; use bitcoin::secp256k1::Secp256k1;
@ -467,7 +469,7 @@ mod test {
// verify template descriptor generates expected address(es) // verify template descriptor generates expected address(es)
fn check( fn check(
desc: Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), KeyError>, desc: Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), DescriptorError>,
is_witness: bool, is_witness: bool,
is_fixed: bool, is_fixed: bool,
expected: &[&str], expected: &[&str],

View File

@ -43,6 +43,7 @@ use miniscript::descriptor::{DescriptorXKey, KeyMap};
pub use miniscript::ScriptContext; pub use miniscript::ScriptContext;
use miniscript::{Miniscript, Terminal}; use miniscript::{Miniscript, Terminal};
use crate::descriptor::{CheckMiniscript, DescriptorError};
use crate::wallet::utils::SecpCtx; use crate::wallet::utils::SecpCtx;
#[cfg(feature = "keys-bip39")] #[cfg(feature = "keys-bip39")]
@ -572,14 +573,13 @@ fn expand_multi_keys<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>(
pub fn make_pk<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>( pub fn make_pk<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>(
descriptor_key: Pk, descriptor_key: Pk,
secp: &SecpCtx, secp: &SecpCtx,
) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), KeyError> { ) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), DescriptorError> {
let (key, key_map, valid_networks) = descriptor_key.to_descriptor_key()?.extract(secp)?; let (key, key_map, valid_networks) = descriptor_key.to_descriptor_key()?.extract(secp)?;
let minisc = Miniscript::from_ast(Terminal::PkK(key))?;
Ok(( minisc.check_minsicript()?;
Miniscript::from_ast(Terminal::PkK(key))?,
key_map, Ok((minisc, key_map, valid_networks))
valid_networks,
))
} }
// Used internally by `bdk::fragment!` to build `multi()` fragments // Used internally by `bdk::fragment!` to build `multi()` fragments
@ -588,14 +588,13 @@ pub fn make_multi<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>(
thresh: usize, thresh: usize,
pks: Vec<Pk>, pks: Vec<Pk>,
secp: &SecpCtx, secp: &SecpCtx,
) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), KeyError> { ) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), DescriptorError> {
let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?; let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?;
let minisc = Miniscript::from_ast(Terminal::Multi(thresh, pks))?;
Ok(( minisc.check_minsicript()?;
Miniscript::from_ast(Terminal::Multi(thresh, pks))?,
key_map, Ok((minisc, key_map, valid_networks))
valid_networks,
))
} }
// Used internally by `bdk::descriptor!` to build `sortedmulti()` fragments // Used internally by `bdk::descriptor!` to build `sortedmulti()` fragments
@ -610,11 +609,14 @@ pub fn make_sortedmulti_inner<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>(
KeyMap, KeyMap,
ValidNetworks, ValidNetworks,
), ),
KeyError, DescriptorError,
> { > {
let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?; let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?;
let minisc = SortedMultiVec::new(thresh, pks)?;
Ok((SortedMultiVec::new(thresh, pks)?, key_map, valid_networks)) // TODO: should we apply the checks here as well?
Ok((minisc, key_map, valid_networks))
} }
/// The "identity" conversion is used internally by some `bdk::fragment`s /// The "identity" conversion is used internally by some `bdk::fragment`s