Skip to content

Commit 1ced03b

Browse files
committed
policy: use Threshold in concrete policy
This one is a pretty big diff but hopefully the unit tests provide some assurance. One maybe-subtle change is that the debug_assert in `generate_combinations` was incorrect -- it checked that k <= n, but the logic depended on k < n. I fixed the debug_assert and nothing broke.
1 parent f83eb64 commit 1ced03b

File tree

3 files changed

+103
-120
lines changed

3 files changed

+103
-120
lines changed

src/policy/compiler.rs

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,8 +1008,9 @@ where
10081008
compile_binary!(&mut l_comp[3], &mut r_comp[2], [lw, rw], Terminal::OrI);
10091009
compile_binary!(&mut r_comp[3], &mut l_comp[2], [rw, lw], Terminal::OrI);
10101010
}
1011-
Concrete::Thresh(k, ref subs) => {
1012-
let n = subs.len();
1011+
Concrete::Thresh(ref thresh) => {
1012+
let k = thresh.k();
1013+
let n = thresh.n();
10131014
let k_over_n = k as f64 / n as f64;
10141015

10151016
let mut sub_ast = Vec::with_capacity(n);
@@ -1019,7 +1020,7 @@ where
10191020
let mut best_ws = Vec::with_capacity(n);
10201021

10211022
let mut min_value = (0, f64::INFINITY);
1022-
for (i, ast) in subs.iter().enumerate() {
1023+
for (i, ast) in thresh.iter().enumerate() {
10231024
let sp = sat_prob * k_over_n;
10241025
//Expressions must be dissatisfiable
10251026
let dp = Some(dissat_prob.unwrap_or(0 as f64) + (1.0 - k_over_n) * sat_prob);
@@ -1037,7 +1038,7 @@ where
10371038
}
10381039
sub_ext_data.push(best_es[min_value.0].0);
10391040
sub_ast.push(Arc::clone(&best_es[min_value.0].1.ms));
1040-
for (i, _ast) in subs.iter().enumerate() {
1041+
for (i, _ast) in thresh.iter().enumerate() {
10411042
if i != min_value.0 {
10421043
sub_ext_data.push(best_ws[i].0);
10431044
sub_ast.push(Arc::clone(&best_ws[i].1.ms));
@@ -1054,7 +1055,7 @@ where
10541055
insert_wrap!(ast_ext);
10551056
}
10561057

1057-
let key_vec: Vec<Pk> = subs
1058+
let key_vec: Vec<Pk> = thresh
10581059
.iter()
10591060
.filter_map(|s| {
10601061
if let Concrete::Key(ref pk) = s.as_ref() {
@@ -1065,7 +1066,7 @@ where
10651066
})
10661067
.collect();
10671068

1068-
if key_vec.len() == subs.len() {
1069+
if key_vec.len() == thresh.n() {
10691070
match Ctx::sig_type() {
10701071
SigType::Schnorr => {
10711072
if key_vec.len() <= MAX_PUBKEYS_IN_CHECKSIGADD {
@@ -1079,8 +1080,8 @@ where
10791080
}
10801081
}
10811082
}
1082-
if k == subs.len() {
1083-
let mut it = subs.iter();
1083+
if k == thresh.n() {
1084+
let mut it = thresh.iter();
10841085
let mut policy = it.next().expect("No sub policy in thresh() ?").clone();
10851086
policy = it.fold(policy, |acc, pol| Concrete::And(vec![acc, pol.clone()]).into());
10861087

@@ -1247,7 +1248,7 @@ mod tests {
12471248
use super::*;
12481249
use crate::miniscript::{Legacy, Segwitv0, Tap};
12491250
use crate::policy::Liftable;
1250-
use crate::{script_num_size, AbsLockTime, RelLockTime, ToPublicKey};
1251+
use crate::{script_num_size, AbsLockTime, RelLockTime, Threshold, ToPublicKey};
12511252

12521253
type SPolicy = Concrete<String>;
12531254
type BPolicy = Concrete<bitcoin::PublicKey>;
@@ -1393,17 +1394,17 @@ mod tests {
13931394
(
13941395
127,
13951396
Arc::new(Concrete::Thresh(
1396-
3,
1397-
key_pol[0..5].iter().map(|p| (p.clone()).into()).collect(),
1397+
Threshold::from_iter(3, key_pol[0..5].iter().map(|p| (p.clone()).into()))
1398+
.unwrap(),
13981399
)),
13991400
),
14001401
(
14011402
1,
14021403
Arc::new(Concrete::And(vec![
14031404
Arc::new(Concrete::Older(RelLockTime::from_height(10000))),
14041405
Arc::new(Concrete::Thresh(
1405-
2,
1406-
key_pol[5..8].iter().map(|p| (p.clone()).into()).collect(),
1406+
Threshold::from_iter(2, key_pol[5..8].iter().map(|p| (p.clone()).into()))
1407+
.unwrap(),
14071408
)),
14081409
])),
14091410
),
@@ -1524,11 +1525,12 @@ mod tests {
15241525
// and to a ms thresh otherwise.
15251526
// k = 1 (or 2) does not compile, see https://github.com/rust-bitcoin/rust-miniscript/issues/114
15261527
for k in &[10, 15, 21] {
1527-
let pubkeys: Vec<Arc<Concrete<bitcoin::PublicKey>>> = keys
1528-
.iter()
1529-
.map(|pubkey| Arc::new(Concrete::Key(*pubkey)))
1530-
.collect();
1531-
let big_thresh = Concrete::Thresh(*k, pubkeys);
1528+
let thresh: Threshold<Arc<Concrete<bitcoin::PublicKey>>, 0> = Threshold::from_iter(
1529+
*k,
1530+
keys.iter().map(|pubkey| Arc::new(Concrete::Key(*pubkey))),
1531+
)
1532+
.unwrap();
1533+
let big_thresh = Concrete::Thresh(thresh);
15321534
let big_thresh_ms: SegwitMiniScript = big_thresh.compile().unwrap();
15331535
if *k == 21 {
15341536
// N * (PUSH + pubkey + CHECKSIGVERIFY)
@@ -1564,8 +1566,8 @@ mod tests {
15641566
.collect();
15651567

15661568
let thresh_res: Result<SegwitMiniScript, _> = Concrete::Or(vec![
1567-
(1, Arc::new(Concrete::Thresh(keys_a.len(), keys_a))),
1568-
(1, Arc::new(Concrete::Thresh(keys_b.len(), keys_b))),
1569+
(1, Arc::new(Concrete::Thresh(Threshold::and_n(keys_a)))),
1570+
(1, Arc::new(Concrete::Thresh(Threshold::and_n(keys_b)))),
15691571
])
15701572
.compile();
15711573
let script_size = thresh_res.clone().map(|m| m.script_size());
@@ -1582,7 +1584,8 @@ mod tests {
15821584
.iter()
15831585
.map(|pubkey| Arc::new(Concrete::Key(*pubkey)))
15841586
.collect();
1585-
let thresh_res: Result<SegwitMiniScript, _> = Concrete::Thresh(keys.len(), keys).compile();
1587+
let thresh_res: Result<SegwitMiniScript, _> =
1588+
Concrete::Thresh(Threshold::and_n(keys)).compile();
15861589
let n_elements = thresh_res
15871590
.clone()
15881591
.map(|m| m.max_satisfaction_witness_elements());
@@ -1598,12 +1601,12 @@ mod tests {
15981601
fn shared_limits() {
15991602
// Test the maximum number of OPs with a 67-of-68 multisig
16001603
let (keys, _) = pubkeys_and_a_sig(68);
1601-
let keys: Vec<Arc<Concrete<bitcoin::PublicKey>>> = keys
1602-
.iter()
1603-
.map(|pubkey| Arc::new(Concrete::Key(*pubkey)))
1604-
.collect();
1605-
let thresh_res: Result<SegwitMiniScript, _> =
1606-
Concrete::Thresh(keys.len() - 1, keys).compile();
1604+
let thresh = Threshold::from_iter(
1605+
keys.len() - 1,
1606+
keys.iter().map(|pubkey| Arc::new(Concrete::Key(*pubkey))),
1607+
)
1608+
.unwrap();
1609+
let thresh_res: Result<SegwitMiniScript, _> = Concrete::Thresh(thresh).compile();
16071610
let ops_count = thresh_res.clone().map(|m| m.ext.ops.op_count());
16081611
assert_eq!(
16091612
thresh_res,
@@ -1613,11 +1616,13 @@ mod tests {
16131616
);
16141617
// For legacy too..
16151618
let (keys, _) = pubkeys_and_a_sig(68);
1616-
let keys: Vec<Arc<Concrete<bitcoin::PublicKey>>> = keys
1617-
.iter()
1618-
.map(|pubkey| Arc::new(Concrete::Key(*pubkey)))
1619-
.collect();
1620-
let thresh_res = Concrete::Thresh(keys.len() - 1, keys).compile::<Legacy>();
1619+
let thresh = Threshold::from_iter(
1620+
keys.len() - 1,
1621+
keys.iter().map(|pubkey| Arc::new(Concrete::Key(*pubkey))),
1622+
)
1623+
.unwrap();
1624+
1625+
let thresh_res = Concrete::Thresh(thresh).compile::<Legacy>();
16211626
let ops_count = thresh_res.clone().map(|m| m.ext.ops.op_count());
16221627
assert_eq!(
16231628
thresh_res,

0 commit comments

Comments
 (0)