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::{ CustomPredicate, CustomPredicateBatch, CustomPredicateRef, Key, NativePredicate, Params, Predicate, RawValue, StatementTmpl, StatementTmplArg, Value, Wildcard, }, }; // 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"], Raw(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()); // 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; // 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()); // 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 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_pods: 3, max_statements: 31, 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_dict) = AND( SignedBy(attestation_dict, src) Equal(attestation_dict["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::SignedBy), args: vec![sta_wc_lit("attestation_dict", 2), sta_wc_lit("src", 0)], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![ sta_ak(("attestation_dict", 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_dict"]), )?; // 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 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["raw"], {}) Equal(C["string"], {}) Equal(D["int"], {}) Equal(E["bool"], {}) Equal(F["sk"], {}) ) "#, Value::from(pk).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(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), "raw"), sta_lit(Value::from(raw))], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![sta_ak(("C", 2), "string"), sta_lit(Value::from(string))], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![sta_ak(("D", 3), "int"), sta_lit(Value::from(int))], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![sta_ak(("E", 4), "bool"), sta_lit(Value::from(bool))], }, StatementTmpl { pred: Predicate::Native(NativePredicate::Equal), args: vec![sta_ak(("F", 5), "sk"), sta_lit(Value::from(sk))], }, ]; 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 = r#" identity_verified(username, private: identity_dict) = AND( Equal(identity_dict["username"], username) Equal(identity_dict["user_public_key"], user_public_key) ) "# .to_string(); 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), } } }