From b083ced24fc430dc812c769ad6e558ffe6627e28 Mon Sep 17 00:00:00 2001 From: startup-dreamer Date: Mon, 10 Apr 2023 06:11:20 +0530 Subject: [PATCH 1/2] renamed taptree, added height caching --- src/descriptor/tr.rs | 78 ++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index 20d0880d8..431803390 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: CC0-1.0 -use core::cmp::{self, max}; +use core::cmp::{self}; use core::str::FromStr; use core::{fmt, hash}; @@ -27,9 +27,9 @@ use crate::{ // Hidden leaves are not yet supported in descriptor spec. Conceptually, it should // be simple to integrate those here, but it is best to wait on core for the exact syntax. #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub enum TapTree { +pub enum TapTreeInner { /// A taproot tree structure - Tree(Arc>, Arc>), + Tree(Arc>, Arc>), /// A taproot leaf denoting a spending condition // A new leaf version would require a new Context, therefore there is no point // in adding a LeafVersion with Leaf type here. All Miniscripts right now @@ -37,12 +37,19 @@ pub enum TapTree { Leaf(Arc>), } +//TapTree struct to cache taptree's height +#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct TapTree { + inner: TapTreeInner, + height: usize, +} + /// A taproot descriptor pub struct Tr { /// A taproot internal key internal_key: Pk, /// Optional Taproot Tree with spending conditions - tree: Option>, + tree: Option>, /// Optional spending information associated with the descriptor /// This will be [`None`] when the descriptor is not derived. /// This information will be cached automatically when it is required @@ -108,18 +115,18 @@ impl hash::Hash for Tr { } impl TapTree { - // Helper function to compute height - // TODO: Instead of computing this every time we add a new leaf, we should - // add height as a separate field in taptree + // Method to get a new TapTree + pub fn new(inner: TapTreeInner, height: usize) -> Self { + Self { inner, height } + } + + // Method to compute taptree_height fn taptree_height(&self) -> usize { - match *self { - TapTree::Tree(ref left_tree, ref right_tree) => { - 1 + max(left_tree.taptree_height(), right_tree.taptree_height()) - } - TapTree::Leaf(..) => 0, - } + self.height } +} +impl TapTreeInner { /// Iterates over all miniscripts in DFS walk order compatible with the /// PSBT requirements (BIP 371). pub fn iter(&self) -> TapTreeIter { @@ -129,49 +136,48 @@ impl TapTree { } // Helper function to translate keys - fn translate_helper(&self, t: &mut T) -> Result, Error> + fn translate_helper(&self, t: &mut T) -> Result, Error> where T: Translator, Q: MiniscriptKey, { let frag = match self { - TapTree::Tree(l, r) => TapTree::Tree( + TapTreeInner::Tree(l, r) => TapTreeInner::Tree( Arc::new(l.translate_helper(t)?), Arc::new(r.translate_helper(t)?), ), - TapTree::Leaf(ms) => TapTree::Leaf(Arc::new(ms.translate_pk(t)?)), + TapTreeInner::Leaf(ms) => TapTreeInner::Leaf(Arc::new(ms.translate_pk(t)?)), }; Ok(frag) } } -impl fmt::Display for TapTree { +impl fmt::Display for TapTreeInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - TapTree::Tree(ref left, ref right) => write!(f, "{{{},{}}}", *left, *right), - TapTree::Leaf(ref script) => write!(f, "{}", *script), + TapTreeInner::Tree(ref left, ref right) => write!(f, "{{{},{}}}", *left, *right), + TapTreeInner::Leaf(ref script) => write!(f, "{}", *script), } } } -impl fmt::Debug for TapTree { +impl fmt::Debug for TapTreeInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - TapTree::Tree(ref left, ref right) => write!(f, "{{{:?},{:?}}}", *left, *right), - TapTree::Leaf(ref script) => write!(f, "{:?}", *script), + TapTreeInner::Tree(ref left, ref right) => write!(f, "{{{:?},{:?}}}", *left, *right), + TapTreeInner::Leaf(ref script) => write!(f, "{:?}", *script), } } } impl Tr { /// Create a new [`Tr`] descriptor from internal key and [`TapTree`] - pub fn new(internal_key: Pk, tree: Option>) -> Result { + pub fn new(internal_key: Pk, tree: Option>) -> Result { let nodes = tree.as_ref().map(|t| t.taptree_height()).unwrap_or(0); - if nodes <= TAPROOT_CONTROL_MAX_NODE_COUNT { Ok(Self { internal_key, - tree, + tree: tree.map(|t| t.inner), spend_info: Mutex::new(None), }) } else { @@ -185,7 +191,7 @@ impl Tr { } /// Obtain the [`TapTree`] of the [`Tr`] descriptor - pub fn taptree(&self) -> &Option> { + pub fn taptree(&self) -> &Option> { &self.tree } @@ -394,7 +400,7 @@ impl Tr { /// #[derive(Debug, Clone)] pub struct TapTreeIter<'a, Pk: MiniscriptKey> { - stack: Vec<(u8, &'a TapTree)>, + stack: Vec<(u8, &'a TapTreeInner)>, } impl<'a, Pk> Iterator for TapTreeIter<'a, Pk> @@ -407,11 +413,11 @@ where while !self.stack.is_empty() { let (depth, last) = self.stack.pop().expect("Size checked above"); match *last { - TapTree::Tree(ref l, ref r) => { + TapTreeInner::Tree(ref l, ref r) => { self.stack.push((depth + 1, r)); self.stack.push((depth + 1, l)); } - TapTree::Leaf(ref ms) => return Some((depth, ms)), + TapTreeInner::Leaf(ref ms) => return Some((depth, ms)), } } None @@ -422,16 +428,16 @@ where impl_block_str!( Tr, // Helper function to parse taproot script path - fn parse_tr_script_spend(tree: &expression::Tree,) -> Result, Error> { + fn parse_tr_script_spend(tree: &expression::Tree,) -> Result, Error> { match tree { expression::Tree { name, args } if !name.is_empty() && args.is_empty() => { let script = Miniscript::::from_str(name)?; - Ok(TapTree::Leaf(Arc::new(script))) + Ok(TapTreeInner::Leaf(Arc::new(script))) } expression::Tree { name, args } if name.is_empty() && args.len() == 2 => { let left = Self::parse_tr_script_spend(&args[0])?; let right = Self::parse_tr_script_spend(&args[1])?; - Ok(TapTree::Tree(Arc::new(left), Arc::new(right))) + Ok(TapTreeInner::Tree(Arc::new(left), Arc::new(right))) } _ => Err(Error::Unexpected( "unknown format for script spending paths while parsing taproot descriptor" @@ -584,14 +590,14 @@ fn split_once(inp: &str, delim: char) -> Option<(&str, &str)> { } } -impl Liftable for TapTree { +impl Liftable for TapTreeInner { fn lift(&self) -> Result, Error> { - fn lift_helper(s: &TapTree) -> Result, Error> { + fn lift_helper(s: &TapTreeInner) -> Result, Error> { match s { - TapTree::Tree(ref l, ref r) => { + TapTreeInner::Tree(ref l, ref r) => { Ok(Policy::Threshold(1, vec![lift_helper(l)?, lift_helper(r)?])) } - TapTree::Leaf(ref leaf) => leaf.lift(), + TapTreeInner::Leaf(ref leaf) => leaf.lift(), } } From f41e6d1252ef5003430fb9daabaee11258adfdfc Mon Sep 17 00:00:00 2001 From: startup-dreamer Date: Fri, 5 May 2023 06:52:14 +0530 Subject: [PATCH 2/2] fixed the macro error --- src/descriptor/tr.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index 431803390..ab8365fa1 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -37,7 +37,7 @@ pub enum TapTreeInner { Leaf(Arc>), } -//TapTree struct to cache taptree's height +/// TapTree struct to cache taptree's height with inner as taptree implimentation #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct TapTree { inner: TapTreeInner, @@ -115,12 +115,12 @@ impl hash::Hash for Tr { } impl TapTree { - // Method to get a new TapTree + /// Method to get a new `TapTree` pub fn new(inner: TapTreeInner, height: usize) -> Self { Self { inner, height } } - // Method to compute taptree_height + /// Method to compute taptree_height fn taptree_height(&self) -> usize { self.height } @@ -428,16 +428,16 @@ where impl_block_str!( Tr, // Helper function to parse taproot script path - fn parse_tr_script_spend(tree: &expression::Tree,) -> Result, Error> { + fn parse_tr_script_spend(tree: &expression::Tree,) -> Result, Error> { match tree { expression::Tree { name, args } if !name.is_empty() && args.is_empty() => { let script = Miniscript::::from_str(name)?; - Ok(TapTreeInner::Leaf(Arc::new(script))) + Ok(TapTree {inner : TapTreeInner::Leaf(Arc::new(script)), height : 0}) } expression::Tree { name, args } if name.is_empty() && args.len() == 2 => { let left = Self::parse_tr_script_spend(&args[0])?; let right = Self::parse_tr_script_spend(&args[1])?; - Ok(TapTreeInner::Tree(Arc::new(left), Arc::new(right))) + Ok(TapTree {inner : TapTreeInner::Tree(Arc::new(left.inner.clone()), Arc::new(right.inner.clone())), height: left.taptree_height()}) } _ => Err(Error::Unexpected( "unknown format for script spending paths while parsing taproot descriptor"