diff --git a/Cargo.lock b/Cargo.lock index 664279bc..c9bd466c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,6 +47,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "arrayvec" version = "0.7.4" @@ -380,7 +395,12 @@ version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", "num-traits", + "wasm-bindgen", + "windows-targets 0.48.5", ] [[package]] @@ -1653,6 +1673,7 @@ dependencies = [ "async-openai", "async-recursion", "async-trait", + "chrono", "clap", "clap-verbosity-flag", "colored", @@ -1830,6 +1851,29 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -4052,6 +4096,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.45.0" diff --git a/common/Cargo.toml b/common/Cargo.toml index 29f1f063..24745de9 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -26,3 +26,4 @@ tokio = {version = "1", features = ["full"]} strsim = "0.10.0" async-recursion = "1.0.5" async-trait = "0.1.51" +chrono = "0.4.31" diff --git a/common/src/ether/compiler.rs b/common/src/ether/compiler.rs index 30d2d595..7e01b477 100644 --- a/common/src/ether/compiler.rs +++ b/common/src/ether/compiler.rs @@ -4,8 +4,7 @@ use crate::io::logging::Logger; // for example: (solc, 0.8.10) or (vyper, 0.2.16) pub fn detect_compiler(bytecode: &str) -> (&'static str, String) { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); let mut compiler = "unknown"; let mut version = "unknown".to_string(); diff --git a/common/src/ether/evm/ext/exec/mod.rs b/common/src/ether/evm/ext/exec/mod.rs index 7babd26f..880b1e7e 100644 --- a/common/src/ether/evm/ext/exec/mod.rs +++ b/common/src/ether/evm/ext/exec/mod.rs @@ -42,8 +42,7 @@ impl VM { } // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); logger.debug_max(&format!("beginning symbolic execution for selector 0x{}", selector)); @@ -57,8 +56,7 @@ impl VM { let mut vm = self.clone(); // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); logger.debug_max("beginning contract-wide symbolic execution"); diff --git a/common/src/ether/evm/ext/exec/util.rs b/common/src/ether/evm/ext/exec/util.rs index e6f94ca3..cf8fae89 100644 --- a/common/src/ether/evm/ext/exec/util.rs +++ b/common/src/ether/evm/ext/exec/util.rs @@ -31,8 +31,7 @@ pub fn stack_contains_too_many_of_the_same_item(stack: &Stack) -> bool { 16 }) { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); logger.debug_max( "jump matches loop-detection heuristic: 'stack_contains_too_many_of_the_same_item'", @@ -49,8 +48,7 @@ pub fn stack_contains_too_many_of_the_same_item(stack: &Stack) -> bool { pub fn stack_item_source_depth_too_deep(stack: &Stack) -> bool { if stack.stack.iter().any(|frame| frame.operation.depth() > 16) { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); logger .debug_max("jump matches loop-detection heuristic: 'stack_item_source_depth_too_deep'"); @@ -70,8 +68,7 @@ pub fn jump_condition_appears_recursive(stack_diff: &[StackFrame], jump_conditio .any(|solidified| jump_condition.contains(&solidified)) { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); logger .debug_max("jump matches loop-detection heuristic: 'jump_condition_appears_recursive'"); @@ -98,8 +95,7 @@ pub fn jump_condition_contains_mutated_memory_access( }) }) { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); logger.debug_max("jump matches loop-detection heuristic: 'jump_condition_contains_mutated_memory_access'"); return true @@ -125,8 +121,7 @@ pub fn jump_condition_contains_mutated_storage_access( }) }) { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); logger.debug_max("jump matches loop-detection heuristic: 'jump_condition_contains_mutated_storage_access'"); return true @@ -168,8 +163,7 @@ pub fn jump_condition_historical_diffs_approximately_equal( } // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); logger.debug_max("jump matches loop-detection heuristic: 'jump_condition_historical_diffs_approximately_equal'"); true diff --git a/common/src/ether/rpc.rs b/common/src/ether/rpc.rs index c65a449a..8e25495e 100644 --- a/common/src/ether/rpc.rs +++ b/common/src/ether/rpc.rs @@ -17,8 +17,7 @@ use heimdall_cache::{read_cache, store_cache}; /// `Result>` pub async fn chain_id(rpc_url: &str) -> Result> { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); logger.debug_max(&format!("checking chain id for rpc url: '{}'", &rpc_url)); @@ -74,8 +73,7 @@ pub async fn get_code( rpc_url: &str, ) -> Result> { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); // get chain_id let _chain_id = chain_id(rpc_url).await?; @@ -145,8 +143,7 @@ pub async fn get_transaction( rpc_url: &str, ) -> Result> { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); logger.debug_max(&format!( "fetching calldata from node for transaction: '{}' .", diff --git a/common/src/ether/selectors.rs b/common/src/ether/selectors.rs index 779b98d5..7a12a225 100644 --- a/common/src/ether/selectors.rs +++ b/common/src/ether/selectors.rs @@ -17,8 +17,7 @@ pub fn find_function_selectors(evm: &VM, assembly: &str) -> HashMap(selectors: Vec) -> HashMap>>> = Arc::new(Mutex::new(HashMap::new())); diff --git a/common/src/ether/signatures.rs b/common/src/ether/signatures.rs index f4c56956..44b7ccc6 100644 --- a/common/src/ether/signatures.rs +++ b/common/src/ether/signatures.rs @@ -41,8 +41,7 @@ pub trait ResolveSelector { impl ResolveSelector for ResolvedError { async fn resolve(selector: &str) -> Option> { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); logger.debug_max(&format!("resolving error selector {}", &selector)); @@ -125,8 +124,7 @@ impl ResolveSelector for ResolvedError { impl ResolveSelector for ResolvedLog { async fn resolve(selector: &str) -> Option> { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); logger.debug_max(&format!("resolving event selector {}", &selector)); @@ -209,8 +207,7 @@ impl ResolveSelector for ResolvedLog { impl ResolveSelector for ResolvedFunction { async fn resolve(selector: &str) -> Option> { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); logger.debug_max(&format!("resolving event selector {}", &selector)); diff --git a/common/src/io/logging.rs b/common/src/io/logging.rs index 48972958..0ff286e5 100644 --- a/common/src/io/logging.rs +++ b/common/src/io/logging.rs @@ -3,18 +3,26 @@ use std::io::{stdin, stdout}; use colored::*; +use crate::utils::time::pretty_timestamp; + use super::super::utils::strings::replace_last; +/// A logger which can be used to log messages to the console +/// in a standardized format. +#[derive(Clone)] pub struct Logger { pub level: i8, } +/// The trace factory is used to build a trace of the program's execution. +/// Has several helper functions to add different types of traces. #[derive(Clone, Debug)] pub struct TraceFactory { pub level: i8, pub traces: Vec, } +/// The trace category is used to determine how the trace is formatted. #[derive(Clone, Debug)] pub enum TraceCategory { Log, @@ -25,6 +33,7 @@ pub enum TraceCategory { Empty, } +/// Individual trace, which is added to the trace factory. #[derive(Clone, Debug)] pub struct Trace { pub category: TraceCategory, @@ -35,12 +44,12 @@ pub struct Trace { } impl TraceFactory { - // creates a new empty trace factory + /// creates a new empty trace factory pub fn new(level: i8) -> TraceFactory { TraceFactory { level: level, traces: Vec::new() } } - // adds a new trace to the factory + /// adds a new trace to the factory pub fn add( &mut self, category: &str, @@ -68,7 +77,7 @@ impl TraceFactory { trace_index } - // pretty print the trace + /// display the trace to the console if the verbosity is high enough pub fn display(&self) { if self.level >= 3 { println!("{}:", "trace".bright_blue().bold()); @@ -84,7 +93,7 @@ impl TraceFactory { } } - // recursive function which prints traces + /// recursive function used to print traces to the console correctly pub fn print_trace(&self, prefix: &str, index: usize) { let trace: &Trace = match self.traces.get(index) { Some(trace) => trace, @@ -227,7 +236,7 @@ impl TraceFactory { // TRACE HELPERS // //////////////////////////////////////////////////////////////////////////////// - // adds a function call trace + /// adds a function call trace pub fn add_call( &mut self, parent_index: u32, @@ -246,7 +255,7 @@ impl TraceFactory { self.add("call", parent_index, instruction, vec![title, returns]) } - // adds a contract creation trace + /// adds a contract creation trace pub fn add_creation( &mut self, parent_index: u32, @@ -259,7 +268,7 @@ impl TraceFactory { self.add("create", parent_index, instruction, vec![contract, format!("{size} bytes")]) } - // adds a known log trace + /// adds a known log trace pub fn add_emission( &mut self, parent_index: u32, @@ -271,7 +280,7 @@ impl TraceFactory { self.add("log", parent_index, instruction, vec![log]) } - // adds an unknown or raw log trace + /// adds an unknown or raw log trace pub fn add_raw_emission( &mut self, parent_index: u32, @@ -283,31 +292,31 @@ impl TraceFactory { self.add("log_unknown", parent_index, instruction, topics) } - // add info to the trace + /// add info message to the trace pub fn add_info(&mut self, parent_index: u32, instruction: u32, message: &str) -> u32 { let message = format!("{} {}", "info:".bright_cyan().bold(), message); self.add("message", parent_index, instruction, vec![message]) } - // add debug to the trace + /// add debug message to the trace pub fn add_debug(&mut self, parent_index: u32, instruction: u32, message: &str) -> u32 { let message = format!("{} {}", "debug:".bright_magenta().bold(), message); self.add("message", parent_index, instruction, vec![message]) } - // add error to the trace + /// add error message to the trace pub fn add_error(&mut self, parent_index: u32, instruction: u32, message: &str) -> u32 { let message = format!("{} {}", "error:".bright_red().bold(), message); self.add("message", parent_index, instruction, vec![message]) } - // add warn to the trace + /// add warn message to the trace pub fn add_warn(&mut self, parent_index: u32, instruction: u32, message: &str) -> u32 { let message = format!("{} {}", "warn:".bright_yellow().bold(), message); self.add("message", parent_index, instruction, vec![message]) } - // add a vector of strings to the trace + /// add a vector of messages to the trace pub fn add_message( &mut self, parent_index: u32, @@ -317,14 +326,14 @@ impl TraceFactory { self.add("message", parent_index, instruction, message) } - // add a line break + /// add a line break to the trace pub fn br(&mut self, parent_index: u32) -> u32 { self.add("empty", parent_index, 0, vec!["".to_string()]) } } impl Trace { - // create a new trace + /// create a new raw trace with the given parameters pub fn new(category: &str, parent_index: u32, instruction: u32, message: Vec) -> Trace { Trace { category: match category { @@ -344,10 +353,32 @@ impl Trace { } } +impl Default for Logger { + fn default() -> Self { + // get the environment variable RUST_LOG and parse it + let level = match std::env::var("RUST_LOG") { + Ok(level) => match level.to_lowercase().as_str() { + "silent" => -1, + "error" => 0, + "warn" => 1, + "info" => 2, + "debug" => 3, + "trace" => 4, + "all" => 5, + "max" => 6, + _ => 1, + }, + Err(_) => 2, + }; + + Logger { level } + } +} + impl Logger { - // create a new logger + /// create a new logger with the given verbosity pub fn new(verbosity: &str) -> (Logger, TraceFactory) { - match verbosity { + match verbosity.to_uppercase().as_str() { "SILENT" => (Logger { level: -1 }, TraceFactory::new(-1)), "ERROR" => (Logger { level: 0 }, TraceFactory::new(0)), "WARN" => (Logger { level: 1 }, TraceFactory::new(1)), @@ -360,51 +391,98 @@ impl Logger { } } + /// log an error message pub fn error(&self, message: &str) { - println!("{}: {}", "error".bright_red().bold(), message); + if self.level >= 0 { + println!( + "{} {}: {}", + pretty_timestamp().dimmed(), + "error".bright_red().bold(), + message + ); + } } + /// log a fatal error, typically an unhanded exception which causes the program to exit pub fn fatal(&self, message: &str) { - println!("{}: {}", "fatal".bright_white().on_bright_red().bold(), message); + println!( + "{} {}: {}", + pretty_timestamp().dimmed(), + "fatal".bright_white().on_bright_red().bold(), + message + ); } + /// log a success message pub fn success(&self, message: &str) { if self.level >= 0 { - println!("{}: {}", "success".bright_green().bold(), message); + println!( + "{} {}: {}", + pretty_timestamp().dimmed(), + "success".bright_green().bold(), + message + ); } } + /// log an info message pub fn info(&self, message: &str) { if self.level >= 1 { - println!("{}: {}", "info".bright_cyan().bold(), message); + println!( + "{} {}: {}", + pretty_timestamp().dimmed(), + "info".bright_cyan().bold(), + message + ); } } + /// log a warning message pub fn warn(&self, message: &str) { - println!("{}: {}", "warn".bright_yellow().bold(), message); + println!("{} {}: {}", pretty_timestamp().dimmed(), "warn".bright_yellow().bold(), message); } + /// log a debug message pub fn debug(&self, message: &str) { if self.level >= 2 { - println!("{}: {}", "debug".bright_magenta().bold(), message); + println!( + "{} {}: {}", + pretty_timestamp().dimmed(), + "debug".bright_magenta().bold(), + message + ); } } + /// log a trace message pub fn trace(&self, message: &str) { if self.level >= 4 { - println!("{}: {}", "trace".bright_blue().bold(), message); + println!( + "{} {}: {}", + pretty_timestamp().dimmed(), + "trace".bright_blue().bold(), + message + ); } } + /// log a max message pub fn debug_max(&self, message: &str) { if self.level >= 6 { - println!("{}: {}", "debug".bright_white().bold(), message); + println!( + "{} {}: {}", + pretty_timestamp().dimmed(), + "debug".bright_white().bold(), + message + ); } } + /// get a formatted spinner for the given function pub fn info_spinner(&self) -> ProgressStyle { ProgressStyle::with_template(&format!( - "{}: {}", + "{} {}: {}", + pretty_timestamp().dimmed(), "info".bright_cyan().bold(), "{spinner} {msg}" )) @@ -412,9 +490,11 @@ impl Logger { .tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏") } + /// get a formatted spinner for the given function pub fn debug_spinner(&self) -> ProgressStyle { ProgressStyle::with_template(&format!( - "{}: {}", + "{} {}: {}", + pretty_timestamp().dimmed(), "debug".bright_magenta().bold(), "{spinner} {msg}" )) @@ -422,6 +502,7 @@ impl Logger { .tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏") } + /// prompt the user to select an option from the given list, or return the default pub fn option( &self, function: &str, @@ -447,7 +528,7 @@ impl Logger { // print the option tree for (i, option) in options.iter().enumerate() { println!( - " {} {}: {}", + " {} {}: {}", if i == options.len() - 1 { "└─".bold().bright_white() } else { @@ -461,7 +542,7 @@ impl Logger { // flush output print prompt let mut selection = String::new(); print!( - "\n Select an option {}: ", + "\n Select an option {}: ", if default.is_some() { format!("(default: {})", default.expect("Failed to get default option.")) } else { @@ -515,3 +596,287 @@ impl Logger { } } } + +#[cfg(test)] +mod tests { + use std::time::Instant; + + use super::*; + + #[test] + fn test_raw_trace() { + let start_time = Instant::now(); + let (logger, mut trace) = Logger::new("TRACE"); + + let parent = trace.add("call", 0, 123123, vec!["Test::test_trace()".to_string()]); + trace.add( + "log", + parent, + 234234, + vec!["ContractCreated(contractAddress: 0x0000000000000000000000000000000000000000)" + .to_string()], + ); + let inner = trace.add( + "create", + parent, + 121234, + vec![ + "TestContract".to_string(), + "0x0000000000000000000000000000000000000000".to_string(), + "917".to_string(), + ], + ); + trace.add( + "log_unknown", + inner, + 12344, + vec!["0x0000000000000000000000000000000000000000000000000000000000000000".to_string()], + ); + let deeper = trace.add( + "call", + inner, + 12344, + vec![ + "Test::transfer(to: 0x0000000000000000000000000000000000000000, amount: 1)" + .to_string(), + "true".to_string(), + ], + ); + trace.add("log", deeper, 12344, vec!["Transfer(from: 0x0000000000000000000000000000000000000000, to: 0x0000000000000000000000000000000000000000, amount: 1)".to_string()]); + trace.add("message", inner, 12344, vec!["warn: Transfer to the zero address!".to_string()]); + trace.add( + "message", + parent, + 12344, + vec![ + "Execution Reverted: Out of Gas.".to_string(), + "Execution Reverted: Out of Gas.".to_string(), + ], + ); + + trace.display(); + logger.info(&format!("Tracing took {}", start_time.elapsed().as_secs_f64())); + } + + #[test] + fn test_helper_functions() { + let start_time = Instant::now(); + let (logger, mut trace) = Logger::new("TRACE"); + + let parent = trace.add_call( + 0, + 123, + "Test".to_string(), + "test_trace".to_string(), + vec!["arg1: 0x0".to_string(), "arg2: 0x1".to_string()], + "()".to_string(), + ); + trace.add_creation( + parent, + 124, + "TestContract".to_string(), + "0x0000000000000000000000000000000000000000".to_string(), + 1232, + ); + trace.add_emission( + parent, + 125, + "ContractCreated".to_string(), + vec!["contractAddress: 0x0000000000000000000000000000000000000000".to_string()], + ); + trace.add_raw_emission( + parent, + 125, + vec![ + "0x0000000000000000000000000000000000000000000000000000000000000000".to_string(), + "0x0000000000000000000000000000000000000000000000000000000000000000".to_string(), + ], + "0x".to_string(), + ); + trace.add_error(parent, 126, "Testing errors"); + trace.add_info(parent, 127, "Testing info"); + trace.add_message( + parent, + 128, + vec!["test multiple".to_string(), "lines".to_string(), "to tracing".to_string()], + ); + + trace.display(); + logger.info(&format!("Tracing took {}", start_time.elapsed().as_secs_f64())); + } + + #[test] + fn test_option() { + let (logger, _) = Logger::new("TRACE"); + + logger.option( + "warn", + "multiple possibilities", + vec!["option 1".to_string(), "option 2".to_string(), "option 3".to_string()], + Some(0), + true, + ); + } + + #[test] + fn test_warn() { + let (logger, _) = Logger::new("SILENT"); + logger.warn("log"); + + let (logger, _) = Logger::new("ERROR"); + logger.warn("log"); + + let (logger, _) = Logger::new("WARN"); + logger.warn("log"); + + let (logger, _) = Logger::new("INFO"); + logger.warn("log"); + + let (logger, _) = Logger::new("DEBUG"); + logger.warn("log"); + + let (logger, _) = Logger::new("TRACE"); + logger.warn("log"); + + let (logger, _) = Logger::new("ALL"); + logger.warn("log"); + + let (logger, _) = Logger::new("MAX"); + logger.warn("log"); + } + + #[test] + fn test_error() { + let (logger, _) = Logger::new("SILENT"); + logger.error("log"); + + let (logger, _) = Logger::new("ERROR"); + logger.error("log"); + + let (logger, _) = Logger::new("WARN"); + logger.error("log"); + + let (logger, _) = Logger::new("INFO"); + logger.error("log"); + + let (logger, _) = Logger::new("DEBUG"); + logger.error("log"); + + let (logger, _) = Logger::new("TRACE"); + logger.error("log"); + + let (logger, _) = Logger::new("ALL"); + logger.error("log"); + + let (logger, _) = Logger::new("MAX"); + logger.error("log"); + } + + #[test] + fn test_info() { + let (logger, _) = Logger::new("SILENT"); + logger.info("log"); + + let (logger, _) = Logger::new("ERROR"); + logger.info("log"); + + let (logger, _) = Logger::new("WARN"); + logger.info("log"); + + let (logger, _) = Logger::new("INFO"); + logger.info("log"); + + let (logger, _) = Logger::new("DEBUG"); + logger.info("log"); + + let (logger, _) = Logger::new("TRACE"); + logger.info("log"); + + let (logger, _) = Logger::new("ALL"); + logger.info("log"); + + let (logger, _) = Logger::new("MAX"); + logger.info("log"); + } + + #[test] + fn test_success() { + let (logger, _) = Logger::new("SILENT"); + logger.success("log"); + + let (logger, _) = Logger::new("ERROR"); + logger.success("log"); + + let (logger, _) = Logger::new("WARN"); + logger.success("log"); + + let (logger, _) = Logger::new("INFO"); + logger.success("log"); + + let (logger, _) = Logger::new("DEBUG"); + logger.success("log"); + + let (logger, _) = Logger::new("TRACE"); + logger.success("log"); + + let (logger, _) = Logger::new("ALL"); + logger.success("log"); + + let (logger, _) = Logger::new("MAX"); + logger.success("log"); + } + + #[test] + fn test_debug() { + let (logger, _) = Logger::new("SILENT"); + logger.debug("log"); + + let (logger, _) = Logger::new("ERROR"); + logger.debug("log"); + + let (logger, _) = Logger::new("WARN"); + logger.debug("log"); + + let (logger, _) = Logger::new("INFO"); + logger.debug("log"); + + let (logger, _) = Logger::new("DEBUG"); + logger.debug("log"); + + let (logger, _) = Logger::new("TRACE"); + logger.debug("log"); + + let (logger, _) = Logger::new("ALL"); + logger.debug("log"); + + let (logger, _) = Logger::new("MAX"); + logger.debug("log"); + } + + #[test] + fn test_max() { + let (logger, _) = Logger::new("SILENT"); + logger.debug_max("log"); + + let (logger, _) = Logger::new("ERROR"); + logger.debug_max("log"); + + let (logger, _) = Logger::new("WARN"); + logger.debug_max("log"); + + let (logger, _) = Logger::new("INFO"); + logger.debug_max("log"); + + let (logger, _) = Logger::new("DEBUG"); + logger.debug_max("log"); + + let (logger, _) = Logger::new("TRACE"); + logger.debug_max("log"); + + let (logger, _) = Logger::new("ALL"); + logger.debug_max("log"); + + let (logger, _) = Logger::new("MAX"); + logger.debug_max("log"); + } +} diff --git a/common/src/io/mod.rs b/common/src/io/mod.rs index 621de5cc..62f9fc36 100644 --- a/common/src/io/mod.rs +++ b/common/src/io/mod.rs @@ -1,3 +1,2 @@ pub mod file; pub mod logging; -mod tests; diff --git a/common/src/io/tests.rs b/common/src/io/tests.rs deleted file mode 100644 index a5b62b4a..00000000 --- a/common/src/io/tests.rs +++ /dev/null @@ -1,283 +0,0 @@ -#[cfg(test)] -mod test_logging { - use std::time::Instant; - - use crate::io::logging::Logger; - - #[test] - fn test_raw_trace() { - let start_time = Instant::now(); - let (logger, mut trace) = Logger::new("TRACE"); - - let parent = trace.add("call", 0, 123123, vec!["Test::test_trace()".to_string()]); - trace.add( - "log", - parent, - 234234, - vec!["ContractCreated(contractAddress: 0x0000000000000000000000000000000000000000)" - .to_string()], - ); - let inner = trace.add( - "create", - parent, - 121234, - vec![ - "TestContract".to_string(), - "0x0000000000000000000000000000000000000000".to_string(), - "917".to_string(), - ], - ); - trace.add( - "log_unknown", - inner, - 12344, - vec!["0x0000000000000000000000000000000000000000000000000000000000000000".to_string()], - ); - let deeper = trace.add( - "call", - inner, - 12344, - vec![ - "Test::transfer(to: 0x0000000000000000000000000000000000000000, amount: 1)" - .to_string(), - "true".to_string(), - ], - ); - trace.add("log", deeper, 12344, vec!["Transfer(from: 0x0000000000000000000000000000000000000000, to: 0x0000000000000000000000000000000000000000, amount: 1)".to_string()]); - trace.add("message", inner, 12344, vec!["warn: Transfer to the zero address!".to_string()]); - trace.add( - "message", - parent, - 12344, - vec![ - "Execution Reverted: Out of Gas.".to_string(), - "Execution Reverted: Out of Gas.".to_string(), - ], - ); - - trace.display(); - logger.info(&format!("Tracing took {}", start_time.elapsed().as_secs_f64())); - } - - #[test] - fn test_helper_functions() { - let start_time = Instant::now(); - let (logger, mut trace) = Logger::new("TRACE"); - - let parent = trace.add_call( - 0, - 123, - "Test".to_string(), - "test_trace".to_string(), - vec!["arg1: 0x0".to_string(), "arg2: 0x1".to_string()], - "()".to_string(), - ); - trace.add_creation( - parent, - 124, - "TestContract".to_string(), - "0x0000000000000000000000000000000000000000".to_string(), - 1232, - ); - trace.add_emission( - parent, - 125, - "ContractCreated".to_string(), - vec!["contractAddress: 0x0000000000000000000000000000000000000000".to_string()], - ); - trace.add_raw_emission( - parent, - 125, - vec![ - "0x0000000000000000000000000000000000000000000000000000000000000000".to_string(), - "0x0000000000000000000000000000000000000000000000000000000000000000".to_string(), - ], - "0x".to_string(), - ); - trace.add_error(parent, 126, "Testing errors"); - trace.add_info(parent, 127, "Testing info"); - trace.add_message( - parent, - 128, - vec!["test multiple".to_string(), "lines".to_string(), "to tracing".to_string()], - ); - - trace.display(); - logger.info(&format!("Tracing took {}", start_time.elapsed().as_secs_f64())); - } - - #[test] - fn test_option() { - let (logger, _) = Logger::new("TRACE"); - - logger.option( - "warn", - "multiple possibilities", - vec!["option 1".to_string(), "option 2".to_string(), "option 3".to_string()], - Some(0), - true, - ); - } - - #[test] - fn test_warn() { - let (logger, _) = Logger::new("SILENT"); - logger.warn("log"); - - let (logger, _) = Logger::new("ERROR"); - logger.warn("log"); - - let (logger, _) = Logger::new("WARN"); - logger.warn("log"); - - let (logger, _) = Logger::new("INFO"); - logger.warn("log"); - - let (logger, _) = Logger::new("DEBUG"); - logger.warn("log"); - - let (logger, _) = Logger::new("TRACE"); - logger.warn("log"); - - let (logger, _) = Logger::new("ALL"); - logger.warn("log"); - - let (logger, _) = Logger::new("MAX"); - logger.warn("log"); - } - - #[test] - fn test_error() { - let (logger, _) = Logger::new("SILENT"); - logger.error("log"); - - let (logger, _) = Logger::new("ERROR"); - logger.error("log"); - - let (logger, _) = Logger::new("WARN"); - logger.error("log"); - - let (logger, _) = Logger::new("INFO"); - logger.error("log"); - - let (logger, _) = Logger::new("DEBUG"); - logger.error("log"); - - let (logger, _) = Logger::new("TRACE"); - logger.error("log"); - - let (logger, _) = Logger::new("ALL"); - logger.error("log"); - - let (logger, _) = Logger::new("MAX"); - logger.error("log"); - } - - #[test] - fn test_info() { - let (logger, _) = Logger::new("SILENT"); - logger.info("log"); - - let (logger, _) = Logger::new("ERROR"); - logger.info("log"); - - let (logger, _) = Logger::new("WARN"); - logger.info("log"); - - let (logger, _) = Logger::new("INFO"); - logger.info("log"); - - let (logger, _) = Logger::new("DEBUG"); - logger.info("log"); - - let (logger, _) = Logger::new("TRACE"); - logger.info("log"); - - let (logger, _) = Logger::new("ALL"); - logger.info("log"); - - let (logger, _) = Logger::new("MAX"); - logger.info("log"); - } - - #[test] - fn test_success() { - let (logger, _) = Logger::new("SILENT"); - logger.success("log"); - - let (logger, _) = Logger::new("ERROR"); - logger.success("log"); - - let (logger, _) = Logger::new("WARN"); - logger.success("log"); - - let (logger, _) = Logger::new("INFO"); - logger.success("log"); - - let (logger, _) = Logger::new("DEBUG"); - logger.success("log"); - - let (logger, _) = Logger::new("TRACE"); - logger.success("log"); - - let (logger, _) = Logger::new("ALL"); - logger.success("log"); - - let (logger, _) = Logger::new("MAX"); - logger.success("log"); - } - - #[test] - fn test_debug() { - let (logger, _) = Logger::new("SILENT"); - logger.debug("log"); - - let (logger, _) = Logger::new("ERROR"); - logger.debug("log"); - - let (logger, _) = Logger::new("WARN"); - logger.debug("log"); - - let (logger, _) = Logger::new("INFO"); - logger.debug("log"); - - let (logger, _) = Logger::new("DEBUG"); - logger.debug("log"); - - let (logger, _) = Logger::new("TRACE"); - logger.debug("log"); - - let (logger, _) = Logger::new("ALL"); - logger.debug("log"); - - let (logger, _) = Logger::new("MAX"); - logger.debug("log"); - } - - #[test] - fn test_max() { - let (logger, _) = Logger::new("SILENT"); - logger.debug_max("log"); - - let (logger, _) = Logger::new("ERROR"); - logger.debug_max("log"); - - let (logger, _) = Logger::new("WARN"); - logger.debug_max("log"); - - let (logger, _) = Logger::new("INFO"); - logger.debug_max("log"); - - let (logger, _) = Logger::new("DEBUG"); - logger.debug_max("log"); - - let (logger, _) = Logger::new("TRACE"); - logger.debug_max("log"); - - let (logger, _) = Logger::new("ALL"); - logger.debug_max("log"); - - let (logger, _) = Logger::new("MAX"); - logger.debug_max("log"); - } -} diff --git a/common/src/resources/openai.rs b/common/src/resources/openai.rs index e4d932e0..7fbe7af4 100644 --- a/common/src/resources/openai.rs +++ b/common/src/resources/openai.rs @@ -5,8 +5,7 @@ pub async fn complete(prompt: &str, api_key: &str) -> Option { let client = Client::new().with_api_key(api_key); // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); let request = match CreateCompletionRequestArgs::default() .model("text-davinci-003") .prompt(prompt) diff --git a/common/src/resources/transpose.rs b/common/src/resources/transpose.rs index f667c098..edca5a37 100644 --- a/common/src/resources/transpose.rs +++ b/common/src/resources/transpose.rs @@ -22,8 +22,7 @@ struct TransposeResponse { async fn _call_transpose(query: &str, api_key: &str) -> Option { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); // build the headers let mut headers = HeaderMap::new(); @@ -82,8 +81,7 @@ pub async fn get_transaction_list( bounds: (&u128, &u128), ) -> Vec<(u128, String)> { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); // get a new progress bar let transaction_list_progress = ProgressBar::new_spinner(); @@ -160,8 +158,7 @@ pub async fn get_contract_creation( api_key: &str, ) -> Option<(u128, String)> { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); // get a new progress bar let transaction_list_progress = ProgressBar::new_spinner(); diff --git a/common/src/utils/http.rs b/common/src/utils/http.rs index 7e6479b6..3db34ce3 100644 --- a/common/src/utils/http.rs +++ b/common/src/utils/http.rs @@ -28,8 +28,7 @@ async fn _get_json_from_url( timeout: u64, ) -> Result, reqwest::Error> { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); logger.debug_max(&format!("GET {}", &url)); diff --git a/common/src/utils/time.rs b/common/src/utils/time.rs index 4db2be75..6265df18 100644 --- a/common/src/utils/time.rs +++ b/common/src/utils/time.rs @@ -1,7 +1,22 @@ +use chrono::Local; + +/// Calculate the ETA for a process based on the number of items processed per second pub fn calculate_eta(items_per_second: f64, items_remaining: usize) -> u128 { (items_remaining as f64 / items_per_second) as u128 } +/// Format seconds into a human readable ETA +/// +/// ## Example +/// ``` +/// use heimdall_common::utils::time::format_eta; +/// +/// let eta = format_eta(86400); +/// assert_eq!(eta, "1d 0s"); +/// +/// let eta = format_eta(86401); +/// assert_eq!(eta, "1d 1s"); +/// ``` pub fn format_eta(seconds_remaining: u128) -> String { let days = seconds_remaining / 86400; let hours = (seconds_remaining % 86400) / 3600; @@ -16,3 +31,9 @@ pub fn format_eta(seconds_remaining: u128) -> String { if seconds > 0 { format!("{seconds}s ") } else { String::from("0s") }, ) } + +/// Get the current timestamp in a pretty format +pub fn pretty_timestamp() -> String { + let now = Local::now(); + now.format("%d-%m-%Y %H:%M:%S.%f").to_string() +} diff --git a/core/src/cfg/output.rs b/core/src/cfg/output.rs index e07f4050..37c7a3ee 100644 --- a/core/src/cfg/output.rs +++ b/core/src/cfg/output.rs @@ -8,8 +8,7 @@ use super::CFGArgs; pub fn write_cfg_to_file(contract_cfg: &Graph, args: &CFGArgs, output_dir: String) { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); // get a new progress bar let progress_bar = ProgressBar::new_spinner(); diff --git a/core/src/decompile/out/abi.rs b/core/src/decompile/out/abi.rs index 1f6cad51..9f098bfc 100644 --- a/core/src/decompile/out/abi.rs +++ b/core/src/decompile/out/abi.rs @@ -61,8 +61,7 @@ pub fn build_abi( trace_parent: u32, ) -> Result, Box> { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); // get a new progress bar let progress_bar = ProgressBar::new_spinner(); diff --git a/core/src/decompile/out/solidity.rs b/core/src/decompile/out/solidity.rs index ad162ba4..6b3b5c77 100644 --- a/core/src/decompile/out/solidity.rs +++ b/core/src/decompile/out/solidity.rs @@ -30,8 +30,7 @@ pub fn build_solidity_output( trace_parent: u32, ) -> Result> { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); // clone functions mutably let mut functions = functions; diff --git a/core/src/decompile/out/yul.rs b/core/src/decompile/out/yul.rs index d818f624..efafd2ef 100644 --- a/core/src/decompile/out/yul.rs +++ b/core/src/decompile/out/yul.rs @@ -20,8 +20,7 @@ pub fn build_yul_output( trace_parent: u32, ) -> Result> { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); // get a new progress bar let progress_bar = ProgressBar::new_spinner(); diff --git a/core/src/decompile/resolve.rs b/core/src/decompile/resolve.rs index dbd3db0b..4d0c780b 100644 --- a/core/src/decompile/resolve.rs +++ b/core/src/decompile/resolve.rs @@ -7,8 +7,7 @@ pub fn match_parameters( function: &Function, ) -> Vec { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); let mut matched_functions: Vec = Vec::new(); for mut resolved_function in resolved_functions { diff --git a/core/src/snapshot/resolve.rs b/core/src/snapshot/resolve.rs index f0026e10..c12a8017 100644 --- a/core/src/snapshot/resolve.rs +++ b/core/src/snapshot/resolve.rs @@ -8,8 +8,7 @@ pub fn match_parameters( function: &Snapshot, ) -> Vec { // get a new logger - let level = std::env::var("RUST_LOG").unwrap_or_else(|_| "INFO".into()); - let (logger, _) = Logger::new(&level); + let logger = Logger::default(); let mut matched_functions: Vec = Vec::new(); for mut resolved_function in resolved_functions {