diff --git a/Cargo.lock b/Cargo.lock index f7540fbf6..51cce0c59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2408,7 +2408,6 @@ dependencies = [ "foundry-compilers", "foundry-macros", "reqwest 0.12.7", - "rustc-hash 1.1.0", "semver 1.0.23", "serde", "serde_json", @@ -2487,7 +2486,6 @@ dependencies = [ "alloy-json-abi", "alloy-primitives 0.7.7", "alloy-sol-types 0.7.7", - "arrayvec", "const-hex", "eyre", "foundry-cheatcodes", @@ -2517,7 +2515,6 @@ dependencies = [ "alloy-rpc-types", "alloy-sol-types 0.7.7", "alloy-transport", - "arrayvec", "auto_impl", "const-hex", "derive_more", diff --git a/crates/edr_napi/index.d.ts b/crates/edr_napi/index.d.ts index 806525216..63796fbfd 100644 --- a/crates/edr_napi/index.d.ts +++ b/crates/edr_napi/index.d.ts @@ -387,8 +387,6 @@ export interface SolidityTestRunnerConfigArgs { fsPermissions?: Array /** Whether to collect traces. Defaults to false. */ trace?: boolean - /** Whether to collect debug info. Defaults to false. */ - debug?: boolean /** Whether to support the `testFail` prefix. Defaults to false. */ testFail?: boolean /** Address labels for traces. Defaults to none. */ @@ -701,8 +699,6 @@ export interface StandardTestKind { } /** See [forge::result::TestKind::Fuzz] */ export interface FuzzTestKind { - /** See [forge::result::TestKind::Fuzz] */ - readonly firstCase: FuzzCase /** See [forge::result::TestKind::Fuzz] */ readonly runs: bigint /** See [forge::result::TestKind::Fuzz] */ diff --git a/crates/edr_napi/src/solidity_tests/config.rs b/crates/edr_napi/src/solidity_tests/config.rs index dbde4a2aa..90596803a 100644 --- a/crates/edr_napi/src/solidity_tests/config.rs +++ b/crates/edr_napi/src/solidity_tests/config.rs @@ -23,8 +23,6 @@ pub struct SolidityTestRunnerConfigArgs { pub fs_permissions: Option>, /// Whether to collect traces. Defaults to false. pub trace: Option, - /// Whether to collect debug info. Defaults to false. - pub debug: Option, /// Whether to support the `testFail` prefix. Defaults to false. pub test_fail: Option, /// Address labels for traces. Defaults to none. @@ -114,7 +112,6 @@ impl Debug for SolidityTestRunnerConfigArgs { .field("project_root", &self.project_root) .field("fs_permissions", &self.fs_permissions) .field("trace", &self.trace) - .field("debug", &self.debug) .field("ffi", &self.ffi) .field("sender", &self.sender.as_ref().map(hex::encode)) .field("tx_origin", &self.tx_origin.as_ref().map(hex::encode)) @@ -151,7 +148,6 @@ impl TryFrom for SolidityTestRunnerConfig { project_root, fs_permissions, trace, - debug, test_fail, labels, isolate, @@ -285,7 +281,6 @@ impl TryFrom for SolidityTestRunnerConfig { Ok(SolidityTestRunnerConfig { project_root: project_root.into(), - debug: debug.unwrap_or_default(), trace: trace.unwrap_or_default(), // TODO coverage: false, diff --git a/crates/edr_napi/src/solidity_tests/test_results.rs b/crates/edr_napi/src/solidity_tests/test_results.rs index e3517e089..f8b5f0c1d 100644 --- a/crates/edr_napi/src/solidity_tests/test_results.rs +++ b/crates/edr_napi/src/solidity_tests/test_results.rs @@ -94,16 +94,10 @@ impl From<(String, forge::result::TestResult)> for TestResult { consumed_gas: BigInt::from(gas_consumed), }), forge::result::TestKind::Fuzz { - first_case, runs, mean_gas, median_gas, } => Either3::B(FuzzTestKind { - first_case: FuzzCase { - calldata: Buffer::from(first_case.calldata.as_ref()), - gas: BigInt::from(first_case.gas), - stipend: BigInt::from(first_case.stipend), - }, // usize as u64 is always safe runs: BigInt::from(runs as u64), mean_gas: BigInt::from(mean_gas), @@ -160,9 +154,6 @@ pub struct StandardTestKind { #[napi(object)] #[derive(Debug, Clone)] pub struct FuzzTestKind { - /// See [forge::result::TestKind::Fuzz] - #[napi(readonly)] - pub first_case: FuzzCase, /// See [forge::result::TestKind::Fuzz] #[napi(readonly)] pub runs: BigInt, diff --git a/crates/foundry/cheatcodes/assets/cheatcodes.json b/crates/foundry/cheatcodes/assets/cheatcodes.json index 64ee3e277..ec0e547a2 100644 --- a/crates/foundry/cheatcodes/assets/cheatcodes.json +++ b/crates/foundry/cheatcodes/assets/cheatcodes.json @@ -3011,46 +3011,6 @@ "status": "stable", "safety": "unsafe" }, - { - "func": { - "id": "breakpoint_0", - "description": "Writes a breakpoint to jump to in the debugger.", - "declaration": "function breakpoint(string calldata char) external;", - "visibility": "external", - "mutability": "", - "signature": "breakpoint(string)", - "selector": "0xf0259e92", - "selectorBytes": [ - 240, - 37, - 158, - 146 - ] - }, - "group": "testing", - "status": "stable", - "safety": "safe" - }, - { - "func": { - "id": "breakpoint_1", - "description": "Writes a conditional breakpoint to jump to in the debugger.", - "declaration": "function breakpoint(string calldata char, bool value) external;", - "visibility": "external", - "mutability": "", - "signature": "breakpoint(string,bool)", - "selector": "0xf7d39a8d", - "selectorBytes": [ - 247, - 211, - 154, - 141 - ] - }, - "group": "testing", - "status": "stable", - "safety": "safe" - }, { "func": { "id": "chainId", diff --git a/crates/foundry/cheatcodes/spec/src/vm.rs b/crates/foundry/cheatcodes/spec/src/vm.rs index c0db61e54..ced4a00de 100644 --- a/crates/foundry/cheatcodes/spec/src/vm.rs +++ b/crates/foundry/cheatcodes/spec/src/vm.rs @@ -672,14 +672,6 @@ interface Vm { #[cheatcode(group = Testing, safety = Safe)] function assume(bool condition) external pure; - /// Writes a breakpoint to jump to in the debugger. - #[cheatcode(group = Testing, safety = Safe)] - function breakpoint(string calldata char) external; - - /// Writes a conditional breakpoint to jump to in the debugger. - #[cheatcode(group = Testing, safety = Safe)] - function breakpoint(string calldata char, bool value) external; - /// Returns the RPC url for the given alias. #[cheatcode(group = Testing, safety = Safe)] function rpcUrl(string calldata rpcAlias) external view returns (string memory json); diff --git a/crates/foundry/cheatcodes/src/inspector.rs b/crates/foundry/cheatcodes/src/inspector.rs index 3585e33bd..b4af4ef25 100644 --- a/crates/foundry/cheatcodes/src/inspector.rs +++ b/crates/foundry/cheatcodes/src/inspector.rs @@ -12,7 +12,7 @@ use std::{ use alloy_primitives::{Address, Bytes, Log, B256, U256}; use alloy_rpc_types::request::TransactionRequest; use alloy_sol_types::{SolInterface, SolValue}; -use foundry_common::{evm::Breakpoints, SELECTOR_LEN}; +use foundry_common::SELECTOR_LEN; use foundry_evm_core::{ abi::Vm::stopExpectSafeMemoryCall, backend::{DatabaseExt, RevertDiagnostic}, @@ -207,9 +207,6 @@ pub struct Cheatcodes { /// The current program counter. pub pc: usize, - /// Breakpoints supplied by the `breakpoint` cheatcode. - /// `char -> (address, pc)` - pub breakpoints: Breakpoints, } impl Cheatcodes { diff --git a/crates/foundry/cheatcodes/src/test.rs b/crates/foundry/cheatcodes/src/test.rs index afae97fe3..de2bb272e 100644 --- a/crates/foundry/cheatcodes/src/test.rs +++ b/crates/foundry/cheatcodes/src/test.rs @@ -1,15 +1,11 @@ //! Implementations of [`Testing`](crate::Group::Testing) cheatcodes. -use alloy_primitives::Address; use alloy_sol_types::SolValue; use foundry_evm_core::constants::{MAGIC_ASSUME, MAGIC_SKIP}; use crate::{ Cheatcode, Cheatcodes, CheatsCtxt, DatabaseExt, Error, Result, - Vm::{ - assumeCall, breakpoint_0Call, breakpoint_1Call, rpcUrlCall, rpcUrlStructsCall, rpcUrlsCall, - skipCall, sleepCall, - }, + Vm::{assumeCall, rpcUrlCall, rpcUrlStructsCall, rpcUrlsCall, skipCall, sleepCall}, }; pub(crate) mod assert; @@ -26,20 +22,6 @@ impl Cheatcode for assumeCall { } } -impl Cheatcode for breakpoint_0Call { - fn apply_full(&self, ccx: &mut CheatsCtxt) -> Result { - let Self { char } = self; - breakpoint(ccx.state, &ccx.caller, char, true) - } -} - -impl Cheatcode for breakpoint_1Call { - fn apply_full(&self, ccx: &mut CheatsCtxt) -> Result { - let Self { char, value } = self; - breakpoint(ccx.state, &ccx.caller, char, *value) - } -} - impl Cheatcode for rpcUrlCall { fn apply(&self, state: &mut Cheatcodes) -> Result { let Self { rpcAlias } = self; @@ -87,23 +69,3 @@ impl Cheatcode for skipCall { } } } - -/// Adds or removes the given breakpoint to the state. -fn breakpoint(state: &mut Cheatcodes, caller: &Address, s: &str, add: bool) -> Result { - let mut chars = s.chars(); - let (Some(point), None) = (chars.next(), chars.next()) else { - bail!("breakpoints must be exactly one character"); - }; - ensure!( - point.is_alphabetic(), - "only alphabetic characters are accepted as breakpoints" - ); - - if add { - state.breakpoints.insert(point, (*caller, state.pc)); - } else { - state.breakpoints.remove(&point); - } - - Ok(Vec::default()) -} diff --git a/crates/foundry/common/Cargo.toml b/crates/foundry/common/Cargo.toml index d66a42ab2..aaf944d31 100644 --- a/crates/foundry/common/Cargo.toml +++ b/crates/foundry/common/Cargo.toml @@ -39,7 +39,6 @@ tracing.workspace = true url = "2" walkdir = "2" yansi.workspace = true -rustc-hash.workspace = true [dev-dependencies] foundry-macros.workspace = true diff --git a/crates/foundry/common/src/evm.rs b/crates/foundry/common/src/evm.rs deleted file mode 100644 index 23b37277a..000000000 --- a/crates/foundry/common/src/evm.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! cli arguments for configuring the evm settings -use alloy_primitives::Address; -use rustc_hash::FxHashMap; - -/// Map keyed by breakpoints char to their location (contract address, pc) -pub type Breakpoints = FxHashMap; diff --git a/crates/foundry/common/src/lib.rs b/crates/foundry/common/src/lib.rs index 714fa44e9..58cc9f625 100644 --- a/crates/foundry/common/src/lib.rs +++ b/crates/foundry/common/src/lib.rs @@ -14,7 +14,6 @@ pub mod constants; pub mod contracts; pub mod ens; pub mod errors; -pub mod evm; pub mod fmt; pub mod fs; pub mod provider; diff --git a/crates/foundry/evm/core/Cargo.toml b/crates/foundry/evm/core/Cargo.toml index 9d60b7015..23ee56301 100644 --- a/crates/foundry/evm/core/Cargo.toml +++ b/crates/foundry/evm/core/Cargo.toml @@ -33,7 +33,6 @@ revm = { workspace = true, features = [ ] } revm-inspectors.workspace = true -arrayvec.workspace = true auto_impl = "1" derive_more.workspace = true eyre = "0.6" diff --git a/crates/foundry/evm/core/src/debug.rs b/crates/foundry/evm/core/src/debug.rs deleted file mode 100644 index ef6e75238..000000000 --- a/crates/foundry/evm/core/src/debug.rs +++ /dev/null @@ -1,260 +0,0 @@ -use alloy_primitives::{Address, Bytes, U256}; -use arrayvec::ArrayVec; -use revm::interpreter::OpCode; -use revm_inspectors::tracing::types::CallKind; -use serde::{Deserialize, Serialize}; - -use crate::opcodes; - -/// An arena of [`DebugNode`]s -#[derive(Clone, Debug, Default, Serialize, Deserialize)] -pub struct DebugArena { - /// The arena of nodes - pub arena: Vec, -} - -impl DebugArena { - /// Pushes a new debug node into the arena - pub fn push_node(&mut self, mut new_node: DebugNode) -> usize { - fn recursively_push( - arena: &mut Vec, - entry: usize, - mut new_node: DebugNode, - ) -> usize { - match new_node.depth { - // We found the parent node, add the new node as a child - _ if arena[entry].depth == new_node.depth - 1 => { - let id = arena.len(); - new_node.location = arena[entry].children.len(); - new_node.parent = Some(entry); - arena[entry].children.push(id); - arena.push(new_node); - id - } - // We haven't found the parent node, go deeper - _ => { - let child = *arena[entry] - .children - .last() - .expect("Disconnected debug node"); - recursively_push(arena, child, new_node) - } - } - } - - if self.arena.is_empty() { - // This is the initial node at depth 0, so we just insert it. - self.arena.push(new_node); - 0 - } else if new_node.depth == 0 { - // This is another node at depth 0, for example instructions between calls. We - // insert it as a child of the original root node. - let id = self.arena.len(); - new_node.location = self.arena[0].children.len(); - new_node.parent = Some(0); - self.arena[0].children.push(id); - self.arena.push(new_node); - id - } else { - // We try to find the parent of this node recursively - recursively_push(&mut self.arena, 0, new_node) - } - } - - /// Recursively traverses the tree of debug nodes and flattens it into a - /// [Vec] where each item contains: - /// - /// - The address of the contract being executed - /// - A [Vec] of debug steps along that contract's execution path - /// - An enum denoting the type of call this is - /// - /// This makes it easy to pretty print the execution steps. - pub fn flatten(&self, entry: usize) -> Vec { - let mut flattened = Vec::new(); - self.flatten_to(entry, &mut flattened); - flattened - } - - /// Recursively traverses the tree of debug nodes and flattens it into the - /// given list. - /// - /// See [`flatten`](Self::flatten) for more information. - pub fn flatten_to(&self, entry: usize, out: &mut Vec) { - let node = &self.arena[entry]; - - if !node.steps.is_empty() { - out.push(node.flat()); - } - - for child in &node.children { - self.flatten_to(*child, out); - } - } -} - -/// A node in the arena. -#[derive(Clone, Debug, Default, Serialize, Deserialize)] -pub struct DebugNode { - /// Parent node index in the arena. - pub parent: Option, - /// Children node indexes in the arena. - pub children: Vec, - /// Location in parent. - pub location: usize, - /// Execution context. - /// - /// Note that this is the address of the *code*, not necessarily the address - /// of the storage. - pub address: Address, - /// The kind of call this is. - pub kind: CallKind, - /// Depth of the call. - pub depth: usize, - /// The debug steps. - pub steps: Vec, -} - -impl From for DebugNodeFlat { - #[inline] - fn from(node: DebugNode) -> Self { - node.into_flat() - } -} - -impl From<&DebugNode> for DebugNodeFlat { - #[inline] - fn from(node: &DebugNode) -> Self { - node.flat() - } -} - -impl DebugNode { - /// Creates a new debug node. - pub fn new(address: Address, depth: usize, steps: Vec) -> Self { - Self { - address, - depth, - steps, - ..Default::default() - } - } - - /// Flattens this node into a [`DebugNodeFlat`]. - pub fn flat(&self) -> DebugNodeFlat { - DebugNodeFlat { - address: self.address, - kind: self.kind, - steps: self.steps.clone(), - } - } - - /// Flattens this node into a [`DebugNodeFlat`]. - pub fn into_flat(self) -> DebugNodeFlat { - DebugNodeFlat { - address: self.address, - kind: self.kind, - steps: self.steps, - } - } -} - -/// Flattened [`DebugNode`] from an arena. -#[derive(Clone, Debug, Default, Serialize, Deserialize)] -pub struct DebugNodeFlat { - /// Execution context. - /// - /// Note that this is the address of the *code*, not necessarily the address - /// of the storage. - pub address: Address, - /// The kind of call this is. - pub kind: CallKind, - /// The debug steps. - pub steps: Vec, -} - -impl DebugNodeFlat { - /// Creates a new debug node flat. - pub fn new(address: Address, kind: CallKind, steps: Vec) -> Self { - Self { - address, - kind, - steps, - } - } -} - -/// A `DebugStep` is a snapshot of the EVM's runtime state. -/// -/// It holds the current program counter (where in the program you are), -/// the stack and memory (prior to the opcodes execution), any bytes to be -/// pushed onto the stack, and the instruction counter for use with sourcemap. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct DebugStep { - /// Stack *prior* to running the associated opcode - pub stack: Vec, - /// Memory *prior* to running the associated opcode - pub memory: Bytes, - /// Calldata *prior* to running the associated opcode - pub calldata: Bytes, - /// Returndata *prior* to running the associated opcode - pub returndata: Bytes, - /// Opcode to be executed - pub instruction: u8, - /// Optional bytes that are being pushed onto the stack. - /// Empty if the opcode is not a push or PUSH0. - #[serde( - serialize_with = "hex::serialize", - deserialize_with = "deserialize_arrayvec_hex" - )] - pub push_bytes: ArrayVec, - /// The program counter at this step. - /// - /// Note: To map this step onto source code using a source map, you must - /// convert the program counter to an instruction counter. - pub pc: usize, - /// Cumulative gas usage - pub total_gas_used: u64, -} - -impl Default for DebugStep { - fn default() -> Self { - Self { - stack: vec![], - memory: Bytes::default(), - calldata: Bytes::default(), - returndata: Bytes::default(), - instruction: revm::interpreter::opcode::INVALID, - push_bytes: ArrayVec::default(), - pc: 0, - total_gas_used: 0, - } - } -} - -impl DebugStep { - /// Pretty print the step's opcode - pub fn pretty_opcode(&self) -> String { - let instruction = OpCode::new(self.instruction).map_or("INVALID", |op| op.as_str()); - if !self.push_bytes.is_empty() { - format!("{instruction}(0x{})", hex::encode(&self.push_bytes)) - } else { - instruction.to_string() - } - } - - /// Returns `true` if the opcode modifies memory. - pub fn opcode_modifies_memory(&self) -> bool { - OpCode::new(self.instruction).map_or(false, opcodes::modifies_memory) - } -} - -fn deserialize_arrayvec_hex<'de, D: serde::Deserializer<'de>>( - deserializer: D, -) -> Result, D::Error> { - let bytes: Vec = hex::deserialize(deserializer)?; - let mut array = ArrayVec::new(); - array - .try_extend_from_slice(&bytes) - .map_err(serde::de::Error::custom)?; - Ok(array) -} diff --git a/crates/foundry/evm/core/src/lib.rs b/crates/foundry/evm/core/src/lib.rs index 1b5470c7b..3220d11e7 100644 --- a/crates/foundry/evm/core/src/lib.rs +++ b/crates/foundry/evm/core/src/lib.rs @@ -16,7 +16,6 @@ mod ic; pub mod abi; pub mod backend; pub mod constants; -pub mod debug; pub mod decode; pub mod fork; pub mod opcodes; diff --git a/crates/foundry/evm/evm/Cargo.toml b/crates/foundry/evm/evm/Cargo.toml index 09dbf4d6d..31635d21a 100644 --- a/crates/foundry/evm/evm/Cargo.toml +++ b/crates/foundry/evm/evm/Cargo.toml @@ -30,7 +30,6 @@ revm = { workspace = true, default-features = false, features = [ ] } revm-inspectors.workspace = true -arrayvec.workspace = true eyre = "0.6" hex.workspace = true parking_lot = "0.12" diff --git a/crates/foundry/evm/evm/src/executors/fuzz/mod.rs b/crates/foundry/evm/evm/src/executors/fuzz/mod.rs index 9c443d2e7..5d3c09a2c 100644 --- a/crates/foundry/evm/evm/src/executors/fuzz/mod.rs +++ b/crates/foundry/evm/evm/src/executors/fuzz/mod.rs @@ -129,7 +129,6 @@ impl FuzzedExecutor { FuzzOutcome::CounterExample(CounterExampleOutcome { exit_reason, counterexample: _counterexample, - .. }) => { let status = exit_reason; // We cannot use the calldata returned by the test runner in `TestError::Fail`, @@ -224,11 +223,6 @@ impl FuzzedExecutor { return Err(TestCaseError::reject(FuzzError::AssumeReject)); } - let breakpoints = call - .cheatcodes - .as_ref() - .map_or_else(Default::default, |cheats| cheats.breakpoints.clone()); - let success = self.executor.is_raw_call_success( address, Cow::Owned(state_changeset), @@ -245,15 +239,11 @@ impl FuzzedExecutor { }, traces: call.traces, coverage: call.coverage, - debug: call.debug, - breakpoints, })) } else { Ok(FuzzOutcome::CounterExample(CounterExampleOutcome { - debug: call.debug.clone(), exit_reason: call.exit_reason, counterexample: (calldata, call), - breakpoints, })) } } diff --git a/crates/foundry/evm/evm/src/executors/fuzz/types.rs b/crates/foundry/evm/evm/src/executors/fuzz/types.rs index 9dee2f075..e387929b1 100644 --- a/crates/foundry/evm/evm/src/executors/fuzz/types.rs +++ b/crates/foundry/evm/evm/src/executors/fuzz/types.rs @@ -1,6 +1,4 @@ use alloy_primitives::Bytes; -use foundry_common::evm::Breakpoints; -use foundry_evm_core::debug::DebugArena; use foundry_evm_coverage::HitMaps; use foundry_evm_fuzz::FuzzCase; use foundry_evm_traces::CallTraceArena; @@ -17,10 +15,6 @@ pub struct CaseOutcome { pub traces: Option, /// The coverage info collected during the call pub coverage: Option, - /// The debug nodes of the call - pub debug: Option, - /// Breakpoints char pc map - pub breakpoints: Breakpoints, } /// Returned by a single fuzz when a counterexample has been discovered @@ -30,10 +24,6 @@ pub struct CounterExampleOutcome { pub counterexample: (Bytes, RawCallResult), /// The status of the call pub exit_reason: InstructionResult, - /// The debug nodes of the call - pub debug: Option, - /// Breakpoints char pc map - pub breakpoints: Breakpoints, } /// Outcome of a single fuzz diff --git a/crates/foundry/evm/evm/src/executors/mod.rs b/crates/foundry/evm/evm/src/executors/mod.rs index 49b7a5b8c..f8facf0da 100644 --- a/crates/foundry/evm/evm/src/executors/mod.rs +++ b/crates/foundry/evm/evm/src/executors/mod.rs @@ -18,7 +18,6 @@ use foundry_evm_core::{ constants::{ CALLER, CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, DEFAULT_CREATE2_DEPLOYER_CODE, }, - debug::DebugArena, decode::RevertDecoder, utils::StateChangeset, }; @@ -197,12 +196,6 @@ impl Executor { self } - #[inline] - pub fn set_debugger(&mut self, debugger: bool) -> &mut Self { - self.inspector.enable_debugger(debugger); - self - } - #[inline] pub fn set_trace_printer(&mut self, trace_printer: bool) -> &mut Self { self.inspector.print(trace_printer); @@ -712,8 +705,6 @@ pub struct RawCallResult { pub traces: Option, /// The coverage info collected during the call pub coverage: Option, - /// The debug nodes of the call - pub debug: Option, /// The changeset of the state. /// /// This is only present if the changed state was not committed to the @@ -744,7 +735,6 @@ impl Default for RawCallResult { labels: HashMap::new(), traces: None, coverage: None, - debug: None, state_changeset: None, env: EnvWithHandlerCfg::new_with_spec_id(Box::default(), SpecId::LATEST), cheatcodes: Option::default(), @@ -880,7 +870,6 @@ fn convert_executed_result( labels, traces, coverage, - debug, cheatcodes, chisel_state, } = inspector.collect(); @@ -897,7 +886,6 @@ fn convert_executed_result( labels, traces, coverage, - debug, state_changeset: Some(state_changeset), env, cheatcodes, diff --git a/crates/foundry/evm/evm/src/inspectors/debugger.rs b/crates/foundry/evm/evm/src/inspectors/debugger.rs deleted file mode 100644 index 8790ea636..000000000 --- a/crates/foundry/evm/evm/src/inspectors/debugger.rs +++ /dev/null @@ -1,174 +0,0 @@ -use alloy_primitives::Address; -use arrayvec::ArrayVec; -use foundry_common::ErrorExt; -use foundry_evm_core::{ - backend::DatabaseExt, - debug::{DebugArena, DebugNode, DebugStep}, - utils::gas_used, -}; -use revm::{ - interpreter::{ - opcode::{self, spec_opcode_gas}, - CallInputs, CallOutcome, CreateInputs, CreateOutcome, Gas, InstructionResult, Interpreter, - InterpreterResult, - }, - EvmContext, Inspector, -}; -use revm_inspectors::tracing::types::CallKind; - -/// An inspector that collects debug nodes on every step of the interpreter. -#[derive(Clone, Debug, Default)] -pub struct Debugger { - /// The arena of [`DebugNode`]s - pub arena: DebugArena, - /// The ID of the current [`DebugNode`]. - pub head: usize, - /// The current execution address. - pub context: Address, -} - -impl Debugger { - /// Enters a new execution context. - pub fn enter(&mut self, depth: usize, address: Address, kind: CallKind) { - self.context = address; - self.head = self.arena.push_node(DebugNode { - address, - kind, - depth, - ..Default::default() - }); - } - - /// Exits the current execution context, replacing it with the previous one. - pub fn exit(&mut self) { - if let Some(parent_id) = self.arena.arena[self.head].parent { - let DebugNode { - depth, - address, - kind, - .. - } = self.arena.arena[parent_id]; - self.context = address; - self.head = self.arena.push_node(DebugNode { - address, - kind, - depth, - ..Default::default() - }); - } - } -} - -impl Inspector for Debugger { - fn step(&mut self, interp: &mut Interpreter, ecx: &mut EvmContext) { - let pc = interp.program_counter(); - let op = interp.current_opcode(); - - // Get opcode information - let opcode_infos = spec_opcode_gas(ecx.spec_id()); - let opcode_info = &opcode_infos[op as usize]; - - // Extract the push bytes - let push_size = if opcode_info.is_push() { - (op - opcode::PUSH0) as usize - } else { - 0 - }; - let push_bytes = (push_size > 0).then(|| { - let start = pc + 1; - let end = start + push_size; - let slice = &interp.contract.bytecode.bytecode()[start..end]; - assert!(slice.len() <= 32); - let mut array = ArrayVec::new(); - array.try_extend_from_slice(slice).unwrap(); - array - }); - - let total_gas_used = gas_used( - ecx.spec_id(), - interp.gas.limit().saturating_sub(interp.gas.remaining()), - interp.gas.refunded() as u64, - ); - - // Reuse the memory from the previous step if the previous opcode did not modify - // it. - let memory = self.arena.arena[self.head] - .steps - .last() - .filter(|step| !step.opcode_modifies_memory()) - .map_or_else( - || interp.shared_memory.context_memory().to_vec().into(), - |step| step.memory.clone(), - ); - - self.arena.arena[self.head].steps.push(DebugStep { - pc, - stack: interp.stack().data().clone(), - memory, - calldata: interp.contract().input.clone(), - returndata: interp.return_data_buffer.clone(), - instruction: op, - push_bytes: push_bytes.unwrap_or_default(), - total_gas_used, - }); - } - - fn call(&mut self, ecx: &mut EvmContext, inputs: &mut CallInputs) -> Option { - self.enter( - ecx.journaled_state.depth() as usize, - inputs.context.code_address, - inputs.context.scheme.into(), - ); - - None - } - - fn call_end( - &mut self, - _context: &mut EvmContext, - _inputs: &CallInputs, - outcome: CallOutcome, - ) -> CallOutcome { - self.exit(); - - outcome - } - - fn create( - &mut self, - ecx: &mut EvmContext, - inputs: &mut CreateInputs, - ) -> Option { - if let Err(err) = ecx.load_account(inputs.caller) { - let gas = Gas::new(inputs.gas_limit); - return Some(CreateOutcome::new( - InterpreterResult { - result: InstructionResult::Revert, - output: err.abi_encode_revert(), - gas, - }, - None, - )); - } - - let nonce = ecx.journaled_state.account(inputs.caller).info.nonce; - self.enter( - ecx.journaled_state.depth() as usize, - inputs.created_address(nonce), - CallKind::Create, - ); - - None - } - - fn create_end( - &mut self, - _context: &mut EvmContext, - _inputs: &CreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { - self.exit(); - - outcome - } -} diff --git a/crates/foundry/evm/evm/src/inspectors/mod.rs b/crates/foundry/evm/evm/src/inspectors/mod.rs index 58ba9cd28..5dcc1bfad 100644 --- a/crates/foundry/evm/evm/src/inspectors/mod.rs +++ b/crates/foundry/evm/evm/src/inspectors/mod.rs @@ -9,9 +9,6 @@ pub use revm_inspectors::access_list::AccessListInspector; mod chisel_state; pub use chisel_state::ChiselState; -mod debugger; -pub use debugger::Debugger; - mod logs; pub use logs::LogCollector; diff --git a/crates/foundry/evm/evm/src/inspectors/stack.rs b/crates/foundry/evm/evm/src/inspectors/stack.rs index bb08aa6a6..ab9d59865 100644 --- a/crates/foundry/evm/evm/src/inspectors/stack.rs +++ b/crates/foundry/evm/evm/src/inspectors/stack.rs @@ -3,7 +3,6 @@ use std::{collections::HashMap, sync::Arc}; use alloy_primitives::{Address, Bytes, Log, U256}; use foundry_evm_core::{ backend::{update_state, DatabaseExt}, - debug::DebugArena, InspectorExt, }; use foundry_evm_coverage::HitMaps; @@ -19,7 +18,7 @@ use revm::{ }; use super::{ - Cheatcodes, CheatsConfig, ChiselState, CoverageCollector, Debugger, Fuzzer, LogCollector, + Cheatcodes, CheatsConfig, ChiselState, CoverageCollector, Fuzzer, LogCollector, StackSnapshotType, TracingInspector, TracingInspectorConfig, }; @@ -42,8 +41,6 @@ pub struct InspectorStackBuilder { pub fuzzer: Option, /// Whether to enable tracing. pub trace: Option, - /// Whether to enable the debugger. - pub debug: Option, /// Whether logs should be collected. pub logs: Option, /// Whether coverage info should be collected. @@ -116,13 +113,6 @@ impl InspectorStackBuilder { self } - /// Set whether to enable the debugger. - #[inline] - pub fn debug(mut self, yes: bool) -> Self { - self.debug = Some(yes); - self - } - /// Set whether to enable the trace printer. #[inline] pub fn print(mut self, yes: bool) -> Self { @@ -157,7 +147,6 @@ impl InspectorStackBuilder { cheatcodes, fuzzer, trace, - debug, logs, coverage, print, @@ -178,7 +167,6 @@ impl InspectorStackBuilder { } stack.collect_coverage(coverage.unwrap_or(false)); stack.collect_logs(logs.unwrap_or(true)); - stack.enable_debugger(debug.unwrap_or(false)); stack.print(print.unwrap_or(false)); stack.tracing(trace.unwrap_or(false)); @@ -256,7 +244,6 @@ pub struct InspectorData { pub logs: Vec, pub labels: HashMap, pub traces: Option, - pub debug: Option, pub coverage: Option, pub cheatcodes: Option, pub chisel_state: Option<(Vec, Vec, InstructionResult)>, @@ -291,7 +278,6 @@ pub struct InspectorStack { pub cheatcodes: Option, pub chisel_state: Option, pub coverage: Option, - pub debugger: Option, pub fuzzer: Option, pub log_collector: Option, pub printer: Option, @@ -361,12 +347,6 @@ impl InspectorStack { self.coverage = yes.then(Default::default); } - /// Set whether to enable the debugger. - #[inline] - pub fn enable_debugger(&mut self, yes: bool) { - self.debugger = yes.then(Default::default); - } - /// Set whether to enable call isolation. #[inline] pub fn enable_isolation(&mut self, yes: bool) { @@ -418,7 +398,6 @@ impl InspectorStack { }) .unwrap_or_default(), traces: self.tracer.map(|tracer| tracer.get_traces().clone()), - debug: self.debugger.map(|debugger| debugger.arena), coverage: self.coverage.map(|coverage| coverage.maps), cheatcodes: self.cheatcodes, chisel_state: self.chisel_state.and_then(|state| state.state), @@ -435,7 +414,6 @@ impl InspectorStack { call_inspectors_adjust_depth!( [ &mut self.fuzzer, - &mut self.debugger, &mut self.tracer, &mut self.cheatcodes, &mut self.printer, @@ -652,7 +630,6 @@ impl Inspector<&mut DB> for InspectorStack { #[no_ret] [ &mut self.fuzzer, - &mut self.debugger, &mut self.tracer, &mut self.coverage, &mut self.cheatcodes, @@ -707,7 +684,6 @@ impl Inspector<&mut DB> for InspectorStack { call_inspectors_adjust_depth!( [ &mut self.fuzzer, - &mut self.debugger, &mut self.tracer, &mut self.log_collector, &mut self.cheatcodes, @@ -784,12 +760,7 @@ impl Inspector<&mut DB> for InspectorStack { } call_inspectors_adjust_depth!( - [ - &mut self.debugger, - &mut self.tracer, - &mut self.coverage, - &mut self.cheatcodes - ], + [&mut self.tracer, &mut self.coverage, &mut self.cheatcodes], |inspector| inspector.create(ecx, create).map(Some), self, ecx @@ -825,12 +796,7 @@ impl Inspector<&mut DB> for InspectorStack { let result = outcome.result.result; call_inspectors_adjust_depth!( - [ - &mut self.debugger, - &mut self.tracer, - &mut self.cheatcodes, - &mut self.printer - ], + [&mut self.tracer, &mut self.cheatcodes, &mut self.printer], |inspector| { let new_outcome = inspector.create_end(ecx, call, outcome.clone()); diff --git a/crates/foundry/evm/evm/src/lib.rs b/crates/foundry/evm/evm/src/lib.rs index 320a463dc..f40fd6272 100644 --- a/crates/foundry/evm/evm/src/lib.rs +++ b/crates/foundry/evm/evm/src/lib.rs @@ -10,7 +10,7 @@ extern crate tracing; pub mod executors; pub mod inspectors; -pub use foundry_evm_core::{backend, constants, debug, decode, fork, opts, utils, InspectorExt}; +pub use foundry_evm_core::{backend, constants, decode, fork, opts, utils, InspectorExt}; pub use foundry_evm_coverage as coverage; pub use foundry_evm_fuzz as fuzz; pub use foundry_evm_traces as traces; diff --git a/crates/foundry/forge/README.md b/crates/foundry/forge/README.md index 14e86a716..81fc4dbae 100644 --- a/crates/foundry/forge/README.md +++ b/crates/foundry/forge/README.md @@ -390,7 +390,6 @@ Over the next months, we intend to add the following features which are availabl 1. Stack Traces: Currently we do not provide any debug information when a call fails. We intend to add a structured printer (something like [this](https://twitter.com/gakonst/status/1434337110111182848) which will show all the calls, logs and arguments passed across intermediate smart contract calls, which should help with debugging. 1. [Invariant Tests](https://github.com/dapphub/dapptools/blob/master/src/dapp/README.md#invariant-testing) -1. [Interactive Debugger](https://github.com/dapphub/dapptools/blob/master/src/hevm/README.md#interactive-debugger-key-bindings) 1. [Code coverage](https://twitter.com/dapptools/status/1435973810545729536) 1. [Gas snapshots](https://github.com/dapphub/dapptools/pull/850/files) 1. [Symbolic EVM](https://fv.ethereum.org/2020/07/28/symbolic-hevm-release/) diff --git a/crates/foundry/forge/src/config.rs b/crates/foundry/forge/src/config.rs index fbec23970..6be2731ff 100644 --- a/crates/foundry/forge/src/config.rs +++ b/crates/foundry/forge/src/config.rs @@ -28,8 +28,6 @@ pub enum SolidityTestRunnerConfigError { pub struct SolidityTestRunnerConfig { /// Project root directory. pub project_root: PathBuf, - /// Whether to enable debug mode. - pub debug: bool, /// Whether to enable trace mode. pub trace: bool, /// Whether to collect coverage info diff --git a/crates/foundry/forge/src/multi_runner.rs b/crates/foundry/forge/src/multi_runner.rs index c29844141..d33eaa95b 100644 --- a/crates/foundry/forge/src/multi_runner.rs +++ b/crates/foundry/forge/src/multi_runner.rs @@ -70,8 +70,6 @@ pub struct MultiContractRunner { coverage: bool, /// Whether to collect traces trace: bool, - /// Whether to collect debug info - debug: bool, /// Whether to support the `testFail` prefix test_fail: bool, /// Whether to enable solidity fuzz fixtures support @@ -97,7 +95,6 @@ impl MultiContractRunner { let fork = config.get_fork().await?; let SolidityTestRunnerConfig { - debug, trace, coverage, test_fail, @@ -131,7 +128,6 @@ impl MultiContractRunner { fork, coverage, trace, - debug, test_fail, solidity_fuzz_fixtures, test_options, @@ -258,8 +254,7 @@ impl MultiContractRunner { .inspectors(|stack| { stack .cheatcodes(Arc::new(cheats_config)) - .trace(self.trace || self.debug) - .debug(self.debug) + .trace(self.trace) .coverage(self.coverage) .enable_isolation(self.evm_opts.isolate) }) @@ -282,7 +277,6 @@ impl MultiContractRunner { ContractRunnerOptions { initial_balance: self.evm_opts.initial_balance, sender: self.evm_opts.sender, - debug: self.debug, test_fail: self.test_fail, solidity_fuzz_fixtures: self.solidity_fuzz_fixtures, }, diff --git a/crates/foundry/forge/src/result.rs b/crates/foundry/forge/src/result.rs index c35cd05f3..8b42ad4e4 100644 --- a/crates/foundry/forge/src/result.rs +++ b/crates/foundry/forge/src/result.rs @@ -8,13 +8,12 @@ use std::{ }; use alloy_primitives::{Address, Log}; -use foundry_common::{evm::Breakpoints, get_contract_name, get_file_name, ContractsByArtifact}; +use foundry_common::{get_contract_name, get_file_name, ContractsByArtifact}; use foundry_compilers::artifacts::Libraries; use foundry_evm::{ coverage::HitMaps, - debug::DebugArena, executors::EvmError, - fuzz::{CounterExample, FuzzCase, FuzzFixtures}, + fuzz::{CounterExample, FuzzFixtures}, traces::{CallTraceArena, CallTraceDecoder, TraceKind, Traces}, }; use serde::{Deserialize, Serialize}; @@ -387,13 +386,7 @@ pub struct TestResult { /// Labeled addresses pub labeled_addresses: HashMap, - /// The debug nodes of the call - pub debug: Option, - pub duration: Duration, - - /// pc breakpoint char map - pub breakpoints: Breakpoints, } impl fmt::Display for TestResult { @@ -513,8 +506,6 @@ pub enum TestKind { Standard(u64), /// A solidity fuzz test, that stores all test cases Fuzz { - /// we keep this for the debugger - first_case: FuzzCase, runs: usize, mean_gas: u64, median_gas: u64, diff --git a/crates/foundry/forge/src/runner.rs b/crates/foundry/forge/src/runner.rs index 1ab525cd8..410580358 100644 --- a/crates/foundry/forge/src/runner.rs +++ b/crates/foundry/forge/src/runner.rs @@ -22,7 +22,7 @@ use foundry_evm::{ coverage::HitMaps, decode::{decode_console_logs, RevertDecoder}, executors::{ - fuzz::{CaseOutcome, CounterExampleOutcome, FuzzOutcome, FuzzedExecutor}, + fuzz::FuzzedExecutor, invariant::{ check_sequence, replay_error, replay_run, InvariantExecutor, InvariantFuzzError, InvariantFuzzTestResult, @@ -61,8 +61,6 @@ pub struct ContractRunner<'a> { pub initial_balance: U256, /// The address which will be used as the `from` field in all EVM calls pub sender: Address, - /// Should generate debug traces - pub debug: bool, /// Whether to support the `testFail` prefix pub test_fail: bool, /// Whether to enable solidity fuzz fixtures support @@ -76,8 +74,6 @@ pub struct ContractRunnerOptions { pub initial_balance: U256, /// The address which will be used as the `from` field in all EVM calls pub sender: Address, - /// Should generate debug traces - pub debug: bool, /// Whether to support the `testFail` prefix pub test_fail: bool, /// whether to enable solidity fuzz fixtures support @@ -95,7 +91,6 @@ impl<'a> ContractRunner<'a> { let ContractRunnerOptions { initial_balance, sender, - debug, test_fail, solidity_fuzz_fixtures, } = options; @@ -107,7 +102,6 @@ impl<'a> ContractRunner<'a> { revert_decoder, initial_balance, sender, - debug, test_fail, solidity_fuzz_fixtures, } @@ -579,13 +573,9 @@ impl<'a> ContractRunner<'a> { coverage: execution_coverage, labels: new_labels, state_changeset, - debug, - cheatcodes, .. } = raw_call_result; - let breakpoints = cheatcodes.map(|c| c.breakpoints).unwrap_or_default(); - let debug_arena = debug; traces.extend(execution_trace.map(|traces| (TraceKind::Execution, traces))); labeled_addresses.extend(new_labels); logs.extend(execution_logs); @@ -615,8 +605,6 @@ impl<'a> ContractRunner<'a> { traces, coverage, labeled_addresses, - debug: debug_arena, - breakpoints, duration, gas_report_traces: Vec::new(), } @@ -824,7 +812,6 @@ impl<'a> ContractRunner<'a> { labeled_addresses: labeled_addresses.clone(), duration: start.elapsed(), gas_report_traces, - ..Default::default() // TODO collect debug traces on the last run or error } } @@ -874,9 +861,6 @@ impl<'a> ContractRunner<'a> { self.revert_decoder, ); - let mut debug = Option::default(); - let mut breakpoints = HashMap::default(); - // Check the last test result and skip the test // if it's marked as so. if let Some("SKIPPED") = result.reason.as_deref() { @@ -887,56 +871,15 @@ impl<'a> ContractRunner<'a> { traces, labeled_addresses, kind: TestKind::Standard(0), - debug, - breakpoints, coverage, duration: start.elapsed(), ..Default::default() }; } - // if should debug - if self.debug { - let mut debug_executor = self.executor.clone(); - // turn the debug traces on - debug_executor.inspector.enable_debugger(true); - debug_executor.inspector.tracing(true); - let calldata = if let Some(counterexample) = result.counterexample.as_ref() { - match counterexample { - CounterExample::Single(ce) => ce.calldata.clone(), - #[allow(clippy::unimplemented)] - CounterExample::Sequence(_) => unimplemented!(), - } - } else { - result.first_case.calldata.clone() - }; - // rerun the last relevant test with traces - let debug_result = - FuzzedExecutor::new(debug_executor, runner, self.sender, fuzz_config).single_fuzz( - address, - should_fail, - calldata, - ); - - (debug, breakpoints) = match debug_result { - Ok(fuzz_outcome) => match fuzz_outcome { - FuzzOutcome::Case(CaseOutcome { - debug, breakpoints, .. - }) - | FuzzOutcome::CounterExample(CounterExampleOutcome { - debug, - breakpoints, - .. - }) => (debug, breakpoints), - }, - Err(_) => (Option::default(), HashMap::default()), - }; - } - let kind = TestKind::Fuzz { median_gas: result.median_gas(false), mean_gas: result.mean_gas(false), - first_case: result.first_case, runs: result.gas_by_case.len(), }; @@ -963,8 +906,6 @@ impl<'a> ContractRunner<'a> { traces, coverage, labeled_addresses, - debug, - breakpoints, duration, gas_report_traces: result .gas_report_traces diff --git a/crates/foundry/forge/tests/it/test_helpers.rs b/crates/foundry/forge/tests/it/test_helpers.rs index c00239839..3e1f151a2 100644 --- a/crates/foundry/forge/tests/it/test_helpers.rs +++ b/crates/foundry/forge/tests/it/test_helpers.rs @@ -83,7 +83,6 @@ impl ForgeTestProfile { fn runner_config() -> SolidityTestRunnerConfig { SolidityTestRunnerConfig { - debug: false, trace: true, evm_opts: Self::evm_opts(), project_root: PROJECT_ROOT.clone(), diff --git a/crates/foundry/testdata/cheats/Vm.sol b/crates/foundry/testdata/cheats/Vm.sol index d4c561d87..143d5bcf0 100644 --- a/crates/foundry/testdata/cheats/Vm.sol +++ b/crates/foundry/testdata/cheats/Vm.sol @@ -146,8 +146,6 @@ interface Vm { function assume(bool condition) external pure; function blobBaseFee(uint256 newBlobBaseFee) external; function blobhashes(bytes32[] calldata hashes) external; - function breakpoint(string calldata char) external; - function breakpoint(string calldata char, bool value) external; function chainId(uint256 newChainId) external; function clearMockedCalls() external; function closeFile(string calldata path) external;