Skip to content
Open
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
83 changes: 77 additions & 6 deletions src/descriptor/dsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -765,8 +765,10 @@ 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)
$crate::miniscript::Threshold::new($thresh, items)
.map_err($crate::miniscript::Error::Threshold)
.map_err($crate::descriptor::DescriptorError::Miniscript)
.and_then(|thresh| $crate::impl_leaf_opcode_value!(Thresh, thresh))
.map(|(minisc, _, _)| (minisc, key_maps, valid_network_kinds))
});
( thresh ( $thresh:expr, $( $inner:tt )* ) ) => ({
Expand All @@ -779,8 +781,10 @@ 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)
$crate::miniscript::Threshold::new(k, pks)
.map($crate::miniscript::Terminal::Multi)
.map_err($crate::miniscript::Error::Threshold)
.map_err($crate::descriptor::DescriptorError::Miniscript)
};

$crate::keys::make_multi($thresh, fun, $keys, &secp)
Expand All @@ -793,8 +797,10 @@ 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)
$crate::miniscript::Threshold::new(k, pks)
.map($crate::miniscript::Terminal::MultiA)
.map_err($crate::miniscript::Error::Threshold)
.map_err($crate::descriptor::DescriptorError::Miniscript)
};

$crate::keys::make_multi($thresh, fun, $keys, &secp)
Expand Down Expand Up @@ -1117,6 +1123,71 @@ mod test {
);
}

#[test]
fn test_dsl_multi_invalid_threshold_returns_error_not_panic() {
let key_1 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
let path_1 = bip32::DerivationPath::from_str("m/0").unwrap();
let key_2 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap();
let path_2 = bip32::DerivationPath::from_str("m/1").unwrap();
let desc_key1 = (key_1, path_1).into_descriptor_key().unwrap();
let desc_key2 = (key_2, path_2).into_descriptor_key().unwrap();

let result = descriptor!(wsh(multi(3, desc_key1, desc_key2)));

assert!(
result.is_err(),
"invalid threshold (k > n) should return Err, not panic"
);
assert!(matches!(
result,
Err(DescriptorError::Miniscript(miniscript::Error::Threshold(_)))
));
}

#[test]
fn test_dsl_thresh_invalid_threshold_returns_error_not_panic() {
let key_1 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
let path_1 = bip32::DerivationPath::from_str("m/0").unwrap();
let key_2 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap();
let path_2 = bip32::DerivationPath::from_str("m/1").unwrap();
let desc_key1 = (key_1, path_1).into_descriptor_key().unwrap();
let desc_key2 = (key_2, path_2).into_descriptor_key().unwrap();

let result = descriptor!(wsh(thresh(3, pk(desc_key1), pk(desc_key2))));

assert!(
result.is_err(),
"invalid threshold (k > n) should return Err, not panic"
);
assert!(matches!(
result,
Err(DescriptorError::Miniscript(miniscript::Error::Threshold(_)))
));
}

#[test]
fn test_dsl_multi_a_invalid_threshold_returns_error_not_panic() {
let internal_key =
PrivateKey::from_wif("cSQPHDBwXGjVzWRqAHm6zfvQhaTuj1f2bFH58h55ghbjtFwvmeXR").unwrap();
let key_1 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
let path_1 = bip32::DerivationPath::from_str("m/0").unwrap();
let key_2 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap();
let path_2 = bip32::DerivationPath::from_str("m/1").unwrap();
let desc_key1 = (key_1, path_1).into_descriptor_key().unwrap();
let desc_key2 = (key_2, path_2).into_descriptor_key().unwrap();

let result = descriptor!(tr(internal_key, multi_a(3, desc_key1, desc_key2)));

assert!(
result.is_err(),
"invalid threshold (k > n) should return Err, not panic"
);
assert!(matches!(
result,
Err(DescriptorError::Miniscript(miniscript::Error::Threshold(_)))
));
}

// Verify that the `valid_network_kinds` returned is correctly computed based on the keys
// present in the descriptor.
#[test]
Expand Down
7 changes: 5 additions & 2 deletions src/keys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,10 @@ pub fn make_pkh<Pk: IntoDescriptorKey<Ctx>, Ctx: ScriptContext>(
pub fn make_multi<
Pk: IntoDescriptorKey<Ctx>,
Ctx: ScriptContext,
V: Fn(usize, Vec<DescriptorPublicKey>) -> Terminal<DescriptorPublicKey, Ctx>,
V: Fn(
usize,
Vec<DescriptorPublicKey>,
) -> Result<Terminal<DescriptorPublicKey, Ctx>, DescriptorError>,
>(
thresh: usize,
variant: V,
Expand All @@ -879,7 +882,7 @@ pub fn make_multi<
DescriptorError,
> {
let (pks, key_map, valid_network_kinds) = expand_multi_keys(pks, secp)?;
let minisc = Miniscript::from_ast(variant(thresh, pks))?;
let minisc = Miniscript::from_ast(variant(thresh, pks)?)?;

minisc.check_miniscript()?;

Expand Down