Merge commit 'refs/pull/264/head' of github.com:bitcoindevkit/bdk
This commit is contained in:
commit
6955a7776d
@ -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
|
||||||
|
@ -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>(())
|
||||||
//! ```
|
//! ```
|
||||||
|
@ -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
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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],
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user