From 009358a700f644efe8f19a19ee9f25e8607790b6 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Mon, 16 Sep 2024 15:09:49 +0700 Subject: [PATCH 1/7] add macros --- Scarb.lock | 5 + packages/client/src/main.cairo | 3 +- packages/client/src/test.cairo | 1 - packages/consensus/Scarb.toml | 5 + packages/consensus/src/lib.cairo | 1 + .../consensus/src/validation/timestamp.cairo | 34 ++- packages/macros/.gitignore | 1 + packages/macros/Cargo.toml | 14 ++ packages/macros/Scarb.toml | 7 + packages/macros/src/lib.rs | 1 + packages/macros/src/logging.rs | 195 ++++++++++++++++++ 11 files changed, 263 insertions(+), 4 deletions(-) create mode 100644 packages/macros/.gitignore create mode 100644 packages/macros/Cargo.toml create mode 100644 packages/macros/Scarb.toml create mode 100644 packages/macros/src/lib.rs create mode 100644 packages/macros/src/logging.rs diff --git a/Scarb.lock b/Scarb.lock index 8beea944..88f69ea5 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -12,9 +12,14 @@ dependencies = [ name = "consensus" version = "0.1.0" dependencies = [ + "raito_macros", "utils", ] +[[package]] +name = "raito_macros" +version = "0.1.0" + [[package]] name = "utils" version = "0.1.0" diff --git a/packages/client/src/main.cairo b/packages/client/src/main.cairo index 34c65fc2..642bd555 100644 --- a/packages/client/src/main.cairo +++ b/packages/client/src/main.cairo @@ -18,9 +18,8 @@ struct Args { fn main(mut arguments: Span) -> ChainState { let Args { mut chain_state, blocks, } = Serde::deserialize(ref arguments) .expect('Failed to deserialize'); - for block in blocks { chain_state = chain_state.validate_and_apply(block).expect('Validation failed'); }; chain_state -} +} \ No newline at end of file diff --git a/packages/client/src/test.cairo b/packages/client/src/test.cairo index a8d03acf..d852a81c 100644 --- a/packages/client/src/test.cairo +++ b/packages/client/src/test.cairo @@ -42,7 +42,6 @@ fn test(mut arguments: Span) { } } }; - if chain_state != expected_chain_state { println!( "FAIL: block={} error='expected state {:?}, actual {:?}'", diff --git a/packages/consensus/Scarb.toml b/packages/consensus/Scarb.toml index 7ca44ee0..75679557 100644 --- a/packages/consensus/Scarb.toml +++ b/packages/consensus/Scarb.toml @@ -5,6 +5,7 @@ edition = "2024_07" [dependencies] utils = { path = "../utils" } +raito_macros = { path = "../macros" } [dev-dependencies] cairo_test.workspace = true @@ -12,3 +13,7 @@ cairo_test.workspace = true [scripts] # TODO: cairo lint lint = "scarb fmt" + +[features] +log_level_trace = [] +log_level_debug = [] \ No newline at end of file diff --git a/packages/consensus/src/lib.cairo b/packages/consensus/src/lib.cairo index 238e5741..6d21393f 100644 --- a/packages/consensus/src/lib.cairo +++ b/packages/consensus/src/lib.cairo @@ -15,3 +15,4 @@ pub mod types { pub mod transaction; pub mod utxo_set; } + diff --git a/packages/consensus/src/validation/timestamp.cairo b/packages/consensus/src/validation/timestamp.cairo index bfd1fcfb..1058d946 100644 --- a/packages/consensus/src/validation/timestamp.cairo +++ b/packages/consensus/src/validation/timestamp.cairo @@ -36,12 +36,25 @@ pub fn validate_timestamp(prev_timestamps: Span, block_time: u32) -> Result } }; }; - + if block_time > *sorted_prev_timestamps.at(sorted_prev_timestamps.len() - 6) { Result::Ok(()) } else { Result::Err("Median time is greater than or equal to block's timestamp") } + +} + +#[cfg(feature: 'log_level_debug')] +fn macro_test(){ + let txid = 1000; + log!("DEBUG", "validating tx: {}", txid); +} + +#[cfg(feature: 'log_level_trace', feature: 'log_level_debug')] +fn log(){ + let txid = 1000; + log!("DEBUG", "validating tx: {}", txid); } /// Update the list of the recent timestamps, removing the oldest and appending the most recent one. @@ -125,4 +138,23 @@ mod tests { let result = validate_timestamp(prev_timestamps, block_time); assert!(result.is_err(), "Median time is greater than block's timestamp"); } + + const TWO_TEN: u128 = pow!(2, 10); + + #[test] + fn test_pow_macro() { + assert_eq!(TWO_TEN, 1024); + assert_eq!(pow!(10, 2), 100); + assert_eq!(pow!(20, 30), 1073741824000000000000000000000000000000_felt252); + assert_eq!( + pow!(2, 255), + 57896044618658097711785492504343953926634992332820282019728792003956564819968_u256 + ); + } + + + #[test] + fn test_log_macro(){ + macro_test(); + } } diff --git a/packages/macros/.gitignore b/packages/macros/.gitignore new file mode 100644 index 00000000..eb5a316c --- /dev/null +++ b/packages/macros/.gitignore @@ -0,0 +1 @@ +target diff --git a/packages/macros/Cargo.toml b/packages/macros/Cargo.toml new file mode 100644 index 00000000..05197593 --- /dev/null +++ b/packages/macros/Cargo.toml @@ -0,0 +1,14 @@ +# Cargo.toml +[package] +name = "raito_macros" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +bigdecimal = "0.4.5" +cairo-lang-macro = "0.1" +cairo-lang-parser = "2.7.0" +cairo-lang-syntax = "2.7.0" \ No newline at end of file diff --git a/packages/macros/Scarb.toml b/packages/macros/Scarb.toml new file mode 100644 index 00000000..83586775 --- /dev/null +++ b/packages/macros/Scarb.toml @@ -0,0 +1,7 @@ +[package] +name = "raito_macros" +version = "0.1.0" +edition = "2024_07" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html +[cairo-plugin] \ No newline at end of file diff --git a/packages/macros/src/lib.rs b/packages/macros/src/lib.rs new file mode 100644 index 00000000..a45608b2 --- /dev/null +++ b/packages/macros/src/lib.rs @@ -0,0 +1 @@ +mod logging; \ No newline at end of file diff --git a/packages/macros/src/logging.rs b/packages/macros/src/logging.rs new file mode 100644 index 00000000..06c4a7b1 --- /dev/null +++ b/packages/macros/src/logging.rs @@ -0,0 +1,195 @@ +use bigdecimal::{num_traits::pow, BigDecimal}; +use cairo_lang_macro::{inline_macro, Diagnostic, ProcMacroResult, TokenStream}; +use cairo_lang_parser::utils::SimpleParserDatabase; +use cairo_lang_syntax::node::{self, kind::SyntaxKind}; + +/// Compile-time power function. +/// +/// Takes two arguments, `x, y`, calculates the value of `x` raised to the power of `y`. +/// +/// ``` +/// const MEGABYTE: u64 = pow!(2, 20); +/// assert_eq!(MEGABYTE, 1048576); +/// ``` + + + +#[inline_macro] +pub fn pow(token_stream: TokenStream) -> ProcMacroResult { + let db = SimpleParserDatabase::default(); + let (parsed, _diag) = db.parse_virtual_with_diagnostics(token_stream); + + let macro_args: Vec = parsed + .descendants(&db) + .filter_map(|node| { + if let SyntaxKind::Arg = node.kind(&db) { + Some(node.get_text(&db)) + } else { + None + } + }) + .collect(); + + if macro_args.len() != 2 { + return ProcMacroResult::new(TokenStream::empty()) + .with_diagnostics(Diagnostic::error("Invalid number of arguments").into()); + } + + let base: BigDecimal = match macro_args[0].parse() { + Ok(val) => val, + Err(_) => { + return ProcMacroResult::new(TokenStream::empty()) + .with_diagnostics(Diagnostic::error("Invalid base value").into()); + } + }; + + let exp: usize = match macro_args[1].parse() { + Ok(val) => val, + Err(_) => { + return ProcMacroResult::new(TokenStream::empty()) + .with_diagnostics(Diagnostic::error("Invalid exponent value").into()); + } + }; + + let result: BigDecimal = pow(base, exp); + + ProcMacroResult::new(TokenStream::new(result.to_string())) +} +#[inline_macro] +pub fn log(token_stream: TokenStream) -> ProcMacroResult { + let db = SimpleParserDatabase::default(); + let (parsed, _diag) = db.parse_virtual_with_diagnostics(token_stream); + + let mut args = parsed.descendants(&db).filter(|node| + matches!(node.kind(&db), + SyntaxKind::Arg ) + ); + + + + // Extract log level + let level = match args.next() { + Some(node) => node.get_text(&db), + _ => { + return ProcMacroResult::new(TokenStream::empty()) + .with_diagnostics(Diagnostic::error("Invalid log level").into()) + }, + }; + + // Validate log level + println!("Level: {}", level); + if level != "\"TRACE\"" && level != "\"DEBUG\"" { + return ProcMacroResult::new(TokenStream::empty()) + .with_diagnostics(Diagnostic::error("Invalid log level. Use TRACE or DEBUG").into()); + } + + // Extract format string + let format_string = match args.next() { + Some(node) => node.get_text(&db), + _ => return ProcMacroResult::new(TokenStream::empty()) + .with_diagnostics(Diagnostic::error("Invalid format string").into()), + }; + + // Extract remaining arguments + let log_args: Vec = args + .filter_map(|node| { + if matches!(node.kind(&db), SyntaxKind::Arg) { + Some(node.get_text(&db)) + } else { + println!("Invalid argument: {:?} {:?}", node.get_text(&db), node.kind(&db)); + None + } + }) + .collect(); + + // Generate the log statement with feature checks + let log_statement = match level.as_str() { + "\"TRACE\"" => { + if log_args.is_empty() { + format!( + "println!(\"{{}}: {{}}\", {}, format!({}))", + "'TRACE'", + format_string + ) + } else { + format!( + "println!(\"{{}}: {{}}\", {}, format!({}, {}))", + "'TRACE'", + format_string, + log_args.join(", ") + ) + } + }, + "\"DEBUG\"" => { + if log_args.is_empty() { + format!( + "println!(\"{{}}: {{}}\", {}, format!({}))", + "'DEBUG'", + format_string + ) + } else { + format!( + "println!(\"{{}}: {{}}\", {}, format!({}, {}))", + "'DEBUG'", + format_string, + log_args.join(", ") + ) + } + }, + _ => unreachable!(), + }; + ProcMacroResult::new(TokenStream::new(log_statement)) +} + + // Helper function to expand macros + +mod tests{ + use super::*; + use cairo_lang_macro::TokenStream; + // Tests for log macro + // Updated tests for log macro + fn expand_macro(macro_fn: fn(TokenStream) -> ProcMacroResult, input: &str) -> String { + let token_stream = TokenStream::new(input.to_string()); + let result = macro_fn(token_stream); + result.token_stream.to_string() + } + + #[test] + fn test_log_macro_debug() { + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "test message: {}", 123)"#); + assert_eq!(expanded, "println!(\"{}: {}\", 'DEBUG', format!(\"test message: {}\", 123))"); + } + + #[test] + fn test_log_macro_trace() { + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("TRACE", "entering function")"#); + assert_eq!(expanded, "println!(\"{}: {}\", 'TRACE', format!(\"entering function\"))"); + } + + #[test] + fn test_log_macro_invalid_level() { + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("INFO", "test message")"#); + assert_eq!(expanded, ""); // Empty TokenStream for error case + } + + #[test] + fn test_log_macro_empty_format() { + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "")"#); + assert_eq!(expanded, "println!(\"{}: {}\", 'DEBUG', format!(\"\"))"); + } + + #[test] + fn test_log_macro_multiple_arguments() { + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "Values: {}, {}, {}", 1, "two", 3.0)"#); + assert_eq!(expanded, "println!(\"{}: {}\", 'DEBUG', format!(\"Values: {}, {}, {}\", 1, \"two\", 3.0))"); + } + + // New test for exact string matching + #[test] + fn test_log_macro_exact_string() { + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "Exact {} string", "test")"#); + assert_eq!(expanded, "println!(\"{}: {}\", 'DEBUG', format!(\"Exact {} string\", \"test\"))"); + } + + } + \ No newline at end of file From 4509808a697b9f793393c32a8e621f87c2f4b874 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Thu, 19 Sep 2024 14:09:23 +0700 Subject: [PATCH 2/7] impl logging macros --- Scarb.toml | 1 + packages/client/src/main.cairo | 2 +- packages/consensus/Scarb.toml | 2 + packages/consensus/src/lib.cairo | 2 + packages/consensus/src/logging.cairo | 17 ++ .../consensus/src/validation/timestamp.cairo | 32 +--- packages/macros/Scarb.toml | 2 +- packages/macros/src/logging.rs | 176 ++++++------------ 8 files changed, 85 insertions(+), 149 deletions(-) create mode 100644 packages/consensus/src/logging.cairo diff --git a/Scarb.toml b/Scarb.toml index 95012dcc..93c10dc0 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -11,3 +11,4 @@ license-file = "LICENSE" [workspace.dependencies] cairo_test = "2.8.0" + diff --git a/packages/client/src/main.cairo b/packages/client/src/main.cairo index 642bd555..4655d7d1 100644 --- a/packages/client/src/main.cairo +++ b/packages/client/src/main.cairo @@ -22,4 +22,4 @@ fn main(mut arguments: Span) -> ChainState { chain_state = chain_state.validate_and_apply(block).expect('Validation failed'); }; chain_state -} \ No newline at end of file +} diff --git a/packages/consensus/Scarb.toml b/packages/consensus/Scarb.toml index 75679557..def811b4 100644 --- a/packages/consensus/Scarb.toml +++ b/packages/consensus/Scarb.toml @@ -15,5 +15,7 @@ cairo_test.workspace = true lint = "scarb fmt" [features] +default = ["log_level_none"] +log_level_none = [] log_level_trace = [] log_level_debug = [] \ No newline at end of file diff --git a/packages/consensus/src/lib.cairo b/packages/consensus/src/lib.cairo index 6d21393f..3dd02bd0 100644 --- a/packages/consensus/src/lib.cairo +++ b/packages/consensus/src/lib.cairo @@ -16,3 +16,5 @@ pub mod types { pub mod utxo_set; } +pub mod logging; + diff --git a/packages/consensus/src/logging.cairo b/packages/consensus/src/logging.cairo new file mode 100644 index 00000000..053ab490 --- /dev/null +++ b/packages/consensus/src/logging.cairo @@ -0,0 +1,17 @@ +#[cfg(feature: 'log_level_trace')] +pub const LOG_LEVEL_TRACE: bool = true; + +#[cfg(feature: 'log_level_trace')] +pub const LOG_LEVEL_DEBUG: bool = true; + +#[cfg(feature: 'log_level_debug')] +pub const LOG_LEVEL_TRACE: bool = false; + +#[cfg(feature: 'log_level_debug')] +pub const LOG_LEVEL_DEBUG: bool = true; + +#[cfg(feature: 'log_level_none')] +pub const LOG_LEVEL_TRACE: bool = false; + +#[cfg(feature: 'log_level_none')] +pub const LOG_LEVEL_DEBUG: bool = false; diff --git a/packages/consensus/src/validation/timestamp.cairo b/packages/consensus/src/validation/timestamp.cairo index 1058d946..3e555261 100644 --- a/packages/consensus/src/validation/timestamp.cairo +++ b/packages/consensus/src/validation/timestamp.cairo @@ -1,7 +1,6 @@ //! Block time validation helpers. //! //! Read more: https://learnmeabitcoin.com/technical/block/time/ - /// Check that the block time is greater than the median of the 11 most recent timestamps. pub fn validate_timestamp(prev_timestamps: Span, block_time: u32) -> Result<(), ByteArray> { // Sort the last 11 timestamps @@ -36,24 +35,23 @@ pub fn validate_timestamp(prev_timestamps: Span, block_time: u32) -> Result } }; }; - + if block_time > *sorted_prev_timestamps.at(sorted_prev_timestamps.len() - 6) { Result::Ok(()) } else { Result::Err("Median time is greater than or equal to block's timestamp") } - } #[cfg(feature: 'log_level_debug')] -fn macro_test(){ - let txid = 1000; +fn macro_test() { + let txid = 1000; log!("DEBUG", "validating tx: {}", txid); } #[cfg(feature: 'log_level_trace', feature: 'log_level_debug')] -fn log(){ - let txid = 1000; +fn log(log_level: ByteArray, format_array: ByteArray,) { + let txid = 1000; log!("DEBUG", "validating tx: {}", txid); } @@ -68,7 +66,6 @@ pub fn next_prev_timestamps(prev_timestamps: Span, block_time: u32) -> Span #[cfg(test)] mod tests { use super::{validate_timestamp, next_prev_timestamps}; - #[test] fn test_validate_timestamp() { let prev_timestamps = array![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].span(); @@ -138,23 +135,4 @@ mod tests { let result = validate_timestamp(prev_timestamps, block_time); assert!(result.is_err(), "Median time is greater than block's timestamp"); } - - const TWO_TEN: u128 = pow!(2, 10); - - #[test] - fn test_pow_macro() { - assert_eq!(TWO_TEN, 1024); - assert_eq!(pow!(10, 2), 100); - assert_eq!(pow!(20, 30), 1073741824000000000000000000000000000000_felt252); - assert_eq!( - pow!(2, 255), - 57896044618658097711785492504343953926634992332820282019728792003956564819968_u256 - ); - } - - - #[test] - fn test_log_macro(){ - macro_test(); - } } diff --git a/packages/macros/Scarb.toml b/packages/macros/Scarb.toml index 83586775..66fff079 100644 --- a/packages/macros/Scarb.toml +++ b/packages/macros/Scarb.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2024_07" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html -[cairo-plugin] \ No newline at end of file +[cairo-plugin] diff --git a/packages/macros/src/logging.rs b/packages/macros/src/logging.rs index 06c4a7b1..ea8d1c75 100644 --- a/packages/macros/src/logging.rs +++ b/packages/macros/src/logging.rs @@ -3,91 +3,30 @@ use cairo_lang_macro::{inline_macro, Diagnostic, ProcMacroResult, TokenStream}; use cairo_lang_parser::utils::SimpleParserDatabase; use cairo_lang_syntax::node::{self, kind::SyntaxKind}; -/// Compile-time power function. -/// -/// Takes two arguments, `x, y`, calculates the value of `x` raised to the power of `y`. -/// -/// ``` -/// const MEGABYTE: u64 = pow!(2, 20); -/// assert_eq!(MEGABYTE, 1048576); -/// ``` - - - -#[inline_macro] -pub fn pow(token_stream: TokenStream) -> ProcMacroResult { - let db = SimpleParserDatabase::default(); - let (parsed, _diag) = db.parse_virtual_with_diagnostics(token_stream); - - let macro_args: Vec = parsed - .descendants(&db) - .filter_map(|node| { - if let SyntaxKind::Arg = node.kind(&db) { - Some(node.get_text(&db)) - } else { - None - } - }) - .collect(); - - if macro_args.len() != 2 { - return ProcMacroResult::new(TokenStream::empty()) - .with_diagnostics(Diagnostic::error("Invalid number of arguments").into()); - } - - let base: BigDecimal = match macro_args[0].parse() { - Ok(val) => val, - Err(_) => { - return ProcMacroResult::new(TokenStream::empty()) - .with_diagnostics(Diagnostic::error("Invalid base value").into()); - } - }; - - let exp: usize = match macro_args[1].parse() { - Ok(val) => val, - Err(_) => { - return ProcMacroResult::new(TokenStream::empty()) - .with_diagnostics(Diagnostic::error("Invalid exponent value").into()); - } - }; - - let result: BigDecimal = pow(base, exp); - - ProcMacroResult::new(TokenStream::new(result.to_string())) -} #[inline_macro] pub fn log(token_stream: TokenStream) -> ProcMacroResult { let db = SimpleParserDatabase::default(); let (parsed, _diag) = db.parse_virtual_with_diagnostics(token_stream); let mut args = parsed.descendants(&db).filter(|node| - matches!(node.kind(&db), - SyntaxKind::Arg ) + matches!(node.kind(&db), SyntaxKind::Arg) ); - - // Extract log level let level = match args.next() { - Some(node) => node.get_text(&db), - _ => { - return ProcMacroResult::new(TokenStream::empty()) - .with_diagnostics(Diagnostic::error("Invalid log level").into()) - }, + Some(node) => node.get_text(&db), + _ => return create_error_result("Invalid log level"), }; // Validate log level - println!("Level: {}", level); - if level != "\"TRACE\"" && level != "\"DEBUG\"" { - return ProcMacroResult::new(TokenStream::empty()) - .with_diagnostics(Diagnostic::error("Invalid log level. Use TRACE or DEBUG").into()); + if !["\"TRACE\"", "\"DEBUG\""].contains(&level.as_str()) { + return create_error_result("Invalid log level. Use TRACE or DEBUG"); } // Extract format string let format_string = match args.next() { Some(node) => node.get_text(&db), - _ => return ProcMacroResult::new(TokenStream::empty()) - .with_diagnostics(Diagnostic::error("Invalid format string").into()), + _ => return create_error_result("Invalid format string"), }; // Extract remaining arguments @@ -102,52 +41,52 @@ pub fn log(token_stream: TokenStream) -> ProcMacroResult { }) .collect(); - // Generate the log statement with feature checks - let log_statement = match level.as_str() { - "\"TRACE\"" => { - if log_args.is_empty() { - format!( - "println!(\"{{}}: {{}}\", {}, format!({}))", - "'TRACE'", - format_string - ) - } else { - format!( - "println!(\"{{}}: {{}}\", {}, format!({}, {}))", - "'TRACE'", - format_string, - log_args.join(", ") - ) - } - }, - "\"DEBUG\"" => { - if log_args.is_empty() { - format!( - "println!(\"{{}}: {{}}\", {}, format!({}))", - "'DEBUG'", - format_string - ) - } else { - format!( - "println!(\"{{}}: {{}}\", {}, format!({}, {}))", - "'DEBUG'", - format_string, - log_args.join(", ") - ) - } - }, - _ => unreachable!(), - }; + // Generate the log statement + let log_statement = generate_log_statement(&level, &format_string, &log_args); + + println!("Log statement: {}", log_statement); ProcMacroResult::new(TokenStream::new(log_statement)) } - // Helper function to expand macros +fn create_error_result(message: &str) -> ProcMacroResult { + ProcMacroResult::new(TokenStream::empty()) + .with_diagnostics(Diagnostic::error(message).into()) +} + +fn generate_log_statement(level: &str, format_string: &str, log_args: &[String]) -> String { + let level_str = level.trim_matches('"'); + let condition = match level_str { + "TRACE" => "LOG_LEVEL_TRACE", + "DEBUG" => "LOG_LEVEL_DEBUG", + _ => unreachable!(), + }; + let level_str = format!("{}", level); + let print_statement = if log_args.is_empty() { + format!( + "println!(\"{{}}: {{}}\", format!({}), format!({}))", + level_str, + format_string + ) + } else { + format!( + "println!(\"{{}}: {{}}\", format!({}), format!({}, {}))", + level_str, + format_string, + log_args.join(", ") + ) + }; -mod tests{ + format!( + "if crate::logging::{} {{ {} }}", + condition, + print_statement + ) +} +mod tests { use super::*; use cairo_lang_macro::TokenStream; - // Tests for log macro - // Updated tests for log macro + + // Helper function to expand macros fn expand_macro(macro_fn: fn(TokenStream) -> ProcMacroResult, input: &str) -> String { let token_stream = TokenStream::new(input.to_string()); let result = macro_fn(token_stream); @@ -156,14 +95,14 @@ mod tests{ #[test] fn test_log_macro_debug() { - let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "test message: {}", 123)"#); - assert_eq!(expanded, "println!(\"{}: {}\", 'DEBUG', format!(\"test message: {}\", 123))"); + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "test message: {}", '123')"#); + assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("test message: {}", '123')) }"#); } #[test] fn test_log_macro_trace() { let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("TRACE", "entering function")"#); - assert_eq!(expanded, "println!(\"{}: {}\", 'TRACE', format!(\"entering function\"))"); + assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_TRACE { println!("{}: {}", format!("TRACE"), format!("entering function")) }"#); } #[test] @@ -174,22 +113,19 @@ mod tests{ #[test] fn test_log_macro_empty_format() { - let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "")"#); - assert_eq!(expanded, "println!(\"{}: {}\", 'DEBUG', format!(\"\"))"); + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", '')"#); + assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!('')) }"#); } #[test] fn test_log_macro_multiple_arguments() { - let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "Values: {}, {}, {}", 1, "two", 3.0)"#); - assert_eq!(expanded, "println!(\"{}: {}\", 'DEBUG', format!(\"Values: {}, {}, {}\", 1, \"two\", 3.0))"); + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "Values: {}, {}, {}", '1', '2', '3')"#); + assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Values: {}, {}, {}", '1', '2', '3')) }"#); } - // New test for exact string matching #[test] fn test_log_macro_exact_string() { - let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "Exact {} string", "test")"#); - assert_eq!(expanded, "println!(\"{}: {}\", 'DEBUG', format!(\"Exact {} string\", \"test\"))"); + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "Exact {} string", 'test')"#); + assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Exact {} string", 'test')) }"#); } - - } - \ No newline at end of file +} \ No newline at end of file From 0c7889793b8f8abf9fb735e9cdb9d36220250e44 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Thu, 19 Sep 2024 14:11:08 +0700 Subject: [PATCH 3/7] lint --- packages/macros/src/logging.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/macros/src/logging.rs b/packages/macros/src/logging.rs index ea8d1c75..4d2ec521 100644 --- a/packages/macros/src/logging.rs +++ b/packages/macros/src/logging.rs @@ -1,7 +1,6 @@ -use bigdecimal::{num_traits::pow, BigDecimal}; use cairo_lang_macro::{inline_macro, Diagnostic, ProcMacroResult, TokenStream}; use cairo_lang_parser::utils::SimpleParserDatabase; -use cairo_lang_syntax::node::{self, kind::SyntaxKind}; +use cairo_lang_syntax::node::{kind::SyntaxKind}; #[inline_macro] pub fn log(token_stream: TokenStream) -> ProcMacroResult { @@ -87,6 +86,7 @@ mod tests { use cairo_lang_macro::TokenStream; // Helper function to expand macros + #[allow(unused)] fn expand_macro(macro_fn: fn(TokenStream) -> ProcMacroResult, input: &str) -> String { let token_stream = TokenStream::new(input.to_string()); let result = macro_fn(token_stream); From 5cabfd8f2d7de842337bfb234b362fd30abad97f Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Sun, 22 Sep 2024 16:33:57 +0700 Subject: [PATCH 4/7] refactor --- Scarb.lock | 6 +- packages/consensus/Scarb.toml | 4 +- packages/consensus/src/logging.cairo | 13 ++ .../consensus/src/validation/timestamp.cairo | 12 -- packages/logging/.gitignore | 1 + packages/logging/Cargo.toml | 14 ++ packages/logging/Scarb.toml | 14 ++ packages/logging/src/lib.cairo | 1 + packages/logging/src/lib.rs | 1 + packages/logging/src/log.cairo | 17 +++ packages/logging/src/logging.rs | 131 ++++++++++++++++++ 11 files changed, 199 insertions(+), 15 deletions(-) create mode 100644 packages/logging/.gitignore create mode 100644 packages/logging/Cargo.toml create mode 100644 packages/logging/Scarb.toml create mode 100644 packages/logging/src/lib.cairo create mode 100644 packages/logging/src/lib.rs create mode 100644 packages/logging/src/log.cairo create mode 100644 packages/logging/src/logging.rs diff --git a/Scarb.lock b/Scarb.lock index 88f69ea5..90f33637 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -12,10 +12,14 @@ dependencies = [ name = "consensus" version = "0.1.0" dependencies = [ - "raito_macros", + "raito_logging", "utils", ] +[[package]] +name = "raito_logging" +version = "0.1.0" + [[package]] name = "raito_macros" version = "0.1.0" diff --git a/packages/consensus/Scarb.toml b/packages/consensus/Scarb.toml index def811b4..4fb64cdf 100644 --- a/packages/consensus/Scarb.toml +++ b/packages/consensus/Scarb.toml @@ -5,7 +5,7 @@ edition = "2024_07" [dependencies] utils = { path = "../utils" } -raito_macros = { path = "../macros" } +raito_logging = { path = "../logging" } [dev-dependencies] cairo_test.workspace = true @@ -18,4 +18,4 @@ lint = "scarb fmt" default = ["log_level_none"] log_level_none = [] log_level_trace = [] -log_level_debug = [] \ No newline at end of file +log_level_debug = [] diff --git a/packages/consensus/src/logging.cairo b/packages/consensus/src/logging.cairo index 053ab490..368f203a 100644 --- a/packages/consensus/src/logging.cairo +++ b/packages/consensus/src/logging.cairo @@ -15,3 +15,16 @@ pub const LOG_LEVEL_TRACE: bool = false; #[cfg(feature: 'log_level_none')] pub const LOG_LEVEL_DEBUG: bool = false; + +mod tests{ + use super::{LOG_LEVEL_TRACE, LOG_LEVEL_DEBUG}; + #[test] + fn test_log_level_debug() { + log!("DEBUG", "log! works") + } + + #[test] + fn test_log_level_trace() { + log!("DEBUG", "log! works") + } +} \ No newline at end of file diff --git a/packages/consensus/src/validation/timestamp.cairo b/packages/consensus/src/validation/timestamp.cairo index 3e555261..1446207d 100644 --- a/packages/consensus/src/validation/timestamp.cairo +++ b/packages/consensus/src/validation/timestamp.cairo @@ -43,18 +43,6 @@ pub fn validate_timestamp(prev_timestamps: Span, block_time: u32) -> Result } } -#[cfg(feature: 'log_level_debug')] -fn macro_test() { - let txid = 1000; - log!("DEBUG", "validating tx: {}", txid); -} - -#[cfg(feature: 'log_level_trace', feature: 'log_level_debug')] -fn log(log_level: ByteArray, format_array: ByteArray,) { - let txid = 1000; - log!("DEBUG", "validating tx: {}", txid); -} - /// Update the list of the recent timestamps, removing the oldest and appending the most recent one. pub fn next_prev_timestamps(prev_timestamps: Span, block_time: u32) -> Span { let mut timestamps: Array = prev_timestamps.into(); diff --git a/packages/logging/.gitignore b/packages/logging/.gitignore new file mode 100644 index 00000000..eb5a316c --- /dev/null +++ b/packages/logging/.gitignore @@ -0,0 +1 @@ +target diff --git a/packages/logging/Cargo.toml b/packages/logging/Cargo.toml new file mode 100644 index 00000000..d2bd244d --- /dev/null +++ b/packages/logging/Cargo.toml @@ -0,0 +1,14 @@ +# Cargo.toml +[package] +name = "raito_logging" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +bigdecimal = "0.4.5" +cairo-lang-macro = "0.1" +cairo-lang-parser = "2.7.0" +cairo-lang-syntax = "2.7.0" diff --git a/packages/logging/Scarb.toml b/packages/logging/Scarb.toml new file mode 100644 index 00000000..9f47c6fb --- /dev/null +++ b/packages/logging/Scarb.toml @@ -0,0 +1,14 @@ +[package] +name = "raito_logging" +version = "0.1.0" +edition = "2024_07" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html +[cairo-plugin] + + +[features] +default = ["log_level_none"] +log_level_none = [] +log_level_trace = [] +log_level_debug = [] diff --git a/packages/logging/src/lib.cairo b/packages/logging/src/lib.cairo new file mode 100644 index 00000000..7e8abe20 --- /dev/null +++ b/packages/logging/src/lib.cairo @@ -0,0 +1 @@ +pub mod log; \ No newline at end of file diff --git a/packages/logging/src/lib.rs b/packages/logging/src/lib.rs new file mode 100644 index 00000000..31348d2f --- /dev/null +++ b/packages/logging/src/lib.rs @@ -0,0 +1 @@ +pub mod logging; diff --git a/packages/logging/src/log.cairo b/packages/logging/src/log.cairo new file mode 100644 index 00000000..053ab490 --- /dev/null +++ b/packages/logging/src/log.cairo @@ -0,0 +1,17 @@ +#[cfg(feature: 'log_level_trace')] +pub const LOG_LEVEL_TRACE: bool = true; + +#[cfg(feature: 'log_level_trace')] +pub const LOG_LEVEL_DEBUG: bool = true; + +#[cfg(feature: 'log_level_debug')] +pub const LOG_LEVEL_TRACE: bool = false; + +#[cfg(feature: 'log_level_debug')] +pub const LOG_LEVEL_DEBUG: bool = true; + +#[cfg(feature: 'log_level_none')] +pub const LOG_LEVEL_TRACE: bool = false; + +#[cfg(feature: 'log_level_none')] +pub const LOG_LEVEL_DEBUG: bool = false; diff --git a/packages/logging/src/logging.rs b/packages/logging/src/logging.rs new file mode 100644 index 00000000..4d2ec521 --- /dev/null +++ b/packages/logging/src/logging.rs @@ -0,0 +1,131 @@ +use cairo_lang_macro::{inline_macro, Diagnostic, ProcMacroResult, TokenStream}; +use cairo_lang_parser::utils::SimpleParserDatabase; +use cairo_lang_syntax::node::{kind::SyntaxKind}; + +#[inline_macro] +pub fn log(token_stream: TokenStream) -> ProcMacroResult { + let db = SimpleParserDatabase::default(); + let (parsed, _diag) = db.parse_virtual_with_diagnostics(token_stream); + + let mut args = parsed.descendants(&db).filter(|node| + matches!(node.kind(&db), SyntaxKind::Arg) + ); + + // Extract log level + let level = match args.next() { + Some(node) => node.get_text(&db), + _ => return create_error_result("Invalid log level"), + }; + + // Validate log level + if !["\"TRACE\"", "\"DEBUG\""].contains(&level.as_str()) { + return create_error_result("Invalid log level. Use TRACE or DEBUG"); + } + + // Extract format string + let format_string = match args.next() { + Some(node) => node.get_text(&db), + _ => return create_error_result("Invalid format string"), + }; + + // Extract remaining arguments + let log_args: Vec = args + .filter_map(|node| { + if matches!(node.kind(&db), SyntaxKind::Arg) { + Some(node.get_text(&db)) + } else { + println!("Invalid argument: {:?} {:?}", node.get_text(&db), node.kind(&db)); + None + } + }) + .collect(); + + // Generate the log statement + let log_statement = generate_log_statement(&level, &format_string, &log_args); + + println!("Log statement: {}", log_statement); + ProcMacroResult::new(TokenStream::new(log_statement)) +} + +fn create_error_result(message: &str) -> ProcMacroResult { + ProcMacroResult::new(TokenStream::empty()) + .with_diagnostics(Diagnostic::error(message).into()) +} + +fn generate_log_statement(level: &str, format_string: &str, log_args: &[String]) -> String { + let level_str = level.trim_matches('"'); + let condition = match level_str { + "TRACE" => "LOG_LEVEL_TRACE", + "DEBUG" => "LOG_LEVEL_DEBUG", + _ => unreachable!(), + }; + let level_str = format!("{}", level); + let print_statement = if log_args.is_empty() { + format!( + "println!(\"{{}}: {{}}\", format!({}), format!({}))", + level_str, + format_string + ) + } else { + format!( + "println!(\"{{}}: {{}}\", format!({}), format!({}, {}))", + level_str, + format_string, + log_args.join(", ") + ) + }; + + format!( + "if crate::logging::{} {{ {} }}", + condition, + print_statement + ) +} +mod tests { + use super::*; + use cairo_lang_macro::TokenStream; + + // Helper function to expand macros + #[allow(unused)] + fn expand_macro(macro_fn: fn(TokenStream) -> ProcMacroResult, input: &str) -> String { + let token_stream = TokenStream::new(input.to_string()); + let result = macro_fn(token_stream); + result.token_stream.to_string() + } + + #[test] + fn test_log_macro_debug() { + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "test message: {}", '123')"#); + assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("test message: {}", '123')) }"#); + } + + #[test] + fn test_log_macro_trace() { + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("TRACE", "entering function")"#); + assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_TRACE { println!("{}: {}", format!("TRACE"), format!("entering function")) }"#); + } + + #[test] + fn test_log_macro_invalid_level() { + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("INFO", "test message")"#); + assert_eq!(expanded, ""); // Empty TokenStream for error case + } + + #[test] + fn test_log_macro_empty_format() { + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", '')"#); + assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!('')) }"#); + } + + #[test] + fn test_log_macro_multiple_arguments() { + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "Values: {}, {}, {}", '1', '2', '3')"#); + assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Values: {}, {}, {}", '1', '2', '3')) }"#); + } + + #[test] + fn test_log_macro_exact_string() { + let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "Exact {} string", 'test')"#); + assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Exact {} string", 'test')) }"#); + } +} \ No newline at end of file From 5e061edf70cdba313fc24db5bc0dbc5cd010dc10 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Sun, 22 Sep 2024 16:55:13 +0700 Subject: [PATCH 5/7] refactor, add cairo test --- packages/consensus/src/logging.cairo | 2 +- packages/logging/src/logging.rs | 71 +++++++++------ packages/macros/.gitignore | 1 - packages/macros/Cargo.toml | 14 --- packages/macros/Scarb.toml | 7 -- packages/macros/src/lib.rs | 1 - packages/macros/src/logging.rs | 131 --------------------------- 7 files changed, 45 insertions(+), 182 deletions(-) delete mode 100644 packages/macros/.gitignore delete mode 100644 packages/macros/Cargo.toml delete mode 100644 packages/macros/Scarb.toml delete mode 100644 packages/macros/src/lib.rs delete mode 100644 packages/macros/src/logging.rs diff --git a/packages/consensus/src/logging.cairo b/packages/consensus/src/logging.cairo index 368f203a..2cb9b8a4 100644 --- a/packages/consensus/src/logging.cairo +++ b/packages/consensus/src/logging.cairo @@ -16,8 +16,8 @@ pub const LOG_LEVEL_TRACE: bool = false; #[cfg(feature: 'log_level_none')] pub const LOG_LEVEL_DEBUG: bool = false; +#[cfg(test)] mod tests{ - use super::{LOG_LEVEL_TRACE, LOG_LEVEL_DEBUG}; #[test] fn test_log_level_debug() { log!("DEBUG", "log! works") diff --git a/packages/logging/src/logging.rs b/packages/logging/src/logging.rs index 4d2ec521..c1d9d078 100644 --- a/packages/logging/src/logging.rs +++ b/packages/logging/src/logging.rs @@ -1,15 +1,15 @@ use cairo_lang_macro::{inline_macro, Diagnostic, ProcMacroResult, TokenStream}; use cairo_lang_parser::utils::SimpleParserDatabase; -use cairo_lang_syntax::node::{kind::SyntaxKind}; +use cairo_lang_syntax::node::kind::SyntaxKind; #[inline_macro] pub fn log(token_stream: TokenStream) -> ProcMacroResult { let db = SimpleParserDatabase::default(); let (parsed, _diag) = db.parse_virtual_with_diagnostics(token_stream); - let mut args = parsed.descendants(&db).filter(|node| - matches!(node.kind(&db), SyntaxKind::Arg) - ); + let mut args = parsed + .descendants(&db) + .filter(|node| matches!(node.kind(&db), SyntaxKind::Arg)); // Extract log level let level = match args.next() { @@ -34,22 +34,20 @@ pub fn log(token_stream: TokenStream) -> ProcMacroResult { if matches!(node.kind(&db), SyntaxKind::Arg) { Some(node.get_text(&db)) } else { - println!("Invalid argument: {:?} {:?}", node.get_text(&db), node.kind(&db)); - None + return create_error_result("Invalid log argument"); } }) .collect(); // Generate the log statement let log_statement = generate_log_statement(&level, &format_string, &log_args); - + println!("Log statement: {}", log_statement); ProcMacroResult::new(TokenStream::new(log_statement)) } fn create_error_result(message: &str) -> ProcMacroResult { - ProcMacroResult::new(TokenStream::empty()) - .with_diagnostics(Diagnostic::error(message).into()) + ProcMacroResult::new(TokenStream::empty()).with_diagnostics(Diagnostic::error(message).into()) } fn generate_log_statement(level: &str, format_string: &str, log_args: &[String]) -> String { @@ -63,8 +61,7 @@ fn generate_log_statement(level: &str, format_string: &str, log_args: &[String]) let print_statement = if log_args.is_empty() { format!( "println!(\"{{}}: {{}}\", format!({}), format!({}))", - level_str, - format_string + level_str, format_string ) } else { format!( @@ -75,11 +72,7 @@ fn generate_log_statement(level: &str, format_string: &str, log_args: &[String]) ) }; - format!( - "if crate::logging::{} {{ {} }}", - condition, - print_statement - ) + format!("if crate::logging::{} {{ {} }}", condition, print_statement) } mod tests { use super::*; @@ -92,40 +85,64 @@ mod tests { let result = macro_fn(token_stream); result.token_stream.to_string() } - + #[test] fn test_log_macro_debug() { - let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "test message: {}", '123')"#); - assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("test message: {}", '123')) }"#); + let expanded = expand_macro( + log_02lvnd9pht92k, + r#"log!("DEBUG", "test message: {}", '123')"#, + ); + assert_eq!( + expanded, + r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("test message: {}", '123')) }"# + ); } #[test] fn test_log_macro_trace() { let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("TRACE", "entering function")"#); - assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_TRACE { println!("{}: {}", format!("TRACE"), format!("entering function")) }"#); + assert_eq!( + expanded, + r#"if crate::logging::LOG_LEVEL_TRACE { println!("{}: {}", format!("TRACE"), format!("entering function")) }"# + ); } #[test] fn test_log_macro_invalid_level() { let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("INFO", "test message")"#); - assert_eq!(expanded, ""); // Empty TokenStream for error case + assert_eq!(expanded, ""); // Empty TokenStream for error case } #[test] fn test_log_macro_empty_format() { let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", '')"#); - assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!('')) }"#); + assert_eq!( + expanded, + r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!('')) }"# + ); } #[test] fn test_log_macro_multiple_arguments() { - let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "Values: {}, {}, {}", '1', '2', '3')"#); - assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Values: {}, {}, {}", '1', '2', '3')) }"#); + let expanded = expand_macro( + log_02lvnd9pht92k, + r#"log!("DEBUG", "Values: {}, {}, {}", '1', '2', '3')"#, + ); + assert_eq!( + expanded, + r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Values: {}, {}, {}", '1', '2', '3')) }"# + ); } #[test] fn test_log_macro_exact_string() { - let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "Exact {} string", 'test')"#); - assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Exact {} string", 'test')) }"#); + let expanded = expand_macro( + log_02lvnd9pht92k, + r#"log!("DEBUG", "Exact {} string", 'test')"#, + ); + assert_eq!( + expanded, + r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Exact {} string", 'test')) }"# + ); } -} \ No newline at end of file +} diff --git a/packages/macros/.gitignore b/packages/macros/.gitignore deleted file mode 100644 index eb5a316c..00000000 --- a/packages/macros/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target diff --git a/packages/macros/Cargo.toml b/packages/macros/Cargo.toml deleted file mode 100644 index 05197593..00000000 --- a/packages/macros/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -# Cargo.toml -[package] -name = "raito_macros" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -bigdecimal = "0.4.5" -cairo-lang-macro = "0.1" -cairo-lang-parser = "2.7.0" -cairo-lang-syntax = "2.7.0" \ No newline at end of file diff --git a/packages/macros/Scarb.toml b/packages/macros/Scarb.toml deleted file mode 100644 index 66fff079..00000000 --- a/packages/macros/Scarb.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "raito_macros" -version = "0.1.0" -edition = "2024_07" - -# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html -[cairo-plugin] diff --git a/packages/macros/src/lib.rs b/packages/macros/src/lib.rs deleted file mode 100644 index a45608b2..00000000 --- a/packages/macros/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -mod logging; \ No newline at end of file diff --git a/packages/macros/src/logging.rs b/packages/macros/src/logging.rs deleted file mode 100644 index 4d2ec521..00000000 --- a/packages/macros/src/logging.rs +++ /dev/null @@ -1,131 +0,0 @@ -use cairo_lang_macro::{inline_macro, Diagnostic, ProcMacroResult, TokenStream}; -use cairo_lang_parser::utils::SimpleParserDatabase; -use cairo_lang_syntax::node::{kind::SyntaxKind}; - -#[inline_macro] -pub fn log(token_stream: TokenStream) -> ProcMacroResult { - let db = SimpleParserDatabase::default(); - let (parsed, _diag) = db.parse_virtual_with_diagnostics(token_stream); - - let mut args = parsed.descendants(&db).filter(|node| - matches!(node.kind(&db), SyntaxKind::Arg) - ); - - // Extract log level - let level = match args.next() { - Some(node) => node.get_text(&db), - _ => return create_error_result("Invalid log level"), - }; - - // Validate log level - if !["\"TRACE\"", "\"DEBUG\""].contains(&level.as_str()) { - return create_error_result("Invalid log level. Use TRACE or DEBUG"); - } - - // Extract format string - let format_string = match args.next() { - Some(node) => node.get_text(&db), - _ => return create_error_result("Invalid format string"), - }; - - // Extract remaining arguments - let log_args: Vec = args - .filter_map(|node| { - if matches!(node.kind(&db), SyntaxKind::Arg) { - Some(node.get_text(&db)) - } else { - println!("Invalid argument: {:?} {:?}", node.get_text(&db), node.kind(&db)); - None - } - }) - .collect(); - - // Generate the log statement - let log_statement = generate_log_statement(&level, &format_string, &log_args); - - println!("Log statement: {}", log_statement); - ProcMacroResult::new(TokenStream::new(log_statement)) -} - -fn create_error_result(message: &str) -> ProcMacroResult { - ProcMacroResult::new(TokenStream::empty()) - .with_diagnostics(Diagnostic::error(message).into()) -} - -fn generate_log_statement(level: &str, format_string: &str, log_args: &[String]) -> String { - let level_str = level.trim_matches('"'); - let condition = match level_str { - "TRACE" => "LOG_LEVEL_TRACE", - "DEBUG" => "LOG_LEVEL_DEBUG", - _ => unreachable!(), - }; - let level_str = format!("{}", level); - let print_statement = if log_args.is_empty() { - format!( - "println!(\"{{}}: {{}}\", format!({}), format!({}))", - level_str, - format_string - ) - } else { - format!( - "println!(\"{{}}: {{}}\", format!({}), format!({}, {}))", - level_str, - format_string, - log_args.join(", ") - ) - }; - - format!( - "if crate::logging::{} {{ {} }}", - condition, - print_statement - ) -} -mod tests { - use super::*; - use cairo_lang_macro::TokenStream; - - // Helper function to expand macros - #[allow(unused)] - fn expand_macro(macro_fn: fn(TokenStream) -> ProcMacroResult, input: &str) -> String { - let token_stream = TokenStream::new(input.to_string()); - let result = macro_fn(token_stream); - result.token_stream.to_string() - } - - #[test] - fn test_log_macro_debug() { - let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "test message: {}", '123')"#); - assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("test message: {}", '123')) }"#); - } - - #[test] - fn test_log_macro_trace() { - let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("TRACE", "entering function")"#); - assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_TRACE { println!("{}: {}", format!("TRACE"), format!("entering function")) }"#); - } - - #[test] - fn test_log_macro_invalid_level() { - let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("INFO", "test message")"#); - assert_eq!(expanded, ""); // Empty TokenStream for error case - } - - #[test] - fn test_log_macro_empty_format() { - let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", '')"#); - assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!('')) }"#); - } - - #[test] - fn test_log_macro_multiple_arguments() { - let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "Values: {}, {}, {}", '1', '2', '3')"#); - assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Values: {}, {}, {}", '1', '2', '3')) }"#); - } - - #[test] - fn test_log_macro_exact_string() { - let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", "Exact {} string", 'test')"#); - assert_eq!(expanded, r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Exact {} string", 'test')) }"#); - } -} \ No newline at end of file From ce7ff20fa4343f6a1ce53bf7aa71c67be8899a6c Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Sun, 22 Sep 2024 19:52:08 +0700 Subject: [PATCH 6/7] fmt --- Scarb.lock | 4 ---- packages/consensus/src/logging.cairo | 4 ++-- packages/logging/src/lib.cairo | 2 +- packages/logging/src/logging.rs | 12 ++++++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Scarb.lock b/Scarb.lock index 90f33637..22cc0a72 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -20,10 +20,6 @@ dependencies = [ name = "raito_logging" version = "0.1.0" -[[package]] -name = "raito_macros" -version = "0.1.0" - [[package]] name = "utils" version = "0.1.0" diff --git a/packages/consensus/src/logging.cairo b/packages/consensus/src/logging.cairo index 2cb9b8a4..4a30c149 100644 --- a/packages/consensus/src/logging.cairo +++ b/packages/consensus/src/logging.cairo @@ -17,7 +17,7 @@ pub const LOG_LEVEL_TRACE: bool = false; pub const LOG_LEVEL_DEBUG: bool = false; #[cfg(test)] -mod tests{ +mod tests { #[test] fn test_log_level_debug() { log!("DEBUG", "log! works") @@ -27,4 +27,4 @@ mod tests{ fn test_log_level_trace() { log!("DEBUG", "log! works") } -} \ No newline at end of file +} diff --git a/packages/logging/src/lib.cairo b/packages/logging/src/lib.cairo index 7e8abe20..f4ee9bc8 100644 --- a/packages/logging/src/lib.cairo +++ b/packages/logging/src/lib.cairo @@ -1 +1 @@ -pub mod log; \ No newline at end of file +pub mod log; diff --git a/packages/logging/src/logging.rs b/packages/logging/src/logging.rs index c1d9d078..d861800f 100644 --- a/packages/logging/src/logging.rs +++ b/packages/logging/src/logging.rs @@ -30,14 +30,18 @@ pub fn log(token_stream: TokenStream) -> ProcMacroResult { // Extract remaining arguments let log_args: Vec = args - .filter_map(|node| { + .map(|node| { if matches!(node.kind(&db), SyntaxKind::Arg) { - Some(node.get_text(&db)) + Ok(node.get_text(&db)) } else { - return create_error_result("Invalid log argument"); + Err(()) } }) - .collect(); + .collect::, ()>>() + .unwrap_or_else(|_| { + create_error_result("Invalid log argument"); + Vec::new() + }); // Generate the log statement let log_statement = generate_log_statement(&level, &format_string, &log_args); From 4b4809f43142d4de3538cdc02693125222124c0d Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Wed, 25 Sep 2024 21:35:57 +0700 Subject: [PATCH 7/7] update --- Scarb.lock | 9 +++++-- packages/consensus/Scarb.toml | 12 +++------ packages/consensus/src/codec.cairo | 3 +-- packages/consensus/src/lib.cairo | 3 --- packages/consensus/src/logging.cairo | 30 --------------------- packages/logging/Scarb.toml | 8 +++--- packages/logging/src/lib.cairo | 2 +- packages/logging/src/log.cairo | 1 + packages/macros/.gitignore | 1 + packages/{logging => macros}/Cargo.toml | 6 ++--- packages/macros/Scarb.toml | 7 +++++ packages/{logging => macros}/src/lib.rs | 0 packages/{logging => macros}/src/logging.rs | 12 ++++----- 13 files changed, 34 insertions(+), 60 deletions(-) delete mode 100644 packages/consensus/src/logging.cairo create mode 100644 packages/macros/.gitignore rename packages/{logging => macros}/Cargo.toml (65%) create mode 100644 packages/macros/Scarb.toml rename packages/{logging => macros}/src/lib.rs (100%) rename packages/{logging => macros}/src/logging.rs (86%) diff --git a/Scarb.lock b/Scarb.lock index 22cc0a72..03a2f9e7 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -12,12 +12,17 @@ dependencies = [ name = "consensus" version = "0.1.0" dependencies = [ - "raito_logging", + "logging", + "raito_macros", "utils", ] [[package]] -name = "raito_logging" +name = "logging" +version = "0.1.0" + +[[package]] +name = "raito_macros" version = "0.1.0" [[package]] diff --git a/packages/consensus/Scarb.toml b/packages/consensus/Scarb.toml index 4fb64cdf..f0793de2 100644 --- a/packages/consensus/Scarb.toml +++ b/packages/consensus/Scarb.toml @@ -5,17 +5,11 @@ edition = "2024_07" [dependencies] utils = { path = "../utils" } -raito_logging = { path = "../logging" } - +raito_macros = { path = "../macros" } +logging = { path = "../logging" } [dev-dependencies] cairo_test.workspace = true [scripts] # TODO: cairo lint -lint = "scarb fmt" - -[features] -default = ["log_level_none"] -log_level_none = [] -log_level_trace = [] -log_level_debug = [] +lint = "scarb fmt" \ No newline at end of file diff --git a/packages/consensus/src/codec.cairo b/packages/consensus/src/codec.cairo index ac5820d4..4c679a33 100644 --- a/packages/consensus/src/codec.cairo +++ b/packages/consensus/src/codec.cairo @@ -2,7 +2,6 @@ use super::types::transaction::{Transaction, TxIn, TxOut, OutPoint}; use utils::hash::Digest; - pub trait Encode { /// Encode using Bitcoin codec and append to the buffer. fn encode_to(self: @T, ref dest: ByteArray); @@ -12,6 +11,7 @@ pub trait Encode { self: @T ) -> ByteArray { let mut dest: ByteArray = Default::default(); + if logging::log::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("tx_encoded: {}", dest)) } Self::encode_to(self, ref dest); dest } @@ -767,7 +767,6 @@ mod tests { "020000000001013ce63f3c9d1375b3d7fc59516dbe57120fe3c912a31ebc29241897b16215cc390000000000fdffffff020f900100000000001976a914998db5e1126bc3a5e04109fbf253a7900462410e88acd9bd150000000000160014579bf4f06510c8683f2451262b6685b00012e46f024730440220537f470c1a18dc1a9d233c0b6af1d2ce18a07f3b244e4d9d54e0e60c34c55e67022058169cd11ac42374cda217d6e28143abd0e79549f7b84acc6542817466dc9b3001210301c1768b48843933bd7f0e8782716e8439fc44723d3745feefde2d57b761f5033f600a00" ); let total_weight = 3 * tx_encoded.len() + wtx_encoded.len(); - assert_eq!(tx_encoded, tx_encoded_expect); assert_eq!(wtx_encoded, wtx_encoded_expect); assert_eq!(total_weight, 3 * 116 + 225); //573 diff --git a/packages/consensus/src/lib.cairo b/packages/consensus/src/lib.cairo index bad55d73..639285f1 100644 --- a/packages/consensus/src/lib.cairo +++ b/packages/consensus/src/lib.cairo @@ -16,6 +16,3 @@ pub mod types { pub mod utxo_set; pub mod state; } - -pub mod logging; - diff --git a/packages/consensus/src/logging.cairo b/packages/consensus/src/logging.cairo deleted file mode 100644 index 4a30c149..00000000 --- a/packages/consensus/src/logging.cairo +++ /dev/null @@ -1,30 +0,0 @@ -#[cfg(feature: 'log_level_trace')] -pub const LOG_LEVEL_TRACE: bool = true; - -#[cfg(feature: 'log_level_trace')] -pub const LOG_LEVEL_DEBUG: bool = true; - -#[cfg(feature: 'log_level_debug')] -pub const LOG_LEVEL_TRACE: bool = false; - -#[cfg(feature: 'log_level_debug')] -pub const LOG_LEVEL_DEBUG: bool = true; - -#[cfg(feature: 'log_level_none')] -pub const LOG_LEVEL_TRACE: bool = false; - -#[cfg(feature: 'log_level_none')] -pub const LOG_LEVEL_DEBUG: bool = false; - -#[cfg(test)] -mod tests { - #[test] - fn test_log_level_debug() { - log!("DEBUG", "log! works") - } - - #[test] - fn test_log_level_trace() { - log!("DEBUG", "log! works") - } -} diff --git a/packages/logging/Scarb.toml b/packages/logging/Scarb.toml index 9f47c6fb..5f646ca9 100644 --- a/packages/logging/Scarb.toml +++ b/packages/logging/Scarb.toml @@ -1,14 +1,14 @@ [package] -name = "raito_logging" +name = "logging" version = "0.1.0" edition = "2024_07" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html -[cairo-plugin] - +[dev-dependencies] +cairo_test = "2.8.2" [features] default = ["log_level_none"] -log_level_none = [] log_level_trace = [] log_level_debug = [] +log_level_none = [] \ No newline at end of file diff --git a/packages/logging/src/lib.cairo b/packages/logging/src/lib.cairo index f4ee9bc8..7e8abe20 100644 --- a/packages/logging/src/lib.cairo +++ b/packages/logging/src/lib.cairo @@ -1 +1 @@ -pub mod log; +pub mod log; \ No newline at end of file diff --git a/packages/logging/src/log.cairo b/packages/logging/src/log.cairo index 053ab490..c9e8367f 100644 --- a/packages/logging/src/log.cairo +++ b/packages/logging/src/log.cairo @@ -15,3 +15,4 @@ pub const LOG_LEVEL_TRACE: bool = false; #[cfg(feature: 'log_level_none')] pub const LOG_LEVEL_DEBUG: bool = false; + diff --git a/packages/macros/.gitignore b/packages/macros/.gitignore new file mode 100644 index 00000000..eb5a316c --- /dev/null +++ b/packages/macros/.gitignore @@ -0,0 +1 @@ +target diff --git a/packages/logging/Cargo.toml b/packages/macros/Cargo.toml similarity index 65% rename from packages/logging/Cargo.toml rename to packages/macros/Cargo.toml index d2bd244d..39af1d49 100644 --- a/packages/logging/Cargo.toml +++ b/packages/macros/Cargo.toml @@ -1,6 +1,6 @@ # Cargo.toml [package] -name = "raito_logging" +name = "raito_macros" version = "0.1.0" edition = "2021" @@ -10,5 +10,5 @@ crate-type = ["cdylib"] [dependencies] bigdecimal = "0.4.5" cairo-lang-macro = "0.1" -cairo-lang-parser = "2.7.0" -cairo-lang-syntax = "2.7.0" +cairo-lang-parser = "2.8.0" +cairo-lang-syntax = "2.8.0" diff --git a/packages/macros/Scarb.toml b/packages/macros/Scarb.toml new file mode 100644 index 00000000..66fff079 --- /dev/null +++ b/packages/macros/Scarb.toml @@ -0,0 +1,7 @@ +[package] +name = "raito_macros" +version = "0.1.0" +edition = "2024_07" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html +[cairo-plugin] diff --git a/packages/logging/src/lib.rs b/packages/macros/src/lib.rs similarity index 100% rename from packages/logging/src/lib.rs rename to packages/macros/src/lib.rs diff --git a/packages/logging/src/logging.rs b/packages/macros/src/logging.rs similarity index 86% rename from packages/logging/src/logging.rs rename to packages/macros/src/logging.rs index d861800f..21a26729 100644 --- a/packages/logging/src/logging.rs +++ b/packages/macros/src/logging.rs @@ -76,7 +76,7 @@ fn generate_log_statement(level: &str, format_string: &str, log_args: &[String]) ) }; - format!("if crate::logging::{} {{ {} }}", condition, print_statement) + format!("if logging::{} {{ {} }}", condition, print_statement) } mod tests { use super::*; @@ -98,7 +98,7 @@ mod tests { ); assert_eq!( expanded, - r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("test message: {}", '123')) }"# + r#"if logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("test message: {}", '123')) }"# ); } @@ -107,7 +107,7 @@ mod tests { let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("TRACE", "entering function")"#); assert_eq!( expanded, - r#"if crate::logging::LOG_LEVEL_TRACE { println!("{}: {}", format!("TRACE"), format!("entering function")) }"# + r#"if logging::LOG_LEVEL_TRACE { println!("{}: {}", format!("TRACE"), format!("entering function")) }"# ); } @@ -122,7 +122,7 @@ mod tests { let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", '')"#); assert_eq!( expanded, - r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!('')) }"# + r#"if logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!('')) }"# ); } @@ -134,7 +134,7 @@ mod tests { ); assert_eq!( expanded, - r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Values: {}, {}, {}", '1', '2', '3')) }"# + r#"if logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Values: {}, {}, {}", '1', '2', '3')) }"# ); } @@ -146,7 +146,7 @@ mod tests { ); assert_eq!( expanded, - r#"if crate::logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Exact {} string", 'test')) }"# + r#"if logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Exact {} string", 'test')) }"# ); } }