## [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
#### Changed
- Remove `BlockchainMarker`, `OfflineClient` and `OfflineWallet` in favor of just using the unit
//! # use bdk::database::{AnyDatabase, MemoryDatabase};
//! # use bdk::{Wallet};
//! let memory = MemoryDatabase::default();
-//! let wallet_memory =
-//! Wallet::new_offline("...", None, Network::Testnet, memory)?;
+//! let wallet_memory = Wallet::new_offline("...", None, Network::Testnet, memory)?;
//!
//! # #[cfg(feature = "key-value-db")]
//! # {
//! let sled = sled::open("my-database")?.open_tree("default_tree")?;
-//! let wallet_sled =
-//! Wallet::new_offline("...", None, Network::Testnet, sled)?;
+//! let wallet_sled = Wallet::new_offline("...", None, Network::Testnet, sled)?;
//! # }
//! # Ok::<(), bdk::Error>(())
//! ```
use std::iter::FromIterator;
-use crate::descriptor::Error;
+use crate::descriptor::DescriptorError;
const INPUT_CHARSET: &str = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ ";
const CHECKSUM_CHARSET: &str = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
}
/// 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 cls = 0;
let mut clscount = 0;
for ch in desc.chars() {
let pos = INPUT_CHARSET
.find(ch)
- .ok_or(Error::InvalidDescriptorCharacter(ch))? as u64;
+ .ok_or(DescriptorError::InvalidDescriptorCharacter(ch))? as u64;
c = poly_mod(c, pos & 31);
cls = cls * 3 + (pos >> 5);
clscount += 1;
assert!(matches!(
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
));
}
}
$key.to_descriptor_key()
.and_then(|key: DescriptorKey<$ctx>| key.extract(&secp))
+ .map_err($crate::descriptor::DescriptorError::Key)
.map(|(pk, key_map, valid_networks)| {
(
$crate::miniscript::Descriptor::<
#[doc(hidden)]
#[macro_export]
macro_rules! impl_leaf_opcode {
- ( $terminal_variant:ident ) => {
+ ( $terminal_variant:ident ) => {{
+ use $crate::descriptor::CheckMiniscript;
+
$crate::miniscript::Miniscript::from_ast(
$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| {
(
minisc,
$crate::keys::any_network(),
)
})
- };
+ }};
}
#[doc(hidden)]
#[macro_export]
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::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| {
(
minisc,
$crate::keys::any_network(),
)
})
- };
+ }};
}
#[doc(hidden)]
#[macro_export]
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::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| {
(
minisc,
$crate::keys::any_network(),
)
})
- };
+ }};
}
#[doc(hidden)]
#[macro_export]
macro_rules! impl_node_opcode_two {
( $terminal_variant:ident, $( $inner:tt )* ) => ({
+ use $crate::descriptor::CheckMiniscript;
+
let inner = $crate::fragment_internal!( @t $( $inner )* );
let (a, b) = $crate::descriptor::dsl::TupleTwo::from(inner).flattened();
// join key_maps
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(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)))
})
});
}
#[macro_export]
macro_rules! impl_node_opcode_three {
( $terminal_variant:ident, $( $inner:tt )* ) => {
+ use $crate::descriptor::CheckMiniscript;
+
let inner = $crate::fragment_internal!( @t $( $inner )* );
let (a, b, c) = $crate::descriptor::dsl::TupleThree::from(inner).flattened();
let networks = $crate::keys::merge_networks(&a_networks, &b_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(b_minisc),
std::sync::Arc::new(c_minisc),
- ))?, a_keymap, networks))
+ ))?;
+
+ minisc.check_minsicript()?;
+
+ Ok((minisc, a_keymap, networks))
})
};
}
)*
keys.into_iter().collect::<Result<Vec<_>, _>>()
+ .map_err($crate::descriptor::DescriptorError::Key)
.and_then(|keys| $crate::keys::make_sortedmulti_inner($thresh, keys, &secp))
});
#[macro_export]
macro_rules! apply_modifier {
( $terminal_variant:ident, $inner:expr ) => {{
+ use $crate::descriptor::CheckMiniscript;
+
$inner
- .map_err(|e| -> $crate::Error { e.into() })
+ .map_err(|e| -> $crate::descriptor::DescriptorError { e.into() })
.and_then(|(minisc, keymap, networks)| {
- Ok((
- $crate::miniscript::Miniscript::from_ast(
- $crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
- std::sync::Arc::new(minisc),
- ),
- )?,
- keymap,
- networks,
- ))
+ let minisc = $crate::miniscript::Miniscript::from_ast(
+ $crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
+ std::sync::Arc::new(minisc),
+ ),
+ )?;
+
+ minisc.check_minsicript()?;
+
+ Ok((minisc, keymap, networks))
})
}};
/// Macro to write full descriptors with code
///
/// 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
/// cannot be grouped together. For instance, a descriptor fragment like `sdv:older(144)` has to be
///
/// ```
/// # use std::str::FromStr;
-/// let my_key_1 = bitcoin::PublicKey::from_str("02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c")?;
-/// let my_key_2 = bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
+/// let my_key_1 = bitcoin::PublicKey::from_str(
+/// "02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c",
+/// )?;
+/// let my_key_2 =
+/// bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
/// let my_timelock = 50;
///
/// let (descriptor_a, key_map_a, networks) = bdk::descriptor! {
/// )
/// }?;
///
+/// #[rustfmt::skip]
/// let b_items = vec![
/// bdk::fragment!(pk(my_key_1))?,
/// bdk::fragment!(s:pk(my_key_2))?,
/// 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!(key_map_a.len(), key_map_b.len());
/// 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, ...))`.
///
/// The syntax to write macro fragment is the same as documented for the [`descriptor`] macro.
)*
keys.into_iter().collect::<Result<Vec<_>, _>>()
+ .map_err($crate::descriptor::DescriptorError::Key)
.and_then(|keys| $crate::keys::make_multi($thresh, keys, &secp))
});
use std::str::FromStr;
- use crate::descriptor::DescriptorMeta;
- use crate::keys::{DescriptorKey, KeyError, ToDescriptorKey, ValidNetworks};
+ use crate::descriptor::{DescriptorError, DescriptorMeta};
+ use crate::keys::{DescriptorKey, ToDescriptorKey, ValidNetworks};
use bitcoin::network::constants::Network::{Bitcoin, Regtest, Testnet};
use bitcoin::util::bip32;
use bitcoin::util::bip32::ChildNumber;
// verify descriptor generates expected script(s) (if bare or pk) or address(es)
fn check(
- desc: Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), KeyError>,
+ desc: Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), DescriptorError>,
is_witness: bool,
is_fixed: bool,
expected: &[&str],
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();
+ // }
}
/// Errors related to the parsing and usage of descriptors
#[derive(Debug)]
pub enum Error {
- //InternalError,
- //InvalidPrefix(Vec<u8>),
- //HardenedDerivationOnXpub,
- //MalformedInput,
/// Invalid HD Key path, such as having a wildcard but a length != 1
InvalidHDKeyPath,
+ /// The provided descriptor doesn't match its checksum
+ InvalidDescriptorChecksum,
- //KeyParsingError(String),
/// Error thrown while working with [`keys`](crate::keys)
Key(crate::keys::KeyError),
/// Error while extracting and manipulating policies
Policy(crate::descriptor::policy::PolicyError),
- //InputIndexDoesntExist,
- //MissingPublicKey,
- //MissingDetails,
/// Invalid character found in the descriptor checksum
InvalidDescriptorCharacter(char),
- //CantDeriveWithMiniscript,
/// BIP32 error
BIP32(bitcoin::util::bip32::Error),
/// Error during base58 decoding
pub mod template;
pub use self::checksum::get_checksum;
-use self::error::Error;
+pub use self::error::Error as DescriptorError;
pub use self::policy::Policy;
use self::template::DescriptorTemplateOut;
use crate::keys::{KeyError, ToDescriptorKey};
fn to_wallet_descriptor(
self,
network: Network,
- ) -> Result<(ExtendedDescriptor, KeyMap), KeyError>;
+ ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError>;
}
impl ToWalletDescriptor for &str {
fn to_wallet_descriptor(
self,
network: Network,
- ) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
+ ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
let descriptor = if self.contains('#') {
let parts: Vec<&str> = self.splitn(2, '#').collect();
if !get_checksum(parts[0])
.map(|computed| computed == parts[1])
.unwrap_or(false)
{
- return Err(KeyError::InvalidChecksum);
+ return Err(DescriptorError::InvalidDescriptorChecksum);
}
parts[0]
fn to_wallet_descriptor(
self,
network: Network,
- ) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
+ ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
self.as_str().to_wallet_descriptor(network)
}
}
fn to_wallet_descriptor(
self,
network: Network,
- ) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
+ ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
(self, KeyMap::default()).to_wallet_descriptor(network)
}
}
fn to_wallet_descriptor(
self,
network: Network,
- ) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
+ ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
use crate::keys::DescriptorKey;
let secp = Secp256k1::new();
if networks.contains(&network) {
Ok(pk)
} else {
- Err(KeyError::InvalidNetwork)
+ Err(DescriptorError::Key(KeyError::InvalidNetwork))
}
};
fn to_wallet_descriptor(
self,
network: Network,
- ) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
+ ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
let valid_networks = &self.2;
let fix_key = |pk: &DescriptorPublicKey| {
Ok(pk)
} else {
- Err(KeyError::InvalidNetwork)
+ Err(DescriptorError::Key(KeyError::InvalidNetwork))
}
};
}
}
+#[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`]
pub trait ExtractPolicy {
/// Extract the spending [`policy`]
&self,
signers: &SignersContainer,
secp: &SecpCtx,
- ) -> Result<Option<Policy>, Error>;
+ ) -> Result<Option<Policy>, DescriptorError>;
}
pub(crate) trait XKeyUtils {
pub(crate) trait DescriptorMeta: Sized {
fn is_witness(&self) -> bool;
- fn get_hd_keypaths(&self, index: u32, secp: &SecpCtx) -> Result<HDKeyPaths, Error>;
- fn get_extended_keys(&self) -> Result<Vec<DescriptorXKey<ExtendedPubKey>>, Error>;
+ fn get_hd_keypaths(&self, index: u32, secp: &SecpCtx) -> Result<HDKeyPaths, DescriptorError>;
+ fn get_extended_keys(&self) -> Result<Vec<DescriptorXKey<ExtendedPubKey>>, DescriptorError>;
fn is_fixed(&self) -> bool;
fn derive_from_hd_keypaths(&self, hd_keypaths: &HDKeyPaths, secp: &SecpCtx) -> Option<Self>;
fn derive_from_psbt_input(
}
}
- 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,
index: u32,
paths: &mut HDKeyPaths|
- -> Result<DummyKey, Error> {
+ -> Result<DummyKey, DescriptorError> {
match key {
DescriptorPublicKey::SinglePub(_) => {}
DescriptorPublicKey::XPub(xpub) => {
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,
keys: &mut Vec<DescriptorXKey<ExtendedPubKey>>|
- -> Result<DummyKey, Error> {
+ -> Result<DummyKey, DescriptorError> {
if let DescriptorPublicKey::XPub(xpub) = key {
keys.push(xpub.clone())
}
}
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 {
DescriptorPublicKey::SinglePub(_) => {}
DescriptorPublicKey::XPub(xpub) => {
let try_key = |key: &DescriptorPublicKey,
index: &HashMap<Fingerprint, DerivationPath>,
found_path: &mut Option<ChildNumber>|
- -> Result<DummyKey, Error> {
+ -> Result<DummyKey, DescriptorError> {
if found_path.is_some() {
// already found a matching path, we are done
return Ok(DummyKey::default());
Some(path) if !xpub.is_wildcard && path.is_empty() => {
*found_path = Some(ChildNumber::Normal { index: 0 })
}
- Some(_) => return Err(Error::InvalidHDKeyPath),
+ Some(_) => return Err(DescriptorError::InvalidHDKeyPath),
_ => {}
}
}
let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)#67ju93jw"
.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"
.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
let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"
.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/*)"
.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
let (prvkey0, _pubkey0, _fingerprint0) = setup_keys(TPRV0_STR);
let (_prvkey1, pubkey1, _fingerprint1) = setup_keys(TPRV1_STR);
let sequence = 50;
+ #[rustfmt::skip]
let desc = descriptor!(wsh(thresh(
2,
pk(prvkey0),
- s: pk(pubkey1),
- s: d: v: older(sequence)
+ s:pk(pubkey1),
+ s:d:v:older(sequence)
)))
.unwrap();
use miniscript::{Legacy, Segwitv0};
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};
/// Type alias for the return type of [`DescriptorTemplate`], [`descriptor!`](crate::descriptor!) and others
/// ## Example
///
/// ```
+/// use bdk::descriptor::error::Error as DescriptorError;
/// use bdk::keys::{KeyError, ToDescriptorKey};
/// use bdk::miniscript::Legacy;
/// use bdk::template::{DescriptorTemplate, DescriptorTemplateOut};
/// struct MyP2PKH<K: ToDescriptorKey<Legacy>>(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))?)
/// }
/// }
/// ```
pub trait DescriptorTemplate {
/// 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
fn to_wallet_descriptor(
self,
network: Network,
- ) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
+ ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
Ok(self.build()?.to_wallet_descriptor(network)?)
}
}
pub struct P2PKH<K: ToDescriptorKey<Legacy>>(pub 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))?)
}
}
pub struct P2WPKH_P2SH<K: ToDescriptorKey<Segwitv0>>(pub 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)))?)
}
}
pub struct P2WPKH<K: ToDescriptorKey<Segwitv0>>(pub 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))?)
}
}
pub struct BIP44<K: DerivableKey<Legacy>>(pub K, pub KeychainKind);
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()?)
}
}
pub struct BIP44Public<K: DerivableKey<Legacy>>(pub K, pub bip32::Fingerprint, pub KeychainKind);
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()?)
}
}
pub struct BIP49<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind);
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()?)
}
}
pub struct BIP49Public<K: DerivableKey<Segwitv0>>(pub K, pub bip32::Fingerprint, pub KeychainKind);
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()?)
}
}
pub struct BIP84<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind);
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()?)
}
}
pub struct BIP84Public<K: DerivableKey<Segwitv0>>(pub K, pub bip32::Fingerprint, pub KeychainKind);
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()?)
}
}
bip: u32,
key: K,
keychain: KeychainKind,
- ) -> Result<impl ToDescriptorKey<$ctx>, KeyError> {
+ ) -> Result<impl ToDescriptorKey<$ctx>, DescriptorError> {
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(0)?);
key: K,
parent_fingerprint: bip32::Fingerprint,
keychain: KeychainKind,
- ) -> Result<impl ToDescriptorKey<$ctx>, KeyError> {
+ ) -> Result<impl ToDescriptorKey<$ctx>, DescriptorError> {
let derivation_path: bip32::DerivationPath = match keychain {
KeychainKind::External => vec![bip32::ChildNumber::from_normal_idx(0)?].into(),
KeychainKind::Internal => vec![bip32::ChildNumber::from_normal_idx(1)?].into(),
// test existing descriptor templates, make sure they are expanded to the right descriptors
use super::*;
- use crate::descriptor::DescriptorMeta;
- use crate::keys::{KeyError, ValidNetworks};
+ use crate::descriptor::{DescriptorError, DescriptorMeta};
+ use crate::keys::ValidNetworks;
use bitcoin::hashes::core::str::FromStr;
use bitcoin::network::constants::Network::Regtest;
use bitcoin::secp256k1::Secp256k1;
// verify template descriptor generates expected address(es)
fn check(
- desc: Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), KeyError>,
+ desc: Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), DescriptorError>,
is_witness: bool,
is_fixed: bool,
expected: &[&str],
pub use miniscript::ScriptContext;
use miniscript::{Miniscript, Terminal};
+use crate::descriptor::{CheckMiniscript, DescriptorError};
use crate::wallet::utils::SecpCtx;
#[cfg(feature = "keys-bip39")]
pub fn make_pk<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>(
descriptor_key: Pk,
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 minisc = Miniscript::from_ast(Terminal::PkK(key))?;
- Ok((
- Miniscript::from_ast(Terminal::PkK(key))?,
- key_map,
- valid_networks,
- ))
+ minisc.check_minsicript()?;
+
+ Ok((minisc, key_map, valid_networks))
}
// Used internally by `bdk::fragment!` to build `multi()` fragments
thresh: usize,
pks: Vec<Pk>,
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 minisc = Miniscript::from_ast(Terminal::Multi(thresh, pks))?;
+
+ minisc.check_minsicript()?;
- Ok((
- Miniscript::from_ast(Terminal::Multi(thresh, pks))?,
- key_map,
- valid_networks,
- ))
+ Ok((minisc, key_map, valid_networks))
}
// Used internally by `bdk::descriptor!` to build `sortedmulti()` fragments
KeyMap,
ValidNetworks,
),
- KeyError,
+ DescriptorError,
> {
let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?;
+ let minisc = SortedMultiVec::new(thresh, pks)?;
+
+ // TODO: should we apply the checks here as well?
- Ok((SortedMultiVec::new(thresh, pks)?, key_map, valid_networks))
+ Ok((minisc, key_map, valid_networks))
}
/// The "identity" conversion is used internally by some `bdk::fragment`s