Rename ScriptLeaf to LeafNode

ScriptLeaf feels like leaf has to be a script, but it can a hidden
subtree. LeafNode conveys this better
This commit is contained in:
sanket1729 2023-02-24 02:02:16 -08:00
parent 289dc1e7f5
commit 74022baa44
2 changed files with 117 additions and 38 deletions

View File

@ -9,6 +9,7 @@
use core::convert::TryFrom;
use core::convert::TryInto;
use crate::VarInt;
use crate::prelude::*;
use crate::io;
@ -386,20 +387,20 @@ impl Deserialize for (Vec<TapLeafHash>, KeySource) {
impl Serialize for TapTree {
fn serialize(&self) -> Vec<u8> {
let script_leaves_iter = self.script_leaves();
let mut buf = Vec::with_capacity(script_leaves_iter.len());
for leaf_info in script_leaves_iter {
// # Panics:
//
// TapTree only has script leaves. We will remove this expect in future commit.
let (script, ver) = leaf_info.leaf().as_script().expect("TapTree only has script leaves");
let capacity = self.script_leaves().map(|l| {
l.script().len() + VarInt(l.script().len() as u64).len() // script version
+ 1 // merkle branch
+ 1 // leaf version
}).sum::<usize>();
let mut buf = Vec::with_capacity(capacity);
for leaf_info in self.script_leaves() {
// # Cast Safety:
//
// 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().len() as u8);
buf.push(ver.to_consensus());
script.consensus_encode(&mut buf).expect("Vecs dont err");
buf.push(leaf_info.version().to_consensus());
leaf_info.script().consensus_encode(&mut buf).expect("Vecs dont err");
}
buf
}

View File

@ -8,6 +8,7 @@
use core::cmp::Reverse;
use core::convert::TryFrom;
use core::fmt;
use core::iter::FusedIterator;
use bitcoin_internals::write_err;
use secp256k1::{self, Scalar, Secp256k1};
@ -94,12 +95,12 @@ impl TapLeafHash {
}
}
impl From<ScriptLeaf> for TapNodeHash {
fn from(leaf: ScriptLeaf) -> TapNodeHash { leaf.node_hash() }
impl From<LeafNode> for TapNodeHash {
fn from(leaf: LeafNode) -> TapNodeHash { leaf.node_hash() }
}
impl From<&ScriptLeaf> for TapNodeHash {
fn from(leaf: &ScriptLeaf) -> TapNodeHash { leaf.node_hash() }
impl From<&LeafNode> for TapNodeHash {
fn from(leaf: &LeafNode) -> TapNodeHash { leaf.node_hash() }
}
impl TapNodeHash {
@ -124,7 +125,7 @@ impl TapNodeHash {
/// Assumes the given 32 byte array as hidden [`TapNodeHash`].
///
/// Similar to [`TapLeafHash::from_inner`], but explicitly conveys that the
/// Similar to [`TapLeafHash::from_byte_array`], but explicitly conveys that the
/// hash is constructed from a hidden node. This also has better ergonomics
/// because it does not require the caller to import the Hash trait.
pub fn assume_hidden(hash: [u8; 32]) -> TapNodeHash {
@ -694,8 +695,8 @@ impl TapTree {
/// Returns [`TapTreeIter<'_>`] iterator for a taproot script tree, operating in DFS order over
/// tree [`ScriptLeaf`]s.
pub fn script_leaves(&self) -> TapTreeIter {
TapTreeIter { leaf_iter: self.0.leaves.iter() }
pub fn script_leaves(&self) -> ScriptLeaves {
ScriptLeaves { leaf_iter: self.0.leaf_nodes() }
}
}
@ -731,29 +732,59 @@ impl TryFrom<NodeInfo> for TapTree {
}
}
/// Iterator for a taproot script tree, operating in DFS order over leaf depth and
/// leaf script pairs.
/// This is guaranteed to not contain any hidden nodes.
// TODO: Enforce this in type system in a later PR. Users should not need to unwrap
// as script leaf when there are no hidden nodes.
// An idea can be to have the iterator return a tuple (depth, script, version).
pub struct TapTreeIter<'tree> {
leaf_iter: core::slice::Iter<'tree, ScriptLeaf>,
/// Iterator for a taproot script tree, operating in DFS order yielding [`ScriptLeaf`].
///
/// Returned by [`TapTree::script_leaves`]. [`TapTree`] does not allow hidden nodes,
/// so this iterator is guaranteed to yield all known leaves.
pub struct ScriptLeaves<'tree> {
leaf_iter: LeafNodes<'tree>,
}
impl<'tree> Iterator for TapTreeIter<'tree> {
type Item = &'tree ScriptLeaf;
impl<'tree> Iterator for ScriptLeaves<'tree> {
type Item = ScriptLeaf<'tree>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
ScriptLeaf::from_leaf_node(self.leaf_iter.next()?)
}
fn size_hint(&self) -> (usize, Option<usize>) { self.leaf_iter.size_hint() }
}
impl<'tree> ExactSizeIterator for ScriptLeaves<'tree> { }
impl <'tree> FusedIterator for ScriptLeaves<'tree> { }
impl <'tree> DoubleEndedIterator for ScriptLeaves<'tree> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
ScriptLeaf::from_leaf_node(self.leaf_iter.next_back()?)
}
}
/// Iterator for a taproot script tree, operating in DFS order yielding [`LeafNode`].
///
/// Returned by [`NodeInfo::leaf_nodes`]. This can potentially yield hidden nodes.
pub struct LeafNodes<'a> {
leaf_iter: core::slice::Iter<'a, LeafNode>,
}
impl<'a> Iterator for LeafNodes<'a> {
type Item = &'a LeafNode;
#[inline]
fn next(&mut self) -> Option<Self::Item> { self.leaf_iter.next() }
fn size_hint(&self) -> (usize, Option<usize>) { self.leaf_iter.size_hint() }
}
impl<'tree> ExactSizeIterator for TapTreeIter<'tree> {
impl<'tree> ExactSizeIterator for LeafNodes<'tree> { }
impl <'tree> FusedIterator for LeafNodes<'tree> { }
impl <'tree> DoubleEndedIterator for LeafNodes<'tree> {
#[inline]
fn len(&self) -> usize { self.leaf_iter.len() }
fn next_back(&mut self) -> Option<Self::Item> { self.leaf_iter.next_back() }
}
/// Represents the node information in taproot tree. In contrast to [`TapTree`], this
/// is allowed to have hidden leaves as children.
///
@ -768,7 +799,7 @@ pub struct NodeInfo {
/// Merkle hash for this node.
pub(crate) hash: TapNodeHash,
/// Information about leaves inside this node.
pub(crate) leaves: Vec<ScriptLeaf>,
pub(crate) leaves: Vec<LeafNode>,
/// Tracks information on hidden nodes below this node.
pub(crate) has_hidden_nodes: bool,
}
@ -793,7 +824,7 @@ impl NodeInfo {
pub fn new_leaf_with_ver(script: ScriptBuf, ver: LeafVersion) -> Self {
Self {
hash: TapNodeHash::from_script(&script, ver),
leaves: vec![ScriptLeaf::new_script(script, ver)],
leaves: vec![LeafNode::new_script(script, ver)],
has_hidden_nodes: false,
}
}
@ -817,6 +848,11 @@ impl NodeInfo {
has_hidden_nodes: a.has_hidden_nodes || b.has_hidden_nodes,
})
}
/// Creates an iterator over all leaves (including hidden leaves) in the tree.
pub fn leaf_nodes(&self) -> LeafNodes {
LeafNodes { leaf_iter: self.leaves.iter() }
}
}
impl TryFrom<TaprootBuilder> for NodeInfo {
@ -917,7 +953,7 @@ impl TapLeaf {
}
}
/// Obtains the script and version if the leaf is known.
/// Obtains a reference to script and version if the leaf is known.
pub fn as_script(&self) -> Option<(&Script, LeafVersion)> {
if let Self::Script(script, ver) = self {
Some((script, *ver))
@ -929,14 +965,14 @@ impl TapLeaf {
/// Store information about taproot leaf node.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ScriptLeaf {
pub struct LeafNode {
/// The [`TapLeaf`]
leaf: TapLeaf,
/// The merkle proof (hashing partners) to get this node.
merkle_branch: TaprootMerkleBranch,
}
impl ScriptLeaf {
impl LeafNode {
/// Creates an new [`ScriptLeaf`] from `script` and `ver` and no merkle branch.
pub fn new_script(script: ScriptBuf, ver: LeafVersion) -> Self {
Self { leaf: TapLeaf::Script(script, ver), merkle_branch: TaprootMerkleBranch(vec![]) }
@ -955,9 +991,11 @@ impl ScriptLeaf {
}
/// Computes a leaf hash for this [`ScriptLeaf`] if the leaf is known.
/// See [`ScriptLeaf::node_hash`] for computing the [`TapNodeHash`] which returns
/// the hidden node hash if the node is hidden.
///
/// This [`TapLeafHash`] is useful while signing taproot script spends.
///
/// See [`LeafNode::node_hash`] for computing the [`TapNodeHash`] which returns the hidden node
/// hash if the node is hidden.
#[inline]
pub fn leaf_hash(&self) -> Option<TapLeafHash> {
let (script, ver) = self.leaf.as_script()?;
@ -967,7 +1005,7 @@ impl ScriptLeaf {
/// Computes the [`TapNodeHash`] for this [`ScriptLeaf`]. This returns the
/// leaf hash if the leaf is known and the hidden node hash if the leaf is
/// hidden.
/// See also, [`ScriptLeaf::leaf_hash`].
/// See also, [`LeafNode::leaf_hash`].
#[inline]
pub fn node_hash(&self) -> TapNodeHash {
match self.leaf {
@ -998,6 +1036,46 @@ impl ScriptLeaf {
}
}
/// Script leaf node in a taproot tree along with the merkle proof to get this node.
/// Returned by [`TapTree::script_leaves`]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ScriptLeaf<'leaf> {
/// The version of the script leaf.
version: LeafVersion,
/// The script.
script: &'leaf Script,
/// The merkle proof (hashing partners) to get this node.
merkle_branch: &'leaf TaprootMerkleBranch,
}
impl<'leaf> ScriptLeaf<'leaf> {
/// Obtains the version of the script leaf.
pub fn version(&self) -> LeafVersion {
self.version
}
/// Obtains a reference to the script inside the leaf.
pub fn script(&self) -> &Script {
self.script
}
/// Obtains a reference to the merkle proof of the leaf.
pub fn merkle_branch(&self) -> &TaprootMerkleBranch {
self.merkle_branch
}
/// Obtains a script leaf from the leaf node if the leaf is not hidden.
pub fn from_leaf_node(leaf_node: &'leaf LeafNode) -> Option<Self> {
let (script, ver) = leaf_node.leaf.as_script()?;
Some(Self {
version: ver,
script,
merkle_branch: &leaf_node.merkle_branch,
})
}
}
/// The merkle proof for inclusion of a tree in a taptree hash.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]