Skip to content

Commit

Permalink
Merge branch 'master' into chore/mock-call-appendix-revamp
Browse files Browse the repository at this point in the history
  • Loading branch information
Arcticae authored Apr 16, 2024
2 parents dbe92e1 + 6df5d97 commit 6a04330
Show file tree
Hide file tree
Showing 34 changed files with 374 additions and 482 deletions.
77 changes: 14 additions & 63 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,89 +1,40 @@
# Contribution Guideline

Starknet Foundry is under active development and is open for contributions!
Want to get started?
Grab any [issue](https://github.com/foundry-rs/starknet-foundry/issues) labeled with `good-first-issue`!
Need some guidance?

Reach out to other developers on [Telegram](https://t.me/+d8ULaPxeRqlhMDNk) or open
a [GitHub discussion](https://github.com/foundry-rs/starknet-foundry/discussions)!
## Opening an issue

### Environment setup

See [development guide](https://foundry-rs.github.io/starknet-foundry/development/environment-setup.html) in Starknet
Foundry book for environment setup.

### Running Tests and Checks

> ⚠️ Make sure you run `./scripts/install_devnet.sh`
> and then set [Scarb](https://docs.swmansion.com/scarb/) version
> [compatible](https://github.com/foundry-rs/starknet-foundry/releases) with both `snforge` and `sncast`
> after setting up the development environment, otherwise the tests will fail.
Before creating a contribution, make sure your code passes the following checks

```shell
$ cargo test
$ cargo fmt --check
$ cargo lint
$ typos
```

Otherwise, it won't be possible to merge your contribution.

You can also run a specific set of tests, by directly running `cargo test`.
If you think something doesn't work or something is missing please open an issue! This way we can address this problem
and make Starknet Foundry better!
Before opening an issue, it is always a good idea to search existing
[issues](https://github.com/foundry-rs/starknet-foundry/issues) and verify if a similar one doesn't already exist.

For forge tests, make sure you are in `crates/forge` directory:

```shell
$ cargo test --lib # runs all unit tests
$ cargo test integration # runs all integration tests
$ cargo test e2e # runs all e2e tests
```

Similarly, to run sncast tests make sure you are in `crates/sncast` directory:

```shell
$ cargo test --lib # runs lib unit tests
$ cargo test helpers # runs helpers unit tests
$ cargo test integration # runs all integration tests
$ cargo test e2e # runs all e2e tests
```
## Contributing

Or to run cheatnet tests make sure you are in `crates/cheatnet` directory:
### Environment setup

```shell
$ cargo test --lib # runs lib unit tests
$ cargo test cheatcodes # runs all cheatcodes tests
$ cargo test starknet # runs all starknet tests
```
See [development guide](https://foundry-rs.github.io/starknet-foundry/development/environment-setup.html) in Starknet
Foundry book for environment setup.

## Contributing
### Selecting an issue
If you are a first time contributor pick up any issue labeled as `good-first-issue`. Write a comment that you would like to
work on it and we will assign it to you. Need some guidance? Reach out to other developers on [Telegram](https://t.me/+d8ULaPxeRqlhMDNk).

Before you open a pull request, it is always a good idea to search
the [issues](https://github.com/foundry-rs/starknet-foundry/issues) and verify if the feature you would like
to add hasn't been already discussed.
We also appreciate creating a feature request before making a contribution, so it can be discussed before you get to
work.
If you are a more experienced Starknet Foundry contributor you can pick any issue labeled as `help-wanted`. Make sure to discuss the details with the core team beforehand.

### Writing Tests

Please make sure the feature you are implementing is thoroughly tested with automatic tests.
You can check existing tests in the repository to see the recommended approach to testing.

### Breaking Changes

If the change you are introducing is changing or breaking the behavior of any already existing features, make sure to
include that information in the pull request description.

### Pull Request Size

Try to make your pull request self-contained, only introducing the necessary changes.
If your feature is complicated,
consider splitting the changes into meaningful parts and introducing them as separate pull requests.

While creating large pull requests usually will not prevent them from being merged, it may significantly increase review
time and increase the risk of complicated to resolve merge conflicts.
Creating very large pull requests may significantly increase review time or even prevent them from being merged.

### Contributions Related to Spelling and Grammar

Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ regex = "1.10.4"
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.115"
starknet = { git = "https://github.com/xJonathanLEI/starknet-rs", rev = "d980869" }
trace-data = { git = "https://github.com/software-mansion/cairo-profiler/", rev = "3af0782" }
trace-data = { git = "https://github.com/software-mansion/cairo-profiler/", rev = "0b9dafb" }
tempfile = "3.10.1"
thiserror = "1.0.58"
ctor = "0.2.7"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::cell::RefCell;
use super::cairo1_execution::execute_entry_point_call_cairo1;
use crate::runtime_extensions::call_to_blockifier_runtime_extension::execution::deprecated::cairo0_execution::execute_entry_point_call_cairo0;
use crate::runtime_extensions::call_to_blockifier_runtime_extension::CheatnetState;
use crate::state::{CallTrace, CheatStatus};
use crate::state::{CallTrace, CallTraceNode, CheatStatus};
use blockifier::execution::call_info::{CallExecution, Retdata};
use blockifier::{
execution::{
Expand Down Expand Up @@ -220,6 +220,9 @@ pub fn execute_constructor_entry_point(
let contract_class = state.get_compiled_contract_class(ctor_context.class_hash)?;
let Some(constructor_selector) = contract_class.constructor_selector() else {
// Contract has no constructor.
cheatnet_state
.trace_data
.add_deploy_without_constructor_node();
return handle_empty_constructor(ctor_context, calldata, remaining_gas);
};

Expand Down Expand Up @@ -278,18 +281,22 @@ fn mocked_call_info(call: CallEntryPoint, ret_data: Vec<StarkFelt>) -> CallInfo

fn aggregate_nested_syscall_counters(trace: &Rc<RefCell<CallTrace>>) -> SyscallCounter {
let mut result = SyscallCounter::new();
for nested_call in &trace.borrow().nested_calls {
let sub_trace_counter = aggregate_syscall_counters(nested_call);
result = sum_syscall_counters(result, &sub_trace_counter);
for nested_call_node in &trace.borrow().nested_calls {
if let CallTraceNode::EntryPointCall(nested_call) = nested_call_node {
let sub_trace_counter = aggregate_syscall_counters(nested_call);
result = sum_syscall_counters(result, &sub_trace_counter);
}
}
result
}

fn aggregate_syscall_counters(trace: &Rc<RefCell<CallTrace>>) -> SyscallCounter {
let mut result = trace.borrow().used_syscalls.clone();
for nested_call in &trace.borrow().nested_calls {
let sub_trace_counter = aggregate_nested_syscall_counters(nested_call);
result = sum_syscall_counters(result, &sub_trace_counter);
for nested_call_node in &trace.borrow().nested_calls {
if let CallTraceNode::EntryPointCall(nested_call) = nested_call_node {
let sub_trace_counter = aggregate_nested_syscall_counters(nested_call);
result = sum_syscall_counters(result, &sub_trace_counter);
}
}
result
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub enum CallResult {
Failure(CallFailure),
}

/// Enum representing possible call failure and its' type.
/// Enum representing possible call failure and its type.
/// `Panic` - Recoverable, meant to be caught by the user.
/// `Error` - Unrecoverable, equivalent of panic! in rust.
#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use self::contracts_data::ContractsData;
use crate::state::CallTraceNode;
use crate::{
runtime_extensions::{
call_to_blockifier_runtime_extension::{
Expand Down Expand Up @@ -686,10 +687,16 @@ fn handle_deploy_result(
fn serialize_call_trace(call_trace: &CallTrace, output: &mut Vec<Felt252>) {
serialize_call_entry_point(&call_trace.entry_point, output);

output.push(Felt252::from(call_trace.nested_calls.len()));
let visible_calls: Vec<_> = call_trace
.nested_calls
.iter()
.filter_map(CallTraceNode::extract_entry_point_call)
.collect();

output.push(Felt252::from(visible_calls.len()));

for call_trace in &call_trace.nested_calls {
serialize_call_trace(&call_trace.borrow(), output);
for call_trace_node in visible_calls {
serialize_call_trace(&call_trace_node.borrow(), output);
}

serialize_call_result(&call_trace.result, output);
Expand Down Expand Up @@ -737,7 +744,7 @@ fn serialize_call_result(call_result: &CallResult, output: &mut Vec<Felt252>) {
serialize_failure_data(0, panic_data.iter().cloned(), panic_data.len(), output);
}
CallFailure::Error { msg } => {
let data = ByteArray::from(msg.as_str()).serialize_with_magic();
let data = ByteArray::from(msg.as_str()).serialize_no_magic();
let len = data.len();
serialize_failure_data(1, data, len, output);
}
Expand Down Expand Up @@ -820,6 +827,7 @@ pub fn update_top_call_execution_resources(runtime: &mut ForgeRuntime) {
let nested_calls_syscalls = top_call
.nested_calls
.iter()
.filter_map(CallTraceNode::extract_entry_point_call)
.fold(SyscallCounter::new(), |syscalls, trace| {
sum_syscall_counters(syscalls, &trace.borrow().used_syscalls)
});
Expand Down
59 changes: 45 additions & 14 deletions crates/cheatnet/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,43 @@ pub struct CallTrace {
pub used_execution_resources: ExecutionResources,
pub used_l1_resources: L1Resources,
pub used_syscalls: SyscallCounter,
pub nested_calls: Vec<Rc<RefCell<CallTrace>>>,
pub nested_calls: Vec<CallTraceNode>,
pub result: CallResult,
pub vm_trace: Option<Vec<TraceEntry>>,
}

impl CallTrace {
fn default_successful_call() -> Self {
Self {
entry_point: Default::default(),
used_execution_resources: Default::default(),
used_l1_resources: Default::default(),
used_syscalls: Default::default(),
nested_calls: vec![],
result: CallResult::Success { ret_data: vec![] },
vm_trace: None,
}
}
}

/// Enum representing node of a trace of a call.
#[derive(Clone)]
pub enum CallTraceNode {
EntryPointCall(Rc<RefCell<CallTrace>>),
DeployWithoutConstructor,
}

impl CallTraceNode {
#[must_use]
pub fn extract_entry_point_call(&self) -> Option<&Rc<RefCell<CallTrace>>> {
if let CallTraceNode::EntryPointCall(trace) = self {
Some(trace)
} else {
None
}
}
}

#[derive(Clone)]
struct CallStackElement {
// when we exit the call we use it to calculate resources used by the call
Expand Down Expand Up @@ -259,12 +291,7 @@ impl Default for CheatnetState {
test_code_entry_point.class_hash = Some(class_hash!(TEST_CONTRACT_CLASS_HASH));
let test_call = Rc::new(RefCell::new(CallTrace {
entry_point: test_code_entry_point,
used_execution_resources: Default::default(),
used_l1_resources: Default::default(),
used_syscalls: Default::default(),
nested_calls: vec![],
result: CallResult::Success { ret_data: vec![] },
vm_trace: None,
..CallTrace::default_successful_call()
}));
Self {
rolled_contracts: Default::default(),
Expand Down Expand Up @@ -396,19 +423,14 @@ impl TraceData {
) {
let new_call = Rc::new(RefCell::new(CallTrace {
entry_point,
used_execution_resources: Default::default(),
used_l1_resources: Default::default(),
used_syscalls: Default::default(),
nested_calls: vec![],
result: CallResult::Success { ret_data: vec![] },
vm_trace: None,
..CallTrace::default_successful_call()
}));
let current_call = self.current_call_stack.top();

current_call
.borrow_mut()
.nested_calls
.push(new_call.clone());
.push(CallTraceNode::EntryPointCall(new_call.clone()));

self.current_call_stack
.push(new_call, resources_used_before_call, cheated_data);
Expand Down Expand Up @@ -446,6 +468,15 @@ impl TraceData {
last_call.result = result;
last_call.vm_trace = vm_trace;
}

pub fn add_deploy_without_constructor_node(&mut self) {
let current_call = self.current_call_stack.top();

current_call
.borrow_mut()
.nested_calls
.push(CallTraceNode::DeployWithoutConstructor);
}
}

fn get_cheat_for_contract<T: Clone>(
Expand Down
18 changes: 15 additions & 3 deletions crates/forge-runner/src/build_trace_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use cairo_vm::vm::runners::cairo_runner::ExecutionResources;
use cairo_vm::vm::trace::trace_entry::TraceEntry;
use cheatnet::constants::{TEST_CONTRACT_CLASS_HASH, TEST_ENTRY_POINT_SELECTOR};
use cheatnet::runtime_extensions::forge_runtime_extension::contracts_data::ContractsData;
use cheatnet::state::CallTrace;
use cheatnet::state::{CallTrace, CallTraceNode};
use conversions::IntoConv;
use itertools::Itertools;
use starknet::core::utils::get_selector_from_name;
Expand All @@ -22,7 +22,7 @@ use starknet_api::deprecated_contract_class::EntryPointType;
use starknet_api::hash::StarkHash;
use trace_data::{
CallEntryPoint as ProfilerCallEntryPoint, CallTrace as ProfilerCallTrace,
CallType as ProfilerCallType, ContractAddress,
CallTraceNode as ProfilerCallTraceNode, CallType as ProfilerCallType, ContractAddress,
DeprecatedSyscallSelector as ProfilerDeprecatedSyscallSelector, EntryPointSelector,
EntryPointType as ProfilerEntryPointType, ExecutionResources as ProfilerExecutionResources,
TraceEntry as ProfilerTraceEntry, VmExecutionResources,
Expand Down Expand Up @@ -55,12 +55,24 @@ pub fn build_profiler_call_trace(
nested_calls: value
.nested_calls
.iter()
.map(|c| build_profiler_call_trace(c, contracts_data))
.map(|c| build_profiler_call_trace_node(c, contracts_data))
.collect(),
vm_trace,
}
}

fn build_profiler_call_trace_node(
value: &CallTraceNode,
contracts_data: &ContractsData,
) -> ProfilerCallTraceNode {
match value {
CallTraceNode::EntryPointCall(trace) => {
ProfilerCallTraceNode::EntryPointCall(build_profiler_call_trace(trace, contracts_data))
}
CallTraceNode::DeployWithoutConstructor => ProfilerCallTraceNode::DeployWithoutConstructor,
}
}

#[must_use]
pub fn build_profiler_execution_resources(
execution_resources: ExecutionResources,
Expand Down
2 changes: 1 addition & 1 deletion crates/forge/tests/data/trace/tests/test_trace.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use trace_info::{

#[test]
#[feature("safe_dispatcher")]
fn test_trace_print() {
fn test_trace() {
let sc = declare("SimpleContract").unwrap();

let (contract_address_A, _) = sc.deploy(@array![]).unwrap();
Expand Down
1 change: 1 addition & 0 deletions crates/forge/tests/e2e/build_profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::common::runner::{setup_package, test_runner};
use forge_runner::profiler_api::PROFILE_DIR;

#[test]
#[ignore] // TODO(#1991): remove ignore when new profiler is released
fn simple_package_build_profile() {
let temp = setup_package("simple_package");

Expand Down
Loading

0 comments on commit 6a04330

Please sign in to comment.