Skip to content
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
b55a950
Add `get_current_step`
franciszekjob Oct 23, 2025
8a8a80f
Minor refactor
franciszekjob Oct 23, 2025
073c95f
Fix scarb formatting
franciszekjob Oct 23, 2025
77dd8b9
Add test
franciszekjob Oct 23, 2025
5672903
Update changelog
franciszekjob Oct 23, 2025
53494da
Ignore cheats test of `meta_tx_v0` on `cairo-native`
MKowalski8 Oct 24, 2025
5dd5177
Additional check native test
MKowalski8 Oct 24, 2025
ab287a4
Enable test on vm
MKowalski8 Oct 24, 2025
d3ceb43
Merge branch 'fix-native-meta-tx-v0-tests' into 3824-get-current-step
franciszekjob Oct 24, 2025
7af1256
Merge branch 'master' of https://github.com/foundry-rs/starknet-found…
franciszekjob Oct 28, 2025
feed6d5
Apply code review suggestions
franciszekjob Oct 28, 2025
2afa790
Fix linting
franciszekjob Oct 28, 2025
9b7e7a2
Merge branch '3824-get-current-step' of https://github.com/foundry-rs…
franciszekjob Oct 28, 2025
30d1404
Fix lock
franciszekjob Oct 28, 2025
b5c1de0
WIP
franciszekjob Nov 3, 2025
57deb3b
Fix resources calculation
franciszekjob Nov 4, 2025
a674c9d
Remove print
franciszekjob Nov 4, 2025
8b22af2
Refactor
franciszekjob Nov 4, 2025
7254799
Little refactor
franciszekjob Nov 4, 2025
86b73b0
Remove unused file
franciszekjob Nov 4, 2025
660ec59
Refactor names
franciszekjob Nov 4, 2025
65c6297
Rename `vm_steps_total` -> `total_steps`
franciszekjob Nov 4, 2025
c691cb1
Apply code review suggestions
franciszekjob Nov 5, 2025
113bc5f
Apply code review suggestions
franciszekjob Nov 5, 2025
cbdd37e
Apply code review suggestions
franciszekjob Nov 6, 2025
d84fe26
Rename test
franciszekjob Nov 6, 2025
e4b5c13
Merge branch 'master' of https://github.com/foundry-rs/starknet-found…
franciszekjob Nov 6, 2025
b94c072
Fix imports
franciszekjob Nov 6, 2025
3a999a8
Remove comments
franciszekjob Nov 6, 2025
48c9e68
Add comment
franciszekjob Nov 6, 2025
7f6a893
Change variable name
franciszekjob Nov 7, 2025
195544a
Add assertions for specific step values in `test_get_current_vm_step`
franciszekjob Nov 10, 2025
ec48ca9
Fix import
franciszekjob Nov 10, 2025
4aab58a
Fix test
franciszekjob Nov 10, 2025
d17f252
Improve test for `get_current_vm_step`
franciszekjob Nov 10, 2025
d37a05b
Fix test
franciszekjob Nov 10, 2025
13f1af4
Reduce explanation
franciszekjob Nov 10, 2025
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Forge

#### Added

- `get_current_step` function to get the current step from Cairo VM during test execution. For more see [docs](https://foundry-rs.github.io/starknet-foundry/snforge-library/testing/get_current_step.html)

#### Changed

- Gas values in fuzzing test output are now displayed as whole numbers without fractional parts
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use cairo_vm::vm::vm_core::VirtualMachine;
use config::RawForgeConfig;
use conversions::serde::deserialize::BufferReader;
use runtime::{CheatcodeHandlingResult, EnhancedHintError, ExtensionLogic, StarknetRuntime};
Expand All @@ -17,6 +18,7 @@ impl<'a> ExtensionLogic for ForgeConfigExtension<'a> {
selector: &str,
mut input_reader: BufferReader<'_>,
_extended_runtime: &mut Self::Runtime,
_vm: &VirtualMachine,
) -> Result<CheatcodeHandlingResult, EnhancedHintError> {
macro_rules! config_cheatcode {
( $prop:ident) => {{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::runtime_extensions::{
};
use crate::trace_data::{CallTrace, CallTraceNode, GasReportData};
use anyhow::{Context, Result, anyhow};
use blockifier::blockifier_versioned_constants::VersionedConstants;
use blockifier::bouncer::vm_resources_to_sierra_gas;
use blockifier::context::TransactionContext;
use blockifier::execution::call_info::{
Expand Down Expand Up @@ -81,6 +82,7 @@ impl<'a> ExtensionLogic for ForgeExtension<'a> {
selector: &str,
mut input_reader: BufferReader<'_>,
extended_runtime: &mut Self::Runtime,
vm: &VirtualMachine,
) -> Result<CheatcodeHandlingResult, EnhancedHintError> {
if let Some(oracle_selector) = self
.oracle_hint_service
Expand Down Expand Up @@ -552,6 +554,27 @@ impl<'a> ExtensionLogic for ForgeExtension<'a> {
.cheat_block_hash(block_number, operation);
Ok(CheatcodeHandlingResult::from_serializable(()))
}
"get_current_step" => {
let top_call = extended_runtime
.extended_runtime
.extension
.cheatnet_state
.trace_data
.current_call_stack
.top();

let top_call_syscalls = &extended_runtime
.extended_runtime
.extended_runtime
.hint_handler
.base
.syscalls_usage;

let steps_from_calls = calculate_steps_from_calls(&top_call, top_call_syscalls);
let total_steps = steps_from_calls + vm.get_current_step();

Ok(CheatcodeHandlingResult::from_serializable(total_steps))
}
_ => Ok(CheatcodeHandlingResult::Forwarded),
}
}
Expand Down Expand Up @@ -858,3 +881,26 @@ pub fn get_all_used_resources(
l1_handler_payload_lengths,
}
}

fn calculate_steps_from_calls(
top_call: &Rc<RefCell<CallTrace>>,
top_call_syscalls: &SyscallUsageMap,
) -> usize {
// Resources from inner calls already include syscall resources used in them
let used_resources =
&top_call
.borrow()
.nested_calls
.iter()
.fold(ExecutionResources::default(), |acc, node| match node {
CallTraceNode::EntryPointCall(call_trace) => {
&acc + &call_trace.borrow().used_execution_resources
}
CallTraceNode::DeployWithoutConstructor => acc,
});
let total_syscalls_exeucution_resources = &VersionedConstants::latest_constants()
.get_additional_os_syscall_resources(&top_call_syscalls);
let resources_from_calls = used_resources + total_syscalls_exeucution_resources;

resources_from_calls.n_steps
}
39 changes: 39 additions & 0 deletions crates/forge/tests/integration/get_current_step.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use forge_runner::forge_config::ForgeTrackedResource;
use indoc::indoc;
use std::path::Path;
use test_utils::runner::{Contract, assert_passed};
use test_utils::running_tests::run_test_case;
use test_utils::test_case;

#[test]
fn test_get_current_step() {
let test = test_case!(
indoc!(
r#"
use snforge_std::testing::get_current_step;
use snforge_std::{ContractClassTrait, DeclareResultTrait, declare};

#[test]
fn check_current_step() {
let step_start = get_current_step();

let contract = declare("HelloStarknet").unwrap().contract_class().clone();
let _ = contract.deploy(@ArrayTrait::new()).unwrap();

let step_end = get_current_step();

assert!(step_end > step_start);
}
"#
),
Contract::from_code_path(
"HelloStarknet".to_string(),
Path::new("tests/data/contracts/hello_starknet.cairo"),
)
.unwrap()
);

let result = run_test_case(&test, ForgeTrackedResource::SierraGas);

assert_passed(&result);
}
1 change: 1 addition & 0 deletions crates/forge/tests/integration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod gas;
mod generate_random_felt;
mod get_available_gas;
mod get_class_hash;
mod get_current_step;
mod interact_with_state;
mod l1_handler_executor;
mod message_to_l1;
Expand Down
2 changes: 2 additions & 0 deletions crates/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ impl<Extension: ExtensionLogic> ExtendedRuntime<Extension> {
&selector,
BufferReader::new(&inputs),
&mut self.extended_runtime,
vm,
);

let res = match result {
Expand Down Expand Up @@ -423,6 +424,7 @@ pub trait ExtensionLogic {
_selector: &str,
_input_reader: BufferReader,
_extended_runtime: &mut Self::Runtime,
_vm: &VirtualMachine,
) -> Result<CheatcodeHandlingResult, EnhancedHintError> {
Ok(CheatcodeHandlingResult::Forwarded)
}
Expand Down
1 change: 1 addition & 0 deletions crates/sncast/src/starknet_commands/script/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ impl<'a> ExtensionLogic for CastScriptExtension<'a> {
selector: &str,
mut input_reader: BufferReader,
_extended_runtime: &mut Self::Runtime,
_vm: &VirtualMachine,
) -> Result<CheatcodeHandlingResult, EnhancedHintError> {
match selector {
"call" => {
Expand Down
12 changes: 12 additions & 0 deletions docs/listings/testing_reference/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "testing_reference"
version = "0.1.0"
edition = "2024_07"

[dependencies]
starknet = "2.12.0"

[dev-dependencies]
snforge_std = { path = "../../../snforge_std" }

[[target.starknet-contract]]
27 changes: 27 additions & 0 deletions docs/listings/testing_reference/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#[starknet::interface]
pub trait ICounter<TContractState> {
fn increment(ref self: TContractState);
}

#[starknet::contract]
pub mod Counter {
use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess};

#[storage]
struct Storage {
i: felt252,
}

#[constructor]
fn constructor(ref self: ContractState) {
self.i.write(0);
}

#[abi(embed_v0)]
impl CounterImpl of super::ICounter<ContractState> {
fn increment(ref self: ContractState) {
let current_value = self.i.read();
self.i.write(current_value + 1);
}
}
}
30 changes: 30 additions & 0 deletions docs/listings/testing_reference/tests/tests.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use snforge_std::testing::get_current_step;
use snforge_std::{ContractClassTrait, DeclareResultTrait, declare};
use testing_reference::{ICounterSafeDispatcher, ICounterSafeDispatcherTrait};

#[feature("safe_dispatcher")]
fn setup() {
// Deploy contract
let (contract_address, _) = declare("Counter")
.unwrap()
.contract_class()
.deploy(@array![])
.unwrap();

let dispatcher = ICounterSafeDispatcher { contract_address };

// Increment counter a few times
dispatcher.increment();
dispatcher.increment();
dispatcher.increment();
}

#[test]
fn test_setup_steps() {
let steps_start = get_current_step();
setup();
let steps_end = get_current_step();

// Assert that setup used no more than 100 steps
assert!(steps_end - steps_start <= 100);
}
2 changes: 2 additions & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@
* [env](appendix/snforge-library/env.md)
* [signature](appendix/snforge-library/signature.md)
* [fuzzable](appendix/snforge-library/fuzzable.md)
* [testing](appendix/snforge-library/testing.md)
* [get_current_step](appendix/snforge-library/testing/get_current_step.md)
* [`sncast` Commands](appendix/sncast.md)
* [common flags](appendix/sncast/common.md)
* [account](appendix/sncast/account/account.md)
Expand Down
7 changes: 7 additions & 0 deletions docs/src/appendix/snforge-library/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# `testing` Module

Module containing functions useful for testing.

## Functions

* [`get_current_step`](./testing/get_current_step.md)
49 changes: 49 additions & 0 deletions docs/src/appendix/snforge-library/testing/get_current_step.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# `get_current_step`

Gets the current step from Cairo VM during test execution.

```rust
fn get_current_step() -> u32;
```

## Example

Let's consider a simple counter contract that increments a value stored in its storage.

```rust
{{#include ../../../../listings/testing_reference/src/lib.cairo}}
```

Now, let's define `setup` function which deploys this contract and increments the counter a few times and assert that `setup` function does not exceed a certain number of steps during its execution. This is particularly useful for performance testing and ensuring that our setup logic remains efficient.

```rust
{{#include ../../../../listings/testing_reference/tests/tests.cairo}}
```

<!-- { "package_name": "testing_reference" } -->
Let's run the test:
```shell
$ snforge test test_setup_steps
```

<details>
<summary>Output:</summary>

```shell
Collected 1 test(s) from testing_reference package
Running 0 test(s) from src/
Running 1 test(s) from tests/
[FAIL] testing_reference_integrationtest::tests::test_setup_steps

Failure data:
"assertion failed: `steps_end - steps_start <= 100`."

Tests: 0 passed, 1 failed, 0 ignored, 0 filtered out

Failures:
testing_reference_integrationtest::tests::test_setup_steps
```
</details>
<br>

As we can see, the test fails because the `setup` function exceeded the allowed number of steps (100 in this case).
2 changes: 2 additions & 0 deletions snforge_std/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ pub mod fuzzable;

pub mod signature;

pub mod testing;

pub mod trace;

#[doc(hidden)]
Expand Down
6 changes: 6 additions & 0 deletions snforge_std/src/testing.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use crate::cheatcode::execute_cheatcode_and_deserialize;

/// Gets the current step from Cairo VM during test execution
pub fn get_current_step() -> u32 {
execute_cheatcode_and_deserialize::<'get_current_step', u32>(array![].span())
}
Loading