Skip to content

Commit 625165c

Browse files
committed
Remove PolicyArc
The `concrete::PolicyArc` type is identical to `Policy` except that it uses `Arc` to wrap the nested `Policy` structs. In preparation for implementing `TreeLike` and removing recursive functions that process the `Policy` type remove the `PolicyArc` and add `Arc` wrappers around the nested `Policy` fields. Note, this patch does a bunch on cloning in the recursive functions. This will dissapear when they are re-written to use tree iteration. There are more optimizaitons available by taking `Arc<Policy<Pk>>` as a parameter to functions in the `compiler` module, left for later. The unit tests are bit klunky, much mapping of iterators to add `Arc`, I think this will come out in the wash as we keep working.
1 parent ff99a1f commit 625165c

File tree

3 files changed

+171
-215
lines changed

3 files changed

+171
-215
lines changed

src/policy/compiler.rs

Lines changed: 93 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -844,10 +844,14 @@ where
844844
}
845845
Concrete::And(ref subs) => {
846846
assert_eq!(subs.len(), 2, "and takes 2 args");
847-
let mut left = best_compilations(policy_cache, &subs[0], sat_prob, dissat_prob)?;
848-
let mut right = best_compilations(policy_cache, &subs[1], sat_prob, dissat_prob)?;
849-
let mut q_zero_right = best_compilations(policy_cache, &subs[1], sat_prob, None)?;
850-
let mut q_zero_left = best_compilations(policy_cache, &subs[0], sat_prob, None)?;
847+
let mut left =
848+
best_compilations(policy_cache, subs[0].as_ref(), sat_prob, dissat_prob)?;
849+
let mut right =
850+
best_compilations(policy_cache, subs[1].as_ref(), sat_prob, dissat_prob)?;
851+
let mut q_zero_right =
852+
best_compilations(policy_cache, subs[1].as_ref(), sat_prob, None)?;
853+
let mut q_zero_left =
854+
best_compilations(policy_cache, subs[0].as_ref(), sat_prob, None)?;
851855

852856
compile_binary!(&mut left, &mut right, [1.0, 1.0], Terminal::AndB);
853857
compile_binary!(&mut right, &mut left, [1.0, 1.0], Terminal::AndB);
@@ -871,48 +875,56 @@ where
871875
let rw = subs[1].0 as f64 / total;
872876

873877
//and-or
874-
if let (Concrete::And(x), _) = (&subs[0].1, &subs[1].1) {
878+
if let (Concrete::And(x), _) = (subs[0].1.as_ref(), subs[1].1.as_ref()) {
875879
let mut a1 = best_compilations(
876880
policy_cache,
877-
&x[0],
881+
x[0].as_ref(),
878882
lw * sat_prob,
879883
Some(dissat_prob.unwrap_or(0 as f64) + rw * sat_prob),
880884
)?;
881-
let mut a2 = best_compilations(policy_cache, &x[0], lw * sat_prob, None)?;
885+
let mut a2 = best_compilations(policy_cache, x[0].as_ref(), lw * sat_prob, None)?;
882886

883887
let mut b1 = best_compilations(
884888
policy_cache,
885-
&x[1],
889+
x[1].as_ref(),
886890
lw * sat_prob,
887891
Some(dissat_prob.unwrap_or(0 as f64) + rw * sat_prob),
888892
)?;
889-
let mut b2 = best_compilations(policy_cache, &x[1], lw * sat_prob, None)?;
893+
let mut b2 = best_compilations(policy_cache, x[1].as_ref(), lw * sat_prob, None)?;
890894

891-
let mut c =
892-
best_compilations(policy_cache, &subs[1].1, rw * sat_prob, dissat_prob)?;
895+
let mut c = best_compilations(
896+
policy_cache,
897+
subs[1].1.as_ref(),
898+
rw * sat_prob,
899+
dissat_prob,
900+
)?;
893901

894902
compile_tern!(&mut a1, &mut b2, &mut c, [lw, rw]);
895903
compile_tern!(&mut b1, &mut a2, &mut c, [lw, rw]);
896904
};
897-
if let (_, Concrete::And(x)) = (&subs[0].1, &subs[1].1) {
905+
if let (_, Concrete::And(x)) = (&subs[0].1.as_ref(), subs[1].1.as_ref()) {
898906
let mut a1 = best_compilations(
899907
policy_cache,
900-
&x[0],
908+
x[0].as_ref(),
901909
rw * sat_prob,
902910
Some(dissat_prob.unwrap_or(0 as f64) + lw * sat_prob),
903911
)?;
904-
let mut a2 = best_compilations(policy_cache, &x[0], rw * sat_prob, None)?;
912+
let mut a2 = best_compilations(policy_cache, x[0].as_ref(), rw * sat_prob, None)?;
905913

906914
let mut b1 = best_compilations(
907915
policy_cache,
908-
&x[1],
916+
x[1].as_ref(),
909917
rw * sat_prob,
910918
Some(dissat_prob.unwrap_or(0 as f64) + lw * sat_prob),
911919
)?;
912-
let mut b2 = best_compilations(policy_cache, &x[1], rw * sat_prob, None)?;
920+
let mut b2 = best_compilations(policy_cache, x[1].as_ref(), rw * sat_prob, None)?;
913921

914-
let mut c =
915-
best_compilations(policy_cache, &subs[0].1, lw * sat_prob, dissat_prob)?;
922+
let mut c = best_compilations(
923+
policy_cache,
924+
subs[0].1.as_ref(),
925+
lw * sat_prob,
926+
dissat_prob,
927+
)?;
916928

917929
compile_tern!(&mut a1, &mut b2, &mut c, [rw, lw]);
918930
compile_tern!(&mut b1, &mut a2, &mut c, [rw, lw]);
@@ -931,12 +943,22 @@ where
931943
let mut r_comp = vec![];
932944

933945
for dissat_prob in dissat_probs(rw).iter() {
934-
let l = best_compilations(policy_cache, &subs[0].1, lw * sat_prob, *dissat_prob)?;
946+
let l = best_compilations(
947+
policy_cache,
948+
subs[0].1.as_ref(),
949+
lw * sat_prob,
950+
*dissat_prob,
951+
)?;
935952
l_comp.push(l);
936953
}
937954

938955
for dissat_prob in dissat_probs(lw).iter() {
939-
let r = best_compilations(policy_cache, &subs[1].1, rw * sat_prob, *dissat_prob)?;
956+
let r = best_compilations(
957+
policy_cache,
958+
subs[1].1.as_ref(),
959+
rw * sat_prob,
960+
*dissat_prob,
961+
)?;
940962
r_comp.push(r);
941963
}
942964

@@ -971,8 +993,8 @@ where
971993
let sp = sat_prob * k_over_n;
972994
//Expressions must be dissatisfiable
973995
let dp = Some(dissat_prob.unwrap_or(0 as f64) + (1.0 - k_over_n) * sat_prob);
974-
let be = best(types::Base::B, policy_cache, ast, sp, dp)?;
975-
let bw = best(types::Base::W, policy_cache, ast, sp, dp)?;
996+
let be = best(types::Base::B, policy_cache, ast.as_ref(), sp, dp)?;
997+
let bw = best(types::Base::W, policy_cache, ast.as_ref(), sp, dp)?;
976998

977999
let diff = be.cost_1d(sp, dp) - bw.cost_1d(sp, dp);
9781000
best_es.push((be.comp_ext_data, be));
@@ -1005,7 +1027,7 @@ where
10051027
let key_vec: Vec<Pk> = subs
10061028
.iter()
10071029
.filter_map(|s| {
1008-
if let Concrete::Key(ref pk) = *s {
1030+
if let Concrete::Key(ref pk) = s.as_ref() {
10091031
Some(pk.clone())
10101032
} else {
10111033
None
@@ -1025,9 +1047,11 @@ where
10251047
_ if k == subs.len() => {
10261048
let mut it = subs.iter();
10271049
let mut policy = it.next().expect("No sub policy in thresh() ?").clone();
1028-
policy = it.fold(policy, |acc, pol| Concrete::And(vec![acc, pol.clone()]));
1050+
policy = it.fold(policy, |acc, pol| {
1051+
Concrete::And(vec![acc, pol.clone()]).into()
1052+
});
10291053

1030-
ret = best_compilations(policy_cache, &policy, sat_prob, dissat_prob)?;
1054+
ret = best_compilations(policy_cache, policy.as_ref(), sat_prob, dissat_prob)?;
10311055
}
10321056
_ => {}
10331057
}
@@ -1239,8 +1263,11 @@ mod tests {
12391263
fn compile_timelocks() {
12401264
// artificially create a policy that is problematic and try to compile
12411265
let pol: SPolicy = Concrete::And(vec![
1242-
Concrete::Key("A".to_string()),
1243-
Concrete::And(vec![Concrete::after(9), Concrete::after(1000_000_000)]),
1266+
Arc::new(Concrete::Key("A".to_string())),
1267+
Arc::new(Concrete::And(vec![
1268+
Arc::new(Concrete::after(9)),
1269+
Arc::new(Concrete::after(1000_000_000)),
1270+
])),
12441271
]);
12451272
assert!(pol.compile::<Segwitv0>().is_err());
12461273

@@ -1346,13 +1373,22 @@ mod tests {
13461373

13471374
// Liquid policy
13481375
let policy: BPolicy = Concrete::Or(vec![
1349-
(127, Concrete::Threshold(3, key_pol[0..5].to_owned())),
1376+
(
1377+
127,
1378+
Arc::new(Concrete::Threshold(
1379+
3,
1380+
key_pol[0..5].iter().map(|p| (p.clone()).into()).collect(),
1381+
)),
1382+
),
13501383
(
13511384
1,
1352-
Concrete::And(vec![
1353-
Concrete::Older(Sequence::from_height(10000)),
1354-
Concrete::Threshold(2, key_pol[5..8].to_owned()),
1355-
]),
1385+
Arc::new(Concrete::And(vec![
1386+
Arc::new(Concrete::Older(Sequence::from_height(10000))),
1387+
Arc::new(Concrete::Threshold(
1388+
2,
1389+
key_pol[5..8].iter().map(|p| (p.clone()).into()).collect(),
1390+
)),
1391+
])),
13561392
),
13571393
]);
13581394

@@ -1471,8 +1507,10 @@ mod tests {
14711507
// and to a ms thresh otherwise.
14721508
// k = 1 (or 2) does not compile, see https://github.com/rust-bitcoin/rust-miniscript/issues/114
14731509
for k in &[10, 15, 21] {
1474-
let pubkeys: Vec<Concrete<bitcoin::PublicKey>> =
1475-
keys.iter().map(|pubkey| Concrete::Key(*pubkey)).collect();
1510+
let pubkeys: Vec<Arc<Concrete<bitcoin::PublicKey>>> = keys
1511+
.iter()
1512+
.map(|pubkey| Arc::new(Concrete::Key(*pubkey)))
1513+
.collect();
14761514
let big_thresh = Concrete::Threshold(*k, pubkeys);
14771515
let big_thresh_ms: SegwitMiniScript = big_thresh.compile().unwrap();
14781516
if *k == 21 {
@@ -1499,18 +1537,18 @@ mod tests {
14991537
// or(thresh(52, [pubkey; 52]), thresh(52, [pubkey; 52])) results in a 3642-bytes long
15001538
// witness script with only 54 stack elements
15011539
let (keys, _) = pubkeys_and_a_sig(104);
1502-
let keys_a: Vec<Concrete<bitcoin::PublicKey>> = keys[..keys.len() / 2]
1540+
let keys_a: Vec<Arc<Concrete<bitcoin::PublicKey>>> = keys[..keys.len() / 2]
15031541
.iter()
1504-
.map(|pubkey| Concrete::Key(*pubkey))
1542+
.map(|pubkey| Arc::new(Concrete::Key(*pubkey)))
15051543
.collect();
1506-
let keys_b: Vec<Concrete<bitcoin::PublicKey>> = keys[keys.len() / 2..]
1544+
let keys_b: Vec<Arc<Concrete<bitcoin::PublicKey>>> = keys[keys.len() / 2..]
15071545
.iter()
1508-
.map(|pubkey| Concrete::Key(*pubkey))
1546+
.map(|pubkey| Arc::new(Concrete::Key(*pubkey)))
15091547
.collect();
15101548

15111549
let thresh_res: Result<SegwitMiniScript, _> = Concrete::Or(vec![
1512-
(1, Concrete::Threshold(keys_a.len(), keys_a)),
1513-
(1, Concrete::Threshold(keys_b.len(), keys_b)),
1550+
(1, Arc::new(Concrete::Threshold(keys_a.len(), keys_a))),
1551+
(1, Arc::new(Concrete::Threshold(keys_b.len(), keys_b))),
15141552
])
15151553
.compile();
15161554
let script_size = thresh_res.clone().and_then(|m| Ok(m.script_size()));
@@ -1523,8 +1561,10 @@ mod tests {
15231561

15241562
// Hit the maximum witness stack elements limit
15251563
let (keys, _) = pubkeys_and_a_sig(100);
1526-
let keys: Vec<Concrete<bitcoin::PublicKey>> =
1527-
keys.iter().map(|pubkey| Concrete::Key(*pubkey)).collect();
1564+
let keys: Vec<Arc<Concrete<bitcoin::PublicKey>>> = keys
1565+
.iter()
1566+
.map(|pubkey| Arc::new(Concrete::Key(*pubkey)))
1567+
.collect();
15281568
let thresh_res: Result<SegwitMiniScript, _> =
15291569
Concrete::Threshold(keys.len(), keys).compile();
15301570
let n_elements = thresh_res
@@ -1542,8 +1582,10 @@ mod tests {
15421582
fn shared_limits() {
15431583
// Test the maximum number of OPs with a 67-of-68 multisig
15441584
let (keys, _) = pubkeys_and_a_sig(68);
1545-
let keys: Vec<Concrete<bitcoin::PublicKey>> =
1546-
keys.iter().map(|pubkey| Concrete::Key(*pubkey)).collect();
1585+
let keys: Vec<Arc<Concrete<bitcoin::PublicKey>>> = keys
1586+
.iter()
1587+
.map(|pubkey| Arc::new(Concrete::Key(*pubkey)))
1588+
.collect();
15471589
let thresh_res: Result<SegwitMiniScript, _> =
15481590
Concrete::Threshold(keys.len() - 1, keys).compile();
15491591
let ops_count = thresh_res.clone().and_then(|m| Ok(m.ext.ops.op_count()));
@@ -1555,8 +1597,10 @@ mod tests {
15551597
);
15561598
// For legacy too..
15571599
let (keys, _) = pubkeys_and_a_sig(68);
1558-
let keys: Vec<Concrete<bitcoin::PublicKey>> =
1559-
keys.iter().map(|pubkey| Concrete::Key(*pubkey)).collect();
1600+
let keys: Vec<Arc<Concrete<bitcoin::PublicKey>>> = keys
1601+
.iter()
1602+
.map(|pubkey| Arc::new(Concrete::Key(*pubkey)))
1603+
.collect();
15601604
let thresh_res = Concrete::Threshold(keys.len() - 1, keys).compile::<Legacy>();
15611605
let ops_count = thresh_res.clone().and_then(|m| Ok(m.ext.ops.op_count()));
15621606
assert_eq!(
@@ -1568,8 +1612,9 @@ mod tests {
15681612

15691613
// Test that we refuse to compile policies with duplicated keys
15701614
let (keys, _) = pubkeys_and_a_sig(1);
1571-
let key = Concrete::Key(keys[0]);
1572-
let res = Concrete::Or(vec![(1, key.clone()), (1, key.clone())]).compile::<Segwitv0>();
1615+
let key = Arc::new(Concrete::Key(keys[0]));
1616+
let res =
1617+
Concrete::Or(vec![(1, Arc::clone(&key)), (1, Arc::clone(&key))]).compile::<Segwitv0>();
15731618
assert_eq!(
15741619
res,
15751620
Err(CompilerError::PolicyError(

0 commit comments

Comments
 (0)