Skip to content

feat: mock_call with dynamic return data #2904

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

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0ff1663
feat(snforge_std): add "dynamic" return value for mock_call
ptisserand Jan 31, 2025
f21e510
feat(cheatnet): add "dynamic" return value fir mock_call
ptisserand Jan 31, 2025
3c37814
forge: update test to support new mock_call cheatcode
ptisserand Jan 31, 2025
d1921ea
fix mock_call test
ptisserand Jan 31, 2025
9594b5a
cheatnet: fixup clippy
ptisserand Jan 31, 2025
c097e3c
snforge_std: revert breaking changes on `mock_call`
ptisserand Feb 3, 2025
e70b4b1
fix(cheatnet): default to any calldata entry when specific CheatSpan:…
ptisserand Feb 3, 2025
02a7dcd
docs: add `mock_call_when` cheatcode
ptisserand Feb 4, 2025
3498701
use `calldata` instead of `call_data`
ptisserand Feb 11, 2025
f4bc282
cheatnet: add MockCalldata enum
ptisserand Feb 18, 2025
e15e00f
Merge remote-tracking branch 'upstream/master'
ptisserand Apr 30, 2025
90cff00
fix: add missing argument for run_test_case
ptisserand May 2, 2025
2cd43a4
scarb fmt
ptisserand May 2, 2025
e1293a8
Merge remote-tracking branch 'upstream/master' into feat/dynamic-mock…
ptisserand May 17, 2025
2c5ec93
remove workaround for #2927
ptisserand May 17, 2025
3aeb496
add test cases with interleaved start/stop mock_call and mock_call_when
ptisserand Jul 15, 2025
1a20bbd
Merge remote-tracking branch 'upstream/master' into feat/dynamic-mock…
ptisserand Jul 15, 2025
f235bd7
cargo fmt
ptisserand Jul 15, 2025
da9bc28
Merge remote-tracking branch 'upstream/master' into master-merged
ptisserand Aug 5, 2025
3ae2a28
add missing use for cheatcodes
ptisserand Aug 5, 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Rust is no longer required to use `snforge` if using Scarb >= 2.10.0 on supported platforms - precompiled `snforge_scarb_plugin` plugin binaries are now published to [package registry](https://scarbs.xyz) for new versions.
- Added a suggestion for using the `--max-n-steps` flag when the Cairo VM returns the error: `Could not reach the end of the program. RunResources has no remaining steps`.
- `mock_call_when`, `start_mock_call_when`, `stop_mock_call_when` cheatcodes.

#### Fixed

Expand Down
1 change: 1 addition & 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 crates/cheatnet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ bimap.workspace = true
camino.workspace = true
starknet_api.workspace = true
starknet-types-core.workspace = true
starknet-crypto.workspace = true
cairo-lang-casm.workspace = true
cairo-lang-utils.workspace = true
cairo-lang-starknet-classes.workspace = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ use cairo_vm::vm::runners::cairo_runner::{CairoRunner, ExecutionResources};
use cairo_vm::vm::trace::trace_entry::RelocatedTraceEntry;
use conversions::FromConv;
use conversions::string::TryFromHexStr;
use num_traits::Zero;
use shared::vm::VirtualMachineExt;
use starknet_api::{
contract_class::EntryPointType,
core::ClassHash,
transaction::{TransactionVersion, fields::Calldata},
};
use starknet_crypto::poseidon_hash_many;
use starknet_types_core::felt::Felt;
use std::collections::{HashMap, HashSet};
use thiserror::Error;
Expand Down Expand Up @@ -415,11 +417,22 @@ fn get_mocked_function_cheat_status<'a>(
if call.call_type == CallType::Delegate {
return None;
}

cheatnet_state
match cheatnet_state
.mocked_functions
.get_mut(&call.storage_address)
.and_then(|contract_functions| contract_functions.get_mut(&call.entry_point_selector))
{
None => None,
Some(contract_functions) => {
let calldata_hash = poseidon_hash_many(call.calldata.0.iter());
let key = (call.entry_point_selector, calldata_hash);
let key_zero = (call.entry_point_selector, Felt::zero());

match contract_functions.get(&key) {
Some(CheatStatus::Cheated(_, _)) => contract_functions.get_mut(&key),
_ => contract_functions.get_mut(&key_zero),
}
}
}
}

fn mocked_call_info(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::CheatnetState;
use crate::state::{CheatSpan, CheatStatus};
use crate::state::{CheatSpan, CheatStatus, MockCalldata};
use num_traits::Zero;
use starknet_api::core::{ContractAddress, EntryPointSelector};
use starknet_crypto::poseidon_hash_many;
use starknet_types_core::felt::Felt;
use std::collections::hash_map::Entry;

Expand All @@ -9,26 +11,30 @@ impl CheatnetState {
&mut self,
contract_address: ContractAddress,
function_selector: EntryPointSelector,
calldata: MockCalldata,
ret_data: &[Felt],
span: CheatSpan,
) {
let contract_mocked_functions = self.mocked_functions.entry(contract_address).or_default();

contract_mocked_functions.insert(
function_selector,
CheatStatus::Cheated(ret_data.to_vec(), span),
);
let calldata_hash = match calldata {
MockCalldata::Values(data) => poseidon_hash_many(data.iter()),
MockCalldata::Any => Felt::zero(),
};
let key = (function_selector, calldata_hash);
contract_mocked_functions.insert(key, CheatStatus::Cheated(ret_data.to_vec(), span));
}

pub fn start_mock_call(
&mut self,
contract_address: ContractAddress,
function_selector: EntryPointSelector,
calldata: MockCalldata,
ret_data: &[Felt],
) {
self.mock_call(
contract_address,
function_selector,
calldata,
ret_data,
CheatSpan::Indefinite,
);
Expand All @@ -38,10 +44,15 @@ impl CheatnetState {
&mut self,
contract_address: ContractAddress,
function_selector: EntryPointSelector,
calldata: MockCalldata,
) {
if let Entry::Occupied(mut e) = self.mocked_functions.entry(contract_address) {
let contract_mocked_functions = e.get_mut();
contract_mocked_functions.remove(&function_selector);
let calldata_hash = match calldata {
MockCalldata::Values(data) => poseidon_hash_many(data.iter()),
MockCalldata::Any => Felt::zero(),
};
contract_mocked_functions.remove(&(function_selector, calldata_hash));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,26 +95,31 @@ impl<'a> ExtensionLogic for ForgeExtension<'a> {
"mock_call" => {
let contract_address = input_reader.read()?;
let function_selector = input_reader.read()?;
let calldata = input_reader.read()?;
let span = input_reader.read()?;

let ret_data: Vec<_> = input_reader.read()?;

extended_runtime
.extended_runtime
.extension
.cheatnet_state
.mock_call(contract_address, function_selector, &ret_data, span);
.mock_call(
contract_address,
function_selector,
calldata,
&ret_data,
span,
);
Ok(CheatcodeHandlingResult::from_serializable(()))
}
"stop_mock_call" => {
let contract_address = input_reader.read()?;
let function_selector = input_reader.read()?;

let calldata = input_reader.read()?;
extended_runtime
.extended_runtime
.extension
.cheatnet_state
.stop_mock_call(contract_address, function_selector);
.stop_mock_call(contract_address, function_selector, calldata);
Ok(CheatcodeHandlingResult::from_serializable(()))
}
"replace_bytecode" => {
Expand Down
9 changes: 8 additions & 1 deletion crates/cheatnet/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ pub enum CheatSpan {
TargetCalls(NonZeroUsize),
}

#[derive(CairoDeserialize, Clone, Debug, PartialEq, Eq)]
pub enum MockCalldata {
Any,
Values(Vec<Felt>),
}

#[derive(Debug)]
pub struct ExtendedStateReader {
pub dict_state_reader: DictStateReader,
Expand Down Expand Up @@ -369,12 +375,13 @@ pub struct TraceData {
pub is_vm_trace_needed: bool,
}

type MockedFunctionKey = (EntryPointSelector, Felt);
pub struct CheatnetState {
pub cheated_execution_info_contracts: HashMap<ContractAddress, ExecutionInfoMock>,
pub global_cheated_execution_info: ExecutionInfoMock,

pub mocked_functions:
HashMap<ContractAddress, HashMap<EntryPointSelector, CheatStatus<Vec<Felt>>>>,
HashMap<ContractAddress, HashMap<MockedFunctionKey, CheatStatus<Vec<Felt>>>>,
pub replaced_bytecode_contracts: HashMap<ContractAddress, ClassHash>,
pub detected_events: Vec<Event>,
pub detected_messages_to_l1: Vec<MessageToL1>,
Expand Down
Loading
Loading