-
Notifications
You must be signed in to change notification settings - Fork 240
Add get_current_vm_step
#3868
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Add get_current_vm_step
#3868
Changes from 30 commits
b55a950
8a8a80f
073c95f
77dd8b9
5672903
53494da
5dd5177
ab287a4
d3ceb43
7af1256
feed6d5
2afa790
9b7e7a2
30d1404
b5c1de0
57deb3b
a674c9d
8b22af2
7254799
86b73b0
660ec59
65c6297
c691cb1
113bc5f
cbdd37e
d84fe26
e4b5c13
b94c072
3a999a8
48c9e68
7f6a893
195544a
ec48ca9
4aab58a
d17f252
d37a05b
13f1af4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we add some kind of sanity check where we assert specific value of used steps (or a delta of steps)? So we detect eventually regressions if these change significantly.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see that we have a test below that does this for contracts but let's have one for top level calls as well.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've extended
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, let's add a test where we have inner calls and these inner calls do some expensive computation (not just increment some counter, but call some more expensive syscalls). Check if steps value is "large enough" there.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should be able to roughly estimate the steps value from fee mechanism docs https://docs.starknet.io/learn/protocol/fees#vm-resources similarly as we do in our gas integration tests and check if values in the test are roughly withing the expected range.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Responded in comment above. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| use crate::utils::runner::{Contract, assert_passed}; | ||
| use crate::utils::running_tests::run_test_case; | ||
| use crate::utils::test_case; | ||
| use forge_runner::forge_config::ForgeTrackedResource; | ||
| use indoc::indoc; | ||
| use std::path::Path; | ||
|
|
||
| #[test] | ||
| fn test_get_current_vm_step() { | ||
| let test = test_case!( | ||
| indoc!( | ||
| r#" | ||
| use snforge_std::testing::get_current_vm_step; | ||
| use snforge_std::{ContractClassTrait, DeclareResultTrait, declare}; | ||
|
|
||
| #[test] | ||
| fn check_current_vm_step() { | ||
| let step_start = get_current_vm_step(); | ||
|
|
||
| let contract = declare("HelloStarknet").unwrap().contract_class().clone(); | ||
| let _ = contract.deploy(@ArrayTrait::new()).unwrap(); | ||
|
|
||
| let step_end = get_current_vm_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::CairoSteps); | ||
|
|
||
| assert_passed(&result); | ||
| } |
| 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]] |
| 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); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| use snforge_std::testing::get_current_vm_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_vm_step(); | ||
| setup(); | ||
| let steps_end = get_current_vm_step(); | ||
|
|
||
| // Assert that setup used no more than 100 steps | ||
| assert!(steps_end - steps_start <= 100); | ||
| } |
| 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_vm_step`](./testing/get_current_vm_step.md) |
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd reword this so it's more of a reference than a tutorial, explanations like that fit more in the Take a look at fuzzable docs for example, let's show an reference for what
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It's not shown in I've reduced the textual description, but kept contract and test code (13f1af4). We can move this little tutorial under |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| # `get_current_vm_step` | ||
|
|
||
| Gets the current step from Cairo VM during test execution. | ||
|
|
||
| ```rust | ||
| fn get_current_vm_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). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -126,6 +126,8 @@ pub mod fuzzable; | |
|
|
||
| pub mod signature; | ||
|
|
||
| pub mod testing; | ||
|
|
||
| pub mod trace; | ||
|
|
||
| #[doc(hidden)] | ||
|
|
||
| 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_vm_step() -> u32 { | ||
| execute_cheatcode_and_deserialize::<'get_current_vm_step', u32>(array![].span()) | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.