pub mod error; pub mod parser; pub mod pretty_print; pub mod processor; use std::sync::Arc; pub use error::LangError; pub use parser::{parse_podlang, Pairs, ParseError, Rule}; pub use pretty_print::PrettyPrint; pub use processor::process_pest_tree; use processor::PodlangOutput; use crate::middleware::{CustomPredicateBatch, Params}; pub fn parse( input: &str, params: &Params, available_batches: &[Arc], ) -> Result { let pairs = parse_podlang(input)?; processor::process_pest_tree(pairs, params, available_batches).map_err(LangError::from) } #[cfg(test)] mod tests { use hex::ToHex; use pretty_assertions::assert_eq; use super::*; use crate::{ backends::plonky2::primitives::ec::schnorr::SecretKey, lang::error::ProcessorError, middleware::{ hash_str, CustomPredicate, CustomPredicateBatch, CustomPredicateRef, Key, NativePredicate, Params, PodId, PodType, Predicate, RawValue, StatementTmpl, StatementTmplArg, Value, Wildcard, KEY_SIGNER, KEY_TYPE, SELF, }, }; // Helper functions fn wc(name: &str, index: usize) -> Wildcard { Wildcard::new(name.to_string(), index) } fn sta_ak(pod_var: (&str, usize), key: &str) -> StatementTmplArg { StatementTmplArg::AnchoredKey(wc(pod_var.0, pod_var.1), Key::from(key)) } fn sta_wc_lit(name: &str, index: usize) -> StatementTmplArg { StatementTmplArg::Wildcard(wc(name, index)) } fn sta_lit(value: impl Into) -> StatementTmplArg { StatementTmplArg::Literal(value.into()) } fn names(names: &[&str]) -> Vec { names.iter().map(|s| s.to_string()).collect() } #[test] fn test_e2e_simple_predicate() -> Result<(), LangError> { let input = r#" is_equal(PodA, PodB) = AND( Equal(?PodA["the_key"], ?PodB["the_key"]) ) "#; let params = Params::default(); let processed = parse(input, ¶ms, &[])?; let batch_result = processed.custom_batch; let request_result = processed.request_templates; assert_eq!(request_result.len(), 0); assert_eq!(batch_result.predicates.len(), 1); let batch = batch_result; // Expected structure let expected_statements = vec![StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![ sta_ak(("PodA", 0), "the_key"), // ?PodA["the_key"] -> Wildcard(0), Key("the_key") sta_ak(("PodB", 1), "the_key"), // ?PodB["the_key"] -> Wildcard(1), Key("the_key") ], }]; let expected_predicate = CustomPredicate::and( ¶ms, "is_equal".to_string(), expected_statements, 2, // args_len (PodA, PodB) names(&["PodA", "PodB"]), )?; let expected_batch = CustomPredicateBatch::new( ¶ms, "PodlangBatch".to_string(), vec![expected_predicate], ); assert_eq!(batch, expected_batch); Ok(()) } #[test] fn test_e2e_simple_request() -> Result<(), LangError> { let input = r#" REQUEST( Equal(?ConstPod["my_val"], 0x0000000000000000000000000000000000000000000000000000000000000001) Lt(?GovPod["dob"], ?ConstPod["my_val"]) ) "#; let params = Params::default(); let processed = parse(input, ¶ms, &[])?; let batch_result = processed.custom_batch; let request_templates = processed.request_templates; assert_eq!(batch_result.predicates.len(), 0); assert!(!request_templates.is_empty()); let request_templates = request_templates; // Expected structure let expected_templates = vec![ StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![ sta_ak(("ConstPod", 0), "my_val"), // ?ConstPod["my_val"] -> Wildcard(0), Key("my_val") sta_lit(RawValue::from(1)), ], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Lt), args: vec![ sta_ak(("GovPod", 1), "dob"), // ?GovPod["dob"] -> Wildcard(1), Key("dob") sta_ak(("ConstPod", 0), "my_val"), // ?ConstPod["my_val"] -> Wildcard(0), Key("my_val") ], }, ]; assert_eq!(request_templates, expected_templates); Ok(()) } #[test] fn test_e2e_predicate_with_private_var() -> Result<(), LangError> { let input = r#" uses_private(A, private: Temp) = AND( Equal(?A["input_key"], ?Temp["const_key"]) Equal(?Temp["const_key"], "some_value") ) "#; let params = Params::default(); let processed = parse(input, ¶ms, &[])?; let batch_result = processed.custom_batch; let request_result = processed.request_templates; assert_eq!(request_result.len(), 0); assert_eq!(batch_result.predicates.len(), 1); let batch = batch_result; // Expected structure: Public args: A (index 0). Private args: Temp (index 1) let expected_statements = vec![ StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![ sta_ak(("A", 0), "input_key"), // ?A["input_key"] -> Wildcard(0), Key("input_key") sta_ak(("Temp", 1), "const_key"), // ?Temp["const_key"] -> Wildcard(1), Key("const_key") ], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![ sta_ak(("Temp", 1), "const_key"), // ?Temp["const_key"] -> Wildcard(1), Key("const_key") sta_lit("some_value"), // Literal("some_value") ], }, ]; let expected_predicate = CustomPredicate::and( ¶ms, "uses_private".to_string(), expected_statements, 1, // args_len (A) names(&["A", "Temp"]), )?; let expected_batch = CustomPredicateBatch::new( ¶ms, "PodlangBatch".to_string(), vec![expected_predicate], ); assert_eq!(batch, expected_batch); Ok(()) } #[test] fn test_e2e_request_with_custom_call() -> Result<(), LangError> { let input = r#" my_pred(X, Y) = AND( Equal(?X["val"], ?Y["val"]) ) REQUEST( my_pred(?Pod1, ?Pod2) ) "#; let params = Params::default(); let processed = parse(input, ¶ms, &[])?; let batch_result = processed.custom_batch; let request_templates = processed.request_templates; assert_eq!(batch_result.predicates.len(), 1); assert!(!request_templates.is_empty()); let batch = batch_result; let request_templates = request_templates; // Expected Batch structure let expected_pred_statements = vec![StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![ sta_ak(("X", 0), "val"), // ?X["val"] -> Wildcard(0), Key("val") sta_ak(("Y", 1), "val"), // ?Y["val"] -> Wildcard(1), Key("val") ], }]; let expected_predicate = CustomPredicate::and( ¶ms, "my_pred".to_string(), expected_pred_statements, 2, // args_len (X, Y) names(&["X", "Y"]), )?; let expected_batch = CustomPredicateBatch::new( ¶ms, "PodlangBatch".to_string(), vec![expected_predicate], ); assert_eq!(batch, expected_batch); // Expected Request structure // Pod1 -> Wildcard 0, Pod2 -> Wildcard 1 let expected_request_templates = vec![StatementTmpl { pred: Predicate::Custom(CustomPredicateRef::new(expected_batch, 0)), args: vec![ StatementTmplArg::Wildcard(wc("Pod1", 0)), StatementTmplArg::Wildcard(wc("Pod2", 1)), ], }]; assert_eq!(request_templates, expected_request_templates); Ok(()) } #[test] fn test_e2e_request_with_various_args() -> Result<(), LangError> { let input = r#" some_pred(A, B, C) = AND( Equal(?A["foo"], ?B["bar"]) ) REQUEST( some_pred( ?Var1, // Wildcard 12345, // Int Literal "hello_string" // String Literal (Removed invalid AK args) ) Equal(?AnotherPod["another_key"], ?Var1["some_field"]) ) "#; let params = Params::default(); let processed = parse(input, ¶ms, &[])?; let batch_result = processed.custom_batch; let request_templates = processed.request_templates; assert_eq!(batch_result.predicates.len(), 1); // some_pred is defined assert!(!request_templates.is_empty()); let request_templates = request_templates; // Expected Wildcard Indices in Request Scope: // ?Var1 -> 0 // ?AnotherPod -> 1 // Expected structure let expected_templates = vec![ StatementTmpl { pred: Predicate::Custom(CustomPredicateRef::new(batch_result, 0)), // Refers to some_pred args: vec![ StatementTmplArg::Wildcard(wc("Var1", 0)), // ?Var1 StatementTmplArg::Literal(Value::from(12345i64)), // 12345 StatementTmplArg::Literal(Value::from("hello_string")), // "hello_string" ], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![ // ?AnotherPod["another_key"] -> Wildcard(1), Key("another_key") sta_ak(("AnotherPod", 1), "another_key"), // ?Var1["some_field"] -> Wildcard(0), Key("some_field") sta_ak(("Var1", 0), "some_field"), ], }, ]; assert_eq!(request_templates, expected_templates); Ok(()) } #[test] fn test_e2e_syntactic_sugar_predicates() -> Result<(), LangError> { let input = r#" REQUEST( GtEq(?A["foo"], ?B["bar"]) Gt(?C["baz"], ?D["qux"]) DictContains(?A["foo"], ?B["bar"], ?C["baz"]) DictNotContains(?A["foo"], ?B["bar"]) ArrayContains(?A["foo"], ?B["bar"], ?C["baz"]) ) "#; let params = Params::default(); let processed = parse(input, ¶ms, &[])?; let batch_result = processed.custom_batch; let request_templates = processed.request_templates; assert_eq!(batch_result.predicates.len(), 0); assert!(!request_templates.is_empty()); let request_templates = request_templates; let expected_templates = vec![ StatementTmpl { pred: Predicate::Native(NativePredicate::LtEq), args: vec![sta_ak(("B", 1), "bar"), sta_ak(("A", 0), "foo")], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Lt), args: vec![sta_ak(("D", 3), "qux"), sta_ak(("C", 2), "baz")], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Contains), args: vec![ sta_ak(("A", 0), "foo"), sta_ak(("B", 1), "bar"), sta_ak(("C", 2), "baz"), ], }, StatementTmpl { pred: Predicate::Native(NativePredicate::NotContains), args: vec![sta_ak(("A", 0), "foo"), sta_ak(("B", 1), "bar")], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Contains), args: vec![ sta_ak(("A", 0), "foo"), sta_ak(("B", 1), "bar"), sta_ak(("C", 2), "baz"), ], }, ]; assert_eq!(request_templates, expected_templates); Ok(()) } #[test] fn test_e2e_zukyc_request_parsing() -> Result<(), LangError> { let input = r#" REQUEST( // Order matters for comparison with the hardcoded templates SetNotContains(?sanctions["sanctionList"], ?gov["idNumber"]) Lt(?gov["dateOfBirth"], ?SELF_HOLDER_18Y["const_18y"]) Equal(?pay["startDate"], ?SELF_HOLDER_1Y["const_1y"]) Equal(?gov["socialSecurityNumber"], ?pay["socialSecurityNumber"]) Equal(?SELF_HOLDER_18Y["const_18y"], 1169909388) Equal(?SELF_HOLDER_1Y["const_1y"], 1706367566) ) "#; // Parse the input string let processed = super::parse(input, &Params::default(), &[])?; let parsed_templates = processed.request_templates; // Define Expected Templates (Copied from prover/mod.rs) let now_minus_18y_val = Value::from(1169909388_i64); let now_minus_1y_val = Value::from(1706367566_i64); // Define wildcards and keys for the request // Note: Indices must match the order of appearance in the *parsed* request // Order: sanctions, gov, SELF_HOLDER_18Y, pay, SELF_HOLDER_1Y let wc_sanctions = wc("sanctions", 0); let wc_gov = wc("gov", 1); let wc_self_18y = wc("SELF_HOLDER_18Y", 2); let wc_pay = wc("pay", 3); let wc_self_1y = wc("SELF_HOLDER_1Y", 4); let id_num_key = "idNumber"; let dob_key = "dateOfBirth"; let const_18y_key = "const_18y"; let start_date_key = "startDate"; let const_1y_key = "const_1y"; let ssn_key = "socialSecurityNumber"; let sanction_list_key = "sanctionList"; // Define the request templates using wildcards for constants let expected_templates = vec![ // 1. NotContains(?sanctions["sanctionList"], ?gov["idNumber"]) StatementTmpl { pred: Predicate::Native(NativePredicate::NotContains), args: vec![ sta_ak( (wc_sanctions.name.as_str(), wc_sanctions.index), sanction_list_key, ), sta_ak((wc_gov.name.as_str(), wc_gov.index), id_num_key), ], }, // 2. Lt(?gov["dateOfBirth"], ?SELF_HOLDER_18Y["const_18y"]) StatementTmpl { pred: Predicate::Native(NativePredicate::Lt), args: vec![ sta_ak((wc_gov.name.as_str(), wc_gov.index), dob_key), sta_ak( (wc_self_18y.name.as_str(), wc_self_18y.index), const_18y_key, ), ], }, // 3. Equal(?pay["startDate"], ?SELF_HOLDER_1Y["const_1y"]) StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![ sta_ak((wc_pay.name.as_str(), wc_pay.index), start_date_key), sta_ak((wc_self_1y.name.as_str(), wc_self_1y.index), const_1y_key), ], }, // 4. Equal(?gov["socialSecurityNumber"], ?pay["socialSecurityNumber"]) StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![ sta_ak((wc_gov.name.as_str(), wc_gov.index), ssn_key), sta_ak((wc_pay.name.as_str(), wc_pay.index), ssn_key), ], }, // 5. Equal(?SELF_HOLDER_18Y["const_18y"], 1169909388) StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![ sta_ak( (wc_self_18y.name.as_str(), wc_self_18y.index), const_18y_key, ), sta_lit(now_minus_18y_val.clone()), ], }, // 6. Equal(?SELF_HOLDER_1Y["const_1y"], 1706367566) StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![ sta_ak((wc_self_1y.name.as_str(), wc_self_1y.index), const_1y_key), sta_lit(now_minus_1y_val.clone()), ], }, ]; assert_eq!( parsed_templates, expected_templates, "Parsed ZuKYC request templates do not match the expected hard-coded version" ); assert!( processed.custom_batch.predicates.is_empty(), "Expected no custom predicates for a REQUEST only input" ); Ok(()) } #[test] fn test_e2e_ethdos_predicates() -> Result<(), LangError> { let params = Params { max_input_signed_pods: 3, max_input_recursive_pods: 3, max_statements: 31, max_signed_pod_values: 8, max_public_statements: 10, max_statement_args: 6, max_operation_args: 5, max_custom_predicate_arity: 5, max_custom_batch_size: 5, max_custom_predicate_wildcards: 12, ..Default::default() }; let input = r#" eth_friend(src, dst, private: attestation_pod) = AND( Equal(?attestation_pod["_type"], 1) Equal(?attestation_pod["_signer"], ?src) Equal(?attestation_pod["attestation"], ?dst) ) eth_dos_distance_base(src, dst, distance) = AND( Equal(?src, ?dst) Equal(?distance, 0) ) eth_dos_distance_ind(src, dst, distance, private: shorter_distance, intermed) = AND( eth_dos_distance(?src, ?dst, ?distance) SumOf(?distance, ?shorter_distance, 1) eth_friend(?intermed, ?dst) ) eth_dos_distance(src, dst, distance) = OR( eth_dos_distance_base(?src, ?dst, ?distance) eth_dos_distance_ind(?src, ?dst, ?distance) ) "#; let processed = super::parse(input, ¶ms, &[])?; assert!( processed.request_templates.is_empty(), "Expected no request templates" ); assert_eq!( processed.custom_batch.predicates.len(), 4, "Expected 4 custom predicates" ); // Predicate Order: eth_friend (0), base (1), ind (2), distance (3) // eth_friend (Index 0) let expected_friend_stmts = vec![ StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![ sta_ak(("attestation_pod", 2), "_type"), // Pub(0-1), Priv(2) sta_lit(PodType::Signed), ], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![ sta_ak(("attestation_pod", 2), "_signer"), sta_wc_lit("src", 0), // Pub arg 0 ], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![ sta_ak(("attestation_pod", 2), "attestation"), sta_wc_lit("dst", 1), // Pub arg 1 ], }, ]; let expected_friend_pred = CustomPredicate::new( ¶ms, "eth_friend".to_string(), true, // AND expected_friend_stmts, 2, // public_args_len: src, dst names(&["src", "dst", "attestation_pod"]), )?; // eth_dos_distance_base (Index 1) let expected_base_stmts = vec![ StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![sta_wc_lit("src", 0), sta_wc_lit("dst", 1)], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![sta_wc_lit("distance", 2), sta_lit(0i64)], }, ]; let expected_base_pred = CustomPredicate::new( ¶ms, "eth_dos_distance_base".to_string(), true, // AND expected_base_stmts, 3, // public_args_len names(&["src", "dst", "distance"]), )?; // eth_dos_distance_ind (Index 2) // Public args indices: 0-2 // Private args indices: 3-4 (shorter_distance, intermed) let expected_ind_stmts = vec![ StatementTmpl { pred: Predicate::BatchSelf(3), // Calls eth_dos_distance (index 3) args: vec![ // WildcardLiteral args sta_wc_lit("src", 0), sta_wc_lit("dst", 1), // private arg sta_wc_lit("distance", 2), // private arg ], }, StatementTmpl { pred: Predicate::Native(NativePredicate::SumOf), args: vec![ sta_wc_lit("distance", 2), // public arg sta_wc_lit("shorter_distance", 3), // private arg sta_lit(1), ], }, StatementTmpl { pred: Predicate::BatchSelf(0), // Calls eth_friend (index 0) args: vec![ // WildcardLiteral args sta_wc_lit("intermed", 4), // private arg sta_wc_lit("dst", 1), // public arg ], }, ]; let expected_ind_pred = CustomPredicate::new( ¶ms, "eth_dos_distance_ind".to_string(), true, // AND expected_ind_stmts, 3, // public_args_len names(&["src", "dst", "distance", "shorter_distance", "intermed"]), )?; // eth_dos_distance (Index 3) let expected_dist_stmts = vec![ StatementTmpl { pred: Predicate::BatchSelf(1), // Calls eth_dos_distance_base (index 1) args: vec![ // WildcardLiteral args sta_wc_lit("src", 0), sta_wc_lit("dst", 1), sta_wc_lit("distance", 2), ], }, StatementTmpl { pred: Predicate::BatchSelf(2), // Calls eth_dos_distance_ind (index 2) args: vec![ // WildcardLiteral args sta_wc_lit("src", 0), sta_wc_lit("dst", 1), sta_wc_lit("distance", 2), ], }, ]; let expected_dist_pred = CustomPredicate::new( ¶ms, "eth_dos_distance".to_string(), false, // OR expected_dist_stmts, 3, // public_args_len names(&["src", "dst", "distance"]), )?; let expected_batch = CustomPredicateBatch::new( ¶ms, "PodlangBatch".to_string(), vec![ expected_friend_pred, expected_base_pred, expected_ind_pred, expected_dist_pred, ], ); assert_eq!( processed.custom_batch, expected_batch, "Processed ETHDoS predicates do not match expected structure" ); Ok(()) } #[test] fn test_e2e_use_statement() -> Result<(), LangError> { let params = Params::default(); // 1. Create a batch to be imported let imported_pred_stmts = vec![StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![ sta_ak(("A", 0), "foo"), // ?A["foo"] sta_ak(("B", 1), "bar"), // ?B["bar"] ], }]; let imported_predicate = CustomPredicate::and( ¶ms, "imported_equal".to_string(), imported_pred_stmts, 2, names(&["A", "B"]), )?; let available_batch = CustomPredicateBatch::new(¶ms, "MyBatch".to_string(), vec![imported_predicate]); let available_batches = vec![available_batch.clone()]; // 2. Create the input string that uses the batch let batch_id_str = available_batch.id().encode_hex::(); let input = format!( r#" use imported_pred from 0x{} REQUEST( imported_pred(?Pod1, ?Pod2) ) "#, batch_id_str ); // 3. Parse the input let processed = parse(&input, ¶ms, &available_batches)?; let request_templates = processed.request_templates; assert!( processed.custom_batch.predicates.is_empty(), "No custom predicates should be defined in the main input" ); assert_eq!(request_templates.len(), 1, "Expected one request template"); // 4. Check the resulting request template let expected_request_templates = vec![StatementTmpl { pred: Predicate::Custom(CustomPredicateRef::new(available_batch, 0)), args: vec![ StatementTmplArg::Wildcard(wc("Pod1", 0)), StatementTmplArg::Wildcard(wc("Pod2", 1)), ], }]; assert_eq!(request_templates, expected_request_templates); Ok(()) } #[test] fn test_e2e_use_statement_complex() -> Result<(), LangError> { let params = Params::default(); // 1. Create a batch with multiple predicates let pred1 = CustomPredicate::and(¶ms, "p1".into(), vec![], 1, names(&["A"]))?; let pred2 = CustomPredicate::and(¶ms, "p2".into(), vec![], 2, names(&["B", "C"]))?; let pred3 = CustomPredicate::and(¶ms, "p3".into(), vec![], 1, names(&["D"]))?; let available_batch = CustomPredicateBatch::new(¶ms, "MyBatch".to_string(), vec![pred1, pred2, pred3]); let available_batches = vec![available_batch.clone()]; // 2. Create the input string that uses the batch with skips let batch_id_str = available_batch.id().encode_hex::(); let input = format!( r#" use pred_one, _, pred_three from 0x{} REQUEST( pred_one(?Pod1) pred_three(?Pod2) ) "#, batch_id_str ); // 3. Parse the input let processed = parse(&input, ¶ms, &available_batches)?; let request_templates = processed.request_templates; assert_eq!(request_templates.len(), 2, "Expected two request templates"); // 4. Check the resulting request templates let expected_templates = vec![ StatementTmpl { pred: Predicate::Custom(CustomPredicateRef::new(available_batch.clone(), 0)), args: vec![StatementTmplArg::Wildcard(wc("Pod1", 0))], }, StatementTmpl { pred: Predicate::Custom(CustomPredicateRef::new(available_batch, 2)), args: vec![StatementTmplArg::Wildcard(wc("Pod2", 1))], }, ]; assert_eq!(request_templates, expected_templates); Ok(()) } #[test] fn test_e2e_custom_predicate_uses_import() -> Result<(), LangError> { let params = Params::default(); // 1. Create a batch with a predicate to be imported let imported_pred_stmts = vec![StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![sta_ak(("A", 0), "foo"), sta_ak(("B", 1), "bar")], }]; let imported_predicate = CustomPredicate::and( ¶ms, "imported_equal".to_string(), imported_pred_stmts, 2, names(&["A", "B"]), )?; let available_batch = CustomPredicateBatch::new(¶ms, "MyBatch".to_string(), vec![imported_predicate]); let available_batches = vec![available_batch.clone()]; // 2. Create the input string that defines a new predicate using the imported one let batch_id_str = available_batch.id().encode_hex::(); let input = format!( r#" use imported_eq from 0x{} wrapper_pred(X, Y) = AND( imported_eq(?X, ?Y) ) "#, batch_id_str ); // 3. Parse the input let processed = parse(&input, ¶ms, &available_batches)?; assert!( processed.request_templates.is_empty(), "No request should be defined" ); assert_eq!( processed.custom_batch.predicates.len(), 1, "Expected one custom predicate to be defined" ); // 4. Check the resulting predicate definition let defined_pred = &processed.custom_batch.predicates[0]; assert_eq!(defined_pred.name, "wrapper_pred"); assert_eq!(defined_pred.statements.len(), 1); let expected_statement = StatementTmpl { pred: Predicate::Custom(CustomPredicateRef::new(available_batch.clone(), 0)), args: vec![ StatementTmplArg::Wildcard(wc("X", 0)), StatementTmplArg::Wildcard(wc("Y", 1)), ], }; assert_eq!(defined_pred.statements[0], expected_statement); Ok(()) } #[test] fn test_e2e_literals() -> Result<(), LangError> { let pk = crate::backends::plonky2::primitives::ec::curve::Point::generator(); let pod_id = PodId(hash_str("test")); let raw = RawValue::from(1); let string = "hello"; let int = 123; let bool = true; let sk = SecretKey::new_rand(); let input = format!( r#" REQUEST( Equal(?A["pk"], {}) Equal(?B["pod_id"], {}) Equal(?C["raw"], {}) Equal(?D["string"], {}) Equal(?E["int"], {}) Equal(?F["bool"], {}) Equal(?G["sk"], {}) Equal(?H["self"], SELF) ) "#, Value::from(pk).to_podlang_string(), Value::from(pod_id).to_podlang_string(), Value::from(raw).to_podlang_string(), Value::from(string).to_podlang_string(), Value::from(int).to_podlang_string(), Value::from(bool).to_podlang_string(), Value::from(sk.clone()).to_podlang_string() ); /* REQUEST( Equal(?A["pk"], PublicKey(3t9fNuU194n7mSJPRdeaJRMqw6ZQCUddzvECWNe1k2b1rdBezXpJxF)) Equal(?B["pod_id"], 0x735b31d3aad0f5b66002ffe1dc7d2eaa0ee9c59c09b641e8261530c5f3a02f29) Equal(?C["raw"], Raw(0x0000000000000000000000000000000000000000000000000000000000000001)) Equal(?D["string"], "hello") Equal(?E["int"], 123) Equal(?F["bool"], true) Equal(?G["sk"], SecretKey(random_secret_key_base_64)) Equal(?H["self"], SELF) ) */ let params = Params::default(); let processed = parse(&input, ¶ms, &[])?; let request_templates = processed.request_templates; let expected_templates = vec![ StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![sta_ak(("A", 0), "pk"), sta_lit(Value::from(pk))], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![sta_ak(("B", 1), "pod_id"), sta_lit(Value::from(pod_id))], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![sta_ak(("C", 2), "raw"), sta_lit(Value::from(raw))], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![sta_ak(("D", 3), "string"), sta_lit(Value::from(string))], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![sta_ak(("E", 4), "int"), sta_lit(Value::from(int))], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![sta_ak(("F", 5), "bool"), sta_lit(Value::from(bool))], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![sta_ak(("G", 6), "sk"), sta_lit(Value::from(sk))], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![sta_ak(("H", 7), "self"), sta_lit(Value::from(SELF))], }, ]; assert_eq!(request_templates, expected_templates); Ok(()) } #[test] fn test_e2e_use_unknown_batch() { let params = Params::default(); let available_batches = &[]; let unknown_batch_id = format!("0x{}", "a".repeat(64)); let input = format!( r#" use some_pred from {} "#, unknown_batch_id ); let result = parse(&input, ¶ms, available_batches); assert!(result.is_err()); match result.err().unwrap() { LangError::Processor(e) => match *e { ProcessorError::BatchNotFound { id, .. } => { assert_eq!(id, unknown_batch_id); } _ => panic!("Expected BatchNotFound error, but got {:?}", e), }, e => panic!("Expected LangError::Processor, but got {:?}", e), } } #[test] fn test_e2e_undefined_wildcard() { let params = Params::default(); let available_batches = &[]; let input = format!( r#" identity_verified(username, private: identity_pod) = AND( Equal(?identity_pod["{key_type}"], {signed_pod_type}) Equal(?identity_pod["{key_signer}"], {identity_server_pk}) Equal(?identity_pod["username"], ?username) Equal(?identity_pod["user_public_key"], ?user_public_key) ) "#, key_type = KEY_TYPE, signed_pod_type = PodType::Signed as u32, key_signer = KEY_SIGNER, identity_server_pk = "0x0000000000000000000000000000000000000000000000000000000000000000" ); let result = parse(&input, ¶ms, available_batches); assert!(result.is_err()); match result.err().unwrap() { LangError::Processor(e) => match *e { ProcessorError::UndefinedWildcard { name, pred_name, .. } => { assert_eq!(name, "user_public_key"); assert_eq!(pred_name, "identity_verified"); } _ => panic!("Expected UndefinedWildcard error, but got {:?}", e), }, e => panic!("Expected LangError::Processor, but got {:?}", e), } } }