Skip to content

Commit 1644ed2

Browse files
authored
Merge pull request #60 from 0xVida/main
feat: add gas optimization checker
2 parents 865d3ef + 872df83 commit 1644ed2

7 files changed

Lines changed: 395 additions & 2 deletions

File tree

src/cli/args.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ pub enum Commands {
2020

2121
/// Inspect contract information without executing
2222
Inspect(InspectArgs),
23+
24+
/// Analyze contract and generate gas optimization suggestions
25+
Optimize(OptimizeArgs),
2326
}
2427

2528
#[derive(Parser)]
@@ -74,3 +77,26 @@ pub struct InspectArgs {
7477
#[arg(long)]
7578
pub metadata: bool,
7679
}
80+
81+
#[derive(Parser)]
82+
pub struct OptimizeArgs {
83+
/// Path to the contract WASM file
84+
#[arg(short, long)]
85+
pub contract: PathBuf,
86+
87+
/// Function name to analyze (can be specified multiple times)
88+
#[arg(short, long)]
89+
pub function: Vec<String>,
90+
91+
/// Function arguments as JSON array (e.g., '["arg1", "arg2"]')
92+
#[arg(short, long)]
93+
pub args: Option<String>,
94+
95+
/// Output file for the optimization report (default: stdout)
96+
#[arg(short, long)]
97+
pub output: Option<PathBuf>,
98+
99+
/// Initial storage state as JSON object
100+
#[arg(short, long)]
101+
pub storage: Option<String>,
102+
}

src/cli/commands.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::cli::args::{InspectArgs, InteractiveArgs, RunArgs};
1+
use crate::cli::args::{InspectArgs, InteractiveArgs, OptimizeArgs, RunArgs};
22
use crate::debugger::engine::DebuggerEngine;
33
use crate::runtime::executor::ContractExecutor;
44
use crate::ui::tui::DebuggerUI;
@@ -125,3 +125,59 @@ fn parse_storage(json: &str) -> Result<String> {
125125
.with_context(|| format!("Invalid JSON storage: {}", json))?;
126126
Ok(json.to_string())
127127
}
128+
129+
/// Execute the optimize command
130+
pub fn optimize(args: OptimizeArgs) -> Result<()> {
131+
println!("Analyzing contract for gas optimization: {:?}", args.contract);
132+
133+
let wasm_bytes = fs::read(&args.contract)
134+
.with_context(|| format!("Failed to read WASM file: {:?}", args.contract))?;
135+
136+
println!("Contract loaded successfully ({} bytes)", wasm_bytes.len());
137+
138+
let mut executor = ContractExecutor::new(wasm_bytes)?;
139+
140+
if let Some(storage_json) = &args.storage {
141+
let storage = parse_storage(storage_json)?;
142+
executor.set_initial_storage(storage)?;
143+
}
144+
145+
let functions_to_analyze = if args.function.is_empty() {
146+
println!("No functions specified, analyzing all exported functions...");
147+
crate::utils::wasm::parse_functions(&wasm_bytes)?
148+
} else {
149+
args.function.clone()
150+
};
151+
152+
let mut optimizer = crate::profiler::analyzer::GasOptimizer::new(executor);
153+
154+
println!("\nAnalyzing {} function(s)...", functions_to_analyze.len());
155+
156+
for function_name in &functions_to_analyze {
157+
println!(" Analyzing function: {}", function_name);
158+
match optimizer.analyze_function(function_name, args.args.as_deref()) {
159+
Ok(profile) => {
160+
println!(" CPU: {} instructions, Memory: {} bytes",
161+
profile.total_cpu, profile.total_memory);
162+
}
163+
Err(e) => {
164+
eprintln!(" Warning: Failed to analyze function {}: {}", function_name, e);
165+
}
166+
}
167+
}
168+
169+
let contract_path_str = args.contract.to_string_lossy().to_string();
170+
let report = optimizer.generate_report(&contract_path_str);
171+
172+
let markdown = optimizer.generate_markdown_report(&report);
173+
174+
if let Some(output_path) = &args.output {
175+
fs::write(output_path, &markdown)
176+
.with_context(|| format!("Failed to write report to: {:?}", output_path))?;
177+
println!("\nOptimization report written to: {:?}", output_path);
178+
} else {
179+
println!("\n{}", markdown);
180+
}
181+
182+
Ok(())
183+
}

src/cli/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
pub mod args;
22
pub mod commands;
33

4-
pub use args::{Cli, Commands, InspectArgs, InteractiveArgs, RunArgs};
4+
pub use args::{Cli, Commands, InspectArgs, InteractiveArgs, OptimizeArgs, RunArgs};

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub mod inspector;
44
pub mod runtime;
55
pub mod ui;
66
pub mod utils;
7+
pub mod profiler;
78

89
pub use debugger::engine::DebuggerEngine;
910
pub use runtime::executor::ContractExecutor;

src/main.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ fn main() -> Result<()> {
2727
Commands::Inspect(args) => {
2828
soroban_debugger::cli::commands::inspect(args)?;
2929
}
30+
Commands::Optimize(args) => {
31+
soroban_debugger::cli::commands::optimize(args)?;
32+
}
3033
}
3134

3235
Ok(())

0 commit comments

Comments
 (0)