bitcoindevkit / bitcoindevkit/bdk
`KeychainTxOutIndex::insert_descriptor` panics on unsupported derivation paths
- Dominant language
- Rust
- Stars
- 1.1k
- Forks
- 483
- Avg merge
- 20d 3h
- Merged PRs (30d)
- 3
Description
**Describe the bug**
Syntactically valid descriptors can parse successfully and then panic inside `KeychainTxOutIndex::insert_descriptor`, before it returns its `Result`:
- `wpkh(/0/*')` and `wpkh(/0'/1)`: miniscript panics with `HardenedStep`.
- `wpkh(/<0;1>/*)`: `descriptor_id()` unwraps `Err(Multipath)`.
`insert_descriptor` computes `descriptor_id()` before validating these derivation forms. Callers cannot handle the failed insertion through the returned `Result`.
This issue was found by AI.
**To Reproduce**
Add this test to `crates/chain/tests/test_keychain_txout_index.rs` and run `cargo test -p bdk_chain --test test_keychain_txout_index insert_descriptor_does_not_panic_on_hardened_wildcard`. Reproduced on `acc06e53220960caa89efd5984d7b43914640dd4` with miniscript 13.1.0.
```rust
#[test]
fn insert_descriptor_does_not_panic_on_hardened_wildcard() {
use bdk_chain::{
keychain_txout::KeychainTxOutIndex,
miniscript::{Descriptor, DescriptorPublicKey},
};
const XPUB: &str = "tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp";
let descriptor: Descriptor =
format!("wpkh({XPUB}/0/*')").parse().unwrap();
let mut index = KeychainTxOutIndex::::new(1, true);
let _ = index.insert_descriptor(0, descriptor); // Panics inside this call.
}
```
Replacing `/0/*'` with `/0'/1` or `/<0;1>/*` reproduces the other cases.
**Expected behavior**
Unsupported descriptor forms should be handled without panicking, allowing callers to handle failed insertion through the API.
Contributor guide
Research direction
Start in the KeychainTxOutIndex::insert_descriptor implementation and inspect its descriptor_id() call before validation. Add or run the regression test in crates/chain/tests/test_keychain_txout_index.rs for the hardened wildcard, alternate derivation, and multipath forms. Done means each unsupported descriptor returns through the Result API without panicking.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100