Refactor frontend/middleware types (#194)
* unify fe/be NativeOp and NativePred * remove Origin in favour of PodId * Combine string and hash in Key * use middleware::AnchoredKey in frontend * merge frontend/middleware types * refactor custom predicates * clean up a bit * fix middleware custom tests * clean up * clean up 2 * add acronyms in typos list
This commit is contained in:
parent
9e860ef262
commit
c232c8dae5
33 changed files with 1985 additions and 2800 deletions
|
|
@ -1,101 +1,85 @@
|
|||
use std::{collections::HashMap, fmt, hash as h, iter, iter::zip, sync::Arc};
|
||||
use std::{fmt, iter, sync::Arc};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use plonky2::field::types::Field;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// use schemars::JsonSchema;
|
||||
|
||||
// use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
backends::plonky2::basetypes::HASH_SIZE,
|
||||
middleware::{
|
||||
hash_fields, AnchoredKey, Hash, NativePredicate, Params, PodId, Statement, StatementArg,
|
||||
ToFields, Value, F,
|
||||
},
|
||||
util::hashmap_insert_no_dupe,
|
||||
middleware::HASH_SIZE,
|
||||
middleware::{hash_fields, Hash, Key, NativePredicate, Params, ToFields, Value, F},
|
||||
};
|
||||
|
||||
// BEGIN Custom 1b
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, h::Hash, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum HashOrWildcard {
|
||||
Hash(Hash),
|
||||
Wildcard(usize),
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Wildcard {
|
||||
pub name: String,
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
impl HashOrWildcard {
|
||||
/// Matches a hash or wildcard against a value, returning a pair
|
||||
/// representing a wildcard binding (if any) or an error if no
|
||||
/// match is possible.
|
||||
pub fn match_against(&self, v: &Value) -> Result<Option<(usize, Value)>> {
|
||||
match self {
|
||||
HashOrWildcard::Hash(h) if &Value::from(*h) == v => Ok(None),
|
||||
HashOrWildcard::Wildcard(i) => Ok(Some((*i, *v))),
|
||||
_ => Err(anyhow!(
|
||||
"Failed to match hash or wildcard {} against value {}.",
|
||||
self,
|
||||
v
|
||||
)),
|
||||
}
|
||||
impl Wildcard {
|
||||
pub fn new(name: String, index: usize) -> Self {
|
||||
Self { name, index }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for HashOrWildcard {
|
||||
impl fmt::Display for Wildcard {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "*{}[{}]", self.index, self.name)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToFields for Wildcard {
|
||||
fn to_fields(&self, _params: &Params) -> Vec<F> {
|
||||
vec![F::from_canonical_u64(self.index as u64)]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum KeyOrWildcard {
|
||||
Key(Key),
|
||||
Wildcard(Wildcard),
|
||||
}
|
||||
|
||||
impl fmt::Display for KeyOrWildcard {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Hash(h) => write!(f, "{}", h),
|
||||
Self::Wildcard(n) => write!(f, "*{}", n),
|
||||
Self::Key(k) => write!(f, "{}", k),
|
||||
Self::Wildcard(wc) => write!(f, "{}", wc),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToFields for HashOrWildcard {
|
||||
impl ToFields for KeyOrWildcard {
|
||||
fn to_fields(&self, params: &Params) -> Vec<F> {
|
||||
match self {
|
||||
HashOrWildcard::Hash(h) => h.to_fields(params),
|
||||
HashOrWildcard::Wildcard(w) => (0..HASH_SIZE - 1)
|
||||
.chain(iter::once(*w))
|
||||
.map(|x| F::from_canonical_u64(x as u64))
|
||||
KeyOrWildcard::Key(k) => k.hash().to_fields(params),
|
||||
KeyOrWildcard::Wildcard(wc) => iter::once(F::ZERO)
|
||||
.take(HASH_SIZE - 1)
|
||||
.chain(iter::once(F::from_canonical_u64(wc.index as u64)))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, h::Hash, Serialize, Deserialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum StatementTmplArg {
|
||||
None,
|
||||
Literal(Value),
|
||||
Key(HashOrWildcard, HashOrWildcard),
|
||||
}
|
||||
|
||||
impl StatementTmplArg {
|
||||
/// Matches a statement template argument against a statement
|
||||
/// argument, returning a wildcard correspondence in the case of
|
||||
/// one or more wildcard matches, nothing in the case of a
|
||||
/// literal/hash match, and an error otherwise.
|
||||
pub fn match_against(&self, s_arg: &StatementArg) -> Result<Vec<(usize, Value)>> {
|
||||
match (self, s_arg) {
|
||||
(Self::None, StatementArg::None) => Ok(vec![]),
|
||||
(Self::Literal(v), StatementArg::Literal(w)) if v == w => Ok(vec![]),
|
||||
(Self::Key(tmpl_o, tmpl_k), StatementArg::Key(AnchoredKey(PodId(o), k))) => {
|
||||
let o_corr = tmpl_o.match_against(&(*o).into())?;
|
||||
let k_corr = tmpl_k.match_against(&(*k).into())?;
|
||||
Ok([o_corr, k_corr].into_iter().flatten().collect())
|
||||
}
|
||||
_ => Err(anyhow!(
|
||||
"Failed to match statement template argument {:?} against statement argument {:?}.",
|
||||
self,
|
||||
s_arg
|
||||
)),
|
||||
}
|
||||
}
|
||||
// AnchoredKey
|
||||
Key(Wildcard, KeyOrWildcard),
|
||||
// TODO: This naming is a bit confusing: a WildcardLiteral that contains a Wildcard...
|
||||
// Could we merge WildcardValue and Value and allow wildcard value apart from pod_id and key?
|
||||
WildcardLiteral(Wildcard),
|
||||
}
|
||||
|
||||
impl ToFields for StatementTmplArg {
|
||||
fn to_fields(&self, params: &Params) -> Vec<F> {
|
||||
// None => (0, ...)
|
||||
// Literal(value) => (1, [value], 0, 0, 0, 0)
|
||||
// Key(hash_or_wildcard1, hash_or_wildcard2)
|
||||
// => (2, [hash_or_wildcard1], [hash_or_wildcard2])
|
||||
// Key(wildcard1, key_or_wildcard2)
|
||||
// => (2, [wildcard1], [key_or_wildcard2])
|
||||
// WildcardLiteral(wildcard) => (3, [wildcard], 0, 0, 0, 0)
|
||||
// In all three cases, we pad to 2 * hash_size + 1 = 9 field elements
|
||||
let statement_tmpl_arg_size = 2 * HASH_SIZE + 1;
|
||||
match self {
|
||||
|
|
@ -107,15 +91,22 @@ impl ToFields for StatementTmplArg {
|
|||
}
|
||||
StatementTmplArg::Literal(v) => {
|
||||
let fields: Vec<F> = iter::once(F::from_canonical_u64(1))
|
||||
.chain(v.to_fields(params))
|
||||
.chain(v.raw().to_fields(params))
|
||||
.chain(iter::repeat_with(|| F::from_canonical_u64(0)).take(HASH_SIZE))
|
||||
.collect();
|
||||
fields
|
||||
}
|
||||
StatementTmplArg::Key(hw1, hw2) => {
|
||||
StatementTmplArg::Key(wc1, kw2) => {
|
||||
let fields: Vec<F> = iter::once(F::from_canonical_u64(2))
|
||||
.chain(hw1.to_fields(params))
|
||||
.chain(hw2.to_fields(params))
|
||||
.chain(wc1.to_fields(params))
|
||||
.chain(kw2.to_fields(params))
|
||||
.collect();
|
||||
fields
|
||||
}
|
||||
StatementTmplArg::WildcardLiteral(wc) => {
|
||||
let fields: Vec<F> = iter::once(F::from_canonical_u64(3))
|
||||
.chain(wc.to_fields(params))
|
||||
.chain(iter::repeat_with(|| F::from_canonical_u64(0)).take(HASH_SIZE))
|
||||
.collect();
|
||||
fields
|
||||
}
|
||||
|
|
@ -129,50 +120,37 @@ impl fmt::Display for StatementTmplArg {
|
|||
Self::None => write!(f, "none"),
|
||||
Self::Literal(v) => write!(f, "{}", v),
|
||||
Self::Key(pod_id, key) => write!(f, "({}, {})", pod_id, key),
|
||||
Self::WildcardLiteral(v) => write!(f, "{}", v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// END
|
||||
|
||||
// BEGIN Custom 2
|
||||
|
||||
// pub enum StatementTmplArg {
|
||||
// None,
|
||||
// Literal(Value),
|
||||
// Wildcard(usize),
|
||||
// }
|
||||
|
||||
// END
|
||||
|
||||
/// Statement Template for a Custom Predicate
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct StatementTmpl(pub Predicate, pub Vec<StatementTmplArg>);
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct StatementTmpl {
|
||||
pub pred: Predicate,
|
||||
pub args: Vec<StatementTmplArg>,
|
||||
}
|
||||
|
||||
impl StatementTmpl {
|
||||
pub fn pred(&self) -> &Predicate {
|
||||
&self.0
|
||||
&self.pred
|
||||
}
|
||||
pub fn args(&self) -> &[StatementTmplArg] {
|
||||
&self.1
|
||||
&self.args
|
||||
}
|
||||
/// Matches a statement template against a statement, returning
|
||||
/// the variable bindings as an association list. Returns an error
|
||||
/// if there is type or argument mismatch.
|
||||
pub fn match_against(&self, s: &Statement) -> Result<Vec<(usize, Value)>> {
|
||||
type P = Predicate;
|
||||
if matches!(self, Self(P::BatchSelf(_), _)) {
|
||||
Err(anyhow!(
|
||||
"Cannot check self-referencing statement templates."
|
||||
))
|
||||
} else if self.pred() != &s.predicate() {
|
||||
Err(anyhow!("Type mismatch between {:?} and {}.", self, s))
|
||||
} else {
|
||||
zip(self.args(), s.args())
|
||||
.map(|(t_arg, s_arg)| t_arg.match_against(&s_arg))
|
||||
.collect::<Result<Vec<_>>>()
|
||||
.map(|v| v.concat())
|
||||
}
|
||||
|
||||
impl fmt::Display for StatementTmpl {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}(", self.pred)?;
|
||||
for (i, arg) in self.args.iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "{}", arg)?;
|
||||
}
|
||||
writeln!(f)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -185,25 +163,26 @@ impl ToFields for StatementTmpl {
|
|||
// TODO think if this check should go into the StatementTmpl creation,
|
||||
// instead of at the `to_fields` method, where we should assume that the
|
||||
// values are already valid
|
||||
if self.1.len() > params.max_statement_args {
|
||||
if self.args.len() > params.max_statement_args {
|
||||
panic!("Statement template has too many arguments");
|
||||
}
|
||||
|
||||
let mut fields: Vec<F> = self
|
||||
.0
|
||||
.pred
|
||||
.to_fields(params)
|
||||
.into_iter()
|
||||
.chain(self.1.iter().flat_map(|sta| sta.to_fields(params)))
|
||||
.chain(self.args.iter().flat_map(|sta| sta.to_fields(params)))
|
||||
.collect();
|
||||
fields.resize_with(params.statement_tmpl_size(), || F::from_canonical_u64(0));
|
||||
fields
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
/// NOTE: fields are not public (outside of crate) to enforce the struct instantiation through
|
||||
/// the `::and/or` methods, which performs checks on the values.
|
||||
pub struct CustomPredicate {
|
||||
pub name: String, // Non-cryptographic metadata
|
||||
/// true for "and", false for "or"
|
||||
pub(crate) conjunction: bool,
|
||||
pub(crate) statements: Vec<StatementTmpl>,
|
||||
|
|
@ -213,13 +192,24 @@ pub struct CustomPredicate {
|
|||
}
|
||||
|
||||
impl CustomPredicate {
|
||||
pub fn and(params: &Params, statements: Vec<StatementTmpl>, args_len: usize) -> Result<Self> {
|
||||
Self::new(params, true, statements, args_len)
|
||||
pub fn and(
|
||||
name: String,
|
||||
params: &Params,
|
||||
statements: Vec<StatementTmpl>,
|
||||
args_len: usize,
|
||||
) -> Result<Self> {
|
||||
Self::new(name, params, true, statements, args_len)
|
||||
}
|
||||
pub fn or(params: &Params, statements: Vec<StatementTmpl>, args_len: usize) -> Result<Self> {
|
||||
Self::new(params, false, statements, args_len)
|
||||
pub fn or(
|
||||
name: String,
|
||||
params: &Params,
|
||||
statements: Vec<StatementTmpl>,
|
||||
args_len: usize,
|
||||
) -> Result<Self> {
|
||||
Self::new(name, params, false, statements, args_len)
|
||||
}
|
||||
pub fn new(
|
||||
name: String,
|
||||
params: &Params,
|
||||
conjunction: bool,
|
||||
statements: Vec<StatementTmpl>,
|
||||
|
|
@ -230,6 +220,7 @@ impl CustomPredicate {
|
|||
}
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
conjunction,
|
||||
statements,
|
||||
args_len,
|
||||
|
|
@ -266,8 +257,8 @@ impl fmt::Display for CustomPredicate {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
writeln!(f, "{}<", if self.conjunction { "and" } else { "or" })?;
|
||||
for st in &self.statements {
|
||||
write!(f, " {}", st.0)?;
|
||||
for (i, arg) in st.1.iter().enumerate() {
|
||||
write!(f, " {}(", st.pred)?;
|
||||
for (i, arg) in st.args.iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
|
|
@ -287,7 +278,7 @@ impl fmt::Display for CustomPredicate {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct CustomPredicateBatch {
|
||||
pub name: String,
|
||||
pub predicates: Vec<CustomPredicate>,
|
||||
|
|
@ -324,67 +315,23 @@ impl CustomPredicateBatch {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct CustomPredicateRef(pub Arc<CustomPredicateBatch>, pub usize);
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct CustomPredicateRef {
|
||||
pub batch: Arc<CustomPredicateBatch>,
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
impl CustomPredicateRef {
|
||||
pub fn arg_len(&self) -> usize {
|
||||
self.0.predicates[self.1].args_len
|
||||
pub fn new(batch: Arc<CustomPredicateBatch>, index: usize) -> Self {
|
||||
Self { batch, index }
|
||||
}
|
||||
pub fn match_against(&self, statements: &[Statement]) -> Result<HashMap<usize, Value>> {
|
||||
let mut bindings = HashMap::new();
|
||||
// Single out custom predicate, replacing batch-self
|
||||
// references with custom predicate references.
|
||||
let custom_predicate = {
|
||||
let cp = &Arc::unwrap_or_clone(self.0.clone()).predicates[self.1];
|
||||
CustomPredicate {
|
||||
conjunction: cp.conjunction,
|
||||
statements: cp
|
||||
.statements
|
||||
.iter()
|
||||
.map(|StatementTmpl(p, args)| {
|
||||
StatementTmpl(
|
||||
match p {
|
||||
Predicate::BatchSelf(i) => {
|
||||
Predicate::Custom(CustomPredicateRef(self.0.clone(), *i))
|
||||
}
|
||||
_ => p.clone(),
|
||||
},
|
||||
args.to_vec(),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
args_len: cp.args_len,
|
||||
}
|
||||
};
|
||||
match custom_predicate.conjunction {
|
||||
true if custom_predicate.statements.len() == statements.len() => {
|
||||
// Match op args against statement templates
|
||||
let match_bindings = iter::zip(custom_predicate.statements, statements).map(
|
||||
|(s_tmpl, s)| s_tmpl.match_against(s)
|
||||
).collect::<Result<Vec<_>>>()
|
||||
.map(|v| v.concat())?;
|
||||
// Add bindings to binding table, throwing if there is an inconsistency.
|
||||
match_bindings.into_iter().try_for_each(|kv| hashmap_insert_no_dupe(&mut bindings, kv))?;
|
||||
Ok(bindings)
|
||||
},
|
||||
false if statements.len() == 1 => {
|
||||
// Match op arg against each statement template
|
||||
custom_predicate.statements.iter().map(
|
||||
|s_tmpl| {
|
||||
let mut bindings = bindings.clone();
|
||||
s_tmpl.match_against(&statements[0])?.into_iter().try_for_each(|kv| hashmap_insert_no_dupe(&mut bindings, kv))?;
|
||||
Ok::<_, anyhow::Error>(bindings)
|
||||
}
|
||||
).find(|m| m.is_ok()).unwrap_or(Err(anyhow!("Statement {} does not match disjunctive custom predicate {}.", &statements[0], custom_predicate)))
|
||||
},
|
||||
_ => Err(anyhow!("Custom predicate statement template list {:?} does not match op argument list {:?}.", custom_predicate.statements, statements))
|
||||
}
|
||||
pub fn arg_len(&self) -> usize {
|
||||
self.batch.predicates[self.index].args_len
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(tag = "type", content = "value")]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
// #[serde(tag = "type", content = "value")]
|
||||
pub enum Predicate {
|
||||
Native(NativePredicate),
|
||||
BatchSelf(usize),
|
||||
|
|
@ -414,10 +361,12 @@ impl ToFields for Predicate {
|
|||
Self::BatchSelf(i) => iter::once(F::from_canonical_u64(2))
|
||||
.chain(iter::once(F::from_canonical_usize(*i)))
|
||||
.collect(),
|
||||
Self::Custom(CustomPredicateRef(pb, i)) => iter::once(F::from_canonical_u64(3))
|
||||
.chain(pb.hash(params).0)
|
||||
.chain(iter::once(F::from_canonical_usize(*i)))
|
||||
.collect(),
|
||||
Self::Custom(CustomPredicateRef { batch, index }) => {
|
||||
iter::once(F::from_canonical_u64(3))
|
||||
.chain(batch.hash(params).0)
|
||||
.chain(iter::once(F::from_canonical_usize(*index)))
|
||||
.collect()
|
||||
}
|
||||
};
|
||||
fields.resize_with(Params::predicate_size(), || F::from_canonical_u64(0));
|
||||
fields
|
||||
|
|
@ -429,7 +378,13 @@ impl fmt::Display for Predicate {
|
|||
match self {
|
||||
Self::Native(p) => write!(f, "{:?}", p),
|
||||
Self::BatchSelf(i) => write!(f, "self.{}", i),
|
||||
Self::Custom(CustomPredicateRef(pb, i)) => write!(f, "{}.{}", pb.name, i),
|
||||
Self::Custom(CustomPredicateRef { batch, index }) => {
|
||||
write!(
|
||||
f,
|
||||
"{}.{}[{}]",
|
||||
batch.name, index, batch.predicates[*index].name
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -441,18 +396,29 @@ mod tests {
|
|||
use anyhow::Result;
|
||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||
|
||||
use super::*;
|
||||
use crate::middleware::{
|
||||
AnchoredKey, CustomPredicate, CustomPredicateBatch, CustomPredicateRef, Hash,
|
||||
HashOrWildcard, NativePredicate, Operation, Params, PodId, PodType, Predicate, Statement,
|
||||
StatementTmpl, StatementTmplArg, SELF,
|
||||
KeyOrWildcard, NativePredicate, Operation, Params, PodId, PodType, Predicate, Statement,
|
||||
StatementTmpl, StatementTmplArg, WildcardValue, SELF,
|
||||
};
|
||||
|
||||
fn st(p: Predicate, args: Vec<StatementTmplArg>) -> StatementTmpl {
|
||||
StatementTmpl(p, args)
|
||||
StatementTmpl { pred: p, args }
|
||||
}
|
||||
|
||||
fn kow_wc(i: usize) -> KOW {
|
||||
KOW::Wildcard(wc(i))
|
||||
}
|
||||
fn wc(i: usize) -> Wildcard {
|
||||
Wildcard {
|
||||
name: format!("{}", i),
|
||||
index: i,
|
||||
}
|
||||
}
|
||||
|
||||
type STA = StatementTmplArg;
|
||||
type HOW = HashOrWildcard;
|
||||
type KOW = KeyOrWildcard;
|
||||
type P = Predicate;
|
||||
type NP = NativePredicate;
|
||||
|
||||
|
|
@ -468,44 +434,42 @@ mod tests {
|
|||
let cust_pred_batch = Arc::new(CustomPredicateBatch {
|
||||
name: "is_double".to_string(),
|
||||
predicates: vec![CustomPredicate::and(
|
||||
"_".into(),
|
||||
¶ms,
|
||||
vec![
|
||||
st(
|
||||
P::Native(NP::ValueOf),
|
||||
vec![
|
||||
STA::Key(HOW::Wildcard(4), HOW::Wildcard(5)),
|
||||
STA::Literal(2.into()),
|
||||
],
|
||||
vec![STA::Key(wc(4), kow_wc(5)), STA::Literal(2.into())],
|
||||
),
|
||||
st(
|
||||
P::Native(NP::ProductOf),
|
||||
vec![
|
||||
STA::Key(HOW::Wildcard(0), HOW::Wildcard(1)),
|
||||
STA::Key(HOW::Wildcard(4), HOW::Wildcard(5)),
|
||||
STA::Key(HOW::Wildcard(2), HOW::Wildcard(3)),
|
||||
STA::Key(wc(0), kow_wc(1)),
|
||||
STA::Key(wc(4), kow_wc(5)),
|
||||
STA::Key(wc(2), kow_wc(3)),
|
||||
],
|
||||
),
|
||||
],
|
||||
4,
|
||||
2,
|
||||
)?],
|
||||
});
|
||||
|
||||
let custom_statement = Statement::Custom(
|
||||
CustomPredicateRef(cust_pred_batch.clone(), 0),
|
||||
CustomPredicateRef::new(cust_pred_batch.clone(), 0),
|
||||
vec![
|
||||
AnchoredKey(SELF, "Some value".into()),
|
||||
AnchoredKey(SELF, "Some other value".into()),
|
||||
WildcardValue::PodId(SELF),
|
||||
WildcardValue::Key(Key::from("Some value")),
|
||||
],
|
||||
);
|
||||
|
||||
let custom_deduction = Operation::Custom(
|
||||
CustomPredicateRef(cust_pred_batch, 0),
|
||||
CustomPredicateRef::new(cust_pred_batch, 0),
|
||||
vec![
|
||||
Statement::ValueOf(AnchoredKey(SELF, "Some constant".into()), 2.into()),
|
||||
Statement::ValueOf(AnchoredKey::from((SELF, "Some constant")), 2.into()),
|
||||
Statement::ProductOf(
|
||||
AnchoredKey(SELF, "Some value".into()),
|
||||
AnchoredKey(SELF, "Some constant".into()),
|
||||
AnchoredKey(SELF, "Some other value".into()),
|
||||
AnchoredKey::from((SELF, "Some value")),
|
||||
AnchoredKey::from((SELF, "Some constant")),
|
||||
AnchoredKey::from((SELF, "Some other value")),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
@ -517,30 +481,34 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn ethdos_test() -> Result<()> {
|
||||
let params = Params::default();
|
||||
let params = Params {
|
||||
max_custom_predicate_wildcards: 12,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let eth_friend_cp = CustomPredicate::and(
|
||||
"eth_friend_cp".into(),
|
||||
¶ms,
|
||||
vec![
|
||||
st(
|
||||
P::Native(NP::ValueOf),
|
||||
vec![
|
||||
STA::Key(HOW::Wildcard(4), HashOrWildcard::Hash("type".into())),
|
||||
STA::Key(wc(4), KeyOrWildcard::Key("type".into())),
|
||||
STA::Literal(PodType::Signed.into()),
|
||||
],
|
||||
),
|
||||
st(
|
||||
P::Native(NP::Equal),
|
||||
vec![
|
||||
STA::Key(HOW::Wildcard(4), HashOrWildcard::Hash("signer".into())),
|
||||
STA::Key(HOW::Wildcard(0), HOW::Wildcard(1)),
|
||||
STA::Key(wc(4), KeyOrWildcard::Key("signer".into())),
|
||||
STA::Key(wc(0), kow_wc(1)),
|
||||
],
|
||||
),
|
||||
st(
|
||||
P::Native(NP::Equal),
|
||||
vec![
|
||||
STA::Key(HOW::Wildcard(4), HashOrWildcard::Hash("attestation".into())),
|
||||
STA::Key(HOW::Wildcard(2), HOW::Wildcard(3)),
|
||||
STA::Key(wc(4), KeyOrWildcard::Key("attestation".into())),
|
||||
STA::Key(wc(2), kow_wc(3)),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
|
@ -552,81 +520,89 @@ mod tests {
|
|||
predicates: vec![eth_friend_cp],
|
||||
});
|
||||
|
||||
// 0
|
||||
let eth_dos_base = CustomPredicate::and(
|
||||
"eth_dos_base".into(),
|
||||
¶ms,
|
||||
vec![
|
||||
st(
|
||||
P::Native(NP::Equal),
|
||||
vec![
|
||||
STA::Key(HOW::Wildcard(0), HOW::Wildcard(1)),
|
||||
STA::Key(HOW::Wildcard(2), HOW::Wildcard(3)),
|
||||
],
|
||||
vec![STA::Key(wc(0), kow_wc(1)), STA::Key(wc(2), kow_wc(3))],
|
||||
),
|
||||
st(
|
||||
P::Native(NP::ValueOf),
|
||||
vec![
|
||||
STA::Key(HOW::Wildcard(4), HOW::Wildcard(5)),
|
||||
STA::Literal(0.into()),
|
||||
],
|
||||
vec![STA::Key(wc(4), kow_wc(5)), STA::Literal(0.into())],
|
||||
),
|
||||
],
|
||||
6,
|
||||
)?;
|
||||
|
||||
// 1
|
||||
let eth_dos_ind = CustomPredicate::and(
|
||||
"eth_dos_ind".into(),
|
||||
¶ms,
|
||||
vec![
|
||||
st(
|
||||
P::BatchSelf(2),
|
||||
vec![
|
||||
STA::Key(HOW::Wildcard(0), HOW::Wildcard(1)),
|
||||
STA::Key(HOW::Wildcard(10), HOW::Wildcard(11)),
|
||||
STA::Key(HOW::Wildcard(8), HOW::Wildcard(9)),
|
||||
STA::WildcardLiteral(wc(0)),
|
||||
STA::WildcardLiteral(wc(1)),
|
||||
STA::WildcardLiteral(wc(10)),
|
||||
STA::WildcardLiteral(wc(11)),
|
||||
STA::WildcardLiteral(wc(8)),
|
||||
STA::WildcardLiteral(wc(9)),
|
||||
],
|
||||
),
|
||||
st(
|
||||
P::Native(NP::ValueOf),
|
||||
vec![
|
||||
STA::Key(HOW::Wildcard(6), HOW::Wildcard(7)),
|
||||
STA::Literal(1.into()),
|
||||
],
|
||||
vec![STA::Key(wc(6), kow_wc(7)), STA::Literal(1.into())],
|
||||
),
|
||||
st(
|
||||
P::Native(NP::SumOf),
|
||||
vec![
|
||||
STA::Key(HOW::Wildcard(4), HOW::Wildcard(5)),
|
||||
STA::Key(HOW::Wildcard(8), HOW::Wildcard(9)),
|
||||
STA::Key(HOW::Wildcard(6), HOW::Wildcard(7)),
|
||||
STA::Key(wc(4), kow_wc(5)),
|
||||
STA::Key(wc(8), kow_wc(9)),
|
||||
STA::Key(wc(6), kow_wc(7)),
|
||||
],
|
||||
),
|
||||
st(
|
||||
P::Custom(CustomPredicateRef(eth_friend_batch.clone(), 0)),
|
||||
P::Custom(CustomPredicateRef::new(eth_friend_batch.clone(), 0)),
|
||||
vec![
|
||||
STA::Key(HOW::Wildcard(10), HOW::Wildcard(11)),
|
||||
STA::Key(HOW::Wildcard(2), HOW::Wildcard(3)),
|
||||
STA::WildcardLiteral(wc(10)),
|
||||
STA::WildcardLiteral(wc(11)),
|
||||
STA::WildcardLiteral(wc(2)),
|
||||
STA::WildcardLiteral(wc(3)),
|
||||
],
|
||||
),
|
||||
],
|
||||
6,
|
||||
)?;
|
||||
|
||||
// 2
|
||||
let eth_dos_distance_either = CustomPredicate::or(
|
||||
"eth_dos_distance_either".into(),
|
||||
¶ms,
|
||||
vec![
|
||||
st(
|
||||
P::BatchSelf(0),
|
||||
vec![
|
||||
STA::Key(HOW::Wildcard(0), HOW::Wildcard(1)),
|
||||
STA::Key(HOW::Wildcard(2), HOW::Wildcard(3)),
|
||||
STA::Key(HOW::Wildcard(4), HOW::Wildcard(5)),
|
||||
STA::WildcardLiteral(wc(0)),
|
||||
STA::WildcardLiteral(wc(1)),
|
||||
STA::WildcardLiteral(wc(2)),
|
||||
STA::WildcardLiteral(wc(3)),
|
||||
STA::WildcardLiteral(wc(4)),
|
||||
STA::WildcardLiteral(wc(5)),
|
||||
],
|
||||
),
|
||||
st(
|
||||
P::BatchSelf(1),
|
||||
vec![
|
||||
STA::Key(HOW::Wildcard(0), HOW::Wildcard(1)),
|
||||
STA::Key(HOW::Wildcard(2), HOW::Wildcard(3)),
|
||||
STA::Key(HOW::Wildcard(4), HOW::Wildcard(5)),
|
||||
STA::WildcardLiteral(wc(0)),
|
||||
STA::WildcardLiteral(wc(1)),
|
||||
STA::WildcardLiteral(wc(2)),
|
||||
STA::WildcardLiteral(wc(3)),
|
||||
STA::WildcardLiteral(wc(4)),
|
||||
STA::WildcardLiteral(wc(5)),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
|
@ -646,11 +622,14 @@ mod tests {
|
|||
|
||||
// Example statement
|
||||
let ethdos_example = Statement::Custom(
|
||||
CustomPredicateRef(eth_dos_distance_batch.clone(), 2),
|
||||
CustomPredicateRef::new(eth_dos_distance_batch.clone(), 2),
|
||||
vec![
|
||||
AnchoredKey(pod_id1, "Alice".into()),
|
||||
AnchoredKey(pod_id2, "Bob".into()),
|
||||
AnchoredKey(SELF, "Seven".into()),
|
||||
WildcardValue::PodId(pod_id1),
|
||||
WildcardValue::Key(Key::from("Alice")),
|
||||
WildcardValue::PodId(pod_id2),
|
||||
WildcardValue::Key(Key::from("Bob")),
|
||||
WildcardValue::PodId(SELF),
|
||||
WildcardValue::Key(Key::from("Seven")),
|
||||
],
|
||||
);
|
||||
|
||||
|
|
@ -659,17 +638,20 @@ mod tests {
|
|||
|
||||
// This could arise as the inductive step.
|
||||
let ethdos_ind_example = Statement::Custom(
|
||||
CustomPredicateRef(eth_dos_distance_batch.clone(), 1),
|
||||
CustomPredicateRef::new(eth_dos_distance_batch.clone(), 1),
|
||||
vec![
|
||||
AnchoredKey(pod_id1, "Alice".into()),
|
||||
AnchoredKey(pod_id2, "Bob".into()),
|
||||
AnchoredKey(SELF, "Seven".into()),
|
||||
WildcardValue::PodId(pod_id1),
|
||||
WildcardValue::Key(Key::from("Alice")),
|
||||
WildcardValue::PodId(pod_id2),
|
||||
WildcardValue::Key(Key::from("Bob")),
|
||||
WildcardValue::PodId(SELF),
|
||||
WildcardValue::Key(Key::from("Seven")),
|
||||
],
|
||||
);
|
||||
|
||||
assert!(Operation::Custom(
|
||||
CustomPredicateRef(eth_dos_distance_batch.clone(), 2),
|
||||
vec![ethdos_ind_example.clone()]
|
||||
CustomPredicateRef::new(eth_dos_distance_batch.clone(), 2),
|
||||
vec![Statement::None, ethdos_ind_example.clone()]
|
||||
)
|
||||
.check(¶ms, ðdos_example)?);
|
||||
|
||||
|
|
@ -678,30 +660,35 @@ mod tests {
|
|||
// less than 7, and Charlie is ETH-friends with Bob.
|
||||
let ethdos_facts = vec![
|
||||
Statement::Custom(
|
||||
CustomPredicateRef(eth_dos_distance_batch.clone(), 2),
|
||||
CustomPredicateRef::new(eth_dos_distance_batch.clone(), 2),
|
||||
vec![
|
||||
AnchoredKey(pod_id1, "Alice".into()),
|
||||
AnchoredKey(pod_id3, "Charlie".into()),
|
||||
AnchoredKey(pod_id4, "Six".into()),
|
||||
WildcardValue::PodId(pod_id1),
|
||||
WildcardValue::Key(Key::from("Alice")),
|
||||
WildcardValue::PodId(pod_id3),
|
||||
WildcardValue::Key(Key::from("Charlie")),
|
||||
WildcardValue::PodId(pod_id4),
|
||||
WildcardValue::Key(Key::from("Six")),
|
||||
],
|
||||
),
|
||||
Statement::ValueOf(AnchoredKey(SELF, "One".into()), 1.into()),
|
||||
Statement::ValueOf(AnchoredKey::from((SELF, "One")), 1.into()),
|
||||
Statement::SumOf(
|
||||
AnchoredKey(SELF, "Seven".into()),
|
||||
AnchoredKey(pod_id4, "Six".into()),
|
||||
AnchoredKey(SELF, "One".into()),
|
||||
AnchoredKey::from((SELF, "Seven")),
|
||||
AnchoredKey::from((pod_id4, "Six")),
|
||||
AnchoredKey::from((SELF, "One")),
|
||||
),
|
||||
Statement::Custom(
|
||||
CustomPredicateRef(eth_friend_batch.clone(), 0),
|
||||
CustomPredicateRef::new(eth_friend_batch.clone(), 0),
|
||||
vec![
|
||||
AnchoredKey(pod_id3, "Charlie".into()),
|
||||
AnchoredKey(pod_id2, "Bob".into()),
|
||||
WildcardValue::PodId(pod_id3),
|
||||
WildcardValue::Key(Key::from("Charlie")),
|
||||
WildcardValue::PodId(pod_id2),
|
||||
WildcardValue::Key(Key::from("Bob")),
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
assert!(Operation::Custom(
|
||||
CustomPredicateRef(eth_dos_distance_batch.clone(), 1),
|
||||
CustomPredicateRef::new(eth_dos_distance_batch.clone(), 1),
|
||||
ethdos_facts
|
||||
)
|
||||
.check(¶ms, ðdos_ind_example)?);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue