use std::convert::TryFrom;
use std::sync::Arc;
use std::{fmt, iter, mem};
use crate::jet::Elements;
use crate::node::{
ConstructNode, CoreConstructible, JetConstructible, NoWitness, WitnessConstructible,
};
use crate::policy::serialize::{self, AssemblyConstructible};
use crate::{Cmr, CommitNode, FailEntropy};
use crate::{SimplicityKey, ToXOnlyPubkey, Translator};
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Policy<Pk: SimplicityKey> {
Unsatisfiable(FailEntropy),
Trivial,
Key(Pk),
After(u32),
Older(u16),
Sha256(Pk::Sha256),
And {
left: Arc<Policy<Pk>>,
right: Arc<Policy<Pk>>,
},
Or {
left: Arc<Policy<Pk>>,
right: Arc<Policy<Pk>>,
},
Threshold(usize, Vec<Policy<Pk>>),
Assembly(Cmr),
}
impl<Pk: ToXOnlyPubkey> Policy<Pk> {
fn serialize_no_witness<N>(&self) -> Option<N>
where
N: CoreConstructible
+ JetConstructible<Elements>
+ WitnessConstructible<NoWitness>
+ AssemblyConstructible,
{
match *self {
Policy::Unsatisfiable(entropy) => Some(serialize::unsatisfiable(entropy)),
Policy::Trivial => Some(serialize::trivial()),
Policy::After(n) => Some(serialize::after(n)),
Policy::Older(n) => Some(serialize::older(n)),
Policy::Key(ref key) => Some(serialize::key(key, NoWitness)),
Policy::Sha256(ref hash) => Some(serialize::sha256::<Pk, _, _>(hash, NoWitness)),
Policy::And {
ref left,
ref right,
} => {
let left = left.serialize_no_witness()?;
let right = right.serialize_no_witness()?;
Some(serialize::and(&left, &right))
}
Policy::Or {
ref left,
ref right,
} => {
let left = left.serialize_no_witness()?;
let right = right.serialize_no_witness()?;
Some(serialize::or(&left, &right, NoWitness))
}
Policy::Threshold(k, ref subs) => {
let k = u32::try_from(k).expect("can have k at most 2^32 in a threshold");
let subs = subs
.iter()
.map(Self::serialize_no_witness)
.collect::<Option<Vec<N>>>()?;
let wits = iter::repeat(NoWitness)
.take(subs.len())
.collect::<Vec<NoWitness>>();
Some(serialize::threshold(k, &subs, &wits))
}
Policy::Assembly(cmr) => N::assembly(cmr),
}
}
pub fn commit(&self) -> Option<Arc<CommitNode<Elements>>> {
let construct: Arc<ConstructNode<Elements>> = self.serialize_no_witness()?;
let commit = construct.finalize_types().expect("policy has sound types");
Some(commit)
}
pub fn cmr(&self) -> Cmr {
self.serialize_no_witness()
.expect("CMR is defined for asm fragment")
}
}
impl<Pk: SimplicityKey> Policy<Pk> {
pub fn translate<T, Q, E>(&self, translator: &mut T) -> Result<Policy<Q>, E>
where
T: Translator<Pk, Q, E>,
Q: SimplicityKey,
{
match *self {
Policy::Unsatisfiable(entropy) => Ok(Policy::Unsatisfiable(entropy)),
Policy::Trivial => Ok(Policy::Trivial),
Policy::Key(ref pk) => translator.pk(pk).map(Policy::Key),
Policy::Sha256(ref h) => translator.sha256(h).map(Policy::Sha256),
Policy::After(n) => Ok(Policy::After(n)),
Policy::Older(n) => Ok(Policy::Older(n)),
Policy::Threshold(k, ref subs) => {
let new_subs: Result<Vec<Policy<Q>>, _> =
subs.iter().map(|sub| sub.translate(translator)).collect();
new_subs.map(|ok| Policy::Threshold(k, ok))
}
Policy::And {
ref left,
ref right,
} => Ok(Policy::And {
left: Arc::new(left.translate(translator)?),
right: Arc::new(right.translate(translator)?),
}),
Policy::Or {
ref left,
ref right,
} => Ok(Policy::Or {
left: Arc::new(left.translate(translator)?),
right: Arc::new(right.translate(translator)?),
}),
Policy::Assembly(cmr) => Ok(Policy::Assembly(cmr)),
}
}
pub fn normalized(self) -> Policy<Pk> {
match self {
Policy::And { left, right } => {
if let Policy::Unsatisfiable(entropy) = *left {
Policy::Unsatisfiable(entropy)
} else if let Policy::Unsatisfiable(entropy) = *right {
Policy::Unsatisfiable(entropy)
} else if *left == Policy::Trivial {
right.as_ref().clone().normalized()
} else if *right == Policy::Trivial {
left.as_ref().clone().normalized()
} else {
Policy::And {
left: Arc::new(left.as_ref().clone().normalized()),
right: Arc::new(right.as_ref().clone().normalized()),
}
}
}
Policy::Or { left, right } => {
if *left == Policy::Trivial || *right == Policy::Trivial {
Policy::Trivial
} else if let Policy::Unsatisfiable(..) = *left {
right.as_ref().clone().normalized()
} else if let Policy::Unsatisfiable(..) = *right {
left.as_ref().clone().normalized()
} else {
Policy::Or {
left: Arc::new(left.as_ref().clone().normalized()),
right: Arc::new(right.as_ref().clone().normalized()),
}
}
}
x => x,
}
}
pub fn sorted(mut self) -> Policy<Pk> {
self.sort();
self
}
fn sort(&mut self) {
match self {
Policy::And {
ref mut left,
ref mut right,
}
| Policy::Or {
ref mut left,
ref mut right,
} => {
left.as_ref().clone().sort();
right.as_ref().clone().sort();
if right > left {
mem::swap(left, right);
}
}
Policy::Threshold(_, ref mut subs) => {
for sub in &mut *subs {
sub.sort();
}
subs.sort();
}
_ => {}
}
}
pub fn iter(&self) -> PolicyIter<'_, Pk> {
PolicyIter::new(self)
}
pub fn iter_pk(&self) -> impl Iterator<Item = Pk> + '_ {
self.iter().filter_map(|fragment| match fragment {
Policy::Key(key) => Some(key.clone()),
_ => None,
})
}
}
impl<Pk: SimplicityKey> fmt::Debug for Policy<Pk> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Policy::Unsatisfiable(..) => f.write_str("UNSATISFIABLE"),
Policy::Trivial => f.write_str("TRIVIAL"),
Policy::Key(pk) => write!(f, "pk({})", pk),
Policy::After(n) => write!(f, "after({})", n),
Policy::Older(n) => write!(f, "older({})", n),
Policy::Sha256(h) => write!(f, "sha256({})", h),
Policy::And { left, right } => write!(f, "and({},{})", left, right),
Policy::Or { left, right } => write!(f, "or({},{})", left, right),
Policy::Threshold(k, sub_policies) => {
write!(f, "thresh({}", k)?;
for sub in sub_policies {
write!(f, ",{:?}", sub)?;
}
f.write_str(")")
}
Policy::Assembly(cmr) => write!(f, "asm({})", cmr),
}
}
}
impl<Pk: SimplicityKey> fmt::Display for Policy<Pk> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
pub struct PolicyIter<'a, Pk: SimplicityKey> {
stack: Vec<&'a Policy<Pk>>,
}
impl<'a, Pk: SimplicityKey> PolicyIter<'a, Pk> {
pub fn new(policy: &'a Policy<Pk>) -> Self {
Self {
stack: vec![policy],
}
}
}
impl<'a, Pk: SimplicityKey> Iterator for PolicyIter<'a, Pk> {
type Item = &'a Policy<Pk>;
fn next(&mut self) -> Option<Self::Item> {
let top = self.stack.pop()?;
match top {
Policy::And { left, right } | Policy::Or { left, right } => {
self.stack.push(right);
self.stack.push(left);
}
Policy::Threshold(_, children) => {
self.stack.extend(children.iter().rev());
}
_ => {}
}
Some(top)
}
}