Skip to content

Commit c960798

Browse files
committed
Add height to tap tree
Convert tuple `TapTree` tuple to a struct and add `height` to it. This saves recusive call in `tap_tree_height` function. While we are at it rename private function `TapTree::tap_tree_height` to `TapTree::height` because it stutters.
1 parent d7bb03b commit c960798

File tree

3 files changed

+83
-48
lines changed

3 files changed

+83
-48
lines changed

src/descriptor/tr.rs

Lines changed: 65 additions & 26 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
@@ -108,14 +115,24 @@ impl<Pk: MiniscriptKey> hash::Hash for Tr<Pk> {
108115
}
109116

110117
impl<Pk: MiniscriptKey> TapTree<Pk> {
111-
// Helper function to compute height
112-
// TODO: Instead of computing this every time we add a new leaf, we should
113-
// add height as a separate field in tap tree
114-
fn tap_tree_height(&self) -> usize {
118+
/// Combine `left` and `right` leaves into a tree.
119+
pub(crate) fn combine(left: TapTree<Pk>, right: TapTree<Pk>) -> Self {
120+
let height = 1 + max(left.height(), right.height());
121+
TapTree::Tree {
122+
left: Arc::new(left),
123+
right: Arc::new(right),
124+
height,
125+
}
126+
}
127+
128+
/// Returns the height of this tree (leaves are defined as height 0).
129+
fn height(&self) -> usize {
115130
match *self {
116-
TapTree::Tree(ref left_tree, ref right_tree) => {
117-
1 + max(left_tree.tap_tree_height(), right_tree.tap_tree_height())
118-
}
131+
TapTree::Tree {
132+
left: _,
133+
right: _,
134+
ref height,
135+
} => *height,
119136
TapTree::Leaf(..) => 0,
120137
}
121138
}
@@ -134,12 +151,17 @@ impl<Pk: MiniscriptKey> TapTree<Pk> {
134151
T: Translator<Pk, Q, E>,
135152
Q: MiniscriptKey,
136153
{
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)?)),
154+
let frag = match *self {
155+
TapTree::Tree {
156+
ref left,
157+
ref right,
158+
ref height,
159+
} => TapTree::Tree {
160+
left: Arc::new(left.translate_helper(t)?),
161+
right: Arc::new(right.translate_helper(t)?),
162+
height: *height,
163+
},
164+
TapTree::Leaf(ref ms) => TapTree::Leaf(Arc::new(ms.translate_pk(t)?)),
143165
};
144166
Ok(frag)
145167
}
@@ -148,7 +170,11 @@ impl<Pk: MiniscriptKey> TapTree<Pk> {
148170
impl<Pk: MiniscriptKey> fmt::Display for TapTree<Pk> {
149171
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150172
match self {
151-
TapTree::Tree(ref left, ref right) => write!(f, "{{{},{}}}", *left, *right),
173+
TapTree::Tree {
174+
ref left,
175+
ref right,
176+
height: _,
177+
} => write!(f, "{{{},{}}}", *left, *right),
152178
TapTree::Leaf(ref script) => write!(f, "{}", *script),
153179
}
154180
}
@@ -157,7 +183,11 @@ impl<Pk: MiniscriptKey> fmt::Display for TapTree<Pk> {
157183
impl<Pk: MiniscriptKey> fmt::Debug for TapTree<Pk> {
158184
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159185
match self {
160-
TapTree::Tree(ref left, ref right) => write!(f, "{{{:?},{:?}}}", *left, *right),
186+
TapTree::Tree {
187+
ref left,
188+
ref right,
189+
height: _,
190+
} => write!(f, "{{{:?},{:?}}}", *left, *right),
161191
TapTree::Leaf(ref script) => write!(f, "{:?}", *script),
162192
}
163193
}
@@ -167,7 +197,7 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
167197
/// Create a new [`Tr`] descriptor from internal key and [`TapTree`]
168198
pub fn new(internal_key: Pk, tree: Option<TapTree<Pk>>) -> Result<Self, Error> {
169199
Tap::check_pk(&internal_key)?;
170-
let nodes = tree.as_ref().map(|t| t.tap_tree_height()).unwrap_or(0);
200+
let nodes = tree.as_ref().map(|t| t.height()).unwrap_or(0);
171201

172202
if nodes <= TAPROOT_CONTROL_MAX_NODE_COUNT {
173203
Ok(Self {
@@ -407,9 +437,13 @@ where
407437
fn next(&mut self) -> Option<Self::Item> {
408438
while let Some((depth, last)) = self.stack.pop() {
409439
match *last {
410-
TapTree::Tree(ref l, ref r) => {
411-
self.stack.push((depth + 1, r));
412-
self.stack.push((depth + 1, l));
440+
TapTree::Tree {
441+
ref left,
442+
ref right,
443+
height: _,
444+
} => {
445+
self.stack.push((depth + 1, right));
446+
self.stack.push((depth + 1, left));
413447
}
414448
TapTree::Leaf(ref ms) => return Some((depth, ms)),
415449
}
@@ -431,7 +465,7 @@ impl_block_str!(
431465
expression::Tree { name, args } if name.is_empty() && args.len() == 2 => {
432466
let left = Self::parse_tr_script_spend(&args[0])?;
433467
let right = Self::parse_tr_script_spend(&args[1])?;
434-
Ok(TapTree::Tree(Arc::new(left), Arc::new(right)))
468+
Ok(TapTree::combine(left, right))
435469
}
436470
_ => Err(Error::Unexpected(
437471
"unknown format for script spending paths while parsing taproot descriptor"
@@ -589,10 +623,15 @@ fn split_once(inp: &str, delim: char) -> Option<(&str, &str)> {
589623
impl<Pk: MiniscriptKey> Liftable<Pk> for TapTree<Pk> {
590624
fn lift(&self) -> Result<Policy<Pk>, Error> {
591625
fn lift_helper<Pk: MiniscriptKey>(s: &TapTree<Pk>) -> Result<Policy<Pk>, Error> {
592-
match s {
593-
TapTree::Tree(ref l, ref r) => {
594-
Ok(Policy::Threshold(1, vec![lift_helper(l)?, lift_helper(r)?]))
595-
}
626+
match *s {
627+
TapTree::Tree {
628+
ref left,
629+
ref right,
630+
height: _,
631+
} => Ok(Policy::Threshold(
632+
1,
633+
vec![lift_helper(left)?, lift_helper(right)?],
634+
)),
596635
TapTree::Leaf(ref leaf) => leaf.lift(),
597636
}
598637
}
@@ -742,6 +781,6 @@ mod tests {
742781
fn height() {
743782
let desc = descriptor();
744783
let tr = Tr::<String>::from_str(&desc).unwrap();
745-
assert_eq!(tr.tap_tree().as_ref().unwrap().tap_tree_height(), 2);
784+
assert_eq!(tr.tap_tree().as_ref().unwrap().height(), 2);
746785
}
747786
}

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)