Skip to content

Commit aacb5d9

Browse files
committed
tr: add conversion from TrSpendInfo to bitcoin::TapTree
Moves a bit of ugly logic out of the PSBT module into the spendinfo module so that it's available for other users. We can convert from a TrSpendInfo to a bitcoin::TapTree but we can't do the opposite conversion since TrSpendInfo expects to have a Miniscript for each leaf.
1 parent de8e418 commit aacb5d9

File tree

2 files changed

+26
-13
lines changed

2 files changed

+26
-13
lines changed

src/descriptor/tr/spend_info.rs

+22
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,28 @@ impl<Pk: ToPublicKey> TrSpendInfo<Pk> {
189189
done_left_stack: BitStack128::default(),
190190
}
191191
}
192+
193+
/// If the Taproot tree is not keyspend-only, converts it to a [`bitcoin::taproot::TapTree`] structure.
194+
///
195+
/// This conversion is not particularly efficient but the resulting data structure is
196+
/// useful for interacting with PSBTs.
197+
pub fn to_tap_tree(&self) -> Option<bitcoin::taproot::TapTree> {
198+
if self.nodes.is_empty() {
199+
return None;
200+
}
201+
202+
let mut builder = bitcoin::taproot::TaprootBuilder::new();
203+
for leaf in self.leaves() {
204+
builder = builder
205+
.add_leaf_with_ver(
206+
leaf.depth(),
207+
ScriptBuf::from(leaf.script()),
208+
leaf.leaf_version(),
209+
)
210+
.expect("iterating through tree in correct DFS order")
211+
}
212+
Some(bitcoin::taproot::TapTree::try_from(builder).expect("tree is complete"))
213+
}
192214
}
193215

194216
/// An internal node of the spend

src/psbt/mod.rs

+4-13
Original file line numberDiff line numberDiff line change
@@ -1109,13 +1109,9 @@ fn update_item_with_descriptor_helper<F: PsbtFields>(
11091109
*merkle_root = spend_info.merkle_root();
11101110
}
11111111

1112-
let mut builder = taproot::TaprootBuilder::new();
11131112
for leaf_derived in spend_info.leaves() {
11141113
let leaf_script = (ScriptBuf::from(leaf_derived.script()), leaf_derived.leaf_version());
11151114
let tapleaf_hash = leaf_derived.leaf_hash();
1116-
builder = builder
1117-
.add_leaf(leaf_derived.depth(), leaf_script.0.clone())
1118-
.expect("Computing spend data on a valid tree should always succeed");
11191115
if let Some(tap_scripts) = item.tap_scripts() {
11201116
let control_block = leaf_derived.control_block().clone();
11211117
tap_scripts.insert(control_block, leaf_script);
@@ -1141,15 +1137,10 @@ fn update_item_with_descriptor_helper<F: PsbtFields>(
11411137
tapleaf_hashes.dedup();
11421138
}
11431139

1144-
match item.tap_tree() {
1145-
// Only set the tap_tree if the item supports it (it's an output) and the descriptor actually
1146-
// contains one, otherwise it'll just be empty
1147-
Some(tap_tree) if tr_derived.tap_tree().is_some() => {
1148-
*tap_tree = Some(
1149-
taproot::TapTree::try_from(builder).expect("The tree should always be valid"),
1150-
);
1151-
}
1152-
_ => {}
1140+
// Only set the tap_tree if the item supports it (it's an output) and the descriptor actually
1141+
// contains one, otherwise it'll just be empty
1142+
if let Some(tap_tree) = item.tap_tree() {
1143+
*tap_tree = spend_info.to_tap_tree();
11531144
}
11541145
} else {
11551146
item.bip32_derivation().append(&mut bip32_derivation.0);

0 commit comments

Comments
 (0)