Skip to content
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

feat(traces): show state changes in cast run and forge test on -vvvvv #9013

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9bf8320
Add options for state changes output and json output in cast run command
cassc Oct 3, 2024
dceddb0
Merge remote-tracking branch 'foundry-rs/master' into add-options-to-…
cassc Oct 3, 2024
5546575
fix test
cassc Oct 3, 2024
28ef6a9
add back serde_json in Cargo.lock
cassc Oct 3, 2024
99a6914
format using nightly
cassc Oct 4, 2024
c6ca2b6
rename parameter
cassc Oct 4, 2024
68f5887
update revm-inspectors
cassc Oct 7, 2024
7bad232
Merge remote-tracking branch 'foundry-rs/master' into add-options-to-…
cassc Oct 7, 2024
4b6af4f
Merge remote-tracking branch 'foundry-rs/master' into add-options-to-…
cassc Oct 18, 2024
16da772
Merge remote-tracking branch 'foundry-rs/master' into add-options-to-…
cassc Oct 23, 2024
8b7807c
supress clippy warning and merge master
cassc Oct 23, 2024
5d66616
Merge remote-tracking branch 'foundry-rs/master' into add-options-to-…
cassc Oct 29, 2024
a0143fe
add serde_json
cassc Oct 29, 2024
e041926
disable some stdout print when --json option is used
cassc Nov 4, 2024
b52f8c8
remove unnecessary check
cassc Nov 5, 2024
73b0323
replace with sh_println
cassc Nov 5, 2024
4511b2a
Merge branch 'master' into add-options-to-output-storage-change-and-j…
cassc Nov 7, 2024
e9b1e3e
Merge remote-tracking branch 'foundry-rs/master' into add-options-to-…
cassc Nov 11, 2024
5420f26
Merge remote-tracking branch 'refs/remotes/origin/add-options-to-outp…
cassc Nov 11, 2024
d45b1b8
Merge branch 'master' into add-options-to-output-storage-change-and-j…
cassc Nov 13, 2024
0f983d9
Merge remote-tracking branch 'foundry-rs/master' into add-options-to-…
cassc Nov 15, 2024
9aa2894
Merge remote-tracking branch 'origin/add-options-to-output-storage-ch…
cassc Nov 15, 2024
cb48139
Merge branch 'master' into add-options-to-output-storage-change-and-j…
cassc Nov 18, 2024
f45e4cc
replace with shell::is_json
cassc Nov 19, 2024
af9ee80
Merge branch 'master' into add-options-to-output-storage-change-and-j…
cassc Nov 19, 2024
0e11203
merge master
cassc Nov 25, 2024
44fbe73
Merge branch 'master' into cast-storage-re
grandizzy Nov 27, 2024
ca94656
Show storage for verbosity > 1, add test
grandizzy Nov 27, 2024
85f9571
Change verbosity to > 4 for both cast and forge test, add test, fix ci
grandizzy Nov 27, 2024
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 Cargo.lock

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

13 changes: 10 additions & 3 deletions crates/cast/bin/cmd/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use foundry_cli::{
opts::{EthereumOpts, TransactionOpts},
utils::{self, handle_traces, parse_ether_value, TraceResult},
};
use foundry_common::ens::NameOrAddress;
use foundry_common::{ens::NameOrAddress, shell};
use foundry_compilers::artifacts::EvmVersion;
use foundry_config::{
figment::{
Expand Down Expand Up @@ -182,8 +182,15 @@ impl CallArgs {
env.cfg.disable_block_gas_limit = true;
env.block.gas_limit = U256::MAX;

let mut executor =
TracingExecutor::new(env, fork, evm_version, debug, decode_internal, alphanet);
let mut executor = TracingExecutor::new(
env,
fork,
evm_version,
debug,
decode_internal,
shell::verbosity() > 4,
alphanet,
);

let value = tx.value.unwrap_or_default();
let input = tx.inner.input.into_input().unwrap_or_default();
Expand Down
7 changes: 5 additions & 2 deletions crates/cast/bin/cmd/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use foundry_cli::{
opts::{EtherscanOpts, RpcOpts},
utils::{handle_traces, init_progress, TraceResult},
};
use foundry_common::{is_known_system_sender, SYSTEM_TRANSACTION_TYPE};
use foundry_common::{is_known_system_sender, shell, SYSTEM_TRANSACTION_TYPE};
use foundry_compilers::artifacts::EvmVersion;
use foundry_config::{
figment::{
Expand Down Expand Up @@ -169,14 +169,17 @@ impl RunArgs {
evm_version,
self.debug,
self.decode_internal,
shell::verbosity() > 4,
alphanet,
);
let mut env =
EnvWithHandlerCfg::new_with_spec_id(Box::new(env.clone()), executor.spec_id());

// Set the state to the moment right before the transaction
if !self.quick {
sh_println!("Executing previous transactions from the block.")?;
if !shell::is_json() {
sh_println!("Executing previous transactions from the block.")?;
}

if let Some(block) = block {
let pb = init_progress(block.transactions.len() as u64, "tx");
Expand Down
65 changes: 64 additions & 1 deletion crates/cast/tests/cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Display options:
- 2 (-vv): Print logs for all tests.
- 3 (-vvv): Print execution traces for failing tests.
- 4 (-vvvv): Print execution traces for all tests, and setup traces for failing tests.
- 5 (-vvvvv): Print execution and setup traces for all tests.
- 5 (-vvvvv): Print execution and setup traces for all tests, including storage changes.

Find more information in the book: http://book.getfoundry.sh/reference/cast/cast.html

Expand Down Expand Up @@ -1713,3 +1713,66 @@ Transaction successfully executed.

"#]]);
});

// tests cast can decode traces when running with verbosity level > 4
forgetest_async!(show_state_changes_in_traces, |prj, cmd| {
let (api, handle) = anvil::spawn(NodeConfig::test()).await;

foundry_test_utils::util::initialize(prj.root());
// Deploy counter contract.
cmd.args([
"script",
"--private-key",
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
"--rpc-url",
&handle.http_endpoint(),
"--broadcast",
"CounterScript",
])
.assert_success();

// Send tx to change counter storage value.
cmd.cast_fuse()
.args([
"send",
"0x5FbDB2315678afecb367f032d93F642f64180aa3",
"setNumber(uint256)",
"111",
"--private-key",
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
"--rpc-url",
&handle.http_endpoint(),
])
.assert_success();

let tx_hash = api
.transaction_by_block_number_and_index(BlockNumberOrTag::Latest, Index::from(0))
.await
.unwrap()
.unwrap()
.tx_hash();

// Assert cast with verbosity displays storage changes.
cmd.cast_fuse()
.args([
"run",
format!("{tx_hash}").as_str(),
"-vvvvv",
"--rpc-url",
&handle.http_endpoint(),
])
.assert_success()
.stdout_eq(str![[r#"
Executing previous transactions from the block.
Traces:
[22287] 0x5FbDB2315678afecb367f032d93F642f64180aa3::setNumber(111)
├─ storage changes:
│ @ 0: 0 → 111
└─ ← [Stop]


Transaction successfully executed.
[GAS]

"#]]);
});
2 changes: 1 addition & 1 deletion crates/cli/src/opts/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub struct GlobalOpts {
/// - 2 (-vv): Print logs for all tests.
/// - 3 (-vvv): Print execution traces for failing tests.
/// - 4 (-vvvv): Print execution traces for all tests, and setup traces for failing tests.
/// - 5 (-vvvvv): Print execution and setup traces for all tests.
/// - 5 (-vvvvv): Print execution and setup traces for all tests, including storage changes.
#[arg(help_heading = "Display options", global = true, short, long, verbatim_doc_comment, conflicts_with = "quiet", action = ArgAction::Count)]
verbosity: Verbosity,

Expand Down
21 changes: 14 additions & 7 deletions crates/cli/src/utils/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ use foundry_evm::{
debug::{ContractSources, DebugTraceIdentifier},
decode_trace_arena,
identifier::{CachedSignatures, SignaturesIdentifier, TraceIdentifiers},
render_trace_arena_with_bytecodes, CallTraceDecoder, CallTraceDecoderBuilder, TraceKind,
Traces,
render_trace_arena_inner, CallTraceDecoder, CallTraceDecoderBuilder, TraceKind, Traces,
},
};
use std::{
Expand Down Expand Up @@ -450,7 +449,7 @@ pub async fn handle_traces(
decoder.debug_identifier = Some(DebugTraceIdentifier::new(sources));
}

print_traces(&mut result, &decoder, shell::verbosity() > 0).await?;
print_traces(&mut result, &decoder, shell::verbosity() > 0, shell::verbosity() > 4).await?;

Ok(())
}
Expand All @@ -459,23 +458,31 @@ pub async fn print_traces(
result: &mut TraceResult,
decoder: &CallTraceDecoder,
verbose: bool,
state_changes: bool,
) -> Result<()> {
let traces = result.traces.as_mut().expect("No traces found");

sh_println!("Traces:")?;
if !shell::is_json() {
sh_println!("Traces:")?;
}

for (_, arena) in traces {
decode_trace_arena(arena, decoder).await?;
sh_println!("{}", render_trace_arena_with_bytecodes(arena, verbose))?;
sh_println!("{}", render_trace_arena_inner(arena, verbose, state_changes))?;
}

if shell::is_json() {
return Ok(());
}
sh_println!()?;

sh_println!()?;
if result.success {
sh_println!("{}", "Transaction successfully executed.".green())?;
} else {
sh_err!("Transaction failed.")?;
}

sh_println!("Gas used: {}", result.gas_used)?;

Ok(())
}

Expand Down
9 changes: 6 additions & 3 deletions crates/evm/evm/src/executors/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@ impl TracingExecutor {
version: Option<EvmVersion>,
debug: bool,
decode_internal: bool,
with_state_changes: bool,
alphanet: bool,
) -> Self {
let db = Backend::spawn(fork);
let trace_mode =
TraceMode::Call.with_debug(debug).with_decode_internal(if decode_internal {
let trace_mode = TraceMode::Call
.with_debug(debug)
.with_decode_internal(if decode_internal {
InternalTraceMode::Full
} else {
InternalTraceMode::None
});
})
.with_state_changes(with_state_changes);
Self {
// configures a bare version of the evm executor: no cheatcode inspector is enabled,
// tracing will be enabled only for the targeted transaction
Expand Down
1 change: 1 addition & 0 deletions crates/evm/traces/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ eyre.workspace = true
futures.workspace = true
itertools.workspace = true
serde.workspace = true
serde_json.workspace = true
tokio = { workspace = true, features = ["time", "macros"] }
tracing.workspace = true
tempfile.workspace = true
Expand Down
37 changes: 31 additions & 6 deletions crates/evm/traces/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ extern crate foundry_common;
#[macro_use]
extern crate tracing;

use foundry_common::contracts::{ContractsByAddress, ContractsByArtifact};
use foundry_common::{
contracts::{ContractsByAddress, ContractsByArtifact},
shell,
};
use revm::interpreter::OpCode;
use revm_inspectors::tracing::{
types::{DecodedTraceStep, TraceMemberOrder},
Expand Down Expand Up @@ -183,15 +186,23 @@ pub async fn decode_trace_arena(

/// Render a collection of call traces to a string.
pub fn render_trace_arena(arena: &SparsedTraceArena) -> String {
render_trace_arena_with_bytecodes(arena, false)
render_trace_arena_inner(arena, false, false)
}

/// Render a collection of call traces to a string optionally including contract creation bytecodes.
pub fn render_trace_arena_with_bytecodes(
/// Render a collection of call traces to a string optionally including contract creation bytecodes
/// and in JSON format.
pub fn render_trace_arena_inner(
arena: &SparsedTraceArena,
with_bytecodes: bool,
with_storage_changes: bool,
) -> String {
let mut w = TraceWriter::new(Vec::<u8>::new()).write_bytecodes(with_bytecodes);
if shell::is_json() {
return serde_json::to_string(&arena.resolve_arena()).expect("Failed to write traces");
}

let mut w = TraceWriter::new(Vec::<u8>::new())
.write_bytecodes(with_bytecodes)
.with_storage_changes(with_storage_changes);
w.write_arena(&arena.resolve_arena()).expect("Failed to write traces");
String::from_utf8(w.into_writer()).expect("trace writer wrote invalid UTF-8")
}
Expand Down Expand Up @@ -289,6 +300,8 @@ pub enum TraceMode {
///
/// Used by debugger.
Debug,
/// Debug trace with storage changes.
RecordStateDiff,
}

impl TraceMode {
Expand All @@ -308,6 +321,10 @@ impl TraceMode {
matches!(self, Self::Jump)
}

pub const fn record_state_diff(self) -> bool {
matches!(self, Self::RecordStateDiff)
}

pub const fn is_debug(self) -> bool {
matches!(self, Self::Debug)
}
Expand All @@ -324,6 +341,14 @@ impl TraceMode {
std::cmp::max(self, mode.into())
}

pub fn with_state_changes(self, yes: bool) -> Self {
if yes {
std::cmp::max(self, Self::RecordStateDiff)
} else {
self
}
}

pub fn with_verbosity(self, verbosiy: u8) -> Self {
if verbosiy >= 3 {
Copy link
Member

Choose a reason for hiding this comment

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

one suggestion for separate improvement @zerosnacks
let's introduce some enum for these numbers

Copy link
Member

Choose a reason for hiding this comment

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

added a ticket for it here: #9426

std::cmp::max(self, Self::Call)
Expand All @@ -345,7 +370,7 @@ impl TraceMode {
StackSnapshotType::None
},
record_logs: true,
record_state_diff: false,
record_state_diff: self.record_state_diff(),
record_returndata_snapshots: self.is_debug(),
record_opcodes_filter: (self.is_jump() || self.is_jump_simple())
.then(|| OpcodeFilter::new().enabled(OpCode::JUMP).enabled(OpCode::JUMPDEST)),
Expand Down
8 changes: 4 additions & 4 deletions crates/forge/bin/cmd/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use forge::{
debug::{ContractSources, DebugTraceIdentifier},
decode_trace_arena, folded_stack_trace,
identifier::SignaturesIdentifier,
render_trace_arena, CallTraceDecoderBuilder, InternalTraceMode, TraceKind,
CallTraceDecoderBuilder, InternalTraceMode, TraceKind,
},
MultiContractRunner, MultiContractRunnerBuilder, TestFilter, TestOptions, TestOptionsBuilder,
};
Expand Down Expand Up @@ -56,7 +56,7 @@ use summary::TestSummaryReporter;

use crate::cmd::test::summary::print_invariant_metrics;
pub use filter::FilterArgs;
use forge::result::TestKind;
use forge::{result::TestKind, traces::render_trace_arena_inner};

// Loads project's figment and merges the build cli arguments into it
foundry_config::merge_impl_figment_convert!(TestArgs, opts, evm_opts);
Expand Down Expand Up @@ -652,7 +652,7 @@ impl TestArgs {
// - 0..3: nothing
// - 3: only display traces for failed tests
// - 4: also display the setup trace for failed tests
// - 5..: display all traces for all tests
// - 5..: display all traces for all tests, including storage changes
let should_include = match kind {
TraceKind::Execution => {
(verbosity == 3 && result.status.is_failure()) || verbosity >= 4
Expand All @@ -665,7 +665,7 @@ impl TestArgs {

if should_include {
decode_trace_arena(arena, &decoder).await?;
decoded_traces.push(render_trace_arena(arena));
decoded_traces.push(render_trace_arena_inner(arena, false, verbosity > 4));
}
}

Expand Down
5 changes: 3 additions & 2 deletions crates/forge/src/multi_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
use alloy_json_abi::{Function, JsonAbi};
use alloy_primitives::{Address, Bytes, U256};
use eyre::Result;
use foundry_common::{get_contract_name, ContractsByArtifact, TestFunctionExt};
use foundry_common::{get_contract_name, shell::verbosity, ContractsByArtifact, TestFunctionExt};
use foundry_compilers::{
artifacts::Libraries, compilers::Compiler, Artifact, ArtifactId, ProjectCompileOutput,
};
Expand Down Expand Up @@ -249,7 +249,8 @@ impl MultiContractRunner {
let trace_mode = TraceMode::default()
.with_debug(self.debug)
.with_decode_internal(self.decode_internal)
.with_verbosity(self.evm_opts.verbosity);
.with_verbosity(self.evm_opts.verbosity)
.with_state_changes(verbosity() > 4);

let executor = ExecutorBuilder::new()
.inspectors(|stack| {
Expand Down
2 changes: 1 addition & 1 deletion crates/forge/tests/cli/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Display options:
- 2 (-vv): Print logs for all tests.
- 3 (-vvv): Print execution traces for failing tests.
- 4 (-vvvv): Print execution traces for all tests, and setup traces for failing tests.
- 5 (-vvvvv): Print execution and setup traces for all tests.
- 5 (-vvvvv): Print execution and setup traces for all tests, including storage changes.

Find more information in the book: http://book.getfoundry.sh/reference/forge/forge.html

Expand Down
Loading