diff --git a/src/policy/mod.rs b/src/policy/mod.rs index be3c69497..2f0f17f1b 100644 --- a/src/policy/mod.rs +++ b/src/policy/mod.rs @@ -409,5 +409,77 @@ mod tests { "Policy contains duplicate keys" ); } + + // Non-trivial multi-node compilation + { + let node_policies = [ + "and(pk(A),pk(B))", + "and(pk(C),older(12960))", + "pk(D)", + "pk(E)", + "thresh(3,pk(F),pk(G),pk(H))", + "and(and(or(2@pk(I),1@pk(J)),or(1@pk(K),20@pk(L))),pk(M))", + "pk(N)", + ]; + + // Floating-point precision errors cause the minor errors + let node_probabilities: [f64; 7] = + [0.12000002, 0.28, 0.08, 0.12, 0.19, 0.18999998, 0.02]; + + let policy: Concrete = policy_str!( + "{}", + &format!( + "or(4@or(3@{},7@{}),6@thresh(1,or(4@{},6@{}),{},or(9@{},1@{})))", + node_policies[0], + node_policies[1], + node_policies[2], + node_policies[3], + node_policies[4], + node_policies[5], + node_policies[6] + ) + ); + let descriptor = policy.compile_tr(Some(unspendable_key.clone())).unwrap(); + + let mut sorted_policy_prob = node_policies + .into_iter() + .zip(node_probabilities.into_iter()) + .collect::>(); + sorted_policy_prob.sort_by(|a, b| (a.1).partial_cmp(&b.1).unwrap()); + let sorted_policies = sorted_policy_prob + .into_iter() + .map(|(x, _prob)| x) + .collect::>(); + + // Generate TapTree leaves compilations from the given sub-policies + let node_compilations = sorted_policies + .into_iter() + .map(|x| { + let leaf_policy: Concrete = policy_str!("{}", x); + TapTree::Leaf(Arc::from(leaf_policy.compile::().unwrap())) + }) + .collect::>(); + + // Arrange leaf compilations (acc. to probabilities) using huffman encoding into a TapTree + let tree = TapTree::Tree( + Arc::from(TapTree::Tree( + Arc::from(node_compilations[4].clone()), + Arc::from(node_compilations[5].clone()), + )), + Arc::from(TapTree::Tree( + Arc::from(TapTree::Tree( + Arc::from(TapTree::Tree( + Arc::from(node_compilations[0].clone()), + Arc::from(node_compilations[1].clone()), + )), + Arc::from(node_compilations[3].clone()), + )), + Arc::from(node_compilations[6].clone()), + )), + ); + + let expected_descriptor = Descriptor::new_tr("E".to_string(), Some(tree)).unwrap(); + assert_eq!(descriptor, expected_descriptor); + } } }