From a6d58585bc94a85ee721a13948383061e8f57c43 Mon Sep 17 00:00:00 2001 From: ccamel Date: Mon, 23 Dec 2024 18:15:32 +0100 Subject: [PATCH 1/2] feat(logic-bindings): introduce function for converting strings to Prolog atoms --- packages/axone-logic-bindings/src/atom.rs | 42 +++++++++++++++++++++++ packages/axone-logic-bindings/src/lib.rs | 2 ++ 2 files changed, 44 insertions(+) create mode 100644 packages/axone-logic-bindings/src/atom.rs diff --git a/packages/axone-logic-bindings/src/atom.rs b/packages/axone-logic-bindings/src/atom.rs new file mode 100644 index 00000000..709e772f --- /dev/null +++ b/packages/axone-logic-bindings/src/atom.rs @@ -0,0 +1,42 @@ +/// Convert a Rust string to a Prolog atom. +pub fn as_prolog_atom(s: &str) -> String { + let mut escaped = String::with_capacity(s.len() + 2); + escaped.push('\''); + for c in s.chars() { + if c == '\'' { + escaped.push('\\'); + escaped.push(c); + } else { + escaped.push(c); + } + } + escaped.push('\''); + + escaped +} + +#[cfg(test)] +mod tests { + use super::as_prolog_atom; + + #[test] + fn test_as_prolog_atom() { + let test_cases = vec![ + ("empty string", "", "''"), + ("simple case", "hello", "'hello'"), + ("space in the string", "hello world", "'hello world'"), + ("single quote in the middle", "foo'bar", "'foo\\'bar'"), + ("enclosed single quotes", "'foo bar'", "'\\'foo bar\\''"), + ("cosmwasm URI", "cosmwasm:name:address?query=%7B%22object_data%22%3A%7B%22id%22%3A%221a88ca1632c7323c0aa594000cda26ed9f48b36351c29c3d1e35e0a0474e862e%22%7D%7D", "'cosmwasm:name:address?query=%7B%22object_data%22%3A%7B%22id%22%3A%221a88ca1632c7323c0aa594000cda26ed9f48b36351c29c3d1e35e0a0474e862e%22%7D%7D'") + ]; + + for (_, input, expected) in test_cases { + let actual = as_prolog_atom(input); + assert_eq!( + actual, expected, + "as_prolog_atom({:?}) should produce {:?}, but got {:?}", + input, expected, actual + ); + } + } +} diff --git a/packages/axone-logic-bindings/src/lib.rs b/packages/axone-logic-bindings/src/lib.rs index 1f58e6bc..566710ab 100644 --- a/packages/axone-logic-bindings/src/lib.rs +++ b/packages/axone-logic-bindings/src/lib.rs @@ -2,10 +2,12 @@ pub mod error; mod query; mod term_parser; +pub use atom::as_prolog_atom; pub use query::{Answer, AskResponse, LogicCustomQuery, Result, Substitution}; pub use term_parser::TermValue; // Exposed for testing only // Both unit tests and integration tests are compiled to native code, so everything in here does not need to compile to Wasm. +mod atom; #[cfg(not(target_arch = "wasm32"))] pub mod testing; From 84df0574ff82dd5650212646fefd9bdf8d438f41 Mon Sep 17 00:00:00 2001 From: ccamel Date: Mon, 23 Dec 2024 18:16:33 +0100 Subject: [PATCH 2/2] refactor(logic-bindings): ensure safe conversion of strings to Prolog atoms --- contracts/axone-law-stone/src/contract.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/contracts/axone-law-stone/src/contract.rs b/contracts/axone-law-stone/src/contract.rs index afab1a59..73983c84 100644 --- a/contracts/axone-law-stone/src/contract.rs +++ b/contracts/axone-law-stone/src/contract.rs @@ -132,7 +132,7 @@ pub fn query(deps: Deps<'_, LogicCustomQuery>, env: Env, msg: QueryMsg) -> StdRe pub mod query { use cosmwasm_std::QueryRequest; - use axone_logic_bindings::{Answer, AskResponse}; + use axone_logic_bindings::{as_prolog_atom, Answer, AskResponse}; use crate::helper::object_ref_to_uri; use crate::msg::ProgramResponse; @@ -184,7 +184,7 @@ pub mod query { let program_uri = object_ref_to_uri(program)?; Ok(LogicCustomQuery::Ask { - program: format!(":- consult('{}').", program_uri), + program: format!(":- consult({}).", as_prolog_atom(&program_uri.to_string())), query, }) } @@ -203,10 +203,10 @@ pub fn reply( } pub mod reply { - use cw_utils::ParseReplyError; - use crate::helper::{ask_response_to_objects, get_reply_event_attribute, object_ref_to_uri}; use crate::state::{LawStone, DEPENDENCIES, PROGRAM}; + use axone_logic_bindings::as_prolog_atom; + use cw_utils::ParseReplyError; use super::*; @@ -267,12 +267,10 @@ pub mod reply { Ok(LogicCustomQuery::Ask { program: "source_files(Files) :- bagof(File, source_file(File), Files).".to_string(), - query: [ - "consult('", - program_uri.as_str(), - "'), source_files(Files).", - ] - .join(""), + query: format!( + "consult({}), source_files(Files).", + as_prolog_atom(&program_uri) + ), }) } }