limit the number of StatementTmpl in CustomPredicate: (#101)
* limit the number of StatementTmpl in CustomPredicate: - add constructor method for CustomPredicate - make size checks at the CustomPredicate creation, so that once instantiated we can assume that contains valid data This resolves #79 * Update tests to use new interface --------- Co-authored-by: Ahmad <root@ahmadafuni.com>
This commit is contained in:
parent
c9f7427967
commit
c92839d897
6 changed files with 119 additions and 79 deletions
|
|
@ -195,14 +195,42 @@ impl ToFields for StatementTmpl {
|
|||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct CustomPredicate {
|
||||
/// NOTE: fields are not public (outside of crate) to enforce the struct instantiation through
|
||||
/// the `::and/or` methods, which performs checks on the values.
|
||||
|
||||
/// true for "and", false for "or"
|
||||
pub conjunction: bool,
|
||||
pub statements: Vec<StatementTmpl>,
|
||||
pub args_len: usize,
|
||||
pub(crate) conjunction: bool,
|
||||
pub(crate) statements: Vec<StatementTmpl>,
|
||||
pub(crate) args_len: usize,
|
||||
// TODO: Add private args length?
|
||||
// TODO: Add args type information?
|
||||
}
|
||||
|
||||
impl CustomPredicate {
|
||||
pub fn and(params: &Params, statements: Vec<StatementTmpl>, args_len: usize) -> Result<Self> {
|
||||
Self::new(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 new(
|
||||
params: &Params,
|
||||
conjunction: bool,
|
||||
statements: Vec<StatementTmpl>,
|
||||
args_len: usize,
|
||||
) -> Result<Self> {
|
||||
if statements.len() > params.max_custom_predicate_arity {
|
||||
return Err(anyhow!("Custom predicate depends on too many statements"));
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
conjunction,
|
||||
statements,
|
||||
args_len,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToFields for CustomPredicate {
|
||||
fn to_fields(&self, params: &Params) -> (Vec<F>, usize) {
|
||||
// serialize as:
|
||||
|
|
@ -212,9 +240,9 @@ impl ToFields for CustomPredicate {
|
|||
// (params.max_custom_predicate_arity * params.statement_tmpl_size())
|
||||
// field elements
|
||||
|
||||
// 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
|
||||
// NOTE: this method assumes that the self.params.len() is inside the
|
||||
// expected bound, as Self should be instantiated with the constructor
|
||||
// method `new` which performs the check.
|
||||
if self.statements.len() > params.max_custom_predicate_arity {
|
||||
panic!("Custom predicate depends on too many statements");
|
||||
}
|
||||
|
|
@ -353,7 +381,7 @@ mod tests {
|
|||
|
||||
use crate::middleware::{
|
||||
AnchoredKey, CustomPredicate, CustomPredicateBatch, CustomPredicateRef, Hash,
|
||||
HashOrWildcard, NativePredicate, Operation, PodId, PodType, Predicate, Statement,
|
||||
HashOrWildcard, NativePredicate, Operation, Params, PodId, PodType, Predicate, Statement,
|
||||
StatementTmpl, StatementTmplArg, SELF,
|
||||
};
|
||||
|
||||
|
|
@ -368,6 +396,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn is_double_test() -> Result<()> {
|
||||
let params = Params::default();
|
||||
|
||||
/*
|
||||
is_double(S1, S2) :-
|
||||
p:value_of(Constant, 2),
|
||||
|
|
@ -375,9 +405,9 @@ mod tests {
|
|||
*/
|
||||
let cust_pred_batch = Arc::new(CustomPredicateBatch {
|
||||
name: "is_double".to_string(),
|
||||
predicates: vec![CustomPredicate {
|
||||
conjunction: true,
|
||||
statements: vec![
|
||||
predicates: vec![CustomPredicate::and(
|
||||
¶ms,
|
||||
vec![
|
||||
st(
|
||||
P::Native(NP::ValueOf),
|
||||
vec![
|
||||
|
|
@ -394,8 +424,8 @@ mod tests {
|
|||
],
|
||||
),
|
||||
],
|
||||
args_len: 4,
|
||||
}],
|
||||
4,
|
||||
)?],
|
||||
});
|
||||
|
||||
let custom_statement = Statement::Custom(
|
||||
|
|
@ -418,16 +448,18 @@ mod tests {
|
|||
],
|
||||
);
|
||||
|
||||
assert!(custom_deduction.check(&custom_statement)?);
|
||||
assert!(custom_deduction.check(¶ms, &custom_statement)?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ethdos_test() -> Result<()> {
|
||||
let eth_friend_cp = CustomPredicate {
|
||||
conjunction: true,
|
||||
statements: vec![
|
||||
let params = Params::default();
|
||||
|
||||
let eth_friend_cp = CustomPredicate::and(
|
||||
¶ms,
|
||||
vec![
|
||||
st(
|
||||
P::Native(NP::ValueOf),
|
||||
vec![
|
||||
|
|
@ -450,17 +482,17 @@ mod tests {
|
|||
],
|
||||
),
|
||||
],
|
||||
args_len: 4,
|
||||
};
|
||||
4,
|
||||
)?;
|
||||
|
||||
let eth_friend_batch = Arc::new(CustomPredicateBatch {
|
||||
name: "eth_friend".to_string(),
|
||||
predicates: vec![eth_friend_cp],
|
||||
});
|
||||
|
||||
let eth_dos_base = CustomPredicate {
|
||||
conjunction: true,
|
||||
statements: vec![
|
||||
let eth_dos_base = CustomPredicate::and(
|
||||
¶ms,
|
||||
vec![
|
||||
st(
|
||||
P::Native(NP::Equal),
|
||||
vec![
|
||||
|
|
@ -476,12 +508,12 @@ mod tests {
|
|||
],
|
||||
),
|
||||
],
|
||||
args_len: 6,
|
||||
};
|
||||
6,
|
||||
)?;
|
||||
|
||||
let eth_dos_ind = CustomPredicate {
|
||||
conjunction: true,
|
||||
statements: vec![
|
||||
let eth_dos_ind = CustomPredicate::and(
|
||||
¶ms,
|
||||
vec![
|
||||
st(
|
||||
P::BatchSelf(2),
|
||||
vec![
|
||||
|
|
@ -513,12 +545,12 @@ mod tests {
|
|||
],
|
||||
),
|
||||
],
|
||||
args_len: 6,
|
||||
};
|
||||
6,
|
||||
)?;
|
||||
|
||||
let eth_dos_distance_either = CustomPredicate {
|
||||
conjunction: false,
|
||||
statements: vec![
|
||||
let eth_dos_distance_either = CustomPredicate::or(
|
||||
¶ms,
|
||||
vec![
|
||||
st(
|
||||
P::BatchSelf(0),
|
||||
vec![
|
||||
|
|
@ -536,8 +568,8 @@ mod tests {
|
|||
],
|
||||
),
|
||||
],
|
||||
args_len: 6,
|
||||
};
|
||||
6,
|
||||
)?;
|
||||
|
||||
let eth_dos_distance_batch = Arc::new(CustomPredicateBatch {
|
||||
name: "ETHDoS_distance".to_string(),
|
||||
|
|
@ -561,7 +593,7 @@ mod tests {
|
|||
);
|
||||
|
||||
// Copies should work.
|
||||
assert!(Operation::CopyStatement(ethdos_example.clone()).check(ðdos_example)?);
|
||||
assert!(Operation::CopyStatement(ethdos_example.clone()).check(¶ms, ðdos_example)?);
|
||||
|
||||
// This could arise as the inductive step.
|
||||
let ethdos_ind_example = Statement::Custom(
|
||||
|
|
@ -577,7 +609,7 @@ mod tests {
|
|||
CustomPredicateRef(eth_dos_distance_batch.clone(), 2),
|
||||
vec![ethdos_ind_example.clone()]
|
||||
)
|
||||
.check(ðdos_example)?);
|
||||
.check(¶ms, ðdos_example)?);
|
||||
|
||||
// And the inductive step would arise as follows: Say the
|
||||
// ETHDoS distance from Alice to Charlie is 6, which is one
|
||||
|
|
@ -610,7 +642,7 @@ mod tests {
|
|||
CustomPredicateRef(eth_dos_distance_batch.clone(), 1),
|
||||
ethdos_facts
|
||||
)
|
||||
.check(ðdos_ind_example)?);
|
||||
.check(¶ms, ðdos_ind_example)?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,6 +92,22 @@ pub struct Params {
|
|||
pub max_custom_batch_size: usize,
|
||||
}
|
||||
|
||||
impl Default for Params {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
max_input_signed_pods: 3,
|
||||
max_input_main_pods: 3,
|
||||
max_statements: 20,
|
||||
max_signed_pod_values: 8,
|
||||
max_public_statements: 10,
|
||||
max_statement_args: 5,
|
||||
max_operation_args: 5,
|
||||
max_custom_predicate_arity: 5,
|
||||
max_custom_batch_size: 5,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Params {
|
||||
pub fn max_priv_statements(&self) -> usize {
|
||||
self.max_statements - self.max_public_statements
|
||||
|
|
@ -134,22 +150,6 @@ impl Params {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for Params {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
max_input_signed_pods: 3,
|
||||
max_input_main_pods: 3,
|
||||
max_statements: 20,
|
||||
max_signed_pod_values: 8,
|
||||
max_public_statements: 10,
|
||||
max_statement_args: 5,
|
||||
max_operation_args: 5,
|
||||
max_custom_predicate_arity: 5,
|
||||
max_custom_batch_size: 5,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Pod: fmt::Debug + DynClone {
|
||||
fn verify(&self) -> bool;
|
||||
fn id(&self) -> PodId;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ use anyhow::{anyhow, Result};
|
|||
|
||||
use super::{CustomPredicateRef, Statement};
|
||||
use crate::{
|
||||
middleware::{AnchoredKey, CustomPredicate, PodId, Predicate, StatementTmpl, Value, SELF},
|
||||
middleware::{
|
||||
AnchoredKey, CustomPredicate, Params, PodId, Predicate, StatementTmpl, Value, SELF,
|
||||
},
|
||||
util::hashmap_insert_no_dupe,
|
||||
};
|
||||
|
||||
|
|
@ -145,7 +147,7 @@ impl Operation {
|
|||
})
|
||||
}
|
||||
/// Checks the given operation against a statement.
|
||||
pub fn check(&self, output_statement: &Statement) -> Result<bool> {
|
||||
pub fn check(&self, params: &Params, output_statement: &Statement) -> Result<bool> {
|
||||
use Statement::*;
|
||||
match (self, output_statement) {
|
||||
(Self::None, None) => Ok(true),
|
||||
|
|
@ -211,10 +213,10 @@ impl Operation {
|
|||
// references with custom predicate references.
|
||||
let custom_predicate = {
|
||||
let cp = (**cpb).predicates[*i].clone();
|
||||
CustomPredicate {
|
||||
conjunction: cp.conjunction,
|
||||
statements: cp
|
||||
.statements
|
||||
CustomPredicate::new(
|
||||
params,
|
||||
cp.conjunction,
|
||||
cp.statements
|
||||
.into_iter()
|
||||
.map(|StatementTmpl(p, args)| {
|
||||
StatementTmpl(
|
||||
|
|
@ -228,8 +230,8 @@ impl Operation {
|
|||
)
|
||||
})
|
||||
.collect(),
|
||||
args_len: cp.args_len,
|
||||
}
|
||||
cp.args_len,
|
||||
)?
|
||||
};
|
||||
match custom_predicate.conjunction {
|
||||
true if custom_predicate.statements.len() == args.len() => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue