Skip to content

Commit 88f96d3

Browse files
committed
Add height to tap tree
Currently calculating the height of a `TapTree::Tree` uses a recursive call, we can optimize this out by storing the height along with the tree nodes. Convert the `TapTree::Tree` tuple struct to a struct with named fields. Include a `height` field in the new struct.
1 parent 3649724 commit 88f96d3

File tree

3 files changed

+65
-40
lines changed

3 files changed

+65
-40
lines changed

src/descriptor/tr.rs

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,14 @@ use crate::{
2929
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
3030
pub enum TapTree<Pk: MiniscriptKey> {
3131
/// A taproot tree structure
32-
Tree(Arc<TapTree<Pk>>, Arc<TapTree<Pk>>),
32+
Tree {
33+
/// Left tree branch.
34+
left: Arc<TapTree<Pk>>,
35+
/// Right tree branch.
36+
right: Arc<TapTree<Pk>>,
37+
/// Tree height, defined as `1 + max(left_height, right_height)`.
38+
height: usize,
39+
},
3340
/// A taproot leaf denoting a spending condition
3441
// A new leaf version would require a new Context, therefore there is no point
3542
// in adding a LeafVersion with Leaf type here. All Miniscripts right now
@@ -134,12 +141,17 @@ impl<Pk: MiniscriptKey> TapTree<Pk> {
134141
T: Translator<Pk, Q, E>,
135142
Q: MiniscriptKey,
136143
{
137-
let frag = match self {
138-
TapTree::Tree(l, r) => TapTree::Tree(
139-
Arc::new(l.translate_helper(t)?),
140-
Arc::new(r.translate_helper(t)?),
141-
),
142-
TapTree::Leaf(ms) => TapTree::Leaf(Arc::new(ms.translate_pk(t)?)),
144+
let frag = match *self {
145+
TapTree::Tree {
146+
ref left,
147+
ref right,
148+
ref height,
149+
} => TapTree::Tree {
150+
left: Arc::new(left.translate_helper(t)?),
151+
right: Arc::new(right.translate_helper(t)?),
152+
height: *height,
153+
},
154+
TapTree::Leaf(ref ms) => TapTree::Leaf(Arc::new(ms.translate_pk(t)?)),
143155
};
144156
Ok(frag)
145157
}
@@ -148,7 +160,11 @@ impl<Pk: MiniscriptKey> TapTree<Pk> {
148160
impl<Pk: MiniscriptKey> fmt::Display for TapTree<Pk> {
149161
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150162
match self {
151-
TapTree::Tree(ref left, ref right) => write!(f, "{{{},{}}}", *left, *right),
163+
TapTree::Tree {
164+
ref left,
165+
ref right,
166+
height: _,
167+
} => write!(f, "{{{},{}}}", *left, *right),
152168
TapTree::Leaf(ref script) => write!(f, "{}", *script),
153169
}
154170
}
@@ -157,7 +173,11 @@ impl<Pk: MiniscriptKey> fmt::Display for TapTree<Pk> {
157173
impl<Pk: MiniscriptKey> fmt::Debug for TapTree<Pk> {
158174
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159175
match self {
160-
TapTree::Tree(ref left, ref right) => write!(f, "{{{:?},{:?}}}", *left, *right),
176+
TapTree::Tree {
177+
ref left,
178+
ref right,
179+
height: _,
180+
} => write!(f, "{{{:?},{:?}}}", *left, *right),
161181
TapTree::Leaf(ref script) => write!(f, "{:?}", *script),
162182
}
163183
}
@@ -413,9 +433,13 @@ where
413433
fn next(&mut self) -> Option<Self::Item> {
414434
while let Some((depth, last)) = self.stack.pop() {
415435
match *last {
416-
TapTree::Tree(ref l, ref r) => {
417-
self.stack.push((depth + 1, r));
418-
self.stack.push((depth + 1, l));
436+
TapTree::Tree {
437+
ref left,
438+
ref right,
439+
height: _,
440+
} => {
441+
self.stack.push((depth + 1, right));
442+
self.stack.push((depth + 1, left));
419443
}
420444
TapTree::Leaf(ref ms) => return Some((depth, ms)),
421445
}
@@ -437,7 +461,7 @@ impl_block_str!(
437461
expression::Tree { name, args } if name.is_empty() && args.len() == 2 => {
438462
let left = Self::parse_tr_script_spend(&args[0])?;
439463
let right = Self::parse_tr_script_spend(&args[1])?;
440-
Ok(TapTree::Tree(Arc::new(left), Arc::new(right)))
464+
Ok(TapTree::combine(left, right))
441465
}
442466
_ => Err(Error::Unexpected(
443467
"unknown format for script spending paths while parsing taproot descriptor"
@@ -595,10 +619,15 @@ fn split_once(inp: &str, delim: char) -> Option<(&str, &str)> {
595619
impl<Pk: MiniscriptKey> Liftable<Pk> for TapTree<Pk> {
596620
fn lift(&self) -> Result<Policy<Pk>, Error> {
597621
fn lift_helper<Pk: MiniscriptKey>(s: &TapTree<Pk>) -> Result<Policy<Pk>, Error> {
598-
match s {
599-
TapTree::Tree(ref l, ref r) => {
600-
Ok(Policy::Threshold(1, vec![lift_helper(l)?, lift_helper(r)?]))
601-
}
622+
match *s {
623+
TapTree::Tree {
624+
ref left,
625+
ref right,
626+
height: _,
627+
} => Ok(Policy::Threshold(
628+
1,
629+
vec![lift_helper(left)?, lift_helper(right)?],
630+
)),
602631
TapTree::Leaf(ref leaf) => leaf.lift(),
603632
}
604633
}
@@ -748,6 +777,6 @@ mod tests {
748777
fn height() {
749778
let desc = descriptor();
750779
let tr = Tr::<String>::from_str(&desc).unwrap();
751-
assert_eq!(tr.tap_tree().as_ref().unwrap().tap_tree_height(), 2);
780+
assert_eq!(tr.tap_tree().as_ref().unwrap().height(), 2);
752781
}
753782
}

src/policy/concrete.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,10 +1202,7 @@ fn with_huffman_tree<Pk: MiniscriptKey>(
12021202
let (p2, s2) = node_weights.pop().expect("len must atleast be two");
12031203

12041204
let p = (p1.0).0 + (p2.0).0;
1205-
node_weights.push((
1206-
Reverse(OrdF64(p)),
1207-
TapTree::Tree(Arc::from(s1), Arc::from(s2)),
1208-
));
1205+
node_weights.push((Reverse(OrdF64(p)), TapTree::combine(s1, s2)));
12091206
}
12101207

12111208
debug_assert!(node_weights.len() == 1);

src/policy/mod.rs

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -387,9 +387,11 @@ mod tests {
387387
Arc::new(ms_str!("and_v(v:pk(C),pk(D))"));
388388
let right_ms_compilation: Arc<Miniscript<String, Tap>> =
389389
Arc::new(ms_str!("and_v(v:pk(A),pk(B))"));
390-
let left_node: Arc<TapTree<String>> = Arc::from(TapTree::Leaf(left_ms_compilation));
391-
let right_node: Arc<TapTree<String>> = Arc::from(TapTree::Leaf(right_ms_compilation));
392-
let tree: TapTree<String> = TapTree::Tree(left_node, right_node);
390+
391+
let left = TapTree::Leaf(left_ms_compilation);
392+
let right = TapTree::Leaf(right_ms_compilation);
393+
let tree = TapTree::combine(left, right);
394+
393395
let expected_descriptor =
394396
Descriptor::new_tr(unspendable_key.clone(), Some(tree)).unwrap();
395397
assert_eq!(descriptor, expected_descriptor);
@@ -457,21 +459,18 @@ mod tests {
457459
.collect::<Vec<_>>();
458460

459461
// Arrange leaf compilations (acc. to probabilities) using huffman encoding into a TapTree
460-
let tree = TapTree::Tree(
461-
Arc::from(TapTree::Tree(
462-
Arc::from(node_compilations[4].clone()),
463-
Arc::from(node_compilations[5].clone()),
464-
)),
465-
Arc::from(TapTree::Tree(
466-
Arc::from(TapTree::Tree(
467-
Arc::from(TapTree::Tree(
468-
Arc::from(node_compilations[0].clone()),
469-
Arc::from(node_compilations[1].clone()),
470-
)),
471-
Arc::from(node_compilations[3].clone()),
472-
)),
473-
Arc::from(node_compilations[6].clone()),
474-
)),
462+
let tree = TapTree::combine(
463+
TapTree::combine(node_compilations[4].clone(), node_compilations[5].clone()),
464+
TapTree::combine(
465+
TapTree::combine(
466+
TapTree::combine(
467+
node_compilations[0].clone(),
468+
node_compilations[1].clone(),
469+
),
470+
node_compilations[3].clone(),
471+
),
472+
node_compilations[6].clone(),
473+
),
475474
);
476475

477476
let expected_descriptor = Descriptor::new_tr("E".to_string(), Some(tree)).unwrap();

0 commit comments

Comments
 (0)