Skip to content

Commit 9d658a9

Browse files
committed
Merge #803: [backport] cleanup: refactor a bunch of concatenation-related code in satisfy
9d81dcf bump version to 12.3.1 (Andrew Poelstra) 7be767c satisfy: clean up a bunch of satisfaction code (Andrew Poelstra) 8efce62 ci: fix new clippy lint related to doccomments (Andrew Poelstra) Pull request description: This backports the main commit in #798 so that the code in (released) 12.x is substantially the same as the code in (unreleased) 13.x. This makes it easier to write and maintain regression tests. ACKs for top commit: sanket1729: ACK 9d81dcf Tree-SHA512: 1996ba4e2d01fc469e43724d7c6b2fbd5d1536181501ecb71ae99566bf7f635e829cfb7383d22241226becc84fcb95efcd105c95e165a401e9bd31e89e89ff19
2 parents 5fbedba + 9d81dcf commit 9d658a9

File tree

5 files changed

+76
-106
lines changed

5 files changed

+76
-106
lines changed

Cargo-minimal.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ dependencies = [
316316

317317
[[package]]
318318
name = "miniscript"
319-
version = "12.3.0"
319+
version = "12.3.1"
320320
dependencies = [
321321
"bech32",
322322
"bitcoin",

Cargo-recent.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ dependencies = [
294294

295295
[[package]]
296296
name = "miniscript"
297-
version = "12.3.0"
297+
version = "12.3.1"
298298
dependencies = [
299299
"bech32",
300300
"bitcoin",

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "miniscript"
3-
version = "12.3.0"
3+
version = "12.3.1"
44
authors = ["Andrew Poelstra <[email protected]>, Sanket Kanjalkar <[email protected]>"]
55
license = "CC0-1.0"
66
homepage = "https://github.com/rust-bitcoin/rust-miniscript/"

src/miniscript/iter.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -199,22 +199,24 @@ impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iterator for PkIter<'a, Pk, Ctx>
199199
}
200200
}
201201

202-
// Module is public since it export testcase generation which may be used in
203-
// dependent libraries for their own tasts based on Miniscript AST
202+
/// Module is public since it export testcase generation which may be used in
203+
/// dependent libraries for their own tasts based on Miniscript AST
204204
#[cfg(test)]
205205
pub mod test {
206206
use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
207207

208208
use super::Miniscript;
209209
use crate::miniscript::context::Segwitv0;
210210

211+
/// Test case.
211212
pub type TestData = (
212213
Miniscript<bitcoin::PublicKey, Segwitv0>,
213214
Vec<bitcoin::PublicKey>,
214215
Vec<hash160::Hash>,
215216
bool, // Indicates that the top-level contains public key or hashes
216217
);
217218

219+
/// Generate a deterministic list of public keys of the given length.
218220
pub fn gen_secp_pubkeys(n: usize) -> Vec<secp256k1::PublicKey> {
219221
let mut ret = Vec::with_capacity(n);
220222
let secp = secp256k1::Secp256k1::new();
@@ -233,13 +235,15 @@ pub mod test {
233235
ret
234236
}
235237

238+
/// Generate a deterministic list of Bitcoin public keys of the given length.
236239
pub fn gen_bitcoin_pubkeys(n: usize, compressed: bool) -> Vec<bitcoin::PublicKey> {
237240
gen_secp_pubkeys(n)
238241
.into_iter()
239242
.map(|inner| bitcoin::PublicKey { inner, compressed })
240243
.collect()
241244
}
242245

246+
/// Generate a deterministic list of test cases of the given length.
243247
pub fn gen_testcases() -> Vec<TestData> {
244248
let k = gen_bitcoin_pubkeys(10, true);
245249
let _h: Vec<hash160::Hash> = k

src/miniscript/satisfy.rs

+67-101
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,34 @@ pub struct Satisfaction<T> {
889889
}
890890

891891
impl<Pk: MiniscriptKey + ToPublicKey> Satisfaction<Placeholder<Pk>> {
892+
/// The empty satisfaction.
893+
///
894+
/// This has the property that, when concatenated on either side with another satisfaction
895+
/// X, the result will be X.
896+
fn empty() -> Self {
897+
Satisfaction {
898+
has_sig: false,
899+
relative_timelock: None,
900+
absolute_timelock: None,
901+
stack: Witness::Stack(vec![]),
902+
}
903+
}
904+
905+
/// Forms a satisfaction which is the concatenation of two satisfactions, with `other`'s
906+
/// stack before `self`'s.
907+
///
908+
/// This order allows callers to write `left.concatenate_rev(right)` which feels more
909+
/// natural than the opposite order, and more importantly, allows this method to be
910+
/// used when folding over an iterator of multiple satisfactions.
911+
fn concatenate_rev(self, other: Self) -> Self {
912+
Satisfaction {
913+
has_sig: self.has_sig || other.has_sig,
914+
relative_timelock: cmp::max(self.relative_timelock, other.relative_timelock),
915+
absolute_timelock: cmp::max(self.absolute_timelock, other.absolute_timelock),
916+
stack: Witness::combine(other.stack, self.stack),
917+
}
918+
}
919+
892920
pub(crate) fn build_template<P, Ctx>(
893921
term: &Terminal<Pk, Ctx>,
894922
provider: &P,
@@ -1041,20 +1069,9 @@ impl<Pk: MiniscriptKey + ToPublicKey> Satisfaction<Placeholder<Pk>> {
10411069
}
10421070
} else {
10431071
// Otherwise flatten everything out
1044-
Satisfaction {
1045-
has_sig: ret_stack.iter().any(|sat| sat.has_sig),
1046-
relative_timelock: ret_stack
1047-
.iter()
1048-
.filter_map(|sat| sat.relative_timelock)
1049-
.max(),
1050-
absolute_timelock: ret_stack
1051-
.iter()
1052-
.filter_map(|sat| sat.absolute_timelock)
1053-
.max(),
1054-
stack: ret_stack
1055-
.into_iter()
1056-
.fold(Witness::empty(), |acc, next| Witness::combine(next.stack, acc)),
1057-
}
1072+
ret_stack
1073+
.into_iter()
1074+
.fold(Satisfaction::empty(), Satisfaction::concatenate_rev)
10581075
}
10591076
}
10601077

@@ -1125,20 +1142,9 @@ impl<Pk: MiniscriptKey + ToPublicKey> Satisfaction<Placeholder<Pk>> {
11251142

11261143
// combine the witness
11271144
// no non-malleability checks needed
1128-
Satisfaction {
1129-
has_sig: ret_stack.iter().any(|sat| sat.has_sig),
1130-
relative_timelock: ret_stack
1131-
.iter()
1132-
.filter_map(|sat| sat.relative_timelock)
1133-
.max(),
1134-
absolute_timelock: ret_stack
1135-
.iter()
1136-
.filter_map(|sat| sat.absolute_timelock)
1137-
.max(),
1138-
stack: ret_stack
1139-
.into_iter()
1140-
.fold(Witness::empty(), |acc, next| Witness::combine(next.stack, acc)),
1141-
}
1145+
ret_stack
1146+
.into_iter()
1147+
.fold(Satisfaction::empty(), Satisfaction::concatenate_rev)
11421148
}
11431149

11441150
fn minimum(sat1: Self, sat2: Self) -> Self {
@@ -1360,12 +1366,7 @@ impl<Pk: MiniscriptKey + ToPublicKey> Satisfaction<Placeholder<Pk>> {
13601366
Self::satisfy_helper(&l.node, stfr, root_has_sig, leaf_hash, min_fn, thresh_fn);
13611367
let r_sat =
13621368
Self::satisfy_helper(&r.node, stfr, root_has_sig, leaf_hash, min_fn, thresh_fn);
1363-
Satisfaction {
1364-
stack: Witness::combine(r_sat.stack, l_sat.stack),
1365-
has_sig: l_sat.has_sig || r_sat.has_sig,
1366-
relative_timelock: cmp::max(l_sat.relative_timelock, r_sat.relative_timelock),
1367-
absolute_timelock: cmp::max(l_sat.absolute_timelock, r_sat.absolute_timelock),
1368-
}
1369+
l_sat.concatenate_rev(r_sat)
13691370
}
13701371
Terminal::AndOr(ref a, ref b, ref c) => {
13711372
let a_sat =
@@ -1383,27 +1384,7 @@ impl<Pk: MiniscriptKey + ToPublicKey> Satisfaction<Placeholder<Pk>> {
13831384
let c_sat =
13841385
Self::satisfy_helper(&c.node, stfr, root_has_sig, leaf_hash, min_fn, thresh_fn);
13851386

1386-
min_fn(
1387-
Satisfaction {
1388-
stack: Witness::combine(b_sat.stack, a_sat.stack),
1389-
has_sig: a_sat.has_sig || b_sat.has_sig,
1390-
relative_timelock: cmp::max(
1391-
a_sat.relative_timelock,
1392-
b_sat.relative_timelock,
1393-
),
1394-
absolute_timelock: cmp::max(
1395-
a_sat.absolute_timelock,
1396-
b_sat.absolute_timelock,
1397-
),
1398-
},
1399-
Satisfaction {
1400-
stack: Witness::combine(c_sat.stack, a_nsat.stack),
1401-
has_sig: a_nsat.has_sig || c_sat.has_sig,
1402-
// timelocks can't be dissatisfied, so here we ignore a_nsat and only consider c_sat
1403-
relative_timelock: c_sat.relative_timelock,
1404-
absolute_timelock: c_sat.absolute_timelock,
1405-
},
1406-
)
1387+
min_fn(a_sat.concatenate_rev(b_sat), a_nsat.concatenate_rev(c_sat))
14071388
}
14081389
Terminal::OrB(ref l, ref r) => {
14091390
let l_sat =
@@ -1431,18 +1412,8 @@ impl<Pk: MiniscriptKey + ToPublicKey> Satisfaction<Placeholder<Pk>> {
14311412
assert!(!r_nsat.has_sig);
14321413

14331414
min_fn(
1434-
Satisfaction {
1435-
stack: Witness::combine(r_sat.stack, l_nsat.stack),
1436-
has_sig: r_sat.has_sig,
1437-
relative_timelock: r_sat.relative_timelock,
1438-
absolute_timelock: r_sat.absolute_timelock,
1439-
},
1440-
Satisfaction {
1441-
stack: Witness::combine(r_nsat.stack, l_sat.stack),
1442-
has_sig: l_sat.has_sig,
1443-
relative_timelock: l_sat.relative_timelock,
1444-
absolute_timelock: l_sat.absolute_timelock,
1445-
},
1415+
Satisfaction::concatenate_rev(l_nsat, r_sat),
1416+
Satisfaction::concatenate_rev(l_sat, r_nsat),
14461417
)
14471418
}
14481419
Terminal::OrD(ref l, ref r) | Terminal::OrC(ref l, ref r) => {
@@ -1461,15 +1432,7 @@ impl<Pk: MiniscriptKey + ToPublicKey> Satisfaction<Placeholder<Pk>> {
14611432

14621433
assert!(!l_nsat.has_sig);
14631434

1464-
min_fn(
1465-
l_sat,
1466-
Satisfaction {
1467-
stack: Witness::combine(r_sat.stack, l_nsat.stack),
1468-
has_sig: r_sat.has_sig,
1469-
relative_timelock: r_sat.relative_timelock,
1470-
absolute_timelock: r_sat.absolute_timelock,
1471-
},
1472-
)
1435+
min_fn(l_sat, Satisfaction::concatenate_rev(l_nsat, r_sat))
14731436
}
14741437
Terminal::OrI(ref l, ref r) => {
14751438
let l_sat =
@@ -1492,7 +1455,24 @@ impl<Pk: MiniscriptKey + ToPublicKey> Satisfaction<Placeholder<Pk>> {
14921455
)
14931456
}
14941457
Terminal::Thresh(ref thresh) => {
1495-
thresh_fn(thresh, stfr, root_has_sig, leaf_hash, min_fn)
1458+
if thresh.k() == thresh.n() {
1459+
// this is just an and
1460+
thresh
1461+
.iter()
1462+
.map(|s| {
1463+
Self::satisfy_helper(
1464+
&s.node,
1465+
stfr,
1466+
root_has_sig,
1467+
leaf_hash,
1468+
min_fn,
1469+
thresh_fn,
1470+
)
1471+
})
1472+
.fold(Satisfaction::empty(), Satisfaction::concatenate_rev)
1473+
} else {
1474+
thresh_fn(thresh, stfr, root_has_sig, leaf_hash, min_fn)
1475+
}
14961476
}
14971477
Terminal::Multi(ref thresh) => {
14981478
// Collect all available signatures
@@ -1682,12 +1662,7 @@ impl<Pk: MiniscriptKey + ToPublicKey> Satisfaction<Placeholder<Pk>> {
16821662
min_fn,
16831663
thresh_fn,
16841664
);
1685-
Satisfaction {
1686-
stack: Witness::combine(odissat.stack, vsat.stack),
1687-
has_sig: vsat.has_sig || odissat.has_sig,
1688-
relative_timelock: None,
1689-
absolute_timelock: None,
1690-
}
1665+
vsat.concatenate_rev(odissat)
16911666
}
16921667
Terminal::AndB(ref l, ref r)
16931668
| Terminal::OrB(ref l, ref r)
@@ -1709,12 +1684,7 @@ impl<Pk: MiniscriptKey + ToPublicKey> Satisfaction<Placeholder<Pk>> {
17091684
min_fn,
17101685
thresh_fn,
17111686
);
1712-
Satisfaction {
1713-
stack: Witness::combine(rnsat.stack, lnsat.stack),
1714-
has_sig: rnsat.has_sig || lnsat.has_sig,
1715-
relative_timelock: None,
1716-
absolute_timelock: None,
1717-
}
1687+
lnsat.concatenate_rev(rnsat)
17181688
}
17191689
Terminal::OrI(ref l, ref r) => {
17201690
let lnsat = Self::dissatisfy_helper(
@@ -1750,23 +1720,19 @@ impl<Pk: MiniscriptKey + ToPublicKey> Satisfaction<Placeholder<Pk>> {
17501720
// Dissatisfactions don't need to non-malleable. Use minimum_mall always
17511721
Satisfaction::minimum_mall(dissat_1, dissat_2)
17521722
}
1753-
Terminal::Thresh(ref thresh) => Satisfaction {
1754-
stack: thresh.iter().fold(Witness::empty(), |acc, sub| {
1755-
let nsat = Self::dissatisfy_helper(
1756-
&sub.node,
1723+
Terminal::Thresh(ref thresh) => thresh
1724+
.iter()
1725+
.map(|s| {
1726+
Self::dissatisfy_helper(
1727+
&s.node,
17571728
stfr,
17581729
root_has_sig,
17591730
leaf_hash,
17601731
min_fn,
17611732
thresh_fn,
1762-
);
1763-
assert!(!nsat.has_sig);
1764-
Witness::combine(nsat.stack, acc)
1765-
}),
1766-
has_sig: false,
1767-
relative_timelock: None,
1768-
absolute_timelock: None,
1769-
},
1733+
)
1734+
})
1735+
.fold(Satisfaction::empty(), Satisfaction::concatenate_rev),
17701736
Terminal::Multi(ref thresh) => Satisfaction {
17711737
stack: Witness::Stack(vec![Placeholder::PushZero; thresh.k() + 1]),
17721738
has_sig: false,

0 commit comments

Comments
 (0)