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(forge): Add call tracing support #192

Merged
merged 40 commits into from
Dec 23, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
b470925
first pass
brockelmore Dec 2, 2021
bfa42a8
fixes
brockelmore Dec 2, 2021
7106cd7
fmt
brockelmore Dec 2, 2021
f83b226
better fmting
brockelmore Dec 2, 2021
bf17ebb
updates
brockelmore Dec 2, 2021
23687c4
fmt
brockelmore Dec 2, 2021
f4671a9
updates
brockelmore Dec 11, 2021
e61cbda
Merge branch 'master' into brock/tracing
brockelmore Dec 11, 2021
f397646
fmt
brockelmore Dec 11, 2021
95cb702
fix after master merge
brockelmore Dec 11, 2021
0594faa
fix tests post master merge
brockelmore Dec 11, 2021
34f75e2
warning fixes
brockelmore Dec 11, 2021
62406e1
fmt
brockelmore Dec 11, 2021
79d210f
lots of fixes
brockelmore Dec 12, 2021
4b91be7
fmt
brockelmore Dec 12, 2021
3f8c2b7
fix
brockelmore Dec 12, 2021
cc7e2ed
cyan color
brockelmore Dec 12, 2021
f558e82
fixes
brockelmore Dec 12, 2021
ba514cb
prettier raw logs + parse setup contracts
brockelmore Dec 12, 2021
133685f
Merge branch 'master' into brock/tracing
brockelmore Dec 12, 2021
36b4cf6
update diff_score threshold
brockelmore Dec 12, 2021
c827d33
better printing
brockelmore Dec 16, 2021
58c6c1b
remove integration tests
brockelmore Dec 22, 2021
38ca049
Merge branch 'master' into brock/tracing
brockelmore Dec 22, 2021
1f759c0
improvements
brockelmore Dec 23, 2021
637c50a
improvements + fmt + clippy
brockelmore Dec 23, 2021
08ee0da
fixes
brockelmore Dec 23, 2021
6271684
more cleanup
brockelmore Dec 23, 2021
ee88892
cleanup and verbosity > 3 setup print
brockelmore Dec 23, 2021
dc10a70
refactor printing
brockelmore Dec 23, 2021
c93da0a
documentation + cleanup
brockelmore Dec 23, 2021
6c825a0
fix negative number printing
brockelmore Dec 23, 2021
54a975f
fix tests to match master and fix tracing_enabled
brockelmore Dec 23, 2021
06eafba
Merge branch 'master' into brock/tracing
brockelmore Dec 23, 2021
a918468
fix unnecessary trace_index set
brockelmore Dec 23, 2021
57affc9
Merge branch 'brock/tracing' of https://github.com/gakonst/foundry in…
brockelmore Dec 23, 2021
b2e9922
refactor runner tracing + tracing_enabled
brockelmore Dec 23, 2021
bb9a707
nits + value printing
brockelmore Dec 23, 2021
4660e3c
Merge branch 'master' into brock/tracing
brockelmore Dec 23, 2021
90d81d2
last nits
brockelmore Dec 23, 2021
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
Prev Previous commit
Next Next commit
Merge branch 'master' into brock/tracing
  • Loading branch information
brockelmore committed Dec 12, 2021
commit 133685fb278f07c3bee98f369d9ae9667d00ae4f
32 changes: 31 additions & 1 deletion cli/src/cmd/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ impl Cmd for TestArgs {

let precompiles = PRECOMPILES_MAP.clone();
let evm =
Executor::new_with_cheatcodes(backend, env.gas_limit, &cfg, &precompiles, ffi);
Executor::new_with_cheatcodes(backend, env.gas_limit, &cfg, &precompiles, ffi, verbosity > 2,);

test(builder, project, evm, pattern, json, verbosity, allow_failure)
}
Expand Down Expand Up @@ -325,6 +325,36 @@ fn test<A: ArtifactOutput + 'static, S: Clone, E: evm_adapters::Evm<S>>(
}

println!();

if verbosity > 2 {
if let Some(traces) = &result.traces {
let mut identified = Default::default();
if traces.len() > 1 {
traces[0].update_identified(
0,
&runner.known_contracts,
&mut identified,
&runner.evm,
);
traces[1].pretty_print(
0,
&runner.known_contracts,
&mut identified,
&runner.evm,
"".to_string(),
);
} else {
traces[0].pretty_print(
0,
&runner.known_contracts,
&mut identified,
&runner.evm,
"".to_string(),
);
}
println!();
}
}
}
}
}
Expand Down
214 changes: 5 additions & 209 deletions cli/src/forge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,102 +21,9 @@ fn main() -> eyre::Result<()> {

let opts = Opts::from_args();
match opts.sub {
Subcommands::Test {
opts,
env,
json,
pattern,
evm_type,
fork_url,
fork_block_number,
initial_balance,
sender,
ffi,
verbosity,
allow_failure,
} => {
// Setup the fuzzer
// TODO: Add CLI Options to modify the persistence
let cfg =
proptest::test_runner::Config { failure_persistence: None, ..Default::default() };
let fuzzer = proptest::test_runner::TestRunner::new(cfg);

// Set up the project
let project = Project::try_from(&opts)?;

// prepare the test builder
let builder = MultiContractRunnerBuilder::default()
.fuzzer(fuzzer)
.initial_balance(initial_balance)
.sender(sender);

// run the tests depending on the chosen EVM
match evm_type {
#[cfg(feature = "sputnik-evm")]
EvmType::Sputnik => {
use evm_adapters::sputnik::Executor;
use sputnik::backend::MemoryBackend;
let mut cfg = opts.evm_version.sputnik_cfg();

// We disable the contract size limit by default, because Solidity
// test smart contracts are likely to be >24kb
cfg.create_contract_limit = None;

let vicinity = if let Some(ref url) = fork_url {
let provider = Provider::try_from(url.as_str())?;
let rt = tokio::runtime::Runtime::new().expect("could not start tokio rt");
rt.block_on(vicinity(&provider, fork_block_number))?
} else {
env.sputnik_state()
};
let mut backend = MemoryBackend::new(&vicinity, Default::default());
// max out the balance of the faucet
let faucet =
backend.state_mut().entry(*FAUCET_ACCOUNT).or_insert_with(Default::default);
faucet.balance = U256::MAX;

let backend: Box<dyn Backend> = if let Some(ref url) = fork_url {
let provider = Provider::try_from(url.as_str())?;
let init_state = backend.state().clone();
let backend = ForkMemoryBackend::new(
provider,
backend,
fork_block_number,
init_state,
);
Box::new(backend)
} else {
Box::new(backend)
};
let backend = Arc::new(backend);

let precompiles = PRECOMPILES_MAP.clone();
let evm = Executor::new_with_cheatcodes(
backend,
env.gas_limit,
&cfg,
&precompiles,
ffi,
verbosity > 2,
);

test(builder, project, evm, pattern, json, verbosity, allow_failure)?;
}
#[cfg(feature = "evmodin-evm")]
EvmType::EvmOdin => {
use evm_adapters::evmodin::EvmOdin;
use evmodin::tracing::NoopTracer;

let revision = opts.evm_version.evmodin_cfg();

// TODO: Replace this with a proper host. We'll want this to also be
// provided generically when we add the Forking host(s).
let host = env.evmodin_state();

let evm = EvmOdin::new(host, env.gas_limit, revision, NoopTracer);
test(builder, project, evm, pattern, json, verbosity, allow_failure)?;
}
}
Subcommands::Test(cmd) => {
let outcome = cmd.run()?;
outcome.ensure_ok()?;
}
Subcommands::Build(cmd) => {
cmd.run()?;
Expand Down Expand Up @@ -229,119 +136,8 @@ fn main() -> eyre::Result<()> {
let project = Project::builder().paths(paths).build()?;
project.cleanup()?;
}
}

Ok(())
}

fn test<A: ArtifactOutput + 'static, S: Clone, E: evm_adapters::Evm<S>>(
builder: MultiContractRunnerBuilder,
project: Project<A>,
evm: E,
pattern: Regex,
json: bool,
verbosity: u8,
allow_failure: bool,
) -> eyre::Result<HashMap<String, HashMap<String, forge::TestResult>>> {
let mut runner = builder.build(project, evm)?;

let mut exit_code = 0;

let results = runner.test(pattern)?;

if json {
let res = serde_json::to_string(&results)?;
println!("{}", res);
} else {
// Dapptools-style printing of test results
for (i, (contract_name, tests)) in results.iter().enumerate() {
if i > 0 {
println!()
}
if !tests.is_empty() {
let term = if tests.len() > 1 { "tests" } else { "test" };
println!("Running {} {} for {}", tests.len(), term, contract_name);
}

for (name, result) in tests {
let status = if result.success {
Colour::Green.paint("[PASS]")
} else {
// if an error is found, return a -1 exit code
exit_code = -1;
let txt = match (&result.reason, &result.counterexample) {
(Some(ref reason), Some(ref counterexample)) => {
format!(
"[FAIL. Reason: {}. Counterexample: {}]",
reason, counterexample
)
}
(None, Some(ref counterexample)) => {
format!("[FAIL. Counterexample: {}]", counterexample)
}
(Some(ref reason), None) => {
format!("[FAIL. Reason: {}]", reason)
}
(None, None) => "[FAIL]".to_string(),
};

Colour::Red.paint(txt)
};
println!(
"{} {} (gas: {})",
status,
name,
result
.gas_used
.map(|x| x.to_string())
.unwrap_or_else(|| "[fuzztest]".to_string())
);
}

if verbosity > 1 {
println!();

for (name, result) in tests {
let status = if result.success { "Success" } else { "Failure" };
println!("{}: {}", status, name);
println!();

for log in &result.logs {
println!(" {}", log);
}

println!();
if verbosity > 2 {
if let Some(traces) = &result.traces {
let mut identified = Default::default();
if traces.len() > 1 {
traces[0].update_identified(
0,
&runner.known_contracts,
&mut identified,
&runner.evm,
);
traces[1].pretty_print(
0,
&runner.known_contracts,
&mut identified,
&runner.evm,
"".to_string(),
);
} else {
traces[0].pretty_print(
0,
&runner.known_contracts,
&mut identified,
&runner.evm,
"".to_string(),
);
}
println!();
}
}
}
}
Subcommands::Snapshot(cmd) => {
cmd.run()?;
}
}

Expand Down
You are viewing a condensed version of this merge commit. You can view the full changes here.