Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,4 @@ tracing-subscriber = { version = "0.3.20", features = ["env-filter"] }
tracing = "0.1.41"
tracing-chrome = "0.7.2"
tracing-log = "0.2.0"
comfy-table = "7"
1 change: 1 addition & 0 deletions crates/forge-runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ strum = "0.27"
strum_macros = "0.27"
scarb-oracle-hint-service.workspace = true
tracing.workspace = true
comfy-table.workspace = true
56 changes: 56 additions & 0 deletions crates/forge-runner/src/gas/report.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use crate::gas::stats::GasStats;
use cheatnet::trace_data::{CallTrace, CallTraceNode};
use comfy_table::modifiers::UTF8_ROUND_CORNERS;
use comfy_table::{Attribute, Cell, Color, Table};
use debugging::ContractsDataStore;
use starknet_api::core::{ClassHash, EntryPointSelector};
use starknet_api::execution_resources::GasVector;
use std::collections::BTreeMap;
use std::fmt;
use std::fmt::Display;

type ContractName = String;
type Selector = String;
Expand Down Expand Up @@ -103,6 +107,25 @@ impl ReportData {
}
}

impl Display for ReportData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0.is_empty() {
writeln!(
f,
"\nNo contract gas usage data to display. Make sure your test include transactions."
)?;
}

for (name, contract_info) in &self.0 {
if !contract_info.functions.is_empty() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a panic for this would make more sense if it cannot occur at all, or an unrachable block.

Unless we are afraid it might happen somehow?

let table = format_table_output(contract_info, name);
writeln!(f, "\n{table}")?;
}
}
Ok(())
}
}

fn get_contract_name(contracts_data: &ContractsDataStore, class_hash: ClassHash) -> ContractName {
contracts_data
.get_contract_name(&class_hash)
Expand All @@ -117,3 +140,36 @@ fn get_selector(contracts_data: &ContractsDataStore, selector: EntryPointSelecto
.0
.clone()
}

pub fn format_table_output(contract_info: &ContractInfo, name: &ContractName) -> Table {
let mut table = Table::new();
table.apply_modifier(UTF8_ROUND_CORNERS);

table.set_header(vec![
Cell::new(format!("{name} Contract")).fg(Color::Magenta),
]);
table.add_row(vec![
Cell::new("Function Name").add_attribute(Attribute::Bold),
Cell::new("Min").add_attribute(Attribute::Bold),
Cell::new("Max").add_attribute(Attribute::Bold),
Cell::new("Avg").add_attribute(Attribute::Bold),
Cell::new("Std Dev").add_attribute(Attribute::Bold),
Cell::new("# Calls").add_attribute(Attribute::Bold),
]);

contract_info
.functions
.iter()
.for_each(|(selector, report_data)| {
table.add_row(vec![
Cell::new(selector),
Cell::new(report_data.gas_stats.min.to_string()),
Cell::new(report_data.gas_stats.max.to_string()),
Cell::new(report_data.gas_stats.mean.round().to_string()),
Cell::new(report_data.gas_stats.std_deviation.round().to_string()),
Cell::new(report_data.n_calls.to_string()),
]);
});

table
}
28 changes: 20 additions & 8 deletions crates/forge-runner/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub struct TestResultMessage {
fuzzer_report: String,
gas_usage: String,
used_resources: String,
gas_report: String,
}

impl TestResultMessage {
Expand Down Expand Up @@ -75,16 +76,25 @@ impl TestResultMessage {
String::new()
};

let gas_usage = match test_result {
let (gas_usage, gas_report) = match test_result {
AnyTestCaseSummary::Single(TestCaseSummary::Passed { gas_info, .. }) => {
format!(
" (l1_gas: ~{}, l1_data_gas: ~{}, l2_gas: ~{})",
gas_info.gas_used.l1_gas,
gas_info.gas_used.l1_data_gas,
gas_info.gas_used.l2_gas
let gas_report = gas_info
.report_data
.as_ref()
.map(std::string::ToString::to_string)
.unwrap_or_default();

(
format!(
" (l1_gas: ~{}, l1_data_gas: ~{}, l2_gas: ~{})",
gas_info.gas_used.l1_gas,
gas_info.gas_used.l1_data_gas,
gas_info.gas_used.l2_gas
),
gas_report,
)
}
_ => String::new(),
_ => (String::new(), String::new()),
};

let used_resources = match (show_detailed_resources, &test_result) {
Expand All @@ -104,6 +114,7 @@ impl TestResultMessage {
fuzzer_report,
gas_usage,
used_resources,
gas_report,
}
}

Expand Down Expand Up @@ -140,10 +151,11 @@ impl Message for TestResultMessage {

let fuzzer_report = &self.fuzzer_report;
let gas_usage = &self.gas_usage;
let gas_report = &self.gas_report;
let used_resources = &self.used_resources;

format!(
"{result_header} {result_name}{fuzzer_report}{gas_usage}{used_resources}{result_msg}{result_debug_trace}"
"{result_header} {result_name}{fuzzer_report}{gas_usage}{used_resources}{result_msg}{result_debug_trace}{gas_report}"
)
}

Expand Down
144 changes: 144 additions & 0 deletions crates/forge/tests/e2e/gas_report.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
use crate::e2e::common::runner::{setup_package, test_runner};
use indoc::indoc;
use shared::test_utils::output_assert::assert_stdout_contains;

#[test]
fn basic() {
let temp = setup_package("simple_package");
let output = test_runner(&temp)
.arg("--gas-report")
.arg("call_and_invoke")
.assert()
.code(0);

assert_stdout_contains(
output,
indoc! {r"
[..]Compiling[..]
[..]Finished[..]


Collected 1 test(s) from simple_package package
Running 0 test(s) from src/
Running 1 test(s) from tests/
[PASS] simple_package_integrationtest::contract::call_and_invoke (l1_gas: ~0, l1_data_gas: ~[..], l2_gas: ~[..])
╭------------------------+-------+-------+-------+---------+---------╮
| HelloStarknet Contract | | | | | |
+====================================================================+
| Function Name | Min | Max | Avg | Std Dev | # Calls |
|------------------------+-------+-------+-------+---------+---------|
| get_balance | 13340 | 13340 | 13340 | 0 | 2 |
|------------------------+-------+-------+-------+---------+---------|
| increase_balance | 24940 | 24940 | 24940 | 0 | 1 |
╰------------------------+-------+-------+-------+---------+---------╯

Tests: 1 passed, 0 failed, 0 ignored, [..] filtered out
"},
);
}

#[test]
fn recursive_calls() {
let temp = setup_package("debugging");

let output = test_runner(&temp)
.arg("test_debugging_trace_success")
.arg("--gas-report")
.assert()
.code(0);

assert_stdout_contains(
output,
indoc! {r"
[..]Compiling[..]
[..]Finished[..]


Collected 1 test(s) from debugging package
Running 0 test(s) from src/
Running 1 test(s) from tests/
[PASS] debugging_integrationtest::test_trace::test_debugging_trace_success (l1_gas: ~0, l1_data_gas: ~[..], l2_gas: ~[..])
╭-------------------------+-------+--------+--------+---------+---------╮
| SimpleContract Contract | | | | | |
+=======================================================================+
| Function Name | Min | Max | Avg | Std Dev | # Calls |
|-------------------------+-------+--------+--------+---------+---------|
| execute_calls | 11680 | 609080 | 183924 | 235859 | 5 |
|-------------------------+-------+--------+--------+---------+---------|
| fail | 17950 | 17950 | 17950 | 0 | 1 |
╰-------------------------+-------+--------+--------+---------+---------╯

Tests: 1 passed, 0 failed, 0 ignored, [..] filtered out
"},
);
}

#[test]
fn multiple_contracts_and_constructor() {
let temp = setup_package("simple_package_with_cheats");
let output = test_runner(&temp)
.arg("--gas-report")
.arg("call_and_invoke_proxy")
.assert()
.code(0);

assert_stdout_contains(
output,
indoc! {r"
[..]Compiling[..]
[..]Finished[..]


Collected 1 test(s) from simple_package_with_cheats package
Running 0 test(s) from src/
Running 1 test(s) from tests/
[PASS] simple_package_with_cheats_integrationtest::contract::call_and_invoke_proxy (l1_gas: ~0, l1_data_gas: ~[..], l2_gas: ~[..])
╭------------------------+-------+-------+-------+---------+---------╮
| HelloStarknet Contract | | | | | |
+====================================================================+
| Function Name | Min | Max | Avg | Std Dev | # Calls |
|------------------------+-------+-------+-------+---------+---------|
| get_block_number | 15780 | 15780 | 15780 | 0 | 2 |
╰------------------------+-------+-------+-------+---------+---------╯

╭-----------------------------+--------+--------+--------+---------+---------╮
| HelloStarknetProxy Contract | | | | | |
+============================================================================+
| Function Name | Min | Max | Avg | Std Dev | # Calls |
|-----------------------------+--------+--------+--------+---------+---------|
| constructor | 14650 | 14650 | 14650 | 0 | 1 |
|-----------------------------+--------+--------+--------+---------+---------|
| get_block_number | 125280 | 125280 | 125280 | 0 | 2 |
╰-----------------------------+--------+--------+--------+---------+---------╯

Tests: 1 passed, 0 failed, 0 ignored, [..] filtered out
"},
);
}

#[test]
fn no_transactions() {
let temp = setup_package("simple_package");
let output = test_runner(&temp)
.arg("--gas-report")
.arg("test_fib")
.assert()
.code(0);

assert_stdout_contains(
output,
indoc! {r"
[..]Compiling[..]
[..]Finished[..]


Collected 1 test(s) from simple_package package
Running 1 test(s) from src/
[PASS] simple_package::tests::test_fib (l1_gas: ~0, l1_data_gas: ~0, l2_gas: ~[..])
No contract gas usage data to display. Make sure your test include transactions.

Running 0 test(s) from tests/
Tests: 1 passed, 0 failed, 0 ignored, [..] filtered out
"},
);
}
1 change: 1 addition & 0 deletions crates/forge/tests/e2e/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod features;
mod fork_warning;
mod forking;
mod fuzzing;
mod gas_report;
mod io_operations;
mod new;
mod package_warnings;
Expand Down
Loading