Skip to content

Commit 0306e67

Browse files
author
ChallengeDev210
committed
Merge rust-bitcoin/rust-bitcoin#1151: Update finalize API
870ad59 Rename is_finalized to is_finalizable (sanket1729) aaadd25 Add breaking test that allowed incomplete builders to be created (sanket1729) 0b88051 Update TaprootBuilder::finalize (sanket1729) 5813ec7 Return EmptyTree instead of OverCompleteTree when there are no scripts to add (sanket1729) Pull request description: Found while reviewing rust-bitcoin/rust-miniscript#450 . There is also a BUG fix in the second commit that would have let users spendinfo from incomplete trees. The bug was introduced in #936 which I am responsible for ACKing ACKs for top commit: apoelstra: ACK 870ad59 Kixunil: ACK 870ad59 tcharding: ACK 870ad59 Tree-SHA512: 61442bd95df6912865cbecdc207f330b241e7fbb88b5e915243b2b48a756bea9eb29cb28d8c8249647a0a2ac514df4737bddab695f63075bd55284be5be228ff
2 parents ef3a73c + 24e2592 commit 0306e67

File tree

3 files changed

+21
-19
lines changed

3 files changed

+21
-19
lines changed

src/util/psbt/map/output.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ impl TryFrom<TaprootBuilder> for TapTree {
194194
/// A [`TapTree`] iff the `builder` is complete, otherwise return [`IncompleteTapTree`]
195195
/// error with the content of incomplete `builder` instance.
196196
fn try_from(builder: TaprootBuilder) -> Result<Self, Self::Error> {
197-
if !builder.is_finalized() {
197+
if !builder.is_finalizable() {
198198
Err(IncompleteTapTree::NotFinalized(builder))
199199
} else if builder.has_hidden_nodes() {
200200
Err(IncompleteTapTree::HiddenParts(builder))

src/util/psbt/serialize.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ impl Deserialize for TapTree {
343343
builder = builder.add_leaf_with_ver(*depth, script, leaf_version)
344344
.map_err(|_| encode::Error::ParseFailed("Tree not in DFS order"))?;
345345
}
346-
if builder.is_finalized() && !builder.has_hidden_nodes() {
346+
if builder.is_finalizable() && !builder.has_hidden_nodes() {
347347
Ok(TapTree(builder))
348348
} else {
349349
Err(encode::Error::ParseFailed("Incomplete taproot Tree"))

src/util/taproot.rs

+19-17
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ impl TaprootSpendInfo {
199199
I: IntoIterator<Item=(u32, Script)>,
200200
C: secp256k1::Verification,
201201
{
202-
TaprootBuilder::with_huffman_tree(script_weights)?.finalize(secp, internal_key)
202+
let builder = TaprootBuilder::with_huffman_tree(script_weights)?;
203+
Ok(builder.finalize(secp, internal_key).expect("Huffman Tree is always complete"))
203204
}
204205

205206
/// Creates a new key spend with `internal_key` and `merkle_root`. Provide [`None`] for
@@ -392,7 +393,7 @@ impl TaprootBuilder {
392393
node_weights.push((Reverse(p), NodeInfo::new_leaf_with_ver(leaf, LeafVersion::TapScript)));
393394
}
394395
if node_weights.is_empty() {
395-
return Err(TaprootBuilderError::IncompleteTree);
396+
return Err(TaprootBuilderError::EmptyTree);
396397
}
397398
while node_weights.len() > 1 {
398399
// Combine the last two elements and insert a new node
@@ -440,7 +441,7 @@ impl TaprootBuilder {
440441
}
441442

442443
/// Checks if the builder has finalized building a tree.
443-
pub fn is_finalized(&self) -> bool {
444+
pub fn is_finalizable(&self) -> bool {
444445
self.branch.len() == 1 && self.branch[0].is_some()
445446
}
446447

@@ -451,19 +452,23 @@ impl TaprootBuilder {
451452

452453
/// Creates a [`TaprootSpendInfo`] with the given internal key.
453454
///
454-
// TODO: in a future breaking API change, this no longer needs to return result
455+
/// Returns the unmodified builder as Err if the builder is not finalizable.
456+
/// See also [`TaprootBuilder::is_finalizable`]
455457
pub fn finalize<C: secp256k1::Verification>(
456458
mut self,
457459
secp: &Secp256k1<C>,
458460
internal_key: UntweakedPublicKey,
459-
) -> Result<TaprootSpendInfo, TaprootBuilderError> {
460-
match self.branch.pop() {
461-
None => Ok(TaprootSpendInfo::new_key_spend(secp, internal_key, None)),
462-
Some(Some(node)) => {
463-
Ok(TaprootSpendInfo::from_node_info(secp, internal_key, node))
461+
) -> Result<TaprootSpendInfo, TaprootBuilder> {
462+
match self.branch.len() {
463+
0 => Ok(TaprootSpendInfo::new_key_spend(secp, internal_key, None)),
464+
1 => {
465+
if let Some(Some(node)) = self.branch.pop() {
466+
Ok(TaprootSpendInfo::from_node_info(secp, internal_key, node))
467+
} else {
468+
unreachable!("Size checked above. Builder guarantees the last element is Some")
469+
}
464470
}
465-
_ => Err(TaprootBuilderError::IncompleteTree),
466-
471+
_ => Err(self),
467472
}
468473
}
469474

@@ -1013,8 +1018,6 @@ pub enum TaprootBuilderError {
10131018
OverCompleteTree,
10141019
/// Invalid taproot internal key.
10151020
InvalidInternalKey(secp256k1::Error),
1016-
/// Called finalize on an incomplete tree.
1017-
IncompleteTree,
10181021
/// Called finalize on a empty tree.
10191022
EmptyTree,
10201023
}
@@ -1036,9 +1039,6 @@ impl fmt::Display for TaprootBuilderError {
10361039
TaprootBuilderError::InvalidInternalKey(ref e) => {
10371040
write_err!(f, "invalid internal x-only key"; e)
10381041
}
1039-
TaprootBuilderError::IncompleteTree => {
1040-
write!(f, "Called finalize on an incomplete tree")
1041-
}
10421042
TaprootBuilderError::EmptyTree => {
10431043
write!(f, "Called finalize on an empty tree")
10441044
}
@@ -1057,7 +1057,6 @@ impl std::error::Error for TaprootBuilderError {
10571057
InvalidMerkleTreeDepth(_)
10581058
| NodeNotInDfsOrder
10591059
| OverCompleteTree
1060-
| IncompleteTree
10611060
| EmptyTree => None
10621061
}
10631062
}
@@ -1341,6 +1340,9 @@ mod test {
13411340
let builder = builder.add_leaf(2, b.clone()).unwrap();
13421341
let builder = builder.add_leaf(2, c.clone()).unwrap();
13431342
let builder = builder.add_leaf(3, d.clone()).unwrap();
1343+
1344+
// Trying to finalize an incomplete tree returns the Err(builder)
1345+
let builder = builder.finalize(&secp, internal_key).unwrap_err();
13441346
let builder = builder.add_leaf(3, e.clone()).unwrap();
13451347

13461348
let tree_info = builder.finalize(&secp, internal_key).unwrap();

0 commit comments

Comments
 (0)