From c83893d4975753c765d5fe7003097a3cf55b65ca Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 31 Mar 2022 14:59:08 +0200 Subject: [PATCH 1/9] Make taproot LeafInfo public LeafInfo structure is a useful form of representing leaf script information (script, leaf version and merkle proof). --- src/util/taproot.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/taproot.rs b/src/util/taproot.rs index 325feaa65a..8715f29421 100644 --- a/src/util/taproot.rs +++ b/src/util/taproot.rs @@ -608,7 +608,7 @@ impl NodeInfo { /// Store information about taproot leaf node. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub(crate) struct LeafInfo { +pub struct LeafInfo { /// The underlying script. pub(crate) script: Script, /// The leaf version. From 59584666783f7384fcd27ba4c4940714cc250faa Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 31 Mar 2022 14:59:34 +0200 Subject: [PATCH 2/9] Make LeafInfo::leaf_hash public and change its name and return type --- src/util/taproot.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/taproot.rs b/src/util/taproot.rs index 8715f29421..ca680210cb 100644 --- a/src/util/taproot.rs +++ b/src/util/taproot.rs @@ -579,7 +579,7 @@ impl NodeInfo { pub fn new_leaf_with_ver(script: Script, ver: LeafVersion) -> Self { let leaf = LeafInfo::new(script, ver); Self { - hash: leaf.hash(), + hash: sha256::Hash::from_inner(leaf.leaf_hash().into_inner()), leaves: vec![leaf], has_hidden_nodes: false, } @@ -628,9 +628,9 @@ impl LeafInfo { } /// Computes a leaf hash for this [`LeafInfo`]. - fn hash(&self) -> sha256::Hash { - let leaf_hash = TapLeafHash::from_script(&self.script, self.ver); - sha256::Hash::from_inner(leaf_hash.into_inner()) + #[inline] + pub fn leaf_hash(&self) -> TapLeafHash { + TapLeafHash::from_script(&self.script, self.ver) } } From 79345fcd023e5928094943cb89855c39833a38ef Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 31 Mar 2022 15:01:48 +0200 Subject: [PATCH 3/9] LeafInfo field accessor methods --- src/util/taproot.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/util/taproot.rs b/src/util/taproot.rs index ca680210cb..efc4257641 100644 --- a/src/util/taproot.rs +++ b/src/util/taproot.rs @@ -632,6 +632,25 @@ impl LeafInfo { pub fn leaf_hash(&self) -> TapLeafHash { TapLeafHash::from_script(&self.script, self.ver) } + + /// Returns reference to the leaf script. + #[inline] + pub fn script(&self) -> &Script { + &self.script + } + + /// Returns leaf version of the script. + #[inline] + pub fn leaf_version(&self) -> LeafVersion { + self.ver + } + + /// Returns reference to the merkle proof (hashing partners) to get this + /// node in form of [`TaprootMerkleBranch`]. + #[inline] + pub fn merkle_branch(&self) -> &TaprootMerkleBranch { + &self.merkle_branch + } } /// The merkle proof for inclusion of a tree in a taptree hash. From d655ff3e9307692318d5c8f248e4a2681ba2ef14 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 30 Mar 2022 12:49:57 +0200 Subject: [PATCH 4/9] Make TapTreeIterator use LeafInfo Previously used depth and script tuple missed information about the leaf version. All three comprises already existing type `LeafInfo` which was made public in previous commits. --- src/util/psbt/map/output.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/util/psbt/map/output.rs b/src/util/psbt/map/output.rs index c49eb760a3..0dd6df22e7 100644 --- a/src/util/psbt/map/output.rs +++ b/src/util/psbt/map/output.rs @@ -169,17 +169,16 @@ pub struct TapTreeIter<'tree> { } impl<'tree> Iterator for TapTreeIter<'tree> { - type Item = (u8, &'tree Script); + type Item = &'tree LeafInfo; + #[inline] fn next(&mut self) -> Option { - self.leaf_iter.next().map(|leaf_info| { - (leaf_info.merkle_branch.as_inner().len() as u8, &leaf_info.script) - }) + self.leaf_iter.next() } } impl<'tree> IntoIterator for &'tree TapTree { - type Item = (u8, &'tree Script); + type Item = &'tree LeafInfo; type IntoIter = TapTreeIter<'tree>; fn into_iter(self) -> Self::IntoIter { From 3c502ffc2d9dd8ab0ce222775228690ce0da3b30 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 31 Mar 2022 15:56:48 +0200 Subject: [PATCH 5/9] Making all LeafInfo fields private --- src/util/psbt/serialize.rs | 6 +++--- src/util/taproot.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/util/psbt/serialize.rs b/src/util/psbt/serialize.rs index 438693f902..3c946ec773 100644 --- a/src/util/psbt/serialize.rs +++ b/src/util/psbt/serialize.rs @@ -327,9 +327,9 @@ impl Serialize for TapTree { // // TaprootMerkleBranch can only have len atmost 128(TAPROOT_CONTROL_MAX_NODE_COUNT). // safe to cast from usize to u8 - buf.push(leaf_info.merkle_branch.as_inner().len() as u8); - buf.push(leaf_info.ver.to_consensus()); - leaf_info.script.consensus_encode(&mut buf).expect("Vecs dont err"); + buf.push(leaf_info.merkle_branch().as_inner().len() as u8); + buf.push(leaf_info.leaf_version().to_consensus()); + leaf_info.script().consensus_encode(&mut buf).expect("Vecs dont err"); } buf } diff --git a/src/util/taproot.rs b/src/util/taproot.rs index efc4257641..1ada92fa0c 100644 --- a/src/util/taproot.rs +++ b/src/util/taproot.rs @@ -610,11 +610,11 @@ impl NodeInfo { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct LeafInfo { /// The underlying script. - pub(crate) script: Script, + script: Script, /// The leaf version. - pub(crate) ver: LeafVersion, + ver: LeafVersion, /// The merkle proof (hashing partners) to get this node. - pub(crate) merkle_branch: TaprootMerkleBranch, + merkle_branch: TaprootMerkleBranch, } impl LeafInfo { From 6f871ba47df8aafe2f7ec7958e32ad5867f88786 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 31 Mar 2022 16:29:56 +0200 Subject: [PATCH 6/9] Add convenience LeafInfo::depth method Without this method computation of the leaf depth requires cloning due to the requirements of merkle_branch.into_inner() --- src/util/taproot.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/util/taproot.rs b/src/util/taproot.rs index 1ada92fa0c..ec8c1ca1d1 100644 --- a/src/util/taproot.rs +++ b/src/util/taproot.rs @@ -627,6 +627,14 @@ impl LeafInfo { } } + /// Returns the depth of this script leaf in the tap tree. + #[inline] + pub fn depth(&self) -> u8 { + // The depth is guaranteed to be < 127 by the TaprootBuilder type. + // TODO: Following MSRV bump implement via `try_into().expect("")`. + self.merkle_branch.0.len() as u8 + } + /// Computes a leaf hash for this [`LeafInfo`]. #[inline] pub fn leaf_hash(&self) -> TapLeafHash { From 2b8d96581a9f2c7722e01070969e4a89cbd25d1f Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 4 Apr 2022 17:59:04 +0200 Subject: [PATCH 7/9] Rename TapTree::iter into TapTree::script_leaves --- src/util/psbt/map/output.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util/psbt/map/output.rs b/src/util/psbt/map/output.rs index 0dd6df22e7..e32792c230 100644 --- a/src/util/psbt/map/output.rs +++ b/src/util/psbt/map/output.rs @@ -155,9 +155,9 @@ impl TapTree { self.0 } - /// Returns iterator for a taproot script tree, operating in DFS order over leaf depth and - /// leaf script pairs. - pub fn iter(&self) -> TapTreeIter { + /// Returns [`TapTreeIter`] iterator for a taproot script tree, operating in DFS order over + /// leaf depth and leaf script pairs. + pub fn script_leaves(&self) -> TapTreeIter { self.into_iter() } } From 7a5482d23a47d7ba4eb7f5670321594cb68e010f Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 4 Apr 2022 17:59:31 +0200 Subject: [PATCH 8/9] Rename LeafInfo into ScriptLeaf --- src/util/psbt/map/output.rs | 10 +++++----- src/util/taproot.rs | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/util/psbt/map/output.rs b/src/util/psbt/map/output.rs index e32792c230..5f96559a7d 100644 --- a/src/util/psbt/map/output.rs +++ b/src/util/psbt/map/output.rs @@ -26,7 +26,7 @@ use util::psbt::map::Map; use util::psbt::raw; use util::psbt::Error; -use util::taproot::{LeafInfo, TapLeafHash}; +use util::taproot::{ScriptLeaf, TapLeafHash}; use util::taproot::{NodeInfo, TaprootBuilder}; @@ -156,7 +156,7 @@ impl TapTree { } /// Returns [`TapTreeIter`] iterator for a taproot script tree, operating in DFS order over - /// leaf depth and leaf script pairs. + /// tree [`ScriptLeaf`]s. pub fn script_leaves(&self) -> TapTreeIter { self.into_iter() } @@ -165,11 +165,11 @@ impl TapTree { /// Iterator for a taproot script tree, operating in DFS order over leaf depth and /// leaf script pairs. pub struct TapTreeIter<'tree> { - leaf_iter: core::slice::Iter<'tree, LeafInfo>, + leaf_iter: core::slice::Iter<'tree, ScriptLeaf>, } impl<'tree> Iterator for TapTreeIter<'tree> { - type Item = &'tree LeafInfo; + type Item = &'tree ScriptLeaf; #[inline] fn next(&mut self) -> Option { @@ -178,7 +178,7 @@ impl<'tree> Iterator for TapTreeIter<'tree> { } impl<'tree> IntoIterator for &'tree TapTree { - type Item = &'tree LeafInfo; + type Item = &'tree ScriptLeaf; type IntoIter = TapTreeIter<'tree>; fn into_iter(self) -> Self::IntoIter { diff --git a/src/util/taproot.rs b/src/util/taproot.rs index ec8c1ca1d1..512d6a9f83 100644 --- a/src/util/taproot.rs +++ b/src/util/taproot.rs @@ -560,7 +560,7 @@ pub struct NodeInfo { /// Merkle hash for this node. pub(crate) hash: sha256::Hash, /// Information about leaves inside this node. - pub(crate) leaves: Vec, + pub(crate) leaves: Vec, /// Tracks information on hidden nodes below this node. pub(crate) has_hidden_nodes: bool, } @@ -577,7 +577,7 @@ impl NodeInfo { /// Creates a new leaf [`NodeInfo`] with given [`Script`] and [`LeafVersion`]. pub fn new_leaf_with_ver(script: Script, ver: LeafVersion) -> Self { - let leaf = LeafInfo::new(script, ver); + let leaf = ScriptLeaf::new(script, ver); Self { hash: sha256::Hash::from_inner(leaf.leaf_hash().into_inner()), leaves: vec![leaf], @@ -608,7 +608,7 @@ impl NodeInfo { /// Store information about taproot leaf node. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct LeafInfo { +pub struct ScriptLeaf { /// The underlying script. script: Script, /// The leaf version. @@ -617,8 +617,8 @@ pub struct LeafInfo { merkle_branch: TaprootMerkleBranch, } -impl LeafInfo { - /// Creates an new [`LeafInfo`] from `script` and `ver` and no merkle branch. +impl ScriptLeaf { + /// Creates an new [`ScriptLeaf`] from `script` and `ver` and no merkle branch. fn new(script: Script, ver: LeafVersion) -> Self { Self { script: script, @@ -635,7 +635,7 @@ impl LeafInfo { self.merkle_branch.0.len() as u8 } - /// Computes a leaf hash for this [`LeafInfo`]. + /// Computes a leaf hash for this [`ScriptLeaf`]. #[inline] pub fn leaf_hash(&self) -> TapLeafHash { TapLeafHash::from_script(&self.script, self.ver) From 3c598975980dec1d76749076bee975bfe94f8956 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 6 Apr 2022 22:20:05 +0200 Subject: [PATCH 9/9] Removed IntoIterator for TapTree implementation In the future, TapTree may iterate over different node types, and that's why it does not have `iter()` function; using instead `script_leafs`. Thus, we should not have IntoIterator implementation as well --- src/util/psbt/map/output.rs | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/util/psbt/map/output.rs b/src/util/psbt/map/output.rs index 5f96559a7d..855524d5de 100644 --- a/src/util/psbt/map/output.rs +++ b/src/util/psbt/map/output.rs @@ -158,7 +158,15 @@ impl TapTree { /// Returns [`TapTreeIter`] iterator for a taproot script tree, operating in DFS order over /// tree [`ScriptLeaf`]s. pub fn script_leaves(&self) -> TapTreeIter { - self.into_iter() + match (self.0.branch().len(), self.0.branch().last()) { + (1, Some(Some(root))) => { + TapTreeIter { + leaf_iter: root.leaves.iter() + } + } + // This should be unreachable as we Taptree is already finalized + _ => unreachable!("non-finalized tree builder inside TapTree"), + } } } @@ -177,23 +185,6 @@ impl<'tree> Iterator for TapTreeIter<'tree> { } } -impl<'tree> IntoIterator for &'tree TapTree { - type Item = &'tree ScriptLeaf; - type IntoIter = TapTreeIter<'tree>; - - fn into_iter(self) -> Self::IntoIter { - match (self.0.branch().len(), self.0.branch().last()) { - (1, Some(Some(root))) => { - TapTreeIter { - leaf_iter: root.leaves.iter() - } - } - // This should be unreachable as we Taptree is already finalized - _ => unreachable!("non-finalized tree builder inside TapTree"), - } - } -} - impl Output { pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), encode::Error> { let raw::Pair {