Skip to content

Commit 0ae4b40

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 0ae4b40

File tree

1 file changed

+33
-25
lines changed

1 file changed

+33
-25
lines changed

src/descriptor/tr.rs

Lines changed: 33 additions & 25 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,9 @@ 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+
fn height(&self) -> usize {
115119
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-
}
120+
TapTree::Tree { left: _, right: _, ref height } => *height,
119121
TapTree::Leaf(..) => 0,
120122
}
121123
}
@@ -134,12 +136,13 @@ impl<Pk: MiniscriptKey> TapTree<Pk> {
134136
T: Translator<Pk, Q, E>,
135137
Q: MiniscriptKey,
136138
{
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)?)),
139+
let frag = match *self {
140+
TapTree::Tree { ref left, ref right, ref height } => TapTree::Tree {
141+
left: Arc::new(left.translate_helper(t)?),
142+
right: Arc::new(right.translate_helper(t)?),
143+
height: *height,
144+
},
145+
TapTree::Leaf(ref ms) => TapTree::Leaf(Arc::new(ms.translate_pk(t)?)),
143146
};
144147
Ok(frag)
145148
}
@@ -148,7 +151,7 @@ impl<Pk: MiniscriptKey> TapTree<Pk> {
148151
impl<Pk: MiniscriptKey> fmt::Display for TapTree<Pk> {
149152
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150153
match self {
151-
TapTree::Tree(ref left, ref right) => write!(f, "{{{},{}}}", *left, *right),
154+
TapTree::Tree {ref left, ref right, height: _ } => write!(f, "{{{},{}}}", *left, *right),
152155
TapTree::Leaf(ref script) => write!(f, "{}", *script),
153156
}
154157
}
@@ -157,7 +160,7 @@ impl<Pk: MiniscriptKey> fmt::Display for TapTree<Pk> {
157160
impl<Pk: MiniscriptKey> fmt::Debug for TapTree<Pk> {
158161
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159162
match self {
160-
TapTree::Tree(ref left, ref right) => write!(f, "{{{:?},{:?}}}", *left, *right),
163+
TapTree::Tree { ref left, ref right, height: _ } => write!(f, "{{{:?},{:?}}}", *left, *right),
161164
TapTree::Leaf(ref script) => write!(f, "{:?}", *script),
162165
}
163166
}
@@ -167,7 +170,7 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
167170
/// Create a new [`Tr`] descriptor from internal key and [`TapTree`]
168171
pub fn new(internal_key: Pk, tree: Option<TapTree<Pk>>) -> Result<Self, Error> {
169172
Tap::check_pk(&internal_key)?;
170-
let nodes = tree.as_ref().map(|t| t.tap_tree_height()).unwrap_or(0);
173+
let nodes = tree.as_ref().map(|t| t.height()).unwrap_or(0);
171174

172175
if nodes <= TAPROOT_CONTROL_MAX_NODE_COUNT {
173176
Ok(Self {
@@ -407,9 +410,9 @@ where
407410
fn next(&mut self) -> Option<Self::Item> {
408411
while let Some((depth, last)) = self.stack.pop() {
409412
match *last {
410-
TapTree::Tree(ref l, ref r) => {
411-
self.stack.push((depth + 1, r));
412-
self.stack.push((depth + 1, l));
413+
TapTree::Tree { ref left, ref right, height: _ } => {
414+
self.stack.push((depth + 1, right));
415+
self.stack.push((depth + 1, left));
413416
}
414417
TapTree::Leaf(ref ms) => return Some((depth, ms)),
415418
}
@@ -431,7 +434,12 @@ impl_block_str!(
431434
expression::Tree { name, args } if name.is_empty() && args.len() == 2 => {
432435
let left = Self::parse_tr_script_spend(&args[0])?;
433436
let right = Self::parse_tr_script_spend(&args[1])?;
434-
Ok(TapTree::Tree(Arc::new(left), Arc::new(right)))
437+
let height = 1 + max(left.height(), right.height());
438+
Ok(TapTree::Tree {
439+
left: Arc::new(left),
440+
right: Arc::new(right),
441+
height,
442+
})
435443
}
436444
_ => Err(Error::Unexpected(
437445
"unknown format for script spending paths while parsing taproot descriptor"
@@ -589,9 +597,9 @@ fn split_once(inp: &str, delim: char) -> Option<(&str, &str)> {
589597
impl<Pk: MiniscriptKey> Liftable<Pk> for TapTree<Pk> {
590598
fn lift(&self) -> Result<Policy<Pk>, Error> {
591599
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)?]))
600+
match *s {
601+
TapTree::Tree { ref left, ref right, height: _ } => {
602+
Ok(Policy::Threshold(1, vec![lift_helper(left)?, lift_helper(right)?]))
595603
}
596604
TapTree::Leaf(ref leaf) => leaf.lift(),
597605
}
@@ -742,6 +750,6 @@ mod tests {
742750
fn height() {
743751
let desc = descriptor();
744752
let tr = Tr::<String>::from_str(&desc).unwrap();
745-
assert_eq!(tr.tap_tree().as_ref().unwrap().tap_tree_height(), 2);
753+
assert_eq!(tr.tap_tree().as_ref().unwrap().height(), 2);
746754
}
747755
}

0 commit comments

Comments
 (0)