Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/cont_integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- ubuntu-latest
- ubuntu-24.04-arm
features:
- --no-default-features --features miniscript/no-std,bdk_chain/hashbrown
- --no-default-features --features bdk_chain/hashbrown
- --all-features
steps:
- name: Checkout
Expand Down Expand Up @@ -51,7 +51,7 @@ jobs:
- ubuntu-latest
- ubuntu-24.04-arm
features:
- --no-default-features --features miniscript/no-std,bdk_chain/hashbrown
- --no-default-features --features bdk_chain/hashbrown
- --all-features
steps:
- name: Checkout
Expand Down Expand Up @@ -84,7 +84,7 @@ jobs:
cache: true
- name: Check no-std
# TODO "--target thumbv6m-none-eabi" should work but currently does not
run: cargo check --no-default-features --features miniscript/no-std,bdk_chain/hashbrown
run: cargo check --no-default-features --features bdk_chain/hashbrown

check-wasm:
name: Check WASM
Expand All @@ -110,7 +110,7 @@ jobs:
- name: Check WASM
run: |
rustup target add wasm32-unknown-unknown
cargo check --target wasm32-unknown-unknown --no-default-features --features miniscript/no-std,bdk_chain/hashbrown
cargo check --target wasm32-unknown-unknown --no-default-features --features bdk_chain/hashbrown

fmt:
name: Rust fmt
Expand Down
37 changes: 34 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(coverage_nightly)'] }
[dependencies]
bdk_chain = { version = "0.23.1", features = ["miniscript", "serde"], default-features = false }
bitcoin = { version = "0.32.7", features = ["serde", "base64"], default-features = false }
miniscript = { version = "12.3.1", features = ["serde"], default-features = false }
miniscript = { version = "13.0.0", features = ["serde"], default-features = false }
rand_core = { version = "0.6.0" }
serde_json = { version = "1" }
serde = { version = "1", features = ["derive"] }

# Optional dependencies
anyhow = { version = "1.0.98", optional = true }
bdk_file_store = { version = "0.21.1", optional = true }
bdk_file_store = { version = "0.22.0", optional = true }
bip39 = { version = "2.0", optional = true }
tempfile = { version = "3.20.0", optional = true }

Expand All @@ -46,7 +46,7 @@ test-utils = ["std", "anyhow", "tempfile"]
[dev-dependencies]
anyhow = "1"
assert_matches = "1.5.0"
bdk_bitcoind_rpc = { version = "0.21.0" }
bdk_bitcoind_rpc = { version = "0.22.0" }
bdk_electrum = { version = "0.23.1" }
bdk_esplora = { version = "0.22.1", features = ["async-https", "blocking-https", "tokio"] }
bdk_wallet = { path = ".", features = ["rusqlite", "file_store", "test-utils"] }
Expand Down Expand Up @@ -77,3 +77,34 @@ name = "esplora_blocking"

[[example]]
name = "bitcoind_rpc"


[patch.crates-io.bdk_chain]
git = "https://github.com/bitcoindevkit/bdk"
branch = "master"
# rev = "b45ecb9bd41c80a03921dcf42a9845b19774502e"

[patch.crates-io.bdk_core]
git = "https://github.com/bitcoindevkit/bdk"
branch = "master"
# rev = "b45ecb9bd41c80a03921dcf42a9845b19774502e"

[patch.crates-io.bdk_bitcoind_rpc]
git = "https://github.com/bitcoindevkit/bdk"
branch = "master"
# rev = "b45ecb9bd41c80a03921dcf42a9845b19774502e"

[patch.crates-io.bdk_electrum]
git = "https://github.com/bitcoindevkit/bdk"
branch = "master"
# rev = "b45ecb9bd41c80a03921dcf42a9845b19774502e"

[patch.crates-io.bdk_esplora]
git = "https://github.com/bitcoindevkit/bdk"
branch = "master"
# rev = "b45ecb9bd41c80a03921dcf42a9845b19774502e"

[patch.crates-io.bdk_file_store]
git = "https://github.com/bitcoindevkit/bdk"
branch = "master"
# rev = "b45ecb9bd41c80a03921dcf42a9845b19774502e"
3 changes: 2 additions & 1 deletion examples/bitcoind_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ fn main() -> anyhow::Result<()> {
args.start_height,
wallet
.transactions()
.filter(|tx| tx.chain_position.is_unconfirmed()),
.filter(|tx| tx.pos.is_unconfirmed())
.map(|tx| tx.tx),
);
spawn(move || -> Result<(), anyhow::Error> {
while let Some(emission) = emitter.next_block()? {
Expand Down
28 changes: 21 additions & 7 deletions src/descriptor/checksum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,23 @@
use crate::descriptor::DescriptorError;
use alloc::string::String;

use miniscript::descriptor::checksum::desc_checksum;
use miniscript::descriptor::checksum::Engine;

/// Compute the checksum of a descriptor, excludes any existing checksum in the descriptor string
/// from the calculation
pub fn calc_checksum(desc: &str) -> Result<String, DescriptorError> {
if let Some(split) = desc.split_once('#') {
let og_checksum = split.1;
let checksum = desc_checksum(split.0)?;
if og_checksum != checksum {
if let Some((descriptor, original_checksum)) = desc.split_once('#') {
let mut engine = Engine::new();
engine.input(descriptor)?;
let checksum = engine.checksum();
if original_checksum != checksum {
return Err(DescriptorError::InvalidDescriptorChecksum);
}
Ok(checksum)
} else {
Ok(desc_checksum(desc)?)
let mut engine = Engine::new();
engine.input(desc)?;
Ok(engine.checksum())
}
}

Expand All @@ -39,6 +42,7 @@ pub fn calc_checksum(desc: &str) -> Result<String, DescriptorError> {
mod test {
use super::*;
use crate::descriptor::calc_checksum;
use alloc::string::ToString;
use assert_matches::assert_matches;

// test calc_checksum() function; it should return the same value as Bitcoin Core
Expand Down Expand Up @@ -81,7 +85,17 @@ mod test {

assert_matches!(
calc_checksum(&invalid_desc),
Err(DescriptorError::Miniscript(miniscript::Error::BadDescriptor(e))) if e == format!("Invalid character in checksum: '{sparkle_heart}'")
Err(DescriptorError::Miniscript(
miniscript::Error::Parse(
miniscript::ParseError::Tree(
miniscript::ParseTreeError::Checksum(
miniscript::descriptor::checksum::Error::InvalidCharacter { ch, pos })
)
)
)
)
if ch.to_string() == sparkle_heart
&& pos == 85
);
}
}
36 changes: 22 additions & 14 deletions src/descriptor/dsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ macro_rules! impl_top_level_sh {
use $crate::miniscript::$ctx;

let build_desc = |k, pks| {
Ok((Descriptor::<DescriptorPublicKey>::$inner_struct($inner_struct::$sortedmulti_constructor(k, pks)?), PhantomData::<$ctx>))
let thresh = miniscript::Threshold::new(k, pks)?;
Ok((Descriptor::<DescriptorPublicKey>::$inner_struct($inner_struct::$sortedmulti_constructor(thresh)?), PhantomData::<$ctx>))
};

$crate::impl_sortedmulti!(build_desc, sortedmulti $( $inner )*)
Expand All @@ -42,7 +43,8 @@ macro_rules! impl_top_level_sh {
use $crate::miniscript::$ctx;

let build_desc = |k, pks| {
Ok((Descriptor::<DescriptorPublicKey>::$inner_struct($inner_struct::$sortedmulti_constructor(k, pks)?), PhantomData::<$ctx>))
let thresh = miniscript::Threshold::new(k, pks)?;
Ok((Descriptor::<DescriptorPublicKey>::$inner_struct($inner_struct::$sortedmulti_constructor(thresh)?), PhantomData::<$ctx>))
};

$crate::impl_sortedmulti!(build_desc, sortedmulti_vec $( $inner )*)
Expand Down Expand Up @@ -294,7 +296,7 @@ macro_rules! parse_tap_tree {
.and_then(|tree_a| Ok((tree_a, $tree_b?)))
.and_then(|((a_tree, mut a_keymap, a_network_kinds), (b_tree, b_keymap, b_network_kinds))| {
a_keymap.extend(b_keymap.into_iter());
Ok((TapTree::combine(a_tree, b_tree), a_keymap, $crate::keys::intersect_network_kinds(&a_network_kinds, &b_network_kinds)))
Ok((TapTree::combine(a_tree, b_tree)?, a_keymap, $crate::keys::intersect_network_kinds(&a_network_kinds, &b_network_kinds)))
})

}};
Expand Down Expand Up @@ -331,11 +333,10 @@ macro_rules! parse_tap_tree {

// Single leaf
( $op:ident ( $( $minisc:tt )* ) ) => {{
use $crate::alloc::sync::Arc;
use $crate::miniscript::descriptor::TapTree;

$crate::fragment!( $op ( $( $minisc )* ) )
.map(|(a_minisc, a_keymap, a_network_kinds)| (TapTree::Leaf(Arc::new(a_minisc)), a_keymap, a_network_kinds))
.map(|(a_minisc, a_keymap, a_network_kinds)| (TapTree::leaf(a_minisc), a_keymap, a_network_kinds))
}};
}

Expand Down Expand Up @@ -721,10 +722,14 @@ macro_rules! fragment {
$crate::keys::make_pkh($key, &secp)
});
( after ( $value:expr ) ) => ({
$crate::impl_leaf_opcode_value!(After, $crate::miniscript::AbsLockTime::from_consensus($value).expect("valid `AbsLockTime`"))
$crate::miniscript::AbsLockTime::from_consensus($value)
.map_err($crate::descriptor::DescriptorError::from)
.and_then(|abs_lt| $crate::impl_leaf_opcode_value!(After, abs_lt))
});
( older ( $value:expr ) ) => ({
$crate::impl_leaf_opcode_value!(Older, $crate::miniscript::RelLockTime::from_consensus($value).expect("valid `RelLockTime`")) // TODO!!
$crate::miniscript::RelLockTime::from_consensus($value)
.map_err($crate::descriptor::DescriptorError::from)
.and_then(|rel_lt| $crate::impl_leaf_opcode_value!(Older, rel_lt))
});
( sha256 ( $hash:expr ) ) => ({
$crate::impl_leaf_opcode_value!(Sha256, $hash)
Expand Down Expand Up @@ -775,9 +780,12 @@ macro_rules! fragment {
(keys_acc, net_acc)
});

let thresh = $crate::miniscript::Threshold::new($thresh, items).expect("valid threshold and pks collection");
$crate::impl_leaf_opcode_value!(Thresh, thresh)
.map(|(minisc, _, _)| (minisc, key_maps, valid_network_kinds))
$crate::miniscript::Threshold::new($thresh, items)
.map_err($crate::descriptor::DescriptorError::from)
.and_then(|thresh| {
$crate::impl_leaf_opcode_value!(Thresh, thresh)
.map(|(minisc, _, _)| (minisc, key_maps, valid_network_kinds))
})
});
( thresh ( $thresh:expr, $( $inner:tt )* ) ) => ({
let items = $crate::fragment_internal!( @v $( $inner )* );
Expand All @@ -789,8 +797,8 @@ macro_rules! fragment {
let secp = $crate::bitcoin::secp256k1::Secp256k1::new();

let fun = |k, pks| {
let thresh = $crate::miniscript::Threshold::new(k, pks).expect("valid threshold and pks collection");
$crate::miniscript::Terminal::Multi(thresh)
let thresh = $crate::miniscript::Threshold::new(k, pks)?;
Ok($crate::miniscript::Terminal::Multi(thresh))
};

$crate::keys::make_multi($thresh, fun, $keys, &secp)
Expand All @@ -803,8 +811,8 @@ macro_rules! fragment {
let secp = $crate::bitcoin::secp256k1::Secp256k1::new();

let fun = |k, pks| {
let thresh = $crate::miniscript::Threshold::new(k, pks).expect("valid threshold and pks collection");
$crate::miniscript::Terminal::MultiA(thresh)
let thresh = $crate::miniscript::Threshold::new(k, pks)?;
Ok($crate::miniscript::Terminal::MultiA(thresh))
};

$crate::keys::make_multi($thresh, fun, $keys, &secp)
Expand Down
34 changes: 33 additions & 1 deletion src/descriptor/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
use core::fmt;

/// Errors related to the parsing and usage of descriptors
#[derive(Debug, PartialEq)]
#[derive(Debug)]
pub enum Error {
/// Invalid HD Key path, such as having a wildcard but a length != 1
InvalidHdKeyPath,
Expand Down Expand Up @@ -126,3 +126,35 @@ impl From<crate::descriptor::policy::PolicyError> for Error {
Error::Policy(err)
}
}

impl From<miniscript::descriptor::checksum::Error> for Error {
fn from(e: miniscript::descriptor::checksum::Error) -> Self {
Self::Miniscript(miniscript::Error::Parse(miniscript::ParseError::Tree(
miniscript::ParseTreeError::Checksum(e),
)))
}
}

impl From<miniscript::descriptor::TapTreeDepthError> for Error {
fn from(e: miniscript::descriptor::TapTreeDepthError) -> Self {
Self::Miniscript(miniscript::Error::TapTreeDepthError(e))
}
}

impl From<miniscript::ThresholdError> for Error {
fn from(e: miniscript::ThresholdError) -> Self {
Self::Miniscript(miniscript::Error::Threshold(e))
}
}

impl From<miniscript::AbsLockTimeError> for Error {
fn from(e: miniscript::AbsLockTimeError) -> Self {
Self::Miniscript(miniscript::Error::AbsoluteLockTime(e))
}
}

impl From<miniscript::RelLockTimeError> for Error {
fn from(e: miniscript::RelLockTimeError) -> Self {
Self::Miniscript(miniscript::Error::RelativeLockTime(e))
}
}
Loading
Loading