Skip to content

Commit 4d23b79

Browse files
committed
Pretty print a policy
1 parent ebed2f9 commit 4d23b79

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

src/policy/semantic.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,52 @@ pub enum Policy<Pk: MiniscriptKey> {
5757
Threshold(usize, Vec<Policy<Pk>>),
5858
}
5959

60+
/// Compute the Policy difference between two policies.
61+
/// This is useful when trying to find out the conditions
62+
/// under which the two policies are different.
63+
#[derive(Debug, Clone)]
64+
pub struct PolicyDiff<Pk: MiniscriptKey> {
65+
/// The first policy
66+
pub a: Vec<Policy<Pk>>,
67+
/// The second policy
68+
pub b: Vec<Policy<Pk>>,
69+
}
70+
71+
impl<Pk: MiniscriptKey> PolicyDiff<Pk> {
72+
/// Combine two policy differences.
73+
// Policies should not generally contain repeated conditions,
74+
// therefore we do not many attempt to deal with those.
75+
pub fn combine(&mut self, second: Self) {
76+
self.a.extend(second.a);
77+
self.b.extend(second.b);
78+
}
79+
80+
// create a new diff directly without removing
81+
// same policies.
82+
fn _new(a: Vec<Policy<Pk>>, b: Vec<Policy<Pk>>) -> Self {
83+
Self { a, b }
84+
}
85+
86+
/// Create a new PolicyDiff in the
87+
pub fn new(a: Policy<Pk>, b: Policy<Pk>) -> Self {
88+
match (a.normalized(), b.normalized()) {
89+
(x, y) if x == y => Self::_new(vec![], vec![]),
90+
(Policy::Threshold(k1, subs1), Policy::Threshold(k2, subs2))
91+
if k1 == k2 && subs1.len() == subs2.len() =>
92+
{
93+
let mut a = Self::_new(vec![], vec![]);
94+
95+
for (sub_a, sub_b) in subs1.into_iter().zip(subs2.into_iter()) {
96+
let sub_diff = Self::_new(vec![sub_a], vec![sub_b]);
97+
a.combine(sub_diff);
98+
}
99+
a
100+
}
101+
(x, y) => Self::_new(vec![x], vec![y]),
102+
}
103+
}
104+
}
105+
60106
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Policy<Pk> {
61107
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool
62108
where
@@ -78,6 +124,42 @@ impl<Pk: MiniscriptKey> ForEachKey<Pk> for Policy<Pk> {
78124
}
79125

80126
impl<Pk: MiniscriptKey> Policy<Pk> {
127+
fn term_name(&self) -> String {
128+
match *self {
129+
Policy::Threshold(k, ref subs) => {
130+
if k == subs.len() {
131+
String::from(format!("and({},{})", k, subs.len()))
132+
} else if k == 1 {
133+
String::from(format!("or({},{})", k, subs.len()))
134+
} else {
135+
String::from(format!("thresh({},{})", k, subs.len()))
136+
}
137+
}
138+
_ => self.to_string(),
139+
}
140+
}
141+
142+
fn _pprint_tree(&self, prefix: String, last: bool) {
143+
let prefix_current = if last { "`-- " } else { "|-- " };
144+
145+
println!("{}{}{}", prefix, prefix_current, self.term_name());
146+
147+
let prefix_child = if last { " " } else { "| " };
148+
let prefix = prefix + prefix_child;
149+
150+
if let Policy::Threshold(_k, ref subs) = *self {
151+
let last_child = subs.len() - 1;
152+
153+
for (i, child) in subs.iter().enumerate() {
154+
child._pprint_tree(prefix.to_string(), i == last_child);
155+
}
156+
}
157+
}
158+
159+
/// Pretty Print a tree
160+
pub fn pprint_tree(&self) {
161+
self._pprint_tree("".to_string(), true);
162+
}
81163
/// Convert a policy using one kind of public key to another
82164
/// type of public key
83165
pub fn translate_pkh<Fpkh, Q, E>(&self, mut translatefpkh: Fpkh) -> Result<Policy<Q>, E>
@@ -641,6 +723,8 @@ mod tests {
641723
// Very bad idea to add master key,pk but let's have it have 50M blocks
642724
let master_key = StringPolicy::from_str("and(older(50000000),pkh(master))").unwrap();
643725
let new_liquid_pol = Policy::Threshold(1, vec![liquid_pol.clone(), master_key]);
726+
// Pretty print a policy
727+
// liquid_pol.pprint_tree();
644728

645729
assert!(liquid_pol.clone().entails(new_liquid_pol.clone()).unwrap());
646730
assert!(!new_liquid_pol.entails(liquid_pol.clone()).unwrap());

0 commit comments

Comments
 (0)