Skip to content

Conversation

@eytan-starkware
Copy link
Contributor

@eytan-starkware eytan-starkware commented Jan 15, 2026

Summary

Added support for capturing and returning VM execution traces in the Cairo runner. This enables checking real run output, debugging and analysis of Cairo program execution by providing access to the program counter, allocation pointer, and frame pointer at each step, as well as the final memory state.


Type of change

Please check one:

  • Bug fix (fixes incorrect behavior)
  • New feature
  • Performance improvement
  • Documentation change with concrete technical impact
  • Style, wording, formatting, or typo-only change

⚠️ Note:
To keep maintainer workload sustainable, we generally do not accept PRs that
are only minor wording, grammar, formatting, or style changes.
Such PRs may be closed without detailed review.


Why is this change needed?

This PR adds the ability to capture and return VM execution traces, which is essential for debugging and analyzing Cairo program execution. The trace provides visibility into the program counter, allocation pointer, and frame pointer at each execution step, along with the final memory state. This is particularly useful for developers who need to understand the low-level execution details of their Cairo programs.


What was the behavior or documentation before?

Previously, the runner would execute Cairo programs but did not provide a way to access the execution trace or memory state after execution. This made debugging complex programs difficult as developers couldn't inspect the execution flow.


What is the behavior or documentation after?

The runner now has the ability to optionally capture and return the execution trace and memory state. This is implemented through:

  1. Added trace field to RunResult and RunResultStarknet structs
  2. Added run_function_with_starknet_context_with_trace method with a return_trace parameter
  3. Updated existing methods to support trace capture
  4. Added test infrastructure to demonstrate and validate trace capture functionality

The e2e test runner now supports a trace: true option and can display the execution trace in a readable table format.


Additional context

The implementation includes comprehensive test cases that demonstrate the trace functionality with different Cairo programs, from simple arithmetic to more complex control flow and loops. This provides examples for users on how to use and interpret the trace data.

@reviewable-StarkWare
Copy link

This change is Reviewable

Copy link
Contributor Author

eytan-starkware commented Jan 15, 2026

@eytan-starkware eytan-starkware force-pushed the eytan_graphite/_test_adding_casm_trace_to_boxed_enum_e2e_tests branch from 9feac89 to 0cd7778 Compare January 15, 2026 12:22
@eytan-starkware eytan-starkware changed the title Changed felt252 deseralization to be based on an iterator. (#9470) (test): Adding casm run and trace to e2e tests Jan 15, 2026
@eytan-starkware eytan-starkware marked this pull request as ready for review January 15, 2026 12:23
Copy link
Collaborator

@orizi orizi left a comment

Choose a reason for hiding this comment

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

@orizi reviewed 1 file and all commit messages, and made 1 comment.
Reviewable status: 1 of 6 files reviewed, 1 unresolved discussion (waiting on @eytan-starkware and @TomerStarkware).


tests/e2e_test.rs line 521 at r1 (raw file):

                .join("\n");
            res.insert("memory".into(), memory_str);
        }

remove everything this requires as well.

printing the trace is good for debug - but for now rather not have the extra "baggage" of getting the trace as part of the function runner flow.

Code quote:

        if params.include_trace {
            // Format trace as a table with headers.
            let trace = match result.trace {
                Some(trace) => trace,
                None => {
                    return TestRunnerResult {
                        outputs: res,
                        error: Some(
                            "trace: true was specified but no trace was returned. Ensure the \
                             function was executed correctly."
                                .to_string(),
                        ),
                    };
                }
            };
            let mut trace_lines = vec!["| PC | AP | FP |".to_string()];
            for entry in &trace {
                trace_lines.push(format!("| {} | {} | {} |", entry.pc, entry.ap, entry.fp));
            }
            res.insert("casm_trace".into(), trace_lines.join("\n"));

            // Include memory state.
            let memory_str = result
                .memory
                .iter()
                .enumerate()
                .filter_map(|(addr, value)| value.as_ref().map(|v| format!("[{}] = {}", addr, v)))
                .join("\n");
            res.insert("memory".into(), memory_str);
        }

Copy link
Contributor Author

@eytan-starkware eytan-starkware left a comment

Choose a reason for hiding this comment

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

@eytan-starkware made 1 comment.
Reviewable status: 1 of 6 files reviewed, 1 unresolved discussion (waiting on @orizi and @TomerStarkware).


tests/e2e_test.rs line 521 at r1 (raw file):

Previously, orizi wrote…

remove everything this requires as well.

printing the trace is good for debug - but for now rather not have the extra "baggage" of getting the trace as part of the function runner flow.

Done.

Copy link
Collaborator

@orizi orizi left a comment

Choose a reason for hiding this comment

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

@orizi reviewed 3 files and all commit messages, made 2 comments, and resolved 1 discussion.
Reviewable status: 4 of 6 files reviewed, 2 unresolved discussions (waiting on @eytan-starkware and @TomerStarkware).


tests/e2e_test_data/libfuncs/casm_run_sanity line 35 at r2 (raw file):


//! > casm_trace
| PC | AP | FP |

remove unproduced.


tests/e2e_test.rs line 250 at r2 (raw file):

    /// Parses test_data format: "function_name(input)=output"
    /// Allows whitespace around all components.
    fn parse(s: &str) -> Result<Self, String> {

f2f

@eytan-starkware eytan-starkware force-pushed the eytan_graphite/_test_adding_casm_trace_to_boxed_enum_e2e_tests branch from 9f17c72 to bf6b4e1 Compare January 18, 2026 13:32
@eytan-starkware eytan-starkware force-pushed the eytan_graphite/_test_adding_casm_trace_to_boxed_enum_e2e_tests branch from bf6b4e1 to 44b56da Compare January 18, 2026 14:03
Copy link
Contributor Author

@eytan-starkware eytan-starkware left a comment

Choose a reason for hiding this comment

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

@eytan-starkware made 2 comments.
Reviewable status: 2 of 6 files reviewed, 2 unresolved discussions (waiting on @orizi and @TomerStarkware).


tests/e2e_test.rs line 250 at r2 (raw file):

Previously, orizi wrote…

f2f

Done.


tests/e2e_test_data/libfuncs/casm_run_sanity line 35 at r2 (raw file):

Previously, orizi wrote…

remove unproduced.

Done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants