Skip to content

Commit aa3f2a2

Browse files
committed
feat: Expose wildcard and sanity checks on Descriptor
1 parent 36ea2f4 commit aa3f2a2

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ Changelog information can also be found in each release's git tag (which can be
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [Unreleased](https://github.com/bitcoindevkit/bdk-ffi/compare/v2.3.0...HEAD)
8+
9+
### Added
10+
- Expose miniscript `has_wildcard` and `sanity_check` methods on `Descriptor` type #945
11+
712
## [v2.3.0]
813

914
This is version `2.3.0` of the BDK language bindings! This release uses the following Rust dependencies:

bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/DescriptorTest.kt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ package org.bitcoindevkit
22

33
import kotlin.test.Test
44
import androidx.test.ext.junit.runners.AndroidJUnit4
5+
import org.junit.Assert.assertFalse
6+
import org.junit.Assert.assertTrue
57
import org.junit.runner.RunWith
68
import kotlin.test.assertFails
9+
import kotlin.test.assertFailsWith
710

811
@RunWith(AndroidJUnit4::class)
912
class DescriptorTest {
@@ -47,4 +50,30 @@ class DescriptorTest {
4750
)
4851
}
4952
}
53+
54+
@Test
55+
fun sanityCheck() {
56+
val safeDescriptor = Descriptor("multi(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", Network.BITCOIN)
57+
58+
safeDescriptor.sanityCheck()
59+
60+
//multi(2, key1, key1)) is structurally valid but unsafe
61+
val unsafeDescriptor = Descriptor("multi(2,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", Network.BITCOIN)
62+
63+
// descriptor failed as expected because it uses the same public key twice in a 2 of 2 multisig
64+
assertFailsWith<DescriptorException.Miniscript> {
65+
unsafeDescriptor.sanityCheck()
66+
}
67+
}
68+
69+
@Test
70+
fun checkDescriptorWildcard(){
71+
val wildcardDescriptor = Descriptor("wpkh($TEST_EXTENDED_PRIVKEY/$BIP84_TEST_RECEIVE_PATH/*)", Network.REGTEST)
72+
val nonWildcardDescriptor = Descriptor("wpkh($TEST_EXTENDED_PRIVKEY/$BIP84_TEST_RECEIVE_PATH/0)", Network.REGTEST)
73+
74+
assertTrue(wildcardDescriptor.hasWildcard())
75+
76+
assertFalse(nonWildcardDescriptor.hasWildcard())
77+
}
78+
5079
}

bdk-ffi/src/descriptor.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,28 @@ impl Descriptor {
384384

385385
Ok(Arc::new(address))
386386
}
387+
388+
/// Whether or not the descriptor has any wildcards.
389+
pub fn has_wildcard(&self) -> bool {
390+
self.extended_descriptor.has_wildcard()
391+
}
392+
393+
/// Checks whether the descriptor is safe.
394+
///
395+
/// Checks whether all the spend paths in the descriptor are possible on the
396+
/// bitcoin network under the current standardness and consensus rules. Also
397+
/// checks whether the descriptor requires signatures on all spend paths and
398+
/// whether the script is malleable.
399+
///
400+
/// In general, all the guarantees of miniscript hold only for safe scripts.
401+
/// The signer may not be able to find satisfactions even if one exists.
402+
pub fn sanity_check(&self) -> Result<(), DescriptorError> {
403+
self.extended_descriptor
404+
.sanity_check()
405+
.map_err(|e| DescriptorError::Miniscript {
406+
error_message: e.to_string(),
407+
})
408+
}
387409
}
388410

389411
impl Display for Descriptor {

0 commit comments

Comments
 (0)