taproot: Split errors up

Currently there are a couple of errors in the `taproot` module that are
too general, resulting in functions that return a general error type
when a specific one would do.

Split two errors out and use them for for enum variants and function
returns as possible.
This commit is contained in:
Tobin C. Harding 2024-06-20 12:24:09 +10:00
parent c03e23b004
commit afe41c8a39
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
2 changed files with 83 additions and 40 deletions

View File

@ -5,7 +5,7 @@
use hashes::Hash; use hashes::Hash;
use super::{ use super::{
TapNodeHash, TaprootBuilderError, TaprootError, TAPROOT_CONTROL_MAX_NODE_COUNT, InvalidMerkleTreeDepthError, TapNodeHash, TaprootError, TAPROOT_CONTROL_MAX_NODE_COUNT,
TAPROOT_CONTROL_NODE_SIZE, TAPROOT_CONTROL_NODE_SIZE,
}; };
use crate::prelude::*; use crate::prelude::*;
@ -49,7 +49,7 @@ impl TaprootMerkleBranch {
if sl.len() % TAPROOT_CONTROL_NODE_SIZE != 0 { if sl.len() % TAPROOT_CONTROL_NODE_SIZE != 0 {
Err(TaprootError::InvalidMerkleBranchSize(sl.len())) Err(TaprootError::InvalidMerkleBranchSize(sl.len()))
} else if sl.len() > TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT { } else if sl.len() > TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT {
Err(TaprootError::InvalidMerkleTreeDepth(sl.len() / TAPROOT_CONTROL_NODE_SIZE)) Err(InvalidMerkleTreeDepthError(sl.len() / TAPROOT_CONTROL_NODE_SIZE).into())
} else { } else {
let inner = sl let inner = sl
.chunks_exact(TAPROOT_CONTROL_NODE_SIZE) .chunks_exact(TAPROOT_CONTROL_NODE_SIZE)
@ -71,9 +71,9 @@ impl TaprootMerkleBranch {
#[inline] #[inline]
fn from_collection<T: AsRef<[TapNodeHash]> + Into<Vec<TapNodeHash>>>( fn from_collection<T: AsRef<[TapNodeHash]> + Into<Vec<TapNodeHash>>>(
collection: T, collection: T,
) -> Result<Self, TaprootError> { ) -> Result<Self, InvalidMerkleTreeDepthError> {
if collection.as_ref().len() > TAPROOT_CONTROL_MAX_NODE_COUNT { if collection.as_ref().len() > TAPROOT_CONTROL_MAX_NODE_COUNT {
Err(TaprootError::InvalidMerkleTreeDepth(collection.as_ref().len())) Err(InvalidMerkleTreeDepthError(collection.as_ref().len()))
} else { } else {
Ok(TaprootMerkleBranch(collection.into())) Ok(TaprootMerkleBranch(collection.into()))
} }
@ -97,9 +97,9 @@ impl TaprootMerkleBranch {
} }
/// Appends elements to proof. /// Appends elements to proof.
pub(super) fn push(&mut self, h: TapNodeHash) -> Result<(), TaprootBuilderError> { pub(super) fn push(&mut self, h: TapNodeHash) -> Result<(), InvalidMerkleTreeDepthError> {
if self.len() >= TAPROOT_CONTROL_MAX_NODE_COUNT { if self.len() >= TAPROOT_CONTROL_MAX_NODE_COUNT {
Err(TaprootBuilderError::InvalidMerkleTreeDepth(self.0.len())) Err(InvalidMerkleTreeDepthError(self.0.len()))
} else { } else {
self.0.push(h); self.0.push(h);
Ok(()) Ok(())
@ -119,7 +119,7 @@ impl TaprootMerkleBranch {
macro_rules! impl_try_from { macro_rules! impl_try_from {
($from:ty) => { ($from:ty) => {
impl TryFrom<$from> for TaprootMerkleBranch { impl TryFrom<$from> for TaprootMerkleBranch {
type Error = TaprootError; type Error = InvalidMerkleTreeDepthError;
/// Creates a merkle proof from list of hashes. /// Creates a merkle proof from list of hashes.
/// ///

View File

@ -546,7 +546,7 @@ impl TaprootBuilder {
// early error on invalid depth. Though this will be checked later // early error on invalid depth. Though this will be checked later
// while constructing TaprootMerkelBranch // while constructing TaprootMerkelBranch
if depth as usize > TAPROOT_CONTROL_MAX_NODE_COUNT { if depth as usize > TAPROOT_CONTROL_MAX_NODE_COUNT {
return Err(TaprootBuilderError::InvalidMerkleTreeDepth(depth as usize)); return Err(InvalidMerkleTreeDepthError(depth as usize).into());
} }
// We cannot insert a leaf at a lower depth while a deeper branch is unfinished. Doing // We cannot insert a leaf at a lower depth while a deeper branch is unfinished. Doing
// so would mean the add_leaf/add_hidden invocations do not correspond to a DFS traversal of a // so would mean the add_leaf/add_hidden invocations do not correspond to a DFS traversal of a
@ -1188,14 +1188,15 @@ impl ControlBlock {
pub struct FutureLeafVersion(u8); pub struct FutureLeafVersion(u8);
impl FutureLeafVersion { impl FutureLeafVersion {
pub(self) fn from_consensus(version: u8) -> Result<FutureLeafVersion, TaprootError> { pub(self) fn from_consensus(
version: u8,
) -> Result<FutureLeafVersion, InvalidTaprootLeafVersionError> {
match version { match version {
TAPROOT_LEAF_TAPSCRIPT => unreachable!( TAPROOT_LEAF_TAPSCRIPT => unreachable!(
"FutureLeafVersion::from_consensus should be never called for 0xC0 value" "FutureLeafVersion::from_consensus should be never called for 0xC0 value"
), ),
TAPROOT_ANNEX_PREFIX => TAPROOT_ANNEX_PREFIX => Err(InvalidTaprootLeafVersionError(TAPROOT_ANNEX_PREFIX)),
Err(TaprootError::InvalidTaprootLeafVersion(TAPROOT_ANNEX_PREFIX)), odd if odd & 0xFE != odd => Err(InvalidTaprootLeafVersionError(odd)),
odd if odd & 0xFE != odd => Err(TaprootError::InvalidTaprootLeafVersion(odd)),
even => Ok(FutureLeafVersion(even)), even => Ok(FutureLeafVersion(even)),
} }
} }
@ -1237,11 +1238,10 @@ impl LeafVersion {
/// ///
/// - If the last bit of the `version` is odd. /// - If the last bit of the `version` is odd.
/// - If the `version` is 0x50 ([`TAPROOT_ANNEX_PREFIX`]). /// - If the `version` is 0x50 ([`TAPROOT_ANNEX_PREFIX`]).
pub fn from_consensus(version: u8) -> Result<Self, TaprootError> { pub fn from_consensus(version: u8) -> Result<Self, InvalidTaprootLeafVersionError> {
match version { match version {
TAPROOT_LEAF_TAPSCRIPT => Ok(LeafVersion::TapScript), TAPROOT_LEAF_TAPSCRIPT => Ok(LeafVersion::TapScript),
TAPROOT_ANNEX_PREFIX => TAPROOT_ANNEX_PREFIX => Err(InvalidTaprootLeafVersionError(TAPROOT_ANNEX_PREFIX)),
Err(TaprootError::InvalidTaprootLeafVersion(TAPROOT_ANNEX_PREFIX)),
future => FutureLeafVersion::from_consensus(future).map(LeafVersion::Future), future => FutureLeafVersion::from_consensus(future).map(LeafVersion::Future),
} }
} }
@ -1332,7 +1332,7 @@ impl<'de> serde::Deserialize<'de> for LeafVersion {
#[non_exhaustive] #[non_exhaustive]
pub enum TaprootBuilderError { pub enum TaprootBuilderError {
/// Merkle tree depth must not be more than 128. /// Merkle tree depth must not be more than 128.
InvalidMerkleTreeDepth(usize), InvalidMerkleTreeDepth(InvalidMerkleTreeDepthError),
/// Nodes must be added specified in DFS walk order. /// Nodes must be added specified in DFS walk order.
NodeNotInDfsOrder, NodeNotInDfsOrder,
/// Two nodes at depth 0 are not allowed. /// Two nodes at depth 0 are not allowed.
@ -1348,13 +1348,7 @@ impl fmt::Display for TaprootBuilderError {
use TaprootBuilderError::*; use TaprootBuilderError::*;
match *self { match *self {
InvalidMerkleTreeDepth(d) => { InvalidMerkleTreeDepth(ref e) => write_err!(f, "invalid Merkle tree depth"; e),
write!(
f,
"Merkle Tree depth({}) must be less than {}",
d, TAPROOT_CONTROL_MAX_NODE_COUNT
)
}
NodeNotInDfsOrder => { NodeNotInDfsOrder => {
write!(f, "add_leaf/add_hidden must be called in DFS walk order",) write!(f, "add_leaf/add_hidden must be called in DFS walk order",)
} }
@ -1375,12 +1369,17 @@ impl std::error::Error for TaprootBuilderError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use TaprootBuilderError::*; use TaprootBuilderError::*;
match self { match *self {
InvalidMerkleTreeDepth(_) | NodeNotInDfsOrder | OverCompleteTree | EmptyTree => None, InvalidMerkleTreeDepth(ref e) => Some(e),
NodeNotInDfsOrder | OverCompleteTree | EmptyTree => None,
} }
} }
} }
impl From<InvalidMerkleTreeDepthError> for TaprootBuilderError {
fn from(e: InvalidMerkleTreeDepthError) -> Self { Self::InvalidMerkleTreeDepth(e) }
}
/// Detailed error type for taproot utilities. /// Detailed error type for taproot utilities.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive] #[non_exhaustive]
@ -1388,9 +1387,9 @@ pub enum TaprootError {
/// Proof size must be a multiple of 32. /// Proof size must be a multiple of 32.
InvalidMerkleBranchSize(usize), InvalidMerkleBranchSize(usize),
/// Merkle tree depth must not be more than 128. /// Merkle tree depth must not be more than 128.
InvalidMerkleTreeDepth(usize), InvalidMerkleTreeDepth(InvalidMerkleTreeDepthError),
/// The last bit of tapleaf version must be zero. /// The last bit of tapleaf version must be zero.
InvalidTaprootLeafVersion(u8), InvalidTaprootLeafVersion(InvalidTaprootLeafVersionError),
/// Invalid control block size. /// Invalid control block size.
InvalidControlBlockSize(usize), InvalidControlBlockSize(usize),
/// Invalid taproot internal key. /// Invalid taproot internal key.
@ -1411,14 +1410,8 @@ impl fmt::Display for TaprootError {
"Merkle branch size({}) must be a multiple of {}", "Merkle branch size({}) must be a multiple of {}",
sz, TAPROOT_CONTROL_NODE_SIZE sz, TAPROOT_CONTROL_NODE_SIZE
), ),
InvalidMerkleTreeDepth(d) => write!( InvalidMerkleTreeDepth(ref e) => write_err!(f, "invalid Merkle tree depth"; e),
f, InvalidTaprootLeafVersion(ref e) => write_err!(f, "invalid Taproot leaf version"; e),
"Merkle Tree depth({}) must be less than {}",
d, TAPROOT_CONTROL_MAX_NODE_COUNT
),
InvalidTaprootLeafVersion(v) => {
write!(f, "Leaf version({}) must have the least significant bit 0", v)
}
InvalidControlBlockSize(sz) => write!( InvalidControlBlockSize(sz) => write!(
f, f,
"Control Block size({}) must be of the form 33 + 32*m where 0 <= m <= {} ", "Control Block size({}) must be of the form 33 + 32*m where 0 <= m <= {} ",
@ -1439,15 +1432,65 @@ impl std::error::Error for TaprootError {
match self { match self {
InvalidInternalKey(e) => Some(e), InvalidInternalKey(e) => Some(e),
InvalidMerkleBranchSize(_) InvalidTaprootLeafVersion(ref e) => Some(e),
| InvalidMerkleTreeDepth(_) InvalidMerkleTreeDepth(ref e) => Some(e),
| InvalidTaprootLeafVersion(_) InvalidMerkleBranchSize(_) | InvalidControlBlockSize(_) | EmptyTree => None,
| InvalidControlBlockSize(_)
| EmptyTree => None,
} }
} }
} }
impl From<InvalidMerkleTreeDepthError> for TaprootError {
fn from(e: InvalidMerkleTreeDepthError) -> Self { Self::InvalidMerkleTreeDepth(e) }
}
impl From<InvalidTaprootLeafVersionError> for TaprootError {
fn from(e: InvalidTaprootLeafVersionError) -> Self { Self::InvalidTaprootLeafVersion(e) }
}
/// Merkle tree depth must not be more than 128.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InvalidMerkleTreeDepthError(usize);
impl InvalidMerkleTreeDepthError {
/// Accessor for the invalid merkle tree depth.
pub fn invalid_merkle_tree_depth(&self) -> usize { self.0 }
}
internals::impl_from_infallible!(InvalidMerkleTreeDepthError);
impl fmt::Display for InvalidMerkleTreeDepthError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Merkle tree depth({}) must be less than {}",
self.0, TAPROOT_CONTROL_MAX_NODE_COUNT
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for InvalidMerkleTreeDepthError {}
/// The last bit of tapleaf version must be zero.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InvalidTaprootLeafVersionError(u8);
impl InvalidTaprootLeafVersionError {
/// Accessor for the invalid leaf version.
pub fn invalid_leaf_version(&self) -> u8 { self.0 }
}
internals::impl_from_infallible!(InvalidTaprootLeafVersionError);
impl fmt::Display for InvalidTaprootLeafVersionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "leaf version({}) must have the least significant bit 0", self.0)
}
}
#[cfg(feature = "std")]
impl std::error::Error for InvalidTaprootLeafVersionError {}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use core::str::FromStr; use core::str::FromStr;