Skip to content

Commit e49c1db

Browse files
committed
Merge #807: [Taproot API project] move several files and tighten up iterator API
8e5d809 tr: rename `iter_scripts` to `leaves` (Andrew Poelstra) 86bee15 tr: move Liftable impl for TapTree (Andrew Poelstra) b463007 tr: move TapTree into taptree module (Andrew Poelstra) 82f58ce tr: move TapTreeIter into taptree module (Andrew Poelstra) 2232979 tr: encapsulate object which is yielded by TapTreeIter (Andrew Poelstra) e5c9bc3 tr: move tr.rs to tr/mod.rs (Andrew Poelstra) Pull request description: This PR mostly just moves files around, but it includes two nontrivial API changes: * It renames the `iter_scripts` iterator to `leaves` on `Tr` and `Taptree` * It yields a dedicated struct rather than just a `(u8, Script)` tuple In the next PRs we will completely rewrite this iterator, and `Taptree` and these preparatory commits help to reduce the diff throughout the rest of the codebase. ACKs for top commit: sanket1729: code review ACK 8e5d809. Tree-SHA512: ae1dcac31fb1ea52541141c39d237fc45348f0b314ea645ca87a80e833b69311a4e2e87ea17c65d0ce842429416ea493165a8689e4a5b747c1489ef44f601e54
2 parents e33e66c + 8e5d809 commit e49c1db

File tree

6 files changed

+268
-181
lines changed

6 files changed

+268
-181
lines changed

bitcoind-tests/tests/test_desc.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,10 @@ pub fn test_desc_satisfy(
185185
}
186186
// ------------------ script spend -------------
187187
let x_only_keypairs_reqd: Vec<(secp256k1::Keypair, TapLeafHash)> = tr
188-
.iter_scripts()
189-
.flat_map(|(_depth, ms)| {
190-
let leaf_hash = TapLeafHash::from_script(&ms.encode(), LeafVersion::TapScript);
191-
ms.iter_pk().filter_map(move |pk| {
188+
.leaves()
189+
.flat_map(|leaf| {
190+
let leaf_hash = TapLeafHash::from_script(&leaf.compute_script(), LeafVersion::TapScript);
191+
leaf.miniscript().iter_pk().filter_map(move |pk| {
192192
let i = x_only_pks.iter().position(|&x| x.to_public_key() == pk);
193193
i.map(|idx| (xonly_keypairs[idx], leaf_hash))
194194
})

examples/taproot.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,18 @@ fn main() {
6666
assert_eq!(p.internal_key(), "Ca");
6767

6868
// Iterate through scripts
69-
let mut iter = p.iter_scripts();
69+
let mut iter = p.leaves();
70+
let mut next = iter.next().unwrap();
7071
assert_eq!(
71-
iter.next().unwrap(),
72+
(next.depth(), next.miniscript().as_ref()),
7273
(
7374
1u8,
7475
&Miniscript::<String, Tap>::from_str("and_v(vc:pk_k(In),older(9))").unwrap()
7576
)
7677
);
78+
next = iter.next().unwrap();
7779
assert_eq!(
78-
iter.next().unwrap(),
80+
(next.depth(), next.miniscript().as_ref()),
7981
(1u8, &Miniscript::<String, Tap>::from_str("and_v(v:pk(hA),pk(S))").unwrap())
8082
);
8183
assert_eq!(iter.next(), None);

src/descriptor/mod.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub use self::bare::{Bare, Pkh};
4242
pub use self::segwitv0::{Wpkh, Wsh, WshInner};
4343
pub use self::sh::{Sh, ShInner};
4444
pub use self::sortedmulti::SortedMultiVec;
45-
pub use self::tr::{TapTree, Tr};
45+
pub use self::tr::{TapTree, TapTreeIter, TapTreeIterItem, Tr};
4646

4747
pub mod checksum;
4848
mod key;
@@ -252,7 +252,7 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
252252

253253
/// For a Taproot descriptor, returns the [`TapTree`] describing the Taproot tree.
254254
///
255-
/// To obtain the individual leaves of the tree, call [`TapTree::iter`] on the
255+
/// To obtain the individual leaves of the tree, call [`TapTree::leaves`] on the
256256
/// returned value.
257257
pub fn tap_tree(&self) -> Option<&TapTree<Pk>> {
258258
if let Descriptor::Tr(ref tr) = self {
@@ -269,7 +269,7 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
269269
pub fn tap_tree_iter(&self) -> tr::TapTreeIter<Pk> {
270270
if let Descriptor::Tr(ref tr) = self {
271271
if let Some(ref tree) = tr.tap_tree() {
272-
return tree.iter();
272+
return tree.leaves();
273273
}
274274
}
275275
tr::TapTreeIter::empty()
@@ -988,8 +988,9 @@ impl<Pk: FromStrKey> FromStr for Descriptor<Pk> {
988988
// FIXME preserve weird/broken behavior from 12.x.
989989
// See https://github.com/rust-bitcoin/rust-miniscript/issues/734
990990
ret.sanity_check()?;
991-
for (_, ms) in inner.iter_scripts() {
992-
ms.ext_check(&crate::miniscript::analyzable::ExtParams::sane())?;
991+
for item in inner.iter_scripts() {
992+
item.miniscript()
993+
.ext_check(&crate::miniscript::analyzable::ExtParams::sane())?;
993994
}
994995
}
995996
Ok(ret)

src/descriptor/tr.rs renamed to src/descriptor/tr/mod.rs

+36-162
Original file line numberDiff line numberDiff line change
@@ -26,26 +26,9 @@ use crate::{
2626
Threshold, ToPublicKey, TranslateErr, Translator,
2727
};
2828

29-
/// A Taproot Tree representation.
30-
// Hidden leaves are not yet supported in descriptor spec. Conceptually, it should
31-
// be simple to integrate those here, but it is best to wait on core for the exact syntax.
32-
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
33-
pub enum TapTree<Pk: MiniscriptKey> {
34-
/// A taproot tree structure
35-
Tree {
36-
/// Left tree branch.
37-
left: Arc<TapTree<Pk>>,
38-
/// Right tree branch.
39-
right: Arc<TapTree<Pk>>,
40-
/// Tree height, defined as `1 + max(left_height, right_height)`.
41-
height: usize,
42-
},
43-
/// A taproot leaf denoting a spending condition
44-
// A new leaf version would require a new Context, therefore there is no point
45-
// in adding a LeafVersion with Leaf type here. All Miniscripts right now
46-
// are of Leafversion::default
47-
Leaf(Arc<Miniscript<Pk, Tap>>),
48-
}
29+
mod taptree;
30+
31+
pub use self::taptree::{TapTree, TapTreeIter, TapTreeIterItem};
4932

5033
/// A taproot descriptor
5134
pub struct Tr<Pk: MiniscriptKey> {
@@ -111,64 +94,6 @@ impl<Pk: MiniscriptKey> hash::Hash for Tr<Pk> {
11194
}
11295
}
11396

114-
impl<Pk: MiniscriptKey> TapTree<Pk> {
115-
/// Creates a `TapTree` by combining `left` and `right` tree nodes.
116-
pub fn combine(left: TapTree<Pk>, right: TapTree<Pk>) -> Self {
117-
let height = 1 + cmp::max(left.height(), right.height());
118-
TapTree::Tree { left: Arc::new(left), right: Arc::new(right), height }
119-
}
120-
121-
/// Returns the height of this tree.
122-
pub fn height(&self) -> usize {
123-
match *self {
124-
TapTree::Tree { left: _, right: _, height } => height,
125-
TapTree::Leaf(..) => 0,
126-
}
127-
}
128-
129-
/// Iterates over all miniscripts in DFS walk order compatible with the
130-
/// PSBT requirements (BIP 371).
131-
pub fn iter(&self) -> TapTreeIter<Pk> { TapTreeIter { stack: vec![(0, self)] } }
132-
133-
// Helper function to translate keys
134-
fn translate_helper<T>(&self, t: &mut T) -> Result<TapTree<T::TargetPk>, TranslateErr<T::Error>>
135-
where
136-
T: Translator<Pk>,
137-
{
138-
let frag = match *self {
139-
TapTree::Tree { ref left, ref right, ref height } => TapTree::Tree {
140-
left: Arc::new(left.translate_helper(t)?),
141-
right: Arc::new(right.translate_helper(t)?),
142-
height: *height,
143-
},
144-
TapTree::Leaf(ref ms) => TapTree::Leaf(Arc::new(ms.translate_pk(t)?)),
145-
};
146-
Ok(frag)
147-
}
148-
}
149-
150-
impl<Pk: MiniscriptKey> fmt::Display for TapTree<Pk> {
151-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152-
match self {
153-
TapTree::Tree { ref left, ref right, height: _ } => {
154-
write!(f, "{{{},{}}}", *left, *right)
155-
}
156-
TapTree::Leaf(ref script) => write!(f, "{}", *script),
157-
}
158-
}
159-
}
160-
161-
impl<Pk: MiniscriptKey> fmt::Debug for TapTree<Pk> {
162-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163-
match self {
164-
TapTree::Tree { ref left, ref right, height: _ } => {
165-
write!(f, "{{{:?},{:?}}}", *left, *right)
166-
}
167-
TapTree::Leaf(ref script) => write!(f, "{:?}", *script),
168-
}
169-
}
170-
}
171-
17297
impl<Pk: MiniscriptKey> Tr<Pk> {
17398
/// Create a new [`Tr`] descriptor from internal key and [`TapTree`]
17499
pub fn new(internal_key: Pk, tree: Option<TapTree<Pk>>) -> Result<Self, Error> {
@@ -194,10 +119,17 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
194119

195120
/// Iterate over all scripts in merkle tree. If there is no script path, the iterator
196121
/// yields [`None`]
197-
pub fn iter_scripts(&self) -> TapTreeIter<Pk> {
122+
#[deprecated(since = "TBD", note = "use `leaves` instead")]
123+
pub fn iter_scripts(&self) -> TapTreeIter<Pk> { self.leaves() }
124+
125+
/// Iterates over all the leaves of the tree in depth-first preorder.
126+
///
127+
/// The yielded elements include the Miniscript for each leave as well as its depth
128+
/// in the tree, which is the data required by PSBT (BIP 371).
129+
pub fn leaves(&self) -> TapTreeIter<Pk> {
198130
match self.tree {
199-
Some(ref t) => t.iter(),
200-
None => TapTreeIter { stack: vec![] },
131+
Some(ref t) => t.leaves(),
132+
None => TapTreeIter::empty(),
201133
}
202134
}
203135

@@ -226,10 +158,10 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
226158
TaprootSpendInfo::new_key_spend(&secp, self.internal_key.to_x_only_pubkey(), None)
227159
} else {
228160
let mut builder = TaprootBuilder::new();
229-
for (depth, ms) in self.iter_scripts() {
230-
let script = ms.encode();
161+
for leaf in self.leaves() {
162+
let script = leaf.miniscript().encode();
231163
builder = builder
232-
.add_leaf(depth, script)
164+
.add_leaf(leaf.depth(), script)
233165
.expect("Computing spend data on a valid Tree should always succeed");
234166
}
235167
// Assert builder cannot error here because we have a well formed descriptor
@@ -245,8 +177,8 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
245177

246178
/// Checks whether the descriptor is safe.
247179
pub fn sanity_check(&self) -> Result<(), Error> {
248-
for (_depth, ms) in self.iter_scripts() {
249-
ms.sanity_check()?;
180+
for leaf in self.leaves() {
181+
leaf.miniscript().sanity_check()?;
250182
}
251183
Ok(())
252184
}
@@ -275,12 +207,12 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
275207
};
276208

277209
let wu = tree
278-
.iter()
279-
.filter_map(|(depth, ms)| {
280-
let script_size = ms.script_size();
281-
let max_sat_elems = ms.max_satisfaction_witness_elements().ok()?;
282-
let max_sat_size = ms.max_satisfaction_size().ok()?;
283-
let control_block_size = control_block_len(depth);
210+
.leaves()
211+
.filter_map(|leaf| {
212+
let script_size = leaf.miniscript().script_size();
213+
let max_sat_elems = leaf.miniscript().max_satisfaction_witness_elements().ok()?;
214+
let max_sat_size = leaf.miniscript().max_satisfaction_size().ok()?;
215+
let control_block_size = control_block_len(leaf.depth());
284216

285217
// stack varint difference (+1 for ctrl block, witness script already included)
286218
let stack_varint_diff = varint_len(max_sat_elems + 1) - varint_len(0);
@@ -325,12 +257,12 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
325257
Some(tree) => tree,
326258
};
327259

328-
tree.iter()
329-
.filter_map(|(depth, ms)| {
330-
let script_size = ms.script_size();
331-
let max_sat_elems = ms.max_satisfaction_witness_elements().ok()?;
332-
let max_sat_size = ms.max_satisfaction_size().ok()?;
333-
let control_block_size = control_block_len(depth);
260+
tree.leaves()
261+
.filter_map(|leaf| {
262+
let script_size = leaf.miniscript().script_size();
263+
let max_sat_elems = leaf.miniscript().max_satisfaction_witness_elements().ok()?;
264+
let max_sat_size = leaf.miniscript().max_satisfaction_size().ok()?;
265+
let control_block_size = control_block_len(leaf.depth());
334266
Some(
335267
// scriptSig len byte
336268
4 +
@@ -447,48 +379,6 @@ impl Tr<DefiniteDescriptorKey> {
447379
}
448380
}
449381

450-
/// Iterator for Taproot structures
451-
/// Yields a pair of (depth, miniscript) in a depth first walk
452-
/// For example, this tree:
453-
/// - N0 -
454-
/// / \\
455-
/// N1 N2
456-
/// / \ / \\
457-
/// A B C N3
458-
/// / \\
459-
/// D E
460-
/// would yield (2, A), (2, B), (2,C), (3, D), (3, E).
461-
///
462-
#[derive(Debug, Clone)]
463-
pub struct TapTreeIter<'a, Pk: MiniscriptKey> {
464-
stack: Vec<(u8, &'a TapTree<Pk>)>,
465-
}
466-
467-
impl<Pk: MiniscriptKey> TapTreeIter<'_, Pk> {
468-
/// Helper function to return an empty iterator from Descriptor::tap_tree_iter.
469-
pub(super) fn empty() -> Self { Self { stack: vec![] } }
470-
}
471-
472-
impl<'a, Pk> Iterator for TapTreeIter<'a, Pk>
473-
where
474-
Pk: MiniscriptKey + 'a,
475-
{
476-
type Item = (u8, &'a Miniscript<Pk, Tap>);
477-
478-
fn next(&mut self) -> Option<Self::Item> {
479-
while let Some((depth, last)) = self.stack.pop() {
480-
match *last {
481-
TapTree::Tree { ref left, ref right, height: _ } => {
482-
self.stack.push((depth + 1, right));
483-
self.stack.push((depth + 1, left));
484-
}
485-
TapTree::Leaf(ref ms) => return Some((depth, ms)),
486-
}
487-
}
488-
None
489-
}
490-
}
491-
492382
impl<Pk: FromStrKey> core::str::FromStr for Tr<Pk> {
493383
type Err = Error;
494384

@@ -597,22 +487,6 @@ impl<Pk: MiniscriptKey> fmt::Display for Tr<Pk> {
597487
}
598488
}
599489

600-
impl<Pk: MiniscriptKey> Liftable<Pk> for TapTree<Pk> {
601-
fn lift(&self) -> Result<Policy<Pk>, Error> {
602-
fn lift_helper<Pk: MiniscriptKey>(s: &TapTree<Pk>) -> Result<Policy<Pk>, Error> {
603-
match *s {
604-
TapTree::Tree { ref left, ref right, height: _ } => Ok(Policy::Thresh(
605-
Threshold::or(Arc::new(lift_helper(left)?), Arc::new(lift_helper(right)?)),
606-
)),
607-
TapTree::Leaf(ref leaf) => leaf.lift(),
608-
}
609-
}
610-
611-
let pol = lift_helper(self)?;
612-
Ok(pol.normalized())
613-
}
614-
}
615-
616490
impl<Pk: MiniscriptKey> Liftable<Pk> for Tr<Pk> {
617491
fn lift(&self) -> Result<Policy<Pk>, Error> {
618492
match &self.tree {
@@ -628,8 +502,8 @@ impl<Pk: MiniscriptKey> Liftable<Pk> for Tr<Pk> {
628502
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Tr<Pk> {
629503
fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool {
630504
let script_keys_res = self
631-
.iter_scripts()
632-
.all(|(_d, ms)| ms.for_each_key(&mut pred));
505+
.leaves()
506+
.all(|leaf| leaf.miniscript().for_each_key(&mut pred));
633507
script_keys_res && pred(&self.internal_key)
634508
}
635509
}
@@ -673,14 +547,14 @@ where
673547
absolute_timelock: None,
674548
};
675549
let mut min_wit_len = None;
676-
for (_depth, ms) in desc.iter_scripts() {
550+
for leaf in desc.leaves() {
677551
let mut satisfaction = if allow_mall {
678-
match ms.build_template(provider) {
552+
match leaf.miniscript().build_template(provider) {
679553
s @ Satisfaction { stack: Witness::Stack(_), .. } => s,
680554
_ => continue, // No witness for this script in tr descriptor, look for next one
681555
}
682556
} else {
683-
match ms.build_template_mall(provider) {
557+
match leaf.miniscript().build_template_mall(provider) {
684558
s @ Satisfaction { stack: Witness::Stack(_), .. } => s,
685559
_ => continue, // No witness for this script in tr descriptor, look for next one
686560
}
@@ -690,7 +564,7 @@ where
690564
_ => unreachable!(),
691565
};
692566

693-
let leaf_script = (ms.encode(), LeafVersion::TapScript);
567+
let leaf_script = (leaf.compute_script(), LeafVersion::TapScript);
694568
let control_block = spend_info
695569
.control_block(&leaf_script)
696570
.expect("Control block must exist in script map for every known leaf");

0 commit comments

Comments
 (0)