Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions Cargo.lock

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

46 changes: 12 additions & 34 deletions crates/cli/src/utils/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ use ethers::{
abi::Abi,
core::types::Chain,
solc::{
artifacts::{CompactBytecode, CompactDeployedBytecode, ContractBytecodeSome},
artifacts::{CompactBytecode, CompactDeployedBytecode},
cache::{CacheEntry, SolFilesCache},
info::ContractInfo,
utils::read_json_file,
Artifact, ArtifactId, ProjectCompileOutput,
Artifact, ProjectCompileOutput,
},
};
use eyre::{Result, WrapErr};
Expand All @@ -20,9 +20,9 @@ use foundry_evm::{
CallTraceDecoder, CallTraceDecoderBuilder, TraceKind, Traces,
},
};
use std::{collections::BTreeMap, fmt::Write, path::PathBuf, str::FromStr};
use std::{fmt::Write, path::PathBuf, str::FromStr};
use tracing::trace;
use ui::{TUIExitReason, Tui, Ui};
use ui::DebuggerArgs;
use yansi::Paint;

/// Given a `Project`'s output, removes the matching ABI, Bytecode and
Expand Down Expand Up @@ -390,8 +390,14 @@ pub async fn handle_traces(
}

if debug {
let (sources, bytecode) = etherscan_identifier.get_compiled_contracts().await?;
run_debugger(result, decoder, bytecode, sources)?;
let (sources, _compiled_contracts) = etherscan_identifier.get_compiled_contracts().await?;
let debugger = DebuggerArgs {
debug: vec![result.debug],
decoder: &decoder,
sources,
breakpoints: Default::default(),
};
debugger.run()?;
} else {
print_traces(&mut result, &decoder, verbose).await?;
}
Expand Down Expand Up @@ -428,31 +434,3 @@ pub async fn print_traces(
println!("Gas used: {}", result.gas_used);
Ok(())
}

pub fn run_debugger(
result: TraceResult,
decoder: CallTraceDecoder,
known_contracts: BTreeMap<ArtifactId, ContractBytecodeSome>,
sources: BTreeMap<ArtifactId, String>,
) -> Result<()> {
let calls: Vec<DebugArena> = vec![result.debug];
let flattened = calls.last().expect("we should have collected debug info").flatten(0);
let tui = Tui::new(
flattened,
0,
decoder.contracts,
known_contracts.into_iter().map(|(id, artifact)| (id.name, artifact)).collect(),
sources
.into_iter()
.map(|(id, source)| {
let mut sources = BTreeMap::new();
sources.insert(0, source);
(id.name, sources)
})
.collect(),
Default::default(),
)?;
match tui.start().expect("Failed to start tui") {
TUIExitReason::CharExit => Ok(()),
}
}
19 changes: 9 additions & 10 deletions crates/common/src/compile.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Support for compiling [ethers::solc::Project]
use crate::{glob::GlobMatcher, term, TestFunctionExt};
use crate::{compact_to_contract, glob::GlobMatcher, term, TestFunctionExt};
use comfy_table::{presets::ASCII_MARKDOWN, *};
use ethers_etherscan::contract::Metadata;
use ethers_solc::{
Expand Down Expand Up @@ -401,7 +401,7 @@ pub fn compile_target_with_filter(
/// Creates and compiles a project from an Etherscan source.
pub async fn compile_from_source(
metadata: &Metadata,
) -> Result<(ArtifactId, ContractBytecodeSome)> {
) -> Result<(ArtifactId, u32, ContractBytecodeSome)> {
let root = tempfile::tempdir()?;
let root_path = root.path();
let project = etherscan_project(metadata, root_path)?;
Expand All @@ -412,19 +412,18 @@ pub async fn compile_from_source(
eyre::bail!(project_output.to_string())
}

let (artifact_id, contract) = project_output
.into_contract_bytecodes()
let (artifact_id, file_id, contract) = project_output
.into_artifacts()
.find(|(artifact_id, _)| artifact_id.name == metadata.contract_name)
.map(|(aid, art)| {
(aid, art.source_file().expect("no source file").id, art.into_contract_bytecode())
})
.expect("there should be a contract with bytecode");
let bytecode = ContractBytecodeSome {
abi: contract.abi.unwrap(),
bytecode: contract.bytecode.unwrap().into(),
deployed_bytecode: contract.deployed_bytecode.unwrap().into(),
};
let bytecode = compact_to_contract(contract);

root.close()?;

Ok((artifact_id, bytecode))
Ok((artifact_id, file_id, bytecode))
}

/// Creates a [Project] from an Etherscan source.
Expand Down
14 changes: 13 additions & 1 deletion crates/common/src/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use ethers_core::{
types::{Address, H256},
utils::hex,
};
use ethers_solc::{artifacts::ContractBytecodeSome, ArtifactId, ProjectPathsConfig};
use ethers_solc::{
artifacts::{CompactContractBytecode, ContractBytecodeSome},
ArtifactId, ProjectPathsConfig,
};
use once_cell::sync::Lazy;
use regex::Regex;
use std::{
Expand Down Expand Up @@ -265,3 +268,12 @@ mod tests {
let _decoded = abi::decode(&params, args).unwrap();
}
}

/// Helper function to convert CompactContractBytecode ~> ContractBytecodeSome
pub fn compact_to_contract(contract: CompactContractBytecode) -> ContractBytecodeSome {
ContractBytecodeSome {
abi: contract.abi.unwrap(),
bytecode: contract.bytecode.unwrap().into(),
deployed_bytecode: contract.deployed_bytecode.unwrap().into(),
}
}
6 changes: 3 additions & 3 deletions crates/evm/src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
use std::fmt::Display;

/// An arena of [DebugNode]s
#[derive(Default, Debug, Clone)]
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct DebugArena {
/// The arena of nodes
pub arena: Vec<DebugNode>,
Expand Down Expand Up @@ -78,7 +78,7 @@ impl DebugArena {
}

/// A node in the arena
#[derive(Default, Debug, Clone)]
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct DebugNode {
/// Parent node index in the arena
pub parent: Option<usize>,
Expand Down Expand Up @@ -109,7 +109,7 @@ impl DebugNode {
/// 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(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DebugStep {
/// Stack *prior* to running the associated opcode
pub stack: Vec<U256>,
Expand Down
2 changes: 1 addition & 1 deletion crates/evm/src/executor/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl ExecutorBuilder {
/// Builds the executor as configured.
#[inline]
pub fn build(self, mut env: Env, db: Backend) -> Executor {
let Self { mut stack, gas_limit, spec_id } = self;
let Self { mut stack, gas_limit, spec_id, .. } = self;
env.cfg.spec_id = spec_id;
stack.block = Some(env.block.clone());
stack.gas_price = Some(env.tx.gas_price.into());
Expand Down
2 changes: 1 addition & 1 deletion crates/evm/src/executor/inspector/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ impl InspectorStackBuilder {
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));
stack.tracing(debug.unwrap_or(false) || trace.unwrap_or(false));

// environment, must come after all of the inspectors
if let Some(block) = block {
Expand Down
6 changes: 0 additions & 6 deletions crates/evm/src/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,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);
Expand Down
Loading