MOVE ONLY: Move TapTree to taproot module
This commit is contained in:
parent
2cf1a4c088
commit
38ed9bdf49
|
@ -9,7 +9,7 @@ mod input;
|
|||
mod output;
|
||||
|
||||
pub use self::input::{Input, PsbtSighashType};
|
||||
pub use self::output::{Output, TapTree, IncompleteTapTree};
|
||||
pub use self::output::Output;
|
||||
|
||||
use super::serialize::Serialize;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::psbt::map::Map;
|
|||
use crate::psbt::raw;
|
||||
use crate::psbt::Error;
|
||||
|
||||
use crate::taproot::{ScriptLeaf, TapLeafHash, NodeInfo, TaprootBuilder};
|
||||
use crate::taproot::{TapTree, TapLeafHash};
|
||||
|
||||
/// Type: Redeem ScriptBuf PSBT_OUT_REDEEM_SCRIPT = 0x00
|
||||
const PSBT_OUT_REDEEM_SCRIPT: u8 = 0x00;
|
||||
|
@ -64,145 +64,6 @@ pub struct Output {
|
|||
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
|
||||
}
|
||||
|
||||
/// Error happening when [`TapTree`] is constructed from a [`TaprootBuilder`]
|
||||
/// having hidden branches or not being finalized.
|
||||
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
|
||||
#[non_exhaustive]
|
||||
pub enum IncompleteTapTree {
|
||||
/// Indicates an attempt to construct a tap tree from a builder containing incomplete branches.
|
||||
NotFinalized(TaprootBuilder),
|
||||
/// Indicates an attempt to construct a tap tree from a builder containing hidden parts.
|
||||
HiddenParts(TaprootBuilder),
|
||||
}
|
||||
|
||||
impl IncompleteTapTree {
|
||||
/// Converts error into the original incomplete [`TaprootBuilder`] instance.
|
||||
pub fn into_builder(self) -> TaprootBuilder {
|
||||
match self {
|
||||
IncompleteTapTree::NotFinalized(builder) |
|
||||
IncompleteTapTree::HiddenParts(builder) => builder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for IncompleteTapTree {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.write_str(match self {
|
||||
IncompleteTapTree::NotFinalized(_) => "an attempt to construct a tap tree from a builder containing incomplete branches.",
|
||||
IncompleteTapTree::HiddenParts(_) => "an attempt to construct a tap tree from a builder containing hidden parts.",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
impl std::error::Error for IncompleteTapTree {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
use self::IncompleteTapTree::*;
|
||||
|
||||
match self {
|
||||
NotFinalized(_) | HiddenParts(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Taproot Tree representing a finalized [`TaprootBuilder`] (a complete binary tree).
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
|
||||
pub struct TapTree(pub(crate) TaprootBuilder);
|
||||
|
||||
impl PartialEq for TapTree {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.node_info().hash.eq(&other.node_info().hash)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::hash::Hash for TapTree {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.node_info().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for TapTree {}
|
||||
|
||||
impl From<TapTree> for TaprootBuilder {
|
||||
#[inline]
|
||||
fn from(tree: TapTree) -> Self {
|
||||
tree.into_builder()
|
||||
}
|
||||
}
|
||||
|
||||
impl TapTree {
|
||||
/// Gets the inner node info as the builder is finalized.
|
||||
pub fn node_info(&self) -> &NodeInfo {
|
||||
// The builder algorithm invariant guarantees that is_complete builder
|
||||
// have only 1 element in branch and that is not None.
|
||||
// We make sure that we only allow is_complete builders via the from_inner
|
||||
// constructor
|
||||
self.0.branch()[0].as_ref().expect("from_inner only parses is_complete builders")
|
||||
}
|
||||
|
||||
/// Converts self into builder [`TaprootBuilder`]. The builder is guaranteed to be finalized.
|
||||
pub fn into_builder(self) -> TaprootBuilder {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Constructs [`TaprootBuilder`] by internally cloning the `self`. The builder is guaranteed
|
||||
/// to be finalized.
|
||||
pub fn to_builder(&self) -> TaprootBuilder {
|
||||
self.0.clone()
|
||||
}
|
||||
|
||||
/// Returns [`TapTreeIter<'_>`] iterator for a taproot script tree, operating in DFS order over
|
||||
/// tree [`ScriptLeaf`]s.
|
||||
pub fn script_leaves(&self) -> TapTreeIter {
|
||||
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 TryFrom<TaprootBuilder> for TapTree {
|
||||
type Error = IncompleteTapTree;
|
||||
|
||||
/// Constructs [`TapTree`] from a [`TaprootBuilder`] if it is complete binary tree.
|
||||
///
|
||||
/// # Returns
|
||||
/// A [`TapTree`] iff the `builder` is complete, otherwise return [`IncompleteTapTree`]
|
||||
/// error with the content of incomplete `builder` instance.
|
||||
fn try_from(builder: TaprootBuilder) -> Result<Self, Self::Error> {
|
||||
if !builder.is_finalizable() {
|
||||
Err(IncompleteTapTree::NotFinalized(builder))
|
||||
} else if builder.has_hidden_nodes() {
|
||||
Err(IncompleteTapTree::HiddenParts(builder))
|
||||
} else {
|
||||
Ok(TapTree(builder))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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, ScriptLeaf>,
|
||||
}
|
||||
|
||||
impl<'tree> Iterator for TapTreeIter<'tree> {
|
||||
type Item = &'tree ScriptLeaf;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.leaf_iter.next()
|
||||
}
|
||||
}
|
||||
|
||||
impl Output {
|
||||
pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), Error> {
|
||||
let raw::Pair {
|
||||
|
|
|
@ -35,7 +35,7 @@ mod error;
|
|||
pub use self::error::Error;
|
||||
|
||||
mod map;
|
||||
pub use self::map::{Input, Output, TapTree, PsbtSighashType, IncompleteTapTree};
|
||||
pub use self::map::{Input, Output, PsbtSighashType};
|
||||
|
||||
/// Partially signed transaction, commonly referred to as a PSBT.
|
||||
pub type Psbt = PartiallySignedTransaction;
|
||||
|
|
|
@ -16,6 +16,7 @@ use crate::blockdata::script::ScriptBuf;
|
|||
use crate::blockdata::witness::Witness;
|
||||
use crate::blockdata::transaction::{Transaction, TxOut};
|
||||
use crate::consensus::encode::{self, serialize, Decodable, Encodable, deserialize_partial};
|
||||
use crate::taproot::TapTree;
|
||||
use secp256k1::{self, XOnlyPublicKey};
|
||||
use crate::bip32::{ChildNumber, Fingerprint, KeySource};
|
||||
use crate::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
||||
|
@ -24,7 +25,7 @@ use crate::psbt::{Error, PartiallySignedTransaction};
|
|||
use crate::taproot::{TapNodeHash, TapLeafHash, ControlBlock, LeafVersion};
|
||||
use crate::crypto::key::PublicKey;
|
||||
|
||||
use super::map::{Map, Input, Output, TapTree, PsbtSighashType};
|
||||
use super::map::{Map, Input, Output, PsbtSighashType};
|
||||
use super::Psbt;
|
||||
|
||||
use crate::taproot::TaprootBuilder;
|
||||
|
|
|
@ -378,7 +378,7 @@ impl TaprootBuilder {
|
|||
/// If the script weight calculations overflow, a sub-optimal tree may be generated. This should
|
||||
/// not happen unless you are dealing with billions of branches with weights close to 2^32.
|
||||
///
|
||||
/// [`TapTree`]: crate::psbt::TapTree
|
||||
/// [`TapTree`]: crate::taproot::TapTree
|
||||
pub fn with_huffman_tree<I>(script_weights: I) -> Result<Self, TaprootBuilderError>
|
||||
where
|
||||
I: IntoIterator<Item = (u32, ScriptBuf)>,
|
||||
|
@ -521,6 +521,132 @@ impl Default for TaprootBuilder {
|
|||
fn default() -> Self { Self::new() }
|
||||
}
|
||||
|
||||
/// Error happening when [`TapTree`] is constructed from a [`TaprootBuilder`]
|
||||
/// having hidden branches or not being finalized.
|
||||
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
|
||||
#[non_exhaustive]
|
||||
pub enum IncompleteTapTree {
|
||||
/// Indicates an attempt to construct a tap tree from a builder containing incomplete branches.
|
||||
NotFinalized(TaprootBuilder),
|
||||
/// Indicates an attempt to construct a tap tree from a builder containing hidden parts.
|
||||
HiddenParts(TaprootBuilder),
|
||||
}
|
||||
|
||||
impl IncompleteTapTree {
|
||||
/// Converts error into the original incomplete [`TaprootBuilder`] instance.
|
||||
pub fn into_builder(self) -> TaprootBuilder {
|
||||
match self {
|
||||
IncompleteTapTree::NotFinalized(builder) | IncompleteTapTree::HiddenParts(builder) =>
|
||||
builder,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for IncompleteTapTree {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.write_str(match self {
|
||||
IncompleteTapTree::NotFinalized(_) =>
|
||||
"an attempt to construct a tap tree from a builder containing incomplete branches.",
|
||||
IncompleteTapTree::HiddenParts(_) =>
|
||||
"an attempt to construct a tap tree from a builder containing hidden parts.",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
impl std::error::Error for IncompleteTapTree {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
use self::IncompleteTapTree::*;
|
||||
|
||||
match self {
|
||||
NotFinalized(_) | HiddenParts(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Taproot Tree representing a finalized [`TaprootBuilder`] (a complete binary tree).
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
|
||||
pub struct TapTree(pub(crate) TaprootBuilder);
|
||||
|
||||
impl PartialEq for TapTree {
|
||||
fn eq(&self, other: &Self) -> bool { self.node_info().hash.eq(&other.node_info().hash) }
|
||||
}
|
||||
|
||||
impl core::hash::Hash for TapTree {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) { self.node_info().hash(state) }
|
||||
}
|
||||
|
||||
impl Eq for TapTree {}
|
||||
|
||||
impl From<TapTree> for TaprootBuilder {
|
||||
#[inline]
|
||||
fn from(tree: TapTree) -> Self { tree.into_builder() }
|
||||
}
|
||||
|
||||
impl TapTree {
|
||||
/// Gets the inner node info as the builder is finalized.
|
||||
pub fn node_info(&self) -> &NodeInfo {
|
||||
// The builder algorithm invariant guarantees that is_complete builder
|
||||
// have only 1 element in branch and that is not None.
|
||||
// We make sure that we only allow is_complete builders via the from_inner
|
||||
// constructor
|
||||
self.0.branch()[0].as_ref().expect("from_inner only parses is_complete builders")
|
||||
}
|
||||
|
||||
/// Converts self into builder [`TaprootBuilder`]. The builder is guaranteed to be finalized.
|
||||
pub fn into_builder(self) -> TaprootBuilder { self.0 }
|
||||
|
||||
/// Constructs [`TaprootBuilder`] by internally cloning the `self`. The builder is guaranteed
|
||||
/// to be finalized.
|
||||
pub fn to_builder(&self) -> TaprootBuilder { self.0.clone() }
|
||||
|
||||
/// Returns [`TapTreeIter<'_>`] iterator for a taproot script tree, operating in DFS order over
|
||||
/// tree [`ScriptLeaf`]s.
|
||||
pub fn script_leaves(&self) -> TapTreeIter {
|
||||
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 TryFrom<TaprootBuilder> for TapTree {
|
||||
type Error = IncompleteTapTree;
|
||||
|
||||
/// Constructs [`TapTree`] from a [`TaprootBuilder`] if it is complete binary tree.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A [`TapTree`] iff the `builder` is complete, otherwise return [`IncompleteBuilder`]
|
||||
/// error with the content of incomplete `builder` instance.
|
||||
fn try_from(builder: TaprootBuilder) -> Result<Self, Self::Error> {
|
||||
if !builder.is_finalizable() {
|
||||
Err(IncompleteTapTree::NotFinalized(builder))
|
||||
} else if builder.has_hidden_nodes() {
|
||||
Err(IncompleteTapTree::HiddenParts(builder))
|
||||
} else {
|
||||
Ok(TapTree(builder))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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, ScriptLeaf>,
|
||||
}
|
||||
|
||||
impl<'tree> Iterator for TapTreeIter<'tree> {
|
||||
type Item = &'tree ScriptLeaf;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> { self.leaf_iter.next() }
|
||||
}
|
||||
|
||||
/// Represents the node information in taproot tree.
|
||||
///
|
||||
/// Helper type used in merkle tree construction allowing one to build sparse merkle trees. The node
|
||||
|
|
Loading…
Reference in New Issue