diff --git a/CHANGELOG.md b/CHANGELOG.md index 629200b8..f4afec27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index 9fad0318..b704bff8 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -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(()) } @@ -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)