Skip to content

Commit 2d8ebb7

Browse files
committed
Merge rust-bitcoin#4375: Add ControlBlock constructor that takes a hex string
3319e6e Add ControlBlock constructor that takes a hex string (Shing Him Ng) Pull request description: Closes rust-bitcoin#4362 ACKs for top commit: Kixunil: ACK 3319e6e apoelstra: ACK 3319e6e; successfully ran local tests Tree-SHA512: 230e4607402b3df6a8c5fe1e03209573baffbd08ca9d28e1208bff1464668a083ddb5ae72781eceb2546bc99b150dd2f832d122570d55aa323c603481c5eff93
2 parents 4a5ea9a + 3319e6e commit 2d8ebb7

File tree

1 file changed

+15
-7
lines changed

1 file changed

+15
-7
lines changed

bitcoin/src/taproot/mod.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use core::fmt;
1313
use core::iter::FusedIterator;
1414

1515
use hashes::{hash_newtype, sha256t, sha256t_tag, HashEngine};
16+
use hex::{FromHex, HexToBytesError};
1617
use internals::array::ArrayExt;
1718
#[allow(unused)] // MSRV polyfill
1819
use internals::slice::SliceExt;
@@ -1198,6 +1199,12 @@ impl ControlBlock {
11981199

11991200
Ok(ControlBlock { leaf_version, output_key_parity, internal_key, merkle_branch })
12001201
}
1202+
1203+
/// Constructs a new [`ControlBlock`] from a hex string.
1204+
pub fn from_hex(hex: &str) -> Result<Self, TaprootError> {
1205+
let vec = Vec::from_hex(hex).map_err(TaprootError::InvalidControlBlockHex)?;
1206+
ControlBlock::decode(vec.as_slice())
1207+
}
12011208
}
12021209

12031210
impl<B, K> ControlBlock<B, K> {
@@ -1514,6 +1521,8 @@ pub enum TaprootError {
15141521
InvalidControlBlockSize(InvalidControlBlockSizeError),
15151522
/// Invalid Taproot internal key.
15161523
InvalidInternalKey(secp256k1::Error),
1524+
/// Invalid control block hex
1525+
InvalidControlBlockHex(HexToBytesError),
15171526
/// Empty Taproot tree.
15181527
EmptyTree,
15191528
}
@@ -1531,6 +1540,7 @@ impl fmt::Display for TaprootError {
15311540
InvalidMerkleTreeDepth(ref e) => write_err!(f, "invalid Merkle tree depth"; e),
15321541
InvalidTaprootLeafVersion(ref e) => write_err!(f, "invalid Taproot leaf version"; e),
15331542
InvalidControlBlockSize(ref e) => write_err!(f, "invalid control block size"; e),
1543+
InvalidControlBlockHex(ref e) => write_err!(f, "invalid control block hex"; e),
15341544
InvalidInternalKey(ref e) => write_err!(f, "invalid internal x-only key"; e),
15351545
EmptyTree => write!(f, "Taproot tree must contain at least one script"),
15361546
}
@@ -1546,6 +1556,7 @@ impl std::error::Error for TaprootError {
15461556
InvalidInternalKey(e) => Some(e),
15471557
InvalidTaprootLeafVersion(ref e) => Some(e),
15481558
InvalidMerkleTreeDepth(ref e) => Some(e),
1559+
InvalidControlBlockHex(ref e) => Some(e),
15491560
InvalidMerkleBranchSize(_) | InvalidControlBlockSize(_) | EmptyTree => None,
15501561
}
15511562
}
@@ -1670,7 +1681,7 @@ impl std::error::Error for InvalidControlBlockSizeError {}
16701681
#[cfg(test)]
16711682
mod test {
16721683
use hashes::sha256;
1673-
use hex::{DisplayHex, FromHex};
1684+
use hex::DisplayHex;
16741685
use secp256k1::VerifyOnly;
16751686

16761687
use super::*;
@@ -1771,8 +1782,7 @@ mod test {
17711782
let out_pk = out_spk_hex[4..].parse::<XOnlyPublicKey>().unwrap();
17721783
let out_pk = TweakedPublicKey::dangerous_assume_tweaked(out_pk);
17731784
let script = ScriptBuf::from_hex(script_hex).unwrap();
1774-
let control_block =
1775-
ControlBlock::decode(&Vec::<u8>::from_hex(control_block_hex).unwrap()).unwrap();
1785+
let control_block = ControlBlock::from_hex(control_block_hex).unwrap();
17761786
assert_eq!(control_block_hex, control_block.serialize().to_lower_hex_string());
17771787
assert!(control_block.verify_taproot_commitment(secp, out_pk.to_inner(), &script));
17781788
}
@@ -2053,10 +2063,8 @@ mod test {
20532063
let spend_info = builder.finalize(secp, internal_key).unwrap();
20542064
for (i, script_ver) in leaves.iter().enumerate() {
20552065
let expected_leaf_hash = leaf_hashes[i].as_str().unwrap();
2056-
let expected_ctrl_blk = ControlBlock::decode(
2057-
&Vec::<u8>::from_hex(ctrl_blks[i].as_str().unwrap()).unwrap(),
2058-
)
2059-
.unwrap();
2066+
let expected_ctrl_blk =
2067+
ControlBlock::from_hex(ctrl_blks[i].as_str().unwrap()).unwrap();
20602068

20612069
let leaf_hash = TapLeafHash::from_script(&script_ver.0, script_ver.1);
20622070
let ctrl_blk = spend_info.control_block(script_ver).unwrap();

0 commit comments

Comments
 (0)