From 641132f5418bd7c268366c2da09e5300f3a8e272 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Wed, 9 Oct 2024 14:57:05 +0400 Subject: [PATCH 1/5] feat(forge): allow passing value to `--optimize` (#9071) feat(forge): allow passing value to --optimize --- crates/cli/src/opts/build/core.rs | 4 ++-- crates/cli/src/opts/build/mod.rs | 4 ++-- crates/forge/bin/cmd/create.rs | 7 +++++-- crates/forge/bin/cmd/inspect.rs | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/crates/cli/src/opts/build/core.rs b/crates/cli/src/opts/build/core.rs index b0d0ccbbd23e..59da53372c77 100644 --- a/crates/cli/src/opts/build/core.rs +++ b/crates/cli/src/opts/build/core.rs @@ -266,8 +266,8 @@ impl Provider for CoreBuildArgs { dict.insert("ast".to_string(), true.into()); } - if self.compiler.optimize { - dict.insert("optimizer".to_string(), self.compiler.optimize.into()); + if let Some(optimize) = self.compiler.optimize { + dict.insert("optimizer".to_string(), optimize.into()); } if !self.compiler.extra_output.is_empty() { diff --git a/crates/cli/src/opts/build/mod.rs b/crates/cli/src/opts/build/mod.rs index dfd5d8366829..fe50a3a9a209 100644 --- a/crates/cli/src/opts/build/mod.rs +++ b/crates/cli/src/opts/build/mod.rs @@ -26,9 +26,9 @@ pub struct CompilerArgs { pub evm_version: Option, /// Activate the Solidity optimizer. - #[arg(long)] + #[arg(long, default_missing_value="true", num_args = 0..=1)] #[serde(skip)] - pub optimize: bool, + pub optimize: Option, /// The number of runs specifies roughly how often each opcode of the deployed code will be /// executed across the life-time of the contract. This means it is a trade-off parameter diff --git a/crates/forge/bin/cmd/create.rs b/crates/forge/bin/cmd/create.rs index 3bcf6b36cbde..df42f458c015 100644 --- a/crates/forge/bin/cmd/create.rs +++ b/crates/forge/bin/cmd/create.rs @@ -335,8 +335,11 @@ impl CreateArgs { println!("Starting contract verification..."); - let num_of_optimizations = - if self.opts.compiler.optimize { self.opts.compiler.optimizer_runs } else { None }; + let num_of_optimizations = if self.opts.compiler.optimize.unwrap_or_default() { + self.opts.compiler.optimizer_runs + } else { + None + }; let verify = forge_verify::VerifyArgs { address, contract: Some(self.contract), diff --git a/crates/forge/bin/cmd/inspect.rs b/crates/forge/bin/cmd/inspect.rs index ddfe60e61d28..14d43d6f5ec4 100644 --- a/crates/forge/bin/cmd/inspect.rs +++ b/crates/forge/bin/cmd/inspect.rs @@ -52,7 +52,7 @@ impl InspectArgs { // Run Optimized? let optimized = if field == ContractArtifactField::AssemblyOptimized { - true + Some(true) } else { build.compiler.optimize }; From a96b8266cf1f11e08ef0dfca9325ea6560d17c55 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:18:51 +0300 Subject: [PATCH 2/5] fix(forge): add logs/decoded logs in json test results (#9074) --- crates/forge/bin/cmd/test/mod.rs | 13 ++++- crates/forge/src/result.rs | 4 ++ crates/forge/tests/cli/test_cmd.rs | 6 +++ .../SimpleContractTestNonVerbose.json | 1 + .../fixtures/SimpleContractTestVerbose.json | 49 ++++++++++++++++++- 5 files changed, 70 insertions(+), 3 deletions(-) diff --git a/crates/forge/bin/cmd/test/mod.rs b/crates/forge/bin/cmd/test/mod.rs index 0e87a4c66915..f83d336ed69b 100644 --- a/crates/forge/bin/cmd/test/mod.rs +++ b/crates/forge/bin/cmd/test/mod.rs @@ -501,7 +501,18 @@ impl TestArgs { // Run tests in a non-streaming fashion and collect results for serialization. if self.json { - let results = runner.test_collect(filter); + let mut results = runner.test_collect(filter); + results.values_mut().for_each(|suite_result| { + for test_result in suite_result.test_results.values_mut() { + if verbosity >= 2 { + // Decode logs at level 2 and above. + test_result.decoded_logs = decode_console_logs(&test_result.logs); + } else { + // Empty logs for non verbose runs. + test_result.logs = vec![]; + } + } + }); println!("{}", serde_json::to_string(&results)?); return Ok(TestOutcome::new(results, self.allow_failure)); } diff --git a/crates/forge/src/result.rs b/crates/forge/src/result.rs index a6d7fded9c48..4fb88dfd0b59 100644 --- a/crates/forge/src/result.rs +++ b/crates/forge/src/result.rs @@ -389,6 +389,10 @@ pub struct TestResult { /// be printed to the user. pub logs: Vec, + /// The decoded DSTest logging events and Hardhat's `console.log` from [logs](Self::logs). + /// Used for json output. + pub decoded_logs: Vec, + /// What kind of test this was pub kind: TestKind, diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index f8b54cc4126e..30c7f9deb4e6 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -275,7 +275,10 @@ Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) }); const SIMPLE_CONTRACT: &str = r#" +pragma solidity 0.8.18; + import "./test.sol"; +import "./console.sol"; contract SimpleContract { uint256 public num; @@ -289,12 +292,14 @@ contract SimpleContractTest is DSTest { function test() public { SimpleContract c = new SimpleContract(); c.setValues(100); + console.log("Value set: ", 100); } } "#; forgetest!(can_run_test_with_json_output_verbose, |prj, cmd| { prj.insert_ds_test(); + prj.insert_console(); prj.add_source("Simple.t.sol", SIMPLE_CONTRACT).unwrap(); @@ -306,6 +311,7 @@ forgetest!(can_run_test_with_json_output_verbose, |prj, cmd| { forgetest!(can_run_test_with_json_output_non_verbose, |prj, cmd| { prj.insert_ds_test(); + prj.insert_console(); prj.add_source("Simple.t.sol", SIMPLE_CONTRACT).unwrap(); diff --git a/crates/forge/tests/fixtures/SimpleContractTestNonVerbose.json b/crates/forge/tests/fixtures/SimpleContractTestNonVerbose.json index 8fd8a0faef53..b4e396863dc6 100644 --- a/crates/forge/tests/fixtures/SimpleContractTestNonVerbose.json +++ b/crates/forge/tests/fixtures/SimpleContractTestNonVerbose.json @@ -7,6 +7,7 @@ "reason": null, "counterexample": null, "logs": [], + "decoded_logs": [], "kind": { "Unit": { "gas": "{...}" diff --git a/crates/forge/tests/fixtures/SimpleContractTestVerbose.json b/crates/forge/tests/fixtures/SimpleContractTestVerbose.json index c7f47cf53477..adc700d4d59d 100644 --- a/crates/forge/tests/fixtures/SimpleContractTestVerbose.json +++ b/crates/forge/tests/fixtures/SimpleContractTestVerbose.json @@ -6,7 +6,18 @@ "status": "Success", "reason": null, "counterexample": null, - "logs": [], + "logs": [ + { + "address": "0x000000000000000000636F6e736F6c652e6c6f67", + "topics": [ + "0x41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000f56616c7565207365743a20203130300000000000000000000000000000000000" + } + ], + "decoded_logs": [ + "Value set: 100" + ], "kind": { "Unit": { "gas": "{...}" @@ -58,7 +69,8 @@ "parent": null, "children": [ 1, - 2 + 2, + 3 ], "idx": 0, "trace": { @@ -91,6 +103,9 @@ }, { "Call": 1 + }, + { + "Call": 2 } ] }, @@ -153,6 +168,36 @@ }, "logs": [], "ordering": [] + }, + { + "parent": 0, + "children": [], + "idx": 3, + "trace": { + "depth": 1, + "success": true, + "caller": "0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496", + "address": "0x000000000000000000636F6e736F6c652e6c6f67", + "maybe_precompile": null, + "selfdestruct_address": null, + "selfdestruct_refund_target": null, + "selfdestruct_transferred_value": null, + "kind": "STATICCALL", + "value": "0x0", + "data": "{...}", + "output": "0x", + "gas_used": "{...}", + "gas_limit": "{...}", + "status": "Stop", + "steps": [], + "decoded": { + "label": null, + "return_data": null, + "call_data": null + } + }, + "logs": [], + "ordering": [] } ] } From d847e0f09a95ef6ff8463521b98136e74dac37da Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:53:33 +0300 Subject: [PATCH 3/5] fix(`forge`): avoid panic when empty fuzz selectors in invariants (#9076) --- crates/evm/evm/src/executors/invariant/mod.rs | 8 +++-- crates/forge/tests/it/invariant.rs | 32 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/crates/evm/evm/src/executors/invariant/mod.rs b/crates/evm/evm/src/executors/invariant/mod.rs index f6edd586a803..58c7efd8fe12 100644 --- a/crates/evm/evm/src/executors/invariant/mod.rs +++ b/crates/evm/evm/src/executors/invariant/mod.rs @@ -742,9 +742,6 @@ impl<'a> InvariantExecutor<'a> { ) -> Result<()> { for (address, (identifier, _)) in self.setup_contracts.iter() { if let Some(selectors) = self.artifact_filters.targeted.get(identifier) { - if selectors.is_empty() { - continue; - } self.add_address_with_functions(*address, selectors, false, targeted_contracts)?; } } @@ -774,6 +771,11 @@ impl<'a> InvariantExecutor<'a> { should_exclude: bool, targeted_contracts: &mut TargetedContracts, ) -> eyre::Result<()> { + // Do not add address in target contracts if no function selected. + if selectors.is_empty() { + return Ok(()) + } + let contract = match targeted_contracts.entry(address) { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => { diff --git a/crates/forge/tests/it/invariant.rs b/crates/forge/tests/it/invariant.rs index 0a9e7910a0ad..37b3c9b23934 100644 --- a/crates/forge/tests/it/invariant.rs +++ b/crates/forge/tests/it/invariant.rs @@ -823,3 +823,35 @@ contract BalanceAssumeTest is Test { ... "#]]); }); + +// Test proper message displayed if `targetSelector`/`excludeSelector` called with empty selectors. +// +forgetest_init!(should_not_panic_if_no_selectors, |prj, cmd| { + prj.add_test( + "NoSelectorTest.t.sol", + r#" +import {Test} from "forge-std/Test.sol"; + +contract TestHandler is Test {} + +contract NoSelectorTest is Test { + bytes4[] selectors; + + function setUp() public { + TestHandler handler = new TestHandler(); + targetSelector(FuzzSelector({addr: address(handler), selectors: selectors})); + excludeSelector(FuzzSelector({addr: address(handler), selectors: selectors})); + } + + function invariant_panic() public {} +} + "#, + ) + .unwrap(); + + cmd.args(["test", "--mt", "invariant_panic"]).assert_failure().stdout_eq(str![[r#" +... +[FAIL: failed to set up invariant testing environment: No contracts to fuzz.] invariant_panic() (runs: 0, calls: 0, reverts: 0) +... +"#]]); +}); From 97ce8c33b518d3600a48bf0e614d98454bf11463 Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Wed, 9 Oct 2024 18:30:55 +0530 Subject: [PATCH 4/5] chore(`anvil`): use op-alloy types (#9047) --- Cargo.lock | 226 +++++--------- Cargo.toml | 7 +- crates/anvil/Cargo.toml | 3 + crates/anvil/core/Cargo.toml | 1 + crates/anvil/core/src/eth/transaction/mod.rs | 15 +- .../core/src/eth/transaction/optimism.rs | 284 +----------------- crates/anvil/src/eth/api.rs | 2 +- crates/anvil/src/eth/sign.rs | 22 +- 8 files changed, 112 insertions(+), 448 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index be6aebeea7de..381ed5a7514f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,30 +83,16 @@ dependencies = [ "strum", ] -[[package]] -name = "alloy-consensus" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629b62e38d471cc15fea534eb7283d2f8a4e8bdb1811bcc5d66dda6cfce6fae1" -dependencies = [ - "alloy-eips 0.3.6", - "alloy-primitives", - "alloy-rlp", - "alloy-serde 0.3.6", - "c-kzg", - "serde", -] - [[package]] name = "alloy-consensus" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "705687d5bfd019fee57cf9e206b27b30a9a9617535d5590a02b171e813208f8e" dependencies = [ - "alloy-eips 0.4.2", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.4.2", + "alloy-serde", "auto_impl", "c-kzg", "derive_more 1.0.0", @@ -122,11 +108,11 @@ dependencies = [ "alloy-dyn-abi", "alloy-json-abi", "alloy-network", - "alloy-network-primitives 0.4.2", + "alloy-network-primitives", "alloy-primitives", "alloy-provider", "alloy-pubsub", - "alloy-rpc-types-eth 0.4.2", + "alloy-rpc-types-eth", "alloy-sol-types", "alloy-transport", "futures", @@ -182,24 +168,6 @@ dependencies = [ "serde", ] -[[package]] -name = "alloy-eips" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f923dd5fca5f67a43d81ed3ebad0880bd41f6dd0ada930030353ac356c54cd0f" -dependencies = [ - "alloy-eip2930", - "alloy-eip7702", - "alloy-primitives", - "alloy-rlp", - "alloy-serde 0.3.6", - "c-kzg", - "derive_more 1.0.0", - "once_cell", - "serde", - "sha2", -] - [[package]] name = "alloy-eips" version = "0.4.2" @@ -210,7 +178,7 @@ dependencies = [ "alloy-eip7702", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.4.2", + "alloy-serde", "c-kzg", "derive_more 1.0.0", "once_cell", @@ -225,7 +193,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8429cf4554eed9b40feec7f4451113e76596086447550275e3def933faf47ce3" dependencies = [ "alloy-primitives", - "alloy-serde 0.4.2", + "alloy-serde", "serde", ] @@ -261,13 +229,13 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85fa23a6a9d612b52e402c995f2d582c25165ec03ac6edf64c861a76bc5b87cd" dependencies = [ - "alloy-consensus 0.4.2", - "alloy-eips 0.4.2", + "alloy-consensus", + "alloy-eips", "alloy-json-rpc", - "alloy-network-primitives 0.4.2", + "alloy-network-primitives", "alloy-primitives", - "alloy-rpc-types-eth 0.4.2", - "alloy-serde 0.4.2", + "alloy-rpc-types-eth", + "alloy-serde", "alloy-signer", "alloy-sol-types", "async-trait", @@ -276,28 +244,16 @@ dependencies = [ "thiserror", ] -[[package]] -name = "alloy-network-primitives" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ad40869867ed2d9cd3842b1e800889e5b49e6b92da346e93862b4a741bedf3" -dependencies = [ - "alloy-eips 0.3.6", - "alloy-primitives", - "alloy-serde 0.3.6", - "serde", -] - [[package]] name = "alloy-network-primitives" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "801492711d4392b2ccf5fc0bc69e299fa1aab15167d74dcaa9aab96a54f684bd" dependencies = [ - "alloy-consensus 0.4.2", - "alloy-eips 0.4.2", + "alloy-consensus", + "alloy-eips", "alloy-primitives", - "alloy-serde 0.4.2", + "alloy-serde", "serde", ] @@ -340,15 +296,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcfaa4ffec0af04e3555686b8aacbcdf7d13638133a0672749209069750f78a6" dependencies = [ "alloy-chains", - "alloy-consensus 0.4.2", - "alloy-eips 0.4.2", + "alloy-consensus", + "alloy-eips", "alloy-json-rpc", "alloy-network", - "alloy-network-primitives 0.4.2", + "alloy-network-primitives", "alloy-primitives", "alloy-pubsub", "alloy-rpc-client", - "alloy-rpc-types-eth 0.4.2", + "alloy-rpc-types-eth", "alloy-rpc-types-trace", "alloy-rpc-types-txpool", "alloy-transport", @@ -447,10 +403,10 @@ dependencies = [ "alloy-primitives", "alloy-rpc-types-anvil", "alloy-rpc-types-engine", - "alloy-rpc-types-eth 0.4.2", + "alloy-rpc-types-eth", "alloy-rpc-types-trace", "alloy-rpc-types-txpool", - "alloy-serde 0.4.2", + "alloy-serde", "serde", ] @@ -461,7 +417,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d780adaa5d95b07ad92006b2feb68ecfa7e2015f7d5976ceaac4c906c73ebd07" dependencies = [ "alloy-primitives", - "alloy-serde 0.4.2", + "alloy-serde", "serde", ] @@ -471,11 +427,11 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0285c4c09f838ab830048b780d7f4a4f460f309aa1194bb049843309524c64c" dependencies = [ - "alloy-consensus 0.4.2", - "alloy-eips 0.4.2", + "alloy-consensus", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.4.2", + "alloy-serde", "derive_more 1.0.0", "jsonwebtoken", "rand", @@ -483,39 +439,18 @@ dependencies = [ "strum", ] -[[package]] -name = "alloy-rpc-types-eth" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83aa984386deda02482660aa31cb8ca1e63d533f1c31a52d7d181ac5ec68e9b8" -dependencies = [ - "alloy-consensus 0.3.6", - "alloy-eips 0.3.6", - "alloy-network-primitives 0.3.6", - "alloy-primitives", - "alloy-rlp", - "alloy-serde 0.3.6", - "alloy-sol-types", - "cfg-if", - "derive_more 1.0.0", - "hashbrown 0.14.5", - "itertools 0.13.0", - "serde", - "serde_json", -] - [[package]] name = "alloy-rpc-types-eth" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413f4aa3ccf2c3e4234a047c5fa4727916d7daf25a89f9b765df0ba09784fd87" dependencies = [ - "alloy-consensus 0.4.2", - "alloy-eips 0.4.2", - "alloy-network-primitives 0.4.2", + "alloy-consensus", + "alloy-eips", + "alloy-network-primitives", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.4.2", + "alloy-serde", "alloy-sol-types", "derive_more 1.0.0", "itertools 0.13.0", @@ -530,8 +465,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "017cad3e5793c5613588c1f9732bcbad77e820ba7d0feaba3527749f856fdbc5" dependencies = [ "alloy-primitives", - "alloy-rpc-types-eth 0.4.2", - "alloy-serde 0.4.2", + "alloy-rpc-types-eth", + "alloy-serde", "serde", "serde_json", "thiserror", @@ -544,20 +479,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b230e321c416be7f50530159392b4c41a45596d40d97e185575bcd0b545e521" dependencies = [ "alloy-primitives", - "alloy-rpc-types-eth 0.4.2", - "alloy-serde 0.4.2", - "serde", -] - -[[package]] -name = "alloy-serde" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "731f75ec5d383107fd745d781619bd9cedf145836c51ecb991623d41278e71fa" -dependencies = [ - "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde", "serde", - "serde_json", ] [[package]] @@ -593,7 +517,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "417e19d9844350d11f7426d4920a5df777f8c2abbb7a70d9de6f1faf284db15b" dependencies = [ - "alloy-consensus 0.4.2", + "alloy-consensus", "alloy-network", "alloy-primitives", "alloy-signer", @@ -611,7 +535,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fd12ae28e8330766821058ed9a6a06ae4f9b12c776e8a7cfb16e3a954f508e" dependencies = [ - "alloy-consensus 0.4.2", + "alloy-consensus", "alloy-network", "alloy-primitives", "alloy-signer", @@ -629,7 +553,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3a02400dea370022151f07581b73a836115c88ce4df350206653493bec024e2" dependencies = [ - "alloy-consensus 0.4.2", + "alloy-consensus", "alloy-dyn-abi", "alloy-network", "alloy-primitives", @@ -649,7 +573,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "494e0a256f3e99f2426f994bcd1be312c02cb8f88260088dacb33a8b8936475f" dependencies = [ - "alloy-consensus 0.4.2", + "alloy-consensus", "alloy-network", "alloy-primitives", "alloy-signer", @@ -668,7 +592,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0d91ddee2390b002148128e47902893deba353eb1b818a3afb6c960ebf4e42c" dependencies = [ - "alloy-consensus 0.4.2", + "alloy-consensus", "alloy-network", "alloy-primitives", "alloy-signer", @@ -928,10 +852,10 @@ name = "anvil" version = "0.2.0" dependencies = [ "alloy-chains", - "alloy-consensus 0.4.2", + "alloy-consensus", "alloy-contract", "alloy-dyn-abi", - "alloy-eips 0.4.2", + "alloy-eips", "alloy-genesis", "alloy-json-abi", "alloy-json-rpc", @@ -942,7 +866,7 @@ dependencies = [ "alloy-rlp", "alloy-rpc-client", "alloy-rpc-types", - "alloy-serde 0.4.2", + "alloy-serde", "alloy-signer", "alloy-signer-local", "alloy-sol-types", @@ -973,6 +897,7 @@ dependencies = [ "hyper 1.4.1", "itertools 0.13.0", "k256", + "op-alloy-consensus", "op-alloy-rpc-types", "parking_lot", "rand", @@ -996,17 +921,18 @@ dependencies = [ name = "anvil-core" version = "0.2.0" dependencies = [ - "alloy-consensus 0.4.2", + "alloy-consensus", "alloy-dyn-abi", - "alloy-eips 0.4.2", + "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-rpc-types", - "alloy-serde 0.4.2", + "alloy-serde", "alloy-trie", "bytes", "foundry-common", "foundry-evm", + "op-alloy-consensus", "rand", "revm", "serde", @@ -3369,14 +3295,14 @@ name = "forge" version = "0.2.0" dependencies = [ "alloy-chains", - "alloy-consensus 0.4.2", + "alloy-consensus", "alloy-dyn-abi", "alloy-json-abi", "alloy-network", "alloy-primitives", "alloy-provider", "alloy-rpc-types", - "alloy-serde 0.4.2", + "alloy-serde", "alloy-signer", "alloy-signer-local", "alloy-sol-macro-expander", @@ -3498,15 +3424,15 @@ name = "forge-script" version = "0.2.0" dependencies = [ "alloy-chains", - "alloy-consensus 0.4.2", + "alloy-consensus", "alloy-dyn-abi", - "alloy-eips 0.4.2", + "alloy-eips", "alloy-json-abi", "alloy-network", "alloy-primitives", "alloy-provider", "alloy-rpc-types", - "alloy-serde 0.4.2", + "alloy-serde", "alloy-signer", "alloy-transport", "async-recursion", @@ -3619,7 +3545,7 @@ name = "foundry-cast" version = "0.2.0" dependencies = [ "alloy-chains", - "alloy-consensus 0.4.2", + "alloy-consensus", "alloy-contract", "alloy-dyn-abi", "alloy-json-abi", @@ -3629,7 +3555,7 @@ dependencies = [ "alloy-provider", "alloy-rlp", "alloy-rpc-types", - "alloy-serde 0.4.2", + "alloy-serde", "alloy-signer", "alloy-signer-local", "alloy-sol-types", @@ -3676,7 +3602,7 @@ dependencies = [ name = "foundry-cheatcodes" version = "0.2.0" dependencies = [ - "alloy-consensus 0.4.2", + "alloy-consensus", "alloy-dyn-abi", "alloy-genesis", "alloy-json-abi", @@ -3767,7 +3693,7 @@ dependencies = [ name = "foundry-common" version = "0.2.0" dependencies = [ - "alloy-consensus 0.4.2", + "alloy-consensus", "alloy-contract", "alloy-dyn-abi", "alloy-json-abi", @@ -3777,7 +3703,7 @@ dependencies = [ "alloy-pubsub", "alloy-rpc-client", "alloy-rpc-types", - "alloy-serde 0.4.2", + "alloy-serde", "alloy-sol-types", "alloy-transport", "alloy-transport-http", @@ -3812,11 +3738,11 @@ dependencies = [ name = "foundry-common-fmt" version = "0.2.0" dependencies = [ - "alloy-consensus 0.4.2", + "alloy-consensus", "alloy-dyn-abi", "alloy-primitives", "alloy-rpc-types", - "alloy-serde 0.4.2", + "alloy-serde", "chrono", "comfy-table", "foundry-macros", @@ -4039,7 +3965,7 @@ dependencies = [ "alloy-primitives", "alloy-provider", "alloy-rpc-types", - "alloy-serde 0.4.2", + "alloy-serde", "alloy-sol-types", "alloy-transport", "auto_impl", @@ -4139,7 +4065,7 @@ dependencies = [ "alloy-primitives", "alloy-provider", "alloy-rpc-types", - "alloy-serde 0.4.2", + "alloy-serde", "alloy-transport", "eyre", "futures", @@ -4199,7 +4125,7 @@ dependencies = [ name = "foundry-wallets" version = "0.2.0" dependencies = [ - "alloy-consensus 0.4.2", + "alloy-consensus", "alloy-dyn-abi", "alloy-network", "alloy-primitives", @@ -4768,7 +4694,6 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", - "serde", ] [[package]] @@ -6131,15 +6056,15 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "op-alloy-consensus" -version = "0.2.12" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21aad1fbf80d2bcd7406880efc7ba109365f44bbb72896758ddcbfa46bf1592c" +checksum = "c4f7f318f885db6e1455370ca91f74b7faed152c8142f6418f0936d606e582ff" dependencies = [ - "alloy-consensus 0.3.6", - "alloy-eips 0.3.6", + "alloy-consensus", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.3.6", + "alloy-serde", "derive_more 1.0.0", "serde", "spin", @@ -6147,17 +6072,16 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types" -version = "0.2.12" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e281fbfc2198b7c0c16457d6524f83d192662bc9f3df70f24c3038d4521616df" +checksum = "547d29c5ab957ff32e14edddb93652dad748d2ef6cbe4b0fe8615ce06b0a3ddb" dependencies = [ - "alloy-eips 0.3.6", - "alloy-network-primitives 0.3.6", + "alloy-consensus", + "alloy-eips", + "alloy-network-primitives", "alloy-primitives", - "alloy-rpc-types-eth 0.3.6", - "alloy-serde 0.3.6", - "cfg-if", - "hashbrown 0.14.5", + "alloy-rpc-types-eth", + "alloy-serde", "op-alloy-consensus", "serde", "serde_json", @@ -7293,7 +7217,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43c44af0bf801f48d25f7baf25cf72aff4c02d610f83b428175228162fef0246" dependencies = [ "alloy-primitives", - "alloy-rpc-types-eth 0.4.2", + "alloy-rpc-types-eth", "alloy-rpc-types-trace", "alloy-sol-types", "anstyle", @@ -7739,9 +7663,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ "windows-sys 0.59.0", ] diff --git a/Cargo.toml b/Cargo.toml index 99637920d14a..9b660adbb1dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -219,8 +219,9 @@ alloy-chains = "0.1" alloy-rlp = "0.3" alloy-trie = "0.6.0" -## op-alloy for tests in anvil -op-alloy-rpc-types = "0.2.9" +## op-alloy +op-alloy-rpc-types = "0.3.3" +op-alloy-consensus = "0.3.3" ## misc async-trait = "0.1" @@ -278,7 +279,7 @@ soldeer-commands = "=0.4.0" proptest = "1" comfy-table = "7" -# [patch.crates-io] +[patch.crates-io] ## alloy-core # alloy-dyn-abi = { path = "../../alloy-rs/core/crates/dyn-abi" } # alloy-json-abi = { path = "../../alloy-rs/core/crates/json-abi" } diff --git a/crates/anvil/Cargo.toml b/crates/anvil/Cargo.toml index 0723fdb47f80..922cb6efc207 100644 --- a/crates/anvil/Cargo.toml +++ b/crates/anvil/Cargo.toml @@ -67,6 +67,7 @@ alloy-transport.workspace = true alloy-chains.workspace = true alloy-genesis.workspace = true alloy-trie.workspace = true +op-alloy-consensus.workspace = true # axum related axum.workspace = true @@ -121,8 +122,10 @@ alloy-pubsub.workspace = true foundry-test-utils.workspace = true similar-asserts.workspace = true tokio = { workspace = true, features = ["full"] } + op-alloy-rpc-types.workspace = true + [features] default = ["cli", "jemalloc"] cmd = ["clap", "clap_complete", "ctrlc", "anvil-server/clap"] diff --git a/crates/anvil/core/Cargo.toml b/crates/anvil/core/Cargo.toml index 8c2720c8f06a..6ea5e53184da 100644 --- a/crates/anvil/core/Cargo.toml +++ b/crates/anvil/core/Cargo.toml @@ -30,6 +30,7 @@ alloy-eips.workspace = true alloy-consensus = { workspace = true, features = ["k256", "kzg"] } alloy-dyn-abi = { workspace = true, features = ["std", "eip712"] } alloy-trie.workspace = true +op-alloy-consensus.workspace = true serde = { workspace = true, optional = true } serde_json.workspace = true diff --git a/crates/anvil/core/src/eth/transaction/mod.rs b/crates/anvil/core/src/eth/transaction/mod.rs index 2ed75db28f14..c3120792028a 100644 --- a/crates/anvil/core/src/eth/transaction/mod.rs +++ b/crates/anvil/core/src/eth/transaction/mod.rs @@ -1,6 +1,6 @@ //! Transaction related types -use crate::eth::transaction::optimism::{DepositTransaction, DepositTransactionRequest}; +use crate::eth::transaction::optimism::DepositTransaction; use alloy_consensus::{ transaction::{ eip4844::{TxEip4844, TxEip4844Variant, TxEip4844WithSidecar}, @@ -21,6 +21,7 @@ use alloy_rpc_types::{ use alloy_serde::{OtherFields, WithOtherFields}; use bytes::BufMut; use foundry_evm::traces::CallTraceNode; +use op_alloy_consensus::TxDeposit; use revm::{ interpreter::InstructionResult, primitives::{OptimismFields, TxEnv}, @@ -59,14 +60,16 @@ pub fn transaction_request_to_typed( // Special case: OP-stack deposit tx if transaction_type == Some(0x7E) || has_optimism_fields(&other) { - return Some(TypedTransactionRequest::Deposit(DepositTransactionRequest { + let mint = other.get_deserialized::("mint")?.map(|m| m.to::()).ok()?; + + return Some(TypedTransactionRequest::Deposit(TxDeposit { from: from.unwrap_or_default(), source_hash: other.get_deserialized::("sourceHash")?.ok()?, - kind: to.unwrap_or_default(), - mint: other.get_deserialized::("mint")?.ok()?, + to: to.unwrap_or_default(), + mint: Some(mint), value: value.unwrap_or_default(), gas_limit: gas.unwrap_or_default(), - is_system_tx: other.get_deserialized::("isSystemTx")?.ok()?, + is_system_transaction: other.get_deserialized::("isSystemTx")?.ok()?, input: input.into_input().unwrap_or_default(), })); } @@ -165,7 +168,7 @@ pub enum TypedTransactionRequest { EIP2930(TxEip2930), EIP1559(TxEip1559), EIP4844(TxEip4844Variant), - Deposit(DepositTransactionRequest), + Deposit(TxDeposit), } /// A wrapper for [TypedTransaction] that allows impersonating accounts. diff --git a/crates/anvil/core/src/eth/transaction/optimism.rs b/crates/anvil/core/src/eth/transaction/optimism.rs index 170d67f1d9ac..6bb4b2abb8a4 100644 --- a/crates/anvil/core/src/eth/transaction/optimism.rs +++ b/crates/anvil/core/src/eth/transaction/optimism.rs @@ -1,276 +1,25 @@ -use alloy_consensus::{SignableTransaction, Signed, Transaction}; -use alloy_primitives::{keccak256, Address, Bytes, ChainId, Signature, TxKind, B256, U256}; -use alloy_rlp::{ - length_of_length, Decodable, Encodable, Error as DecodeError, Header as RlpHeader, -}; -use bytes::BufMut; +use alloy_primitives::{Address, Bytes, TxKind, B256, U256}; +use alloy_rlp::{Decodable, Encodable, Error as DecodeError, Header as RlpHeader}; +use op_alloy_consensus::TxDeposit; use serde::{Deserialize, Serialize}; -use std::mem; pub const DEPOSIT_TX_TYPE_ID: u8 = 0x7E; -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct DepositTransactionRequest { - pub source_hash: B256, - pub from: Address, - pub kind: TxKind, - pub mint: U256, - pub value: U256, - pub gas_limit: u64, - pub is_system_tx: bool, - pub input: Bytes, -} - -impl DepositTransactionRequest { - pub fn hash(&self) -> B256 { - let mut encoded = Vec::new(); - encoded.put_u8(DEPOSIT_TX_TYPE_ID); - self.encode(&mut encoded); - - B256::from_slice(alloy_primitives::keccak256(encoded).as_slice()) - } - - /// Encodes only the transaction's fields into the desired buffer, without a RLP header. - pub(crate) fn encode_fields(&self, out: &mut dyn alloy_rlp::BufMut) { - self.source_hash.encode(out); - self.from.encode(out); - self.kind.encode(out); - self.mint.encode(out); - self.value.encode(out); - self.gas_limit.encode(out); - self.is_system_tx.encode(out); - self.input.encode(out); - } - - /// Calculates the length of the RLP-encoded transaction's fields. - pub(crate) fn fields_len(&self) -> usize { - let mut len = 0; - len += self.source_hash.length(); - len += self.from.length(); - len += self.kind.length(); - len += self.mint.length(); - len += self.value.length(); - len += self.gas_limit.length(); - len += self.is_system_tx.length(); - len += self.input.length(); - len - } - - /// Decodes the inner [DepositTransactionRequest] fields from RLP bytes. - /// - /// NOTE: This assumes a RLP header has already been decoded, and _just_ decodes the following - /// RLP fields in the following order: - /// - /// - `source_hash` - /// - `from` - /// - `kind` - /// - `mint` - /// - `value` - /// - `gas_limit` - /// - `is_system_tx` - /// - `input` - pub fn decode_inner(buf: &mut &[u8]) -> Result { - Ok(Self { - source_hash: Decodable::decode(buf)?, - from: Decodable::decode(buf)?, - kind: Decodable::decode(buf)?, - mint: Decodable::decode(buf)?, - value: Decodable::decode(buf)?, - gas_limit: Decodable::decode(buf)?, - is_system_tx: Decodable::decode(buf)?, - input: Decodable::decode(buf)?, - }) - } - - /// Inner encoding function that is used for both rlp [`Encodable`] trait and for calculating - /// hash that for eip2718 does not require rlp header - pub(crate) fn encode_with_signature( - &self, - signature: &Signature, - out: &mut dyn alloy_rlp::BufMut, - ) { - let payload_length = self.fields_len() + signature.rlp_vrs_len(); - let header = alloy_rlp::Header { list: true, payload_length }; - header.encode(out); - self.encode_fields(out); - signature.write_rlp_vrs(out); - } - - /// Output the length of the RLP signed transaction encoding, _without_ a RLP string header. - pub fn payload_len_with_signature_without_header(&self, signature: &Signature) -> usize { - let payload_length = self.fields_len() + signature.rlp_vrs_len(); - // 'transaction type byte length' + 'header length' + 'payload length' - 1 + length_of_length(payload_length) + payload_length - } - - /// Output the length of the RLP signed transaction encoding. This encodes with a RLP header. - pub fn payload_len_with_signature(&self, signature: &Signature) -> usize { - let len = self.payload_len_with_signature_without_header(signature); - length_of_length(len) + len - } - - /// Get transaction type - pub(crate) const fn tx_type(&self) -> u8 { - DEPOSIT_TX_TYPE_ID - } - - /// Calculates a heuristic for the in-memory size of the [DepositTransaction] transaction. - pub fn size(&self) -> usize { - mem::size_of::() + // source_hash - mem::size_of::
() + // from - self.kind.size() + // to - mem::size_of::() + // mint - mem::size_of::() + // value - mem::size_of::() + // gas_limit - mem::size_of::() + // is_system_transaction - self.input.len() // input - } - - /// Encodes the legacy transaction in RLP for signing. - pub(crate) fn encode_for_signing(&self, out: &mut dyn alloy_rlp::BufMut) { - out.put_u8(self.tx_type()); - alloy_rlp::Header { list: true, payload_length: self.fields_len() }.encode(out); - self.encode_fields(out); - } - - /// Outputs the length of the signature RLP encoding for the transaction. - pub(crate) fn payload_len_for_signature(&self) -> usize { - let payload_length = self.fields_len(); - // 'transaction type byte length' + 'header length' + 'payload length' - 1 + length_of_length(payload_length) + payload_length - } - - fn encoded_len_with_signature(&self, signature: &Signature) -> usize { - // this counts the tx fields and signature fields - let payload_length = self.fields_len() + signature.rlp_vrs_len(); - - // this counts: - // * tx type byte - // * inner header length - // * inner payload length - 1 + alloy_rlp::Header { list: true, payload_length }.length() + payload_length - } -} - -impl Transaction for DepositTransactionRequest { - fn input(&self) -> &[u8] { - &self.input - } - - /// Get `to`. - fn to(&self) -> TxKind { - self.kind - } - - /// Get `value`. - fn value(&self) -> U256 { - self.value - } - - /// Get `chain_id`. - fn chain_id(&self) -> Option { - None - } - - /// Get `nonce`. - fn nonce(&self) -> u64 { - u64::MAX - } - - /// Get `gas_limit`. - fn gas_limit(&self) -> u64 { - self.gas_limit - } - - /// Get `gas_price`. - fn gas_price(&self) -> Option { - None - } - - fn ty(&self) -> u8 { - 0x7E - } - - // Below fields are not found in a `DepositTransactionRequest` - - fn access_list(&self) -> Option<&alloy_rpc_types::AccessList> { - None - } - - fn authorization_list(&self) -> Option<&[revm::primitives::SignedAuthorization]> { - None - } - - fn blob_versioned_hashes(&self) -> Option<&[B256]> { - None - } - - fn effective_tip_per_gas(&self, _base_fee: u64) -> Option { - None - } - - fn max_fee_per_blob_gas(&self) -> Option { - None - } - - fn max_fee_per_gas(&self) -> u128 { - 0 - } - - fn max_priority_fee_per_gas(&self) -> Option { - None - } - - fn priority_fee_or_price(&self) -> u128 { - 0 - } -} - -impl SignableTransaction for DepositTransactionRequest { - fn set_chain_id(&mut self, _chain_id: ChainId) {} - - fn payload_len_for_signature(&self) -> usize { - self.payload_len_for_signature() - } - - fn into_signed(self, signature: Signature) -> Signed { - let mut buf = Vec::with_capacity(self.encoded_len_with_signature(&signature)); - self.encode_with_signature(&signature, &mut buf); - let hash = keccak256(&buf); - - // Drop any v chain id value to ensure the signature format is correct at the time of - // combination for an EIP-4844 transaction. V should indicate the y-parity of the - // signature. - Signed::new_unchecked(self, signature.with_parity_bool(), hash) - } - - fn encode_for_signing(&self, out: &mut dyn alloy_rlp::BufMut) { - self.encode_for_signing(out); - } -} - -impl From for DepositTransactionRequest { +impl From for TxDeposit { fn from(tx: DepositTransaction) -> Self { Self { from: tx.from, source_hash: tx.source_hash, - kind: tx.kind, - mint: tx.mint, + to: tx.kind, + mint: Some(tx.mint.to::()), value: tx.value, gas_limit: tx.gas_limit, - is_system_tx: tx.is_system_tx, + is_system_transaction: tx.is_system_tx, input: tx.input, } } } -impl Encodable for DepositTransactionRequest { - fn encode(&self, out: &mut dyn bytes::BufMut) { - RlpHeader { list: true, payload_length: self.fields_len() }.encode(out); - self.encode_fields(out); - } -} - /// An op-stack deposit transaction. /// See #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -443,23 +192,4 @@ mod tests { assert_eq!(tx, decoded_tx); } - - #[test] - fn test_tx_request_hash_equals_tx_hash() { - let tx = DepositTransaction { - nonce: 0, - source_hash: B256::default(), - from: Address::default(), - kind: TxKind::Call(Address::default()), - mint: U256::from(100), - value: U256::from(100), - gas_limit: 50000, - is_system_tx: false, - input: Bytes::default(), - }; - - let tx_request = DepositTransactionRequest::from(tx.clone()); - - assert_eq!(tx.hash(), tx_request.hash()); - } } diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 78b52d49496a..a85862664684 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -2903,7 +2903,7 @@ fn determine_base_gas_by_kind(request: &WithOtherFields) -> TxKind::Create => MIN_CREATE_GAS, }, TypedTransactionRequest::EIP4844(_) => MIN_TRANSACTION_GAS, - TypedTransactionRequest::Deposit(req) => match req.kind { + TypedTransactionRequest::Deposit(req) => match req.to { TxKind::Call(_) => MIN_TRANSACTION_GAS, TxKind::Create => MIN_CREATE_GAS, }, diff --git a/crates/anvil/src/eth/sign.rs b/crates/anvil/src/eth/sign.rs index d322e47d2265..5f99ef9ca17d 100644 --- a/crates/anvil/src/eth/sign.rs +++ b/crates/anvil/src/eth/sign.rs @@ -2,13 +2,13 @@ use crate::eth::error::BlockchainError; use alloy_consensus::SignableTransaction; use alloy_dyn_abi::TypedData; use alloy_network::TxSignerSync; -use alloy_primitives::{map::AddressHashMap, Address, Signature, B256}; +use alloy_primitives::{map::AddressHashMap, Address, Signature, B256, U256}; use alloy_signer::Signer as AlloySigner; use alloy_signer_local::PrivateKeySigner; use anvil_core::eth::transaction::{ - optimism::{DepositTransaction, DepositTransactionRequest}, - TypedTransaction, TypedTransactionRequest, + optimism::DepositTransaction, TypedTransaction, TypedTransactionRequest, }; +use op_alloy_consensus::TxDeposit; /// A transaction signer #[async_trait::async_trait] @@ -105,7 +105,9 @@ impl Signer for DevSigner { TypedTransactionRequest::EIP2930(mut tx) => Ok(signer.sign_transaction_sync(&mut tx)?), TypedTransactionRequest::EIP1559(mut tx) => Ok(signer.sign_transaction_sync(&mut tx)?), TypedTransactionRequest::EIP4844(mut tx) => Ok(signer.sign_transaction_sync(&mut tx)?), - TypedTransactionRequest::Deposit(mut tx) => Ok(signer.sign_transaction_sync(&mut tx)?), + TypedTransactionRequest::Deposit(_) => { + unreachable!("op deposit txs should not be signed") + } } } } @@ -131,26 +133,26 @@ pub fn build_typed_transaction( TypedTransaction::EIP4844(tx.into_signed(signature)) } TypedTransactionRequest::Deposit(tx) => { - let DepositTransactionRequest { + let TxDeposit { from, gas_limit, - kind, + to, value, input, source_hash, mint, - is_system_tx, + is_system_transaction, .. } = tx; TypedTransaction::Deposit(DepositTransaction { from, gas_limit, - kind, + kind: to, value, input, source_hash, - mint, - is_system_tx, + mint: mint.map_or(U256::ZERO, U256::from), + is_system_tx: is_system_transaction, nonce: 0, }) } From 1465e39f853a7c7a151609cb3abe5dc19c52a94b Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:34:31 +0200 Subject: [PATCH 5/5] fix: redact RPC URLs in traces if URL is passed in directly (#9077) redact RPC urls if string is a URL, not an alias --- crates/evm/traces/src/decoder/mod.rs | 294 ++++++++++++++++++++++++++- 1 file changed, 293 insertions(+), 1 deletion(-) diff --git a/crates/evm/traces/src/decoder/mod.rs b/crates/evm/traces/src/decoder/mod.rs index 25d9f4f2b894..de3a0c02f201 100644 --- a/crates/evm/traces/src/decoder/mod.rs +++ b/crates/evm/traces/src/decoder/mod.rs @@ -516,6 +516,24 @@ impl CallTraceDecoder { Some(decoded.iter().map(format_token).collect()) } } + "createFork" | + "createSelectFork" | + "rpc" => { + let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..], false).ok()?; + + // Redact RPC URL except if referenced by an alias + if !decoded.is_empty() && func.inputs[0].ty == "string" { + let url_or_alias = decoded[0].as_str().unwrap_or_default(); + + if url_or_alias.starts_with("http") || url_or_alias.starts_with("ws") { + decoded[0] = DynSolValue::String("".to_string()); + } + } else { + return None; + } + + Some(decoded.iter().map(format_token).collect()) + } _ => None, } } @@ -558,6 +576,7 @@ impl CallTraceDecoder { "promptSecret" | "promptSecretUint" => Some(""), "parseJson" if self.verbosity < 5 => Some(""), "readFile" if self.verbosity < 5 => Some(""), + "rpcUrl" | "rpcUrls" | "rpcUrlStructs" => Some(""), _ => None, } .map(Into::into) @@ -670,7 +689,7 @@ mod tests { use alloy_primitives::hex; #[test] - fn test_should_redact_pk() { + fn test_should_redact() { let decoder = CallTraceDecoder::new(); // [function_signature, data, expected] @@ -726,6 +745,275 @@ mod tests { .to_string(), ]), ), + ( + // cast calldata "createFork(string)" "https://eth-mainnet.g.alchemy.com/v2/api_key" + "createFork(string)", + hex!( + " + 31ba3498 + 0000000000000000000000000000000000000000000000000000000000000020 + 000000000000000000000000000000000000000000000000000000000000002c + 68747470733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f + 6d2f76322f6170695f6b65790000000000000000000000000000000000000000 + " + ) + .to_vec(), + Some(vec!["\"\"".to_string()]), + ), + ( + // cast calldata "createFork(string)" "wss://eth-mainnet.g.alchemy.com/v2/api_key" + "createFork(string)", + hex!( + " + 31ba3498 + 0000000000000000000000000000000000000000000000000000000000000020 + 000000000000000000000000000000000000000000000000000000000000002a + 7773733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f6d2f + 76322f6170695f6b657900000000000000000000000000000000000000000000 + " + ) + .to_vec(), + Some(vec!["\"\"".to_string()]), + ), + ( + // cast calldata "createFork(string)" "mainnet" + "createFork(string)", + hex!( + " + 31ba3498 + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000007 + 6d61696e6e657400000000000000000000000000000000000000000000000000 + " + ) + .to_vec(), + Some(vec!["\"mainnet\"".to_string()]), + ), + ( + // cast calldata "createFork(string,uint256)" "https://eth-mainnet.g.alchemy.com/v2/api_key" 1 + "createFork(string,uint256)", + hex!( + " + 6ba3ba2b + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000001 + 000000000000000000000000000000000000000000000000000000000000002c + 68747470733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f + 6d2f76322f6170695f6b65790000000000000000000000000000000000000000 + " + ) + .to_vec(), + Some(vec!["\"\"".to_string(), "1".to_string()]), + ), + ( + // cast calldata "createFork(string,uint256)" "mainnet" 1 + "createFork(string,uint256)", + hex!( + " + 6ba3ba2b + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000001 + 0000000000000000000000000000000000000000000000000000000000000007 + 6d61696e6e657400000000000000000000000000000000000000000000000000 + " + ) + .to_vec(), + Some(vec!["\"mainnet\"".to_string(), "1".to_string()]), + ), + ( + // cast calldata "createFork(string,bytes32)" "https://eth-mainnet.g.alchemy.com/v2/api_key" 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + "createFork(string,bytes32)", + hex!( + " + 7ca29682 + 0000000000000000000000000000000000000000000000000000000000000040 + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + 000000000000000000000000000000000000000000000000000000000000002c + 68747470733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f + 6d2f76322f6170695f6b65790000000000000000000000000000000000000000 + " + ) + .to_vec(), + Some(vec![ + "\"\"".to_string(), + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + .to_string(), + ]), + ), + ( + // cast calldata "createFork(string,bytes32)" "mainnet" + // 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + "createFork(string,bytes32)", + hex!( + " + 7ca29682 + 0000000000000000000000000000000000000000000000000000000000000040 + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + 0000000000000000000000000000000000000000000000000000000000000007 + 6d61696e6e657400000000000000000000000000000000000000000000000000 + " + ) + .to_vec(), + Some(vec![ + "\"mainnet\"".to_string(), + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + .to_string(), + ]), + ), + ( + // cast calldata "createSelectFork(string)" "https://eth-mainnet.g.alchemy.com/v2/api_key" + "createSelectFork(string)", + hex!( + " + 98680034 + 0000000000000000000000000000000000000000000000000000000000000020 + 000000000000000000000000000000000000000000000000000000000000002c + 68747470733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f + 6d2f76322f6170695f6b65790000000000000000000000000000000000000000 + " + ) + .to_vec(), + Some(vec!["\"\"".to_string()]), + ), + ( + // cast calldata "createSelectFork(string)" "mainnet" + "createSelectFork(string)", + hex!( + " + 98680034 + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000007 + 6d61696e6e657400000000000000000000000000000000000000000000000000 + " + ) + .to_vec(), + Some(vec!["\"mainnet\"".to_string()]), + ), + ( + // cast calldata "createSelectFork(string,uint256)" "https://eth-mainnet.g.alchemy.com/v2/api_key" 1 + "createSelectFork(string,uint256)", + hex!( + " + 71ee464d + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000001 + 000000000000000000000000000000000000000000000000000000000000002c + 68747470733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f + 6d2f76322f6170695f6b65790000000000000000000000000000000000000000 + " + ) + .to_vec(), + Some(vec!["\"\"".to_string(), "1".to_string()]), + ), + ( + // cast calldata "createSelectFork(string,uint256)" "mainnet" 1 + "createSelectFork(string,uint256)", + hex!( + " + 71ee464d + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000001 + 0000000000000000000000000000000000000000000000000000000000000007 + 6d61696e6e657400000000000000000000000000000000000000000000000000 + " + ) + .to_vec(), + Some(vec!["\"mainnet\"".to_string(), "1".to_string()]), + ), + ( + // cast calldata "createSelectFork(string,bytes32)" "https://eth-mainnet.g.alchemy.com/v2/api_key" 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + "createSelectFork(string,bytes32)", + hex!( + " + 84d52b7a + 0000000000000000000000000000000000000000000000000000000000000040 + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + 000000000000000000000000000000000000000000000000000000000000002c + 68747470733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f + 6d2f76322f6170695f6b65790000000000000000000000000000000000000000 + " + ) + .to_vec(), + Some(vec![ + "\"\"".to_string(), + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + .to_string(), + ]), + ), + ( + // cast calldata "createSelectFork(string,bytes32)" "mainnet" + // 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + "createSelectFork(string,bytes32)", + hex!( + " + 84d52b7a + 0000000000000000000000000000000000000000000000000000000000000040 + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + 0000000000000000000000000000000000000000000000000000000000000007 + 6d61696e6e657400000000000000000000000000000000000000000000000000 + " + ) + .to_vec(), + Some(vec![ + "\"mainnet\"".to_string(), + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + .to_string(), + ]), + ), + ( + // cast calldata "rpc(string,string,string)" "https://eth-mainnet.g.alchemy.com/v2/api_key" "eth_getBalance" "[\"0x551e7784778ef8e048e495df49f2614f84a4f1dc\",\"0x0\"]" + "rpc(string,string,string)", + hex!( + " + 0199a220 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000c0 + 0000000000000000000000000000000000000000000000000000000000000100 + 000000000000000000000000000000000000000000000000000000000000002c + 68747470733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f + 6d2f76322f6170695f6b65790000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000000e + 6574685f67657442616c616e6365000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000034 + 5b22307835353165373738343737386566386530343865343935646634396632 + 363134663834613466316463222c22307830225d000000000000000000000000 + " + ) + .to_vec(), + Some(vec![ + "\"\"".to_string(), + "\"eth_getBalance\"".to_string(), + "\"[\\\"0x551e7784778ef8e048e495df49f2614f84a4f1dc\\\",\\\"0x0\\\"]\"" + .to_string(), + ]), + ), + ( + // cast calldata "rpc(string,string,string)" "mainnet" "eth_getBalance" + // "[\"0x551e7784778ef8e048e495df49f2614f84a4f1dc\",\"0x0\"]" + "rpc(string,string,string)", + hex!( + " + 0199a220 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a0 + 00000000000000000000000000000000000000000000000000000000000000e0 + 0000000000000000000000000000000000000000000000000000000000000007 + 6d61696e6e657400000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000000e + 6574685f67657442616c616e6365000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000034 + 5b22307835353165373738343737386566386530343865343935646634396632 + 363134663834613466316463222c22307830225d000000000000000000000000 + " + ) + .to_vec(), + Some(vec![ + "\"mainnet\"".to_string(), + "\"eth_getBalance\"".to_string(), + "\"[\\\"0x551e7784778ef8e048e495df49f2614f84a4f1dc\\\",\\\"0x0\\\"]\"" + .to_string(), + ]), + ), ]; // [function_signature, expected] @@ -733,6 +1021,10 @@ mod tests { // Should redact private key on output in all cases: ("createWallet(string)", Some("".to_string())), ("deriveKey(string,uint32)", Some("".to_string())), + // Should redact RPC URL if defined, except if referenced by an alias: + ("rpcUrl(string)", Some("".to_string())), + ("rpcUrls()", Some("".to_string())), + ("rpcUrlStructs()", Some("".to_string())), ]; for (function_signature, data, expected) in cheatcode_input_test_cases {