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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- `ct()` descriptors accept `eltr` with script leaves that contain no extension fragments.
- Miniscript and policy strings accept a trailing descriptor checksum, which is verified. The text after the last `#` is read as the checksum, so a key containing `#` is only accepted when a valid checksum follows.
- `pegin()` and `legacy_pegin()` descriptors can be parsed from strings. `LegacyPegin` displays its inner descriptor without the inner checksum. A successful parse does not check the restrictions that pegin spending places on the descriptor. Unsupported forms, such as an `eltr` Elements descriptor, still parse and can panic in the unchanged Bitcoin-side methods, including `bitcoin_address`, `bitcoin_witness_script` and `get_bitcoin_satisfaction`.
- Updating a PSET output with an `eltr` descriptor that has no script tree sets its `tap_tree` to `None`.

# 0.5.0 - Sep 20, 2026

Expand Down
32 changes: 24 additions & 8 deletions src/psbt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1345,15 +1345,14 @@ where
tapleaf_hashes.dedup();
}

match item.tap_tree() {
// Only set the tap_tree if the item supports it (it's an output) and the descriptor actually
// contains one, otherwise it'll just be empty
Some(tap_tree) if tr_derived.taptree().is_some() => {
*tap_tree =
Some(psbt::TapTree::from_inner(builder).expect("The tree should always be valid"));
}
_ => {}
// Only set the tap_tree if the item supports it (it's an output) and the descriptor actually
// contains one, otherwise it'll just be empty
if let Some(tap_tree) = item.tap_tree() {
*tap_tree = tr_derived.taptree().as_ref().map(|_| {
psbt::TapTree::from_inner(builder).expect("The tree should always be valid")
});
}

Ok(())
}

Expand Down Expand Up @@ -1695,6 +1694,23 @@ mod tests {
}
}

#[test]
fn test_update_output_tr_key_only_clears_tap_tree() {
let xpub = "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ";
let with_tree = Descriptor::from_str(&format!("eltr({xpub}/0/0,pk({xpub}/0/1))")).unwrap();
let key_only = Descriptor::from_str(&format!("eltr({xpub}/0/0)")).unwrap();

let mut psbt_output = psbt::Output::default();
psbt_output
.update_with_descriptor_unchecked(&with_tree)
.unwrap();
assert!(psbt_output.tap_tree.is_some());
psbt_output
.update_with_descriptor_unchecked(&key_only)
.unwrap();
assert_eq!(psbt_output.tap_tree, None);
}

#[test]
fn test_update_item_non_tr_multi() {
// values taken from https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki (after removing zpub thingy)
Expand Down
Loading