From c0914e4d86d0f53abe8a5683c486219d6ea5c40b Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 8 Apr 2025 13:09:23 +0300 Subject: [PATCH 001/244] fix(forge): coverage for contracts with ctor with args (#10270) --- crates/common/src/contracts.rs | 20 ++++++- crates/forge/tests/cli/coverage.rs | 92 ++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/crates/common/src/contracts.rs b/crates/common/src/contracts.rs index 0d3170f7c39cb..ecfb67d67f1cd 100644 --- a/crates/common/src/contracts.rs +++ b/crates/common/src/contracts.rs @@ -1,6 +1,7 @@ //! Commonly used contract types and functions. use crate::compile::PathOrContractInfo; +use alloy_dyn_abi::JsonAbiExt; use alloy_json_abi::{Event, Function, JsonAbi}; use alloy_primitives::{hex, Address, Bytes, Selector, B256}; use eyre::{OptionExt, Result}; @@ -123,24 +124,39 @@ impl ContractsByArtifact { /// Finds a contract which has a similar bytecode as `code`. pub fn find_by_creation_code(&self, code: &[u8]) -> Option> { - self.find_by_code(code, 0.1, ContractData::bytecode) + self.find_by_code(code, 0.1, true, ContractData::bytecode) } /// Finds a contract which has a similar deployed bytecode as `code`. pub fn find_by_deployed_code(&self, code: &[u8]) -> Option> { - self.find_by_code(code, 0.15, ContractData::deployed_bytecode) + self.find_by_code(code, 0.15, false, ContractData::deployed_bytecode) } /// Finds a contract based on provided bytecode and accepted match score. + /// If strip constructor args flag is true then removes args from bytecode to compare. fn find_by_code( &self, code: &[u8], accepted_score: f64, + strip_ctor_args: bool, get: impl Fn(&ContractData) -> Option<&Bytes>, ) -> Option> { self.iter() .filter_map(|(id, contract)| { if let Some(deployed_bytecode) = get(contract) { + let mut code = code; + if strip_ctor_args && code.len() > deployed_bytecode.len() { + // Try to decode ctor args with contract abi. + if let Some(constructor) = contract.abi.constructor() { + let constructor_args = &code[deployed_bytecode.len()..]; + if constructor.abi_decode_input(constructor_args, false).is_ok() { + // If we can decode args with current abi then remove args from + // code to compare. + code = &code[..deployed_bytecode.len()] + } + } + }; + let score = bytecode_diff_score(deployed_bytecode.as_ref(), code); (score <= accepted_score).then_some((score, (id, contract))) } else { diff --git a/crates/forge/tests/cli/coverage.rs b/crates/forge/tests/cli/coverage.rs index 2557a5fe94206..5f8ad1e873b95 100644 --- a/crates/forge/tests/cli/coverage.rs +++ b/crates/forge/tests/cli/coverage.rs @@ -1753,6 +1753,98 @@ contract AContractTest is DSTest { assert!(files.is_empty()); }); +// +forgetest!(constructor_with_args, |prj, cmd| { + prj.insert_ds_test(); + prj.add_source( + "ArrayCondition.sol", + r#" +contract ArrayCondition { + uint8 public constant MAX_SIZE = 32; + error TooLarge(); + error EmptyArray(); + // Storage variable to ensure the constructor does something + uint256 private _arrayLength; + + constructor(uint256[] memory values) { + // Check for empty array + if (values.length == 0) { + revert EmptyArray(); + } + + if (values.length > MAX_SIZE) { + revert TooLarge(); + } + + // Store the array length + _arrayLength = values.length; + } + + function getArrayLength() external view returns (uint256) { + return _arrayLength; + } +} + "#, + ) + .unwrap(); + + prj.add_source( + "ArrayConditionTest.sol", + r#" +import "./test.sol"; +import {ArrayCondition} from "./ArrayCondition.sol"; + +interface Vm { + function expectRevert(bytes4 revertData) external; +} + +contract ArrayConditionTest is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + function testValidSize() public { + uint256[] memory values = new uint256[](10); + ArrayCondition condition = new ArrayCondition(values); + assertEq(condition.getArrayLength(), 10); + } + + // Test with maximum array size (should NOT revert) + function testMaxSize() public { + uint256[] memory values = new uint256[](32); + ArrayCondition condition = new ArrayCondition(values); + assertEq(condition.getArrayLength(), 32); + } + + // Test with too large array size (should revert) + function testTooLarge() public { + uint256[] memory values = new uint256[](33); + vm.expectRevert(ArrayCondition.TooLarge.selector); + new ArrayCondition(values); + } + + // Test with empty array (should revert) + function testEmptyArray() public { + uint256[] memory values = new uint256[](0); + vm.expectRevert(ArrayCondition.EmptyArray.selector); + new ArrayCondition(values); + } +} + "#, + ) + .unwrap(); + + cmd.arg("coverage").assert_success().stdout_eq(str![[r#" +... +╭------------------------+---------------+---------------+---------------+---------------╮ +| File | % Lines | % Statements | % Branches | % Funcs | ++========================================================================================+ +| src/ArrayCondition.sol | 100.00% (8/8) | 100.00% (6/6) | 100.00% (2/2) | 100.00% (2/2) | +|------------------------+---------------+---------------+---------------+---------------| +| Total | 100.00% (8/8) | 100.00% (6/6) | 100.00% (2/2) | 100.00% (2/2) | +╰------------------------+---------------+---------------+---------------+---------------╯ +... +"#]]); +}); + #[track_caller] fn assert_lcov(cmd: &mut TestCommand, data: impl IntoData) { cmd.args(["--report=lcov", "--report-file"]).assert_file(data.into_data()); From dc9ff38d161a5b8663131c8b4ede719a1b6ccc23 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 8 Apr 2025 18:34:48 +0300 Subject: [PATCH 002/244] feat(forge): allow invariant contract address as targetContract (#10274) --- crates/evm/evm/src/executors/invariant/mod.rs | 5 ++ crates/forge/tests/it/invariant.rs | 66 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/crates/evm/evm/src/executors/invariant/mod.rs b/crates/evm/evm/src/executors/invariant/mod.rs index aaf9a881a1f50..11c38bf43f29b 100644 --- a/crates/evm/evm/src/executors/invariant/mod.rs +++ b/crates/evm/evm/src/executors/invariant/mod.rs @@ -721,6 +721,11 @@ impl<'a> InvariantExecutor<'a> { .setup_contracts .iter() .filter(|&(addr, (identifier, _))| { + // Include to address if explicitly set as target. + if *addr == to && selected.contains(&to) { + return true; + } + *addr != to && *addr != CHEATCODE_ADDRESS && *addr != HARDHAT_CONSOLE_ADDRESS && diff --git a/crates/forge/tests/it/invariant.rs b/crates/forge/tests/it/invariant.rs index 777cb19409695..43db084d06df3 100644 --- a/crates/forge/tests/it/invariant.rs +++ b/crates/forge/tests/it/invariant.rs @@ -1267,3 +1267,69 @@ Warning: Failure from "[..]/invariant/failures/OwnableTest/invariant_never_owner ... "#]]); }); + +// +forgetest_init!(invariant_test_target, |prj, cmd| { + prj.update_config(|config| { + config.invariant.runs = 5; + config.invariant.depth = 5; + }); + prj.add_test( + "InvariantTest.t.sol", + r#" +import {Test} from "forge-std/Test.sol"; + +contract InvariantTest is Test { + uint256 count; + + function setCount(uint256 _count) public { + count = _count; + } + + function setUp() public { + } + + function invariant_check_count() public { + } +} + "#, + ) + .unwrap(); + + cmd.args(["test", "--mt", "invariant_check_count"]).assert_failure().stdout_eq(str![[r#" +... +[FAIL: failed to set up invariant testing environment: No contracts to fuzz.] invariant_check_count() (runs: 0, calls: 0, reverts: 0) +... +"#]]); + + prj.add_test( + "InvariantTest.t.sol", + r#" +import {Test} from "forge-std/Test.sol"; + +contract InvariantTest is Test { + uint256 count; + + function setCount(uint256 _count) public { + count = _count; + } + + function setUp() public { + targetContract(address(this)); + } + + function invariant_check_count() public { + } +} + "#, + ) + .unwrap(); + + cmd.forge_fuse().args(["test", "--mt", "invariant_check_count"]).assert_success().stdout_eq( + str![[r#" +... +[PASS] invariant_check_count() (runs: 5, calls: 25, reverts: 0) +... +"#]], + ); +}); From 94ba51d9fb4496520299293134683af9c5b59c10 Mon Sep 17 00:00:00 2001 From: GarmashAlex Date: Tue, 8 Apr 2025 18:58:43 +0300 Subject: [PATCH 003/244] feat: improve uninformative error messages (#10201) * feat: improve uninformative error messages * Update dispatcher.rs * Update dispatcher.rs * Update dispatcher.rs --------- Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> --- crates/chisel/src/dispatcher.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/crates/chisel/src/dispatcher.rs b/crates/chisel/src/dispatcher.rs index a445e99e744f7..97b78369ec565 100644 --- a/crates/chisel/src/dispatcher.rs +++ b/crates/chisel/src/dispatcher.rs @@ -258,7 +258,10 @@ impl ChiselDispatcher { self.session.id.as_ref().unwrap() ))) } else { - DispatchResult::CommandFailed(Self::make_error("Too many arguments supplied!")) + DispatchResult::CommandFailed(Self::make_error(format!( + "Too many arguments supplied: [{}]. Please check command syntax.", + args.join(", ") + ))) } } ChiselCommand::Load => { @@ -333,7 +336,9 @@ impl ChiselDispatcher { self.session.id = None; DispatchResult::CommandSuccess(Some(String::from("Cleared chisel cache!"))) } - Err(_) => DispatchResult::CommandFailed(Self::make_error("Failed to clear cache!")), + Err(_) => DispatchResult::CommandFailed(Self::make_error( + "Failed to clear cache! Check file permissions or disk space.", + )), }, ChiselCommand::Fork => { if args.is_empty() || args[0].trim().is_empty() { @@ -371,7 +376,9 @@ impl ChiselDispatcher { // Check validity of URL if Url::parse(&fork_url).is_err() { - return DispatchResult::CommandFailed(Self::make_error("Invalid fork URL!")) + return DispatchResult::CommandFailed(Self::make_error( + "Invalid fork URL! Please provide a valid RPC endpoint URL.", + )) } // Create success message before moving the fork_url @@ -634,7 +641,9 @@ impl ChiselDispatcher { } ChiselCommand::Exec => { if args.is_empty() { - return DispatchResult::CommandFailed(Self::make_error("No command supplied!")) + return DispatchResult::CommandFailed(Self::make_error( + "No command supplied! Please provide a valid command after '!'.", + )) } let mut cmd = Command::new(args[0]); From 5bd034f33366020f4d5137ad54218e0b978c0869 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Wed, 9 Apr 2025 07:48:07 +0300 Subject: [PATCH 004/244] fix(forge): trace identify by creation code with stripped args (#10271) --- crates/evm/traces/src/identifier/local.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/evm/traces/src/identifier/local.rs b/crates/evm/traces/src/identifier/local.rs index 90c28e016e1ff..718f7162fb920 100644 --- a/crates/evm/traces/src/identifier/local.rs +++ b/crates/evm/traces/src/identifier/local.rs @@ -1,4 +1,5 @@ use super::{AddressIdentity, TraceIdentifier}; +use alloy_dyn_abi::JsonAbiExt; use alloy_json_abi::JsonAbi; use alloy_primitives::Address; use foundry_common::contracts::{bytecode_diff_score, ContractsByArtifact}; @@ -53,6 +54,19 @@ impl<'a> LocalTraceIdentifier<'a> { }; if let Some(bytecode) = contract_bytecode { + let mut current_bytecode = current_bytecode; + if is_creation && current_bytecode.len() > bytecode.len() { + // Try to decode ctor args with contract abi. + if let Some(constructor) = contract.abi.constructor() { + let constructor_args = ¤t_bytecode[bytecode.len()..]; + if constructor.abi_decode_input(constructor_args, false).is_ok() { + // If we can decode args with current abi then remove args from + // code to compare. + current_bytecode = ¤t_bytecode[..bytecode.len()] + } + } + } + let score = bytecode_diff_score(bytecode, current_bytecode); if score == 0.0 { trace!(target: "evm::traces", "found exact match"); From 25c363e0725d6be0992373b49d6ddec138ec8cf6 Mon Sep 17 00:00:00 2001 From: Ahsan Javaid <104683677+ahsan-javaiid@users.noreply.github.com> Date: Wed, 9 Apr 2025 12:40:42 +0500 Subject: [PATCH 005/244] Force `prevrandao` on Rootstock network (#10279) fix: force prevrandao on rootstock network --- crates/evm/core/src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/evm/core/src/utils.rs b/crates/evm/core/src/utils.rs index 3064d29aa2dd1..7125535694d49 100644 --- a/crates/evm/core/src/utils.rs +++ b/crates/evm/core/src/utils.rs @@ -56,7 +56,7 @@ pub fn apply_chain_and_block_specific_env_changes( env.block.prevrandao = Some(env.block.difficulty.into()); return; } - Moonbeam | Moonbase | Moonriver | MoonbeamDev => { + Moonbeam | Moonbase | Moonriver | MoonbeamDev | Rsk => { if env.block.prevrandao.is_none() { // env.block.prevrandao = Some(B256::random()); From 7825a06862b0c97a510618f5c6901eca279e4802 Mon Sep 17 00:00:00 2001 From: VolodymyrBg Date: Wed, 9 Apr 2025 18:51:17 +0300 Subject: [PATCH 006/244] feat(abi): Implement UIfmt for DSTest console logs (#10185) --- crates/evm/abi/src/console/ds.rs | 43 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/crates/evm/abi/src/console/ds.rs b/crates/evm/abi/src/console/ds.rs index 444be0d77dce5..6d46412c3374f 100644 --- a/crates/evm/abi/src/console/ds.rs +++ b/crates/evm/abi/src/console/ds.rs @@ -4,78 +4,79 @@ use super::{format_units_int, format_units_uint}; use alloy_primitives::hex; use alloy_sol_types::sol; use derive_more::Display; +use foundry_common_fmt::UIfmt; use itertools::Itertools; -// TODO: Use `UiFmt` +// Using UIfmt for consistent and user-friendly formatting sol! { #[sol(abi)] #[derive(Display)] interface Console { - #[display("{val}")] + #[display("{}", val.pretty())] event log(string val); #[display("{}", hex::encode_prefixed(val))] event logs(bytes val); - #[display("{val}")] + #[display("{}", val.pretty())] event log_address(address val); - #[display("{val}")] + #[display("{}", val.pretty())] event log_bytes32(bytes32 val); - #[display("{val}")] + #[display("{}", val.pretty())] event log_int(int val); - #[display("{val}")] + #[display("{}", val.pretty())] event log_uint(uint val); #[display("{}", hex::encode_prefixed(val))] event log_bytes(bytes val); - #[display("{val}")] + #[display("{}", val.pretty())] event log_string(string val); - #[display("[{}]", val.iter().format(", "))] + #[display("[{}]", val.iter().map(|v| v.pretty()).format(", "))] event log_array(uint256[] val); - #[display("[{}]", val.iter().format(", "))] + #[display("[{}]", val.iter().map(|v| v.pretty()).format(", "))] event log_array(int256[] val); - #[display("[{}]", val.iter().format(", "))] + #[display("[{}]", val.iter().map(|v| v.pretty()).format(", "))] event log_array(address[] val); - #[display("{key}: {val}")] + #[display("{}: {}", key.pretty(), val.pretty())] event log_named_address(string key, address val); - #[display("{key}: {val}")] + #[display("{}: {}", key.pretty(), val.pretty())] event log_named_bytes32(string key, bytes32 val); - #[display("{key}: {}", format_units_int(val, decimals))] + #[display("{}: {}", key.pretty(), format_units_int(val, decimals))] event log_named_decimal_int(string key, int val, uint decimals); - #[display("{key}: {}", format_units_uint(val, decimals))] + #[display("{}: {}", key.pretty(), format_units_uint(val, decimals))] event log_named_decimal_uint(string key, uint val, uint decimals); - #[display("{key}: {val}")] + #[display("{}: {}", key.pretty(), val.pretty())] event log_named_int(string key, int val); - #[display("{key}: {val}")] + #[display("{}: {}", key.pretty(), val.pretty())] event log_named_uint(string key, uint val); - #[display("{key}: {}", hex::encode_prefixed(val))] + #[display("{}: {}", key.pretty(), hex::encode_prefixed(val))] event log_named_bytes(string key, bytes val); - #[display("{key}: {val}")] + #[display("{}: {}", key.pretty(), val.pretty())] event log_named_string(string key, string val); - #[display("{key}: [{}]", val.iter().format(", "))] + #[display("{}: [{}]", key.pretty(), val.iter().map(|v| v.pretty()).format(", "))] event log_named_array(string key, uint256[] val); - #[display("{key}: [{}]", val.iter().format(", "))] + #[display("{}: [{}]", key.pretty(), val.iter().map(|v| v.pretty()).format(", "))] event log_named_array(string key, int256[] val); - #[display("{key}: [{}]", val.iter().format(", "))] + #[display("{}: [{}]", key.pretty(), val.iter().map(|v| v.pretty()).format(", "))] event log_named_array(string key, address[] val); } } From b53e6a9d9c3332303b83920f1d181f04752987d7 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Thu, 10 Apr 2025 13:48:52 +0200 Subject: [PATCH 007/244] refactor: signatures identifier, trace decoding (#10282) * refactor: signatures identifier * nit * cleanup * dedup fallback decoding * fix * chore: clippy * feat: ignore non ABI calldata * feat: skip decoding create traces * fixes * fixes * chore: use CallTraceNode directly * chore: etherscan code dedup * chore: more filtering --- crates/cast/src/args.rs | 30 +- crates/cast/src/lib.rs | 29 +- crates/cast/src/opts.rs | 6 +- crates/cast/src/tx.rs | 25 +- crates/cast/tests/cli/main.rs | 2 - crates/cast/tests/cli/selectors.rs | 4 +- crates/chisel/src/dispatcher.rs | 9 +- crates/cli/src/utils/cmd.rs | 53 +-- .../common/src/provider/runtime_transport.rs | 6 +- crates/common/src/selectors.rs | 240 ++++++------ crates/evm/traces/src/decoder/mod.rs | 222 +++++++----- crates/evm/traces/src/decoder/precompiles.rs | 21 +- crates/evm/traces/src/identifier/etherscan.rs | 63 ++-- crates/evm/traces/src/identifier/local.rs | 39 +- crates/evm/traces/src/identifier/mod.rs | 33 +- .../evm/traces/src/identifier/signatures.rs | 343 +++++++++++------- crates/evm/traces/src/lib.rs | 11 +- crates/forge/src/cmd/selectors.rs | 2 +- crates/forge/src/cmd/test/mod.rs | 10 +- crates/forge/tests/it/config.rs | 4 +- crates/script/src/execute.rs | 9 +- crates/script/src/simulate.rs | 2 +- crates/test-utils/src/util.rs | 2 +- 23 files changed, 651 insertions(+), 514 deletions(-) diff --git a/crates/cast/src/args.rs b/crates/cast/src/args.rs index a01d87b76d373..78ca1d3076a63 100644 --- a/crates/cast/src/args.rs +++ b/crates/cast/src/args.rs @@ -20,11 +20,10 @@ use foundry_common::{ selectors::{ decode_calldata, decode_event_topic, decode_function_selector, decode_selectors, import_selectors, parse_signatures, pretty_calldata, ParsedSignatures, SelectorImportData, - SelectorType, + SelectorKind, }, shell, stdin, }; -use foundry_config::Config; use std::time::Instant; /// Run the `cast` command-line interface. @@ -209,11 +208,7 @@ pub async fn run_command(args: CastArgs) -> Result<()> { let data = data.strip_prefix("0x").unwrap_or(data.as_str()); let selector = data.get(..64).unwrap_or_default(); let identified_event = - SignaturesIdentifier::new(Config::foundry_cache_dir(), false)? - .write() - .await - .identify_event(&hex::decode(selector)?) - .await; + SignaturesIdentifier::new(false)?.identify_event(selector.parse()?).await; if let Some(event) = identified_event { let _ = sh_println!("{}", event.signature()); let data = data.get(64..).unwrap_or_default(); @@ -235,11 +230,7 @@ pub async fn run_command(args: CastArgs) -> Result<()> { let data = data.strip_prefix("0x").unwrap_or(data.as_str()); let selector = data.get(..8).unwrap_or_default(); let identified_error = - SignaturesIdentifier::new(Config::foundry_cache_dir(), false)? - .write() - .await - .identify_error(&hex::decode(selector)?) - .await; + SignaturesIdentifier::new(false)?.identify_error(selector.parse()?).await; if let Some(error) = identified_error { let _ = sh_println!("{}", error.signature()); error @@ -385,9 +376,12 @@ pub async fn run_command(args: CastArgs) -> Result<()> { let max_mutability_len = functions.iter().map(|r| r.2.len()).max().unwrap_or(0); let resolve_results = if resolve { - let selectors_it = functions.iter().map(|r| &r.0); - let ds = decode_selectors(SelectorType::Function, selectors_it).await?; - ds.into_iter().map(|v| v.unwrap_or_default().join("|")).collect() + let selectors = functions + .iter() + .map(|&(selector, ..)| SelectorKind::Function(selector)) + .collect::>(); + let ds = decode_selectors(&selectors).await?; + ds.into_iter().map(|v| v.join("|")).collect() } else { vec![] }; @@ -501,7 +495,7 @@ pub async fn run_command(args: CastArgs) -> Result<()> { // 4Byte CastSubcommand::FourByte { selector } => { let selector = stdin::unwrap_line(selector)?; - let sigs = decode_function_selector(&selector).await?; + let sigs = decode_function_selector(selector).await?; if sigs.is_empty() { eyre::bail!("No matching function signatures found for selector `{selector}`"); } @@ -514,7 +508,7 @@ pub async fn run_command(args: CastArgs) -> Result<()> { let calldata = stdin::unwrap_line(calldata)?; if calldata.len() == 10 { - let sigs = decode_function_selector(&calldata).await?; + let sigs = decode_function_selector(calldata.parse()?).await?; if sigs.is_empty() { eyre::bail!("No matching function signatures found for calldata `{calldata}`"); } @@ -544,7 +538,7 @@ pub async fn run_command(args: CastArgs) -> Result<()> { CastSubcommand::FourByteEvent { topic } => { let topic = stdin::unwrap_line(topic)?; - let sigs = decode_event_topic(&topic).await?; + let sigs = decode_event_topic(topic).await?; if sigs.is_empty() { eyre::bail!("No matching event signatures found for topic `{topic}`"); } diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index cb8bd28986aaa..f369c5de03f46 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -9,7 +9,7 @@ use alloy_network::AnyNetwork; use alloy_primitives::{ hex, utils::{keccak256, ParseUnits, Unit}, - Address, Keccak256, TxHash, TxKind, B256, I256, U256, + Address, Keccak256, Selector, TxHash, TxKind, B256, I256, U256, }; use alloy_provider::{ network::eip2718::{Decodable2718, Encodable2718}, @@ -367,22 +367,16 @@ impl> Cast

{ } async fn block_field_as_num>(&self, block: B, field: String) -> Result { - let block = block.into(); - let block_field = Self::block( + Self::block( self, - block, + block.into(), false, // Select only select field Some(field), ) - .await?; - - let ret = if block_field.starts_with("0x") { - U256::from_str_radix(strip_0x(&block_field), 16).expect("Unable to convert hex to U256") - } else { - U256::from_str_radix(&block_field, 10).expect("Unable to convert decimal to U256") - }; - Ok(ret) + .await? + .parse() + .map_err(Into::into) } pub async fn base_fee>(&self, block: B) -> Result { @@ -2132,15 +2126,16 @@ impl SimpleCast { /// # Example /// /// ``` + /// use alloy_primitives::fixed_bytes; /// use cast::SimpleCast as Cast; /// /// let bytecode = "6080604052348015600e575f80fd5b50600436106026575f3560e01c80632125b65b14602a575b5f80fd5b603a6035366004603c565b505050565b005b5f805f60608486031215604d575f80fd5b833563ffffffff81168114605f575f80fd5b925060208401356001600160a01b03811681146079575f80fd5b915060408401356001600160e01b03811681146093575f80fd5b80915050925092509256"; /// let functions = Cast::extract_functions(bytecode)?; - /// assert_eq!(functions, vec![("0x2125b65b".to_string(), "uint32,address,uint224".to_string(), "pure")]); + /// assert_eq!(functions, vec![(fixed_bytes!("0x2125b65b"), "uint32,address,uint224".to_string(), "pure")]); /// # Ok::<(), eyre::Report>(()) /// ``` - pub fn extract_functions(bytecode: &str) -> Result> { - let code = hex::decode(strip_0x(bytecode))?; + pub fn extract_functions(bytecode: &str) -> Result> { + let code = hex::decode(bytecode)?; let info = evmole::contract_info( evmole::ContractInfoArgs::new(&code) .with_selectors() @@ -2153,7 +2148,7 @@ impl SimpleCast { .into_iter() .map(|f| { ( - hex::encode_prefixed(f.selector), + f.selector.into(), f.arguments .expect("arguments extraction was requested") .into_iter() @@ -2180,7 +2175,7 @@ impl SimpleCast { /// let tx_envelope = Cast::decode_raw_transaction(&tx)?; /// # Ok::<(), eyre::Report>(()) pub fn decode_raw_transaction(tx: &str) -> Result { - let tx_hex = hex::decode(strip_0x(tx))?; + let tx_hex = hex::decode(tx)?; let tx = TxEnvelope::decode_2718(&mut tx_hex.as_slice())?; Ok(tx) } diff --git a/crates/cast/src/opts.rs b/crates/cast/src/opts.rs index 9bf4ef27801ed..8ffb6326c025e 100644 --- a/crates/cast/src/opts.rs +++ b/crates/cast/src/opts.rs @@ -5,7 +5,7 @@ use crate::cmd::{ mktx::MakeTxArgs, rpc::RpcArgs, run::RunArgs, send::SendTxArgs, storage::StorageArgs, txpool::TxPoolSubcommands, wallet::WalletSubcommands, }; -use alloy_primitives::{Address, B256, U256}; +use alloy_primitives::{Address, Selector, B256, U256}; use alloy_rpc_types::BlockId; use clap::{Parser, Subcommand, ValueHint}; use eyre::Result; @@ -646,7 +646,7 @@ pub enum CastSubcommand { #[command(name = "4byte", visible_aliases = &["4", "4b"])] FourByte { /// The function selector. - selector: Option, + selector: Option, }, /// Decode ABI-encoded calldata using . @@ -661,7 +661,7 @@ pub enum CastSubcommand { FourByteEvent { /// Topic 0 #[arg(value_name = "TOPIC_0")] - topic: Option, + topic: Option, }, /// Upload the given signatures to . diff --git a/crates/cast/src/tx.rs b/crates/cast/src/tx.rs index 46f7c811bced3..1097da794e15f 100644 --- a/crates/cast/src/tx.rs +++ b/crates/cast/src/tx.rs @@ -459,23 +459,18 @@ where /// Helper function that tries to decode custom error name and inputs from error payload data. async fn decode_execution_revert(data: &RawValue) -> Result> { - if let Some(err_data) = serde_json::from_str::(data.get())?.strip_prefix("0x") { - let Some(selector) = err_data.get(..8) else { return Ok(None) }; - - if let Some(known_error) = SignaturesIdentifier::new(Config::foundry_cache_dir(), false)? - .write() - .await - .identify_error(&hex::decode(selector)?) - .await - { - let mut decoded_error = known_error.name.clone(); - if !known_error.inputs.is_empty() { - if let Ok(error) = known_error.decode_error(&hex::decode(err_data)?) { - write!(decoded_error, "({})", format_tokens(&error.body).format(", "))?; - } + let err_data = serde_json::from_str::(data.get())?; + let Some(selector) = err_data.get(..4) else { return Ok(None) }; + if let Some(known_error) = + SignaturesIdentifier::new(false)?.identify_error(selector.try_into().unwrap()).await + { + let mut decoded_error = known_error.name.clone(); + if !known_error.inputs.is_empty() { + if let Ok(error) = known_error.decode_error(&err_data) { + write!(decoded_error, "({})", format_tokens(&error.body).format(", "))?; } - return Ok(Some(decoded_error)) } + return Ok(Some(decoded_error)) } Ok(None) } diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 6e5ad4aa66b6e..5e511256f88cd 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -2179,11 +2179,9 @@ contract CounterInExternalLibScript is Script { .tx_hash(); // Cache project selectors. - cmd.forge_fuse().set_current_dir(prj.root()); cmd.forge_fuse().args(["selectors", "cache"]).assert_success(); // Assert cast with local artifacts can decode external lib signature. - cmd.cast_fuse().set_current_dir(prj.root()); cmd.cast_fuse() .args(["run", format!("{tx_hash}").as_str(), "--rpc-url", &handle.http_endpoint()]) .assert_success() diff --git a/crates/cast/tests/cli/selectors.rs b/crates/cast/tests/cli/selectors.rs index d72f0e85f3a1c..d3a7e84b88079 100644 --- a/crates/cast/tests/cli/selectors.rs +++ b/crates/cast/tests/cli/selectors.rs @@ -20,7 +20,9 @@ transfer(address,uint256) casttest!(fourbyte_invalid, |_prj, cmd| { cmd.args(["4byte", "0xa9059c"]).assert_failure().stderr_eq(str![[r#" -Error: Invalid selector 0xa9059c: expected 10 characters (including 0x prefix). +error: invalid value '0xa9059c' for '[SELECTOR]': invalid string length + +For more information, try '--help'. "#]]); }); diff --git a/crates/chisel/src/dispatcher.rs b/crates/chisel/src/dispatcher.rs index 97b78369ec565..5dd6c882ffed6 100644 --- a/crates/chisel/src/dispatcher.rs +++ b/crates/chisel/src/dispatcher.rs @@ -13,7 +13,7 @@ use crate::{ use alloy_json_abi::{InternalType, JsonAbi}; use alloy_primitives::{hex, Address}; use forge_fmt::FormatterConfig; -use foundry_config::{Config, RpcEndpointUrl}; +use foundry_config::RpcEndpointUrl; use foundry_evm::{ decode::decode_console_logs, traces::{ @@ -925,9 +925,8 @@ impl ChiselDispatcher { ) -> eyre::Result { let mut decoder = CallTraceDecoderBuilder::new() .with_labels(result.labeled_addresses.clone()) - .with_signature_identifier(SignaturesIdentifier::new( - Config::foundry_cache_dir(), - session_config.foundry_config.offline, + .with_signature_identifier(SignaturesIdentifier::from_config( + &session_config.foundry_config, )?) .build(); @@ -965,7 +964,7 @@ impl ChiselDispatcher { for (kind, trace) in &mut result.traces { // Display all Setup + Execution traces. if matches!(kind, TraceKind::Setup | TraceKind::Execution) { - decode_trace_arena(trace, decoder).await?; + decode_trace_arena(trace, decoder).await; sh_println!("{}", render_trace_arena(trace))?; } } diff --git a/crates/cli/src/utils/cmd.rs b/crates/cli/src/utils/cmd.rs index 3dcec54ec218d..a28b0780e450b 100644 --- a/crates/cli/src/utils/cmd.rs +++ b/crates/cli/src/utils/cmd.rs @@ -1,7 +1,10 @@ use alloy_json_abi::JsonAbi; use alloy_primitives::Address; use eyre::{Result, WrapErr}; -use foundry_common::{compile::ProjectCompiler, fs, shell, ContractsByArtifact, TestFunctionExt}; +use foundry_common::{ + compile::ProjectCompiler, fs, selectors::SelectorKind, shell, ContractsByArtifact, + TestFunctionExt, +}; use foundry_compilers::{ artifacts::{CompactBytecode, Settings}, cache::{CacheEntry, CompilerCache}, @@ -16,7 +19,7 @@ use foundry_evm::{ traces::{ debug::{ContractSources, DebugTraceIdentifier}, decode_trace_arena, - identifier::{CachedSignatures, SignaturesIdentifier, TraceIdentifiers}, + identifier::{SignaturesCache, SignaturesIdentifier, TraceIdentifiers}, render_trace_arena_inner, CallTraceDecoder, CallTraceDecoderBuilder, TraceKind, Traces, }, }; @@ -364,10 +367,7 @@ pub async fn handle_traces( let mut builder = CallTraceDecoderBuilder::new() .with_labels(labels.chain(config_labels)) - .with_signature_identifier(SignaturesIdentifier::new( - Config::foundry_cache_dir(), - config.offline, - )?); + .with_signature_identifier(SignaturesIdentifier::from_config(config)?); let mut identifier = TraceIdentifiers::new().with_etherscan(config, chain)?; if let Some(contracts) = &known_contracts { builder = builder.with_known_contracts(contracts); @@ -416,7 +416,7 @@ pub async fn print_traces( } for (_, arena) in traces { - decode_trace_arena(arena, decoder).await?; + decode_trace_arena(arena, decoder).await; sh_println!("{}", render_trace_arena_inner(arena, verbose, state_changes))?; } @@ -437,34 +437,21 @@ pub async fn print_traces( /// Traverse the artifacts in the project to generate local signatures and merge them into the cache /// file. -pub fn cache_local_signatures(output: &ProjectCompileOutput, cache_path: PathBuf) -> Result<()> { - let path = cache_path.join("signatures"); - let mut cached_signatures = CachedSignatures::load(cache_path); - output.artifacts().for_each(|(_, artifact)| { +pub fn cache_local_signatures(output: &ProjectCompileOutput, cache_dir: &Path) -> Result<()> { + let path = cache_dir.join("signatures"); + let mut signatures = SignaturesCache::load(&path); + for (_, artifact) in output.artifacts() { if let Some(abi) = &artifact.abi { - for func in abi.functions() { - cached_signatures.functions.insert(func.selector().to_string(), func.signature()); - } - for event in abi.events() { - cached_signatures - .events - .insert(event.selector().to_string(), event.full_signature()); - } - for error in abi.errors() { - cached_signatures.errors.insert(error.selector().to_string(), error.signature()); - } - // External libraries doesn't have functions included in abi, but `methodIdentifiers`. - if let Some(method_identifiers) = &artifact.method_identifiers { - method_identifiers.iter().for_each(|(signature, selector)| { - cached_signatures - .functions - .entry(format!("0x{selector}")) - .or_insert(signature.to_string()); - }); - } + signatures.extend_from_abi(abi); } - }); - fs::write_json_file(&path, &cached_signatures)?; + // External libraries don't have functions included in the ABI, but `methodIdentifiers`. + if let Some(method_identifiers) = &artifact.method_identifiers { + signatures.extend(method_identifiers.iter().filter_map(|(signature, selector)| { + Some((SelectorKind::Function(selector.parse().ok()?), signature.clone())) + })); + } + } + signatures.save(&path); Ok(()) } diff --git a/crates/common/src/provider/runtime_transport.rs b/crates/common/src/provider/runtime_transport.rs index 3796e9123e308..9a59f6ed20423 100644 --- a/crates/common/src/provider/runtime_transport.rs +++ b/crates/common/src/provider/runtime_transport.rs @@ -138,7 +138,7 @@ impl RuntimeTransport { /// Connects the underlying transport, depending on the URL scheme. pub async fn connect(&self) -> Result { match self.url.scheme() { - "http" | "https" => self.connect_http().await, + "http" | "https" => self.connect_http(), "ws" | "wss" => self.connect_ws().await, "file" => self.connect_ipc().await, _ => Err(RuntimeTransportError::BadScheme(self.url.scheme().to_string())), @@ -190,7 +190,7 @@ impl RuntimeTransport { } /// Connects to an HTTP [alloy_transport_http::Http] transport. - async fn connect_http(&self) -> Result { + fn connect_http(&self) -> Result { let client = self.reqwest_client()?; Ok(InnerTransport::Http(Http::with_client(client, self.url.clone()))) } @@ -351,7 +351,7 @@ mod tests { let transport = RuntimeTransportBuilder::new(url.clone()) .with_headers(vec!["User-Agent: test-agent".to_string()]) .build(); - let inner = transport.connect_http().await.unwrap(); + let inner = transport.connect_http().unwrap(); match inner { InnerTransport::Http(http) => { diff --git a/crates/common/src/selectors.rs b/crates/common/src/selectors.rs index c360a353c35c3..9dc20044f2ce5 100644 --- a/crates/common/src/selectors.rs +++ b/crates/common/src/selectors.rs @@ -4,8 +4,9 @@ use crate::{abi::abi_decode_calldata, provider::runtime_transport::RuntimeTransportBuilder}; use alloy_json_abi::JsonAbi; -use alloy_primitives::map::HashMap; +use alloy_primitives::{map::HashMap, Selector, B256}; use eyre::Context; +use itertools::Itertools; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::{ fmt, @@ -26,6 +27,9 @@ const REQ_TIMEOUT: Duration = Duration::from_secs(15); /// How many request can time out before we decide this is a spurious connection. const MAX_TIMEDOUT_REQ: usize = 4usize; +/// List of signatures for a given [`SelectorKind`]. +pub type OpenChainSignatures = Vec; + /// A client that can request API data from OpenChain. #[derive(Clone, Debug)] pub struct OpenChainClient { @@ -54,7 +58,7 @@ impl OpenChainClient { }) } - async fn get_text(&self, url: &str) -> reqwest::Result { + async fn get_text(&self, url: impl reqwest::IntoUrl + fmt::Display) -> reqwest::Result { trace!(%url, "GET"); self.inner .get(url) @@ -128,108 +132,83 @@ impl OpenChainClient { /// Decodes the given function or event selector using OpenChain pub async fn decode_selector( &self, - selector: &str, - selector_type: SelectorType, - ) -> eyre::Result> { - self.decode_selectors(selector_type, std::iter::once(selector)) - .await? - .pop() // Not returning on the previous line ensures a vector with exactly 1 element - .unwrap() - .ok_or_else(|| eyre::eyre!("No signature found")) + selector: SelectorKind, + ) -> eyre::Result { + Ok(self.decode_selectors(&[selector]).await?.pop().unwrap()) } /// Decodes the given function, error or event selectors using OpenChain. pub async fn decode_selectors( &self, - selector_type: SelectorType, - selectors: impl IntoIterator>, - ) -> eyre::Result>>> { - let selectors: Vec = selectors - .into_iter() - .map(Into::into) - .map(|s| s.to_lowercase()) - .map(|s| if s.starts_with("0x") { s } else { format!("0x{s}") }) - .collect(); - + selectors: &[SelectorKind], + ) -> eyre::Result> { if selectors.is_empty() { return Ok(vec![]); } - debug!(len = selectors.len(), "decoding selectors"); - trace!(?selectors, "decoding selectors"); - - // exit early if spurious connection - self.ensure_not_spurious()?; - - let expected_len = match selector_type { - SelectorType::Function | SelectorType::Error => 10, // 0x + hex(4bytes) - SelectorType::Event => 66, // 0x + hex(32bytes) - }; - if let Some(s) = selectors.iter().find(|s| s.len() != expected_len) { - eyre::bail!( - "Invalid selector {s}: expected {expected_len} characters (including 0x prefix)." - ) - } - - #[derive(Deserialize)] - struct Decoded { - name: String, - } - - #[derive(Deserialize)] - struct ApiResult { - event: HashMap>>, - function: HashMap>>, - } - - #[derive(Deserialize)] - struct ApiResponse { - ok: bool, - result: ApiResult, + if enabled!(tracing::Level::TRACE) { + trace!(?selectors, "decoding selectors"); + } else { + debug!(len = selectors.len(), "decoding selectors"); } - let url = format!( - "{SELECTOR_LOOKUP_URL}?{ltype}={selectors_str}", - ltype = match selector_type { - SelectorType::Function | SelectorType::Error => "function", - SelectorType::Event => "event", - }, - selectors_str = selectors.join(",") - ); + // Exit early if spurious connection. + self.ensure_not_spurious()?; - let res = self.get_text(&url).await?; - let api_response = match serde_json::from_str::(&res) { - Ok(inner) => inner, - Err(err) => { - eyre::bail!("Could not decode response:\n {res}.\nError: {err}") + // Build the URL with the query string. + let mut url: url::Url = SELECTOR_LOOKUP_URL.parse().unwrap(); + { + let mut query = url.query_pairs_mut(); + let functions = selectors.iter().filter_map(SelectorKind::as_function); + if functions.clone().next().is_some() { + query.append_pair("function", &functions.format(",").to_string()); } - }; - - if !api_response.ok { - eyre::bail!("Failed to decode:\n {res}") + let events = selectors.iter().filter_map(SelectorKind::as_event); + if events.clone().next().is_some() { + query.append_pair("event", &events.format(",").to_string()); + } + let _ = query.finish(); } - let decoded = match selector_type { - SelectorType::Function | SelectorType::Error => api_response.result.function, - SelectorType::Event => api_response.result.event, + let text = self.get_text(url).await?; + let SignatureResponse { ok, result } = match serde_json::from_str(&text) { + Ok(response) => response, + Err(err) => eyre::bail!("could not decode response: {err}: {text}"), }; + if !ok { + eyre::bail!("OpenChain returned an error: {text}"); + } Ok(selectors - .into_iter() - .map(|selector| match decoded.get(&selector) { - Some(Some(r)) => Some(r.iter().map(|d| d.name.clone()).collect()), - _ => None, + .iter() + .map(|selector| { + let signatures = match selector { + SelectorKind::Function(selector) | SelectorKind::Error(selector) => { + result.function.get(selector) + } + SelectorKind::Event(hash) => result.event.get(hash), + }; + signatures + .map(Option::as_deref) + .unwrap_or_default() + .unwrap_or_default() + .iter() + .map(|sig| sig.name.clone()) + .collect() }) .collect()) } /// Fetches a function signature given the selector using OpenChain - pub async fn decode_function_selector(&self, selector: &str) -> eyre::Result> { - self.decode_selector(selector, SelectorType::Function).await + pub async fn decode_function_selector( + &self, + selector: Selector, + ) -> eyre::Result { + self.decode_selector(SelectorKind::Function(selector)).await } /// Fetches all possible signatures and attempts to abi decode the calldata - pub async fn decode_calldata(&self, calldata: &str) -> eyre::Result> { + pub async fn decode_calldata(&self, calldata: &str) -> eyre::Result { let calldata = calldata.strip_prefix("0x").unwrap_or(calldata); if calldata.len() < 8 { eyre::bail!( @@ -238,19 +217,15 @@ impl OpenChainClient { ) } - let sigs = self.decode_function_selector(&calldata[..8]).await?; - - // filter for signatures that can be decoded - Ok(sigs - .iter() - .filter(|sig| abi_decode_calldata(sig, calldata, true, true).is_ok()) - .cloned() - .collect::>()) + let mut sigs = self.decode_function_selector(calldata[..8].parse().unwrap()).await?; + // Retain only signatures that can be decoded. + sigs.retain(|sig| abi_decode_calldata(sig, calldata, true, true).is_ok()); + Ok(sigs) } - /// Fetches an event signature given the 32 byte topic using OpenChain - pub async fn decode_event_topic(&self, topic: &str) -> eyre::Result> { - self.decode_selector(topic, SelectorType::Event).await + /// Fetches an event signature given the 32 byte topic using OpenChain. + pub async fn decode_event_topic(&self, topic: B256) -> eyre::Result { + self.decode_selector(SelectorKind::Event(topic)).await } /// Pretty print calldata and if available, fetch possible function signatures @@ -284,6 +259,7 @@ impl OpenChainClient { let sigs = if offline { vec![] } else { + let selector = selector.parse()?; self.decode_function_selector(selector).await.unwrap_or_default().into_iter().collect() }; let (_, data) = calldata.split_at(8); @@ -314,7 +290,7 @@ impl OpenChainClient { let request = match data { SelectorImportData::Abi(abis) => { - let functions_and_errors: Vec = abis + let functions_and_errors: OpenChainSignatures = abis .iter() .flat_map(|abi| { abi.functions() @@ -344,12 +320,12 @@ impl OpenChainClient { pub enum SelectorOrSig { Selector(String), - Sig(Vec), + Sig(OpenChainSignatures), } pub struct PossibleSigs { method: SelectorOrSig, - data: Vec, + data: OpenChainSignatures, } impl PossibleSigs { @@ -382,45 +358,59 @@ impl fmt::Display for PossibleSigs { } } -/// The type of selector fetched from OpenChain. -#[derive(Clone, Copy)] -pub enum SelectorType { +/// The kind of selector to fetch from OpenChain. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum SelectorKind { /// A function selector. - Function, + Function(Selector), + /// A custom error selector. Behaves the same as a function selector. + Error(Selector), /// An event selector. - Event, - /// An custom error selector. - Error, + Event(B256), +} + +impl SelectorKind { + /// Returns the function selector if it is a function OR custom error. + pub fn as_function(&self) -> Option { + match *self { + Self::Function(selector) | Self::Error(selector) => Some(selector), + _ => None, + } + } + + /// Returns the event selector if it is an event. + pub fn as_event(&self) -> Option { + match *self { + Self::Event(hash) => Some(hash), + _ => None, + } + } } /// Decodes the given function or event selector using OpenChain. -pub async fn decode_selector( - selector_type: SelectorType, - selector: &str, -) -> eyre::Result> { - OpenChainClient::new()?.decode_selector(selector, selector_type).await +pub async fn decode_selector(selector: SelectorKind) -> eyre::Result { + OpenChainClient::new()?.decode_selector(selector).await } /// Decodes the given function or event selectors using OpenChain. pub async fn decode_selectors( - selector_type: SelectorType, - selectors: impl IntoIterator>, -) -> eyre::Result>>> { - OpenChainClient::new()?.decode_selectors(selector_type, selectors).await + selectors: &[SelectorKind], +) -> eyre::Result> { + OpenChainClient::new()?.decode_selectors(selectors).await } /// Fetches a function signature given the selector using OpenChain. -pub async fn decode_function_selector(selector: &str) -> eyre::Result> { +pub async fn decode_function_selector(selector: Selector) -> eyre::Result { OpenChainClient::new()?.decode_function_selector(selector).await } /// Fetches all possible signatures and attempts to abi decode the calldata using OpenChain. -pub async fn decode_calldata(calldata: &str) -> eyre::Result> { +pub async fn decode_calldata(calldata: &str) -> eyre::Result { OpenChainClient::new()?.decode_calldata(calldata).await } /// Fetches an event signature given the 32 byte topic using OpenChain. -pub async fn decode_event_topic(topic: &str) -> eyre::Result> { +pub async fn decode_event_topic(topic: B256) -> eyre::Result { OpenChainClient::new()?.decode_event_topic(topic).await } @@ -448,9 +438,9 @@ pub async fn pretty_calldata( #[derive(Debug, Default, PartialEq, Eq, Serialize)] pub struct RawSelectorImportData { - pub function: Vec, - pub event: Vec, - pub error: Vec, + pub function: OpenChainSignatures, + pub event: OpenChainSignatures, + pub error: OpenChainSignatures, } impl RawSelectorImportData { @@ -468,8 +458,8 @@ pub enum SelectorImportData { #[derive(Debug, Default, Serialize)] struct SelectorImportRequest { - function: Vec, - event: Vec, + function: OpenChainSignatures, + event: OpenChainSignatures, } #[derive(Debug, Deserialize)] @@ -574,6 +564,24 @@ pub fn parse_signatures(tokens: Vec) -> ParsedSignatures { ParsedSignatures { signatures, abis } } +/// [`SELECTOR_LOOKUP_URL`] response. +#[derive(Deserialize)] +struct SignatureResponse { + ok: bool, + result: SignatureResult, +} + +#[derive(Deserialize)] +struct SignatureResult { + event: HashMap>>, + function: HashMap>>, +} + +#[derive(Deserialize)] +struct Signature { + name: String, +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/evm/traces/src/decoder/mod.rs b/crates/evm/traces/src/decoder/mod.rs index e023285eb054f..2e22ca7cdc358 100644 --- a/crates/evm/traces/src/decoder/mod.rs +++ b/crates/evm/traces/src/decoder/mod.rs @@ -1,18 +1,17 @@ use crate::{ debug::DebugTraceIdentifier, - identifier::{ - AddressIdentity, LocalTraceIdentifier, SingleSignaturesIdentifier, TraceIdentifier, - }, + identifier::{IdentifiedAddress, LocalTraceIdentifier, SignaturesIdentifier, TraceIdentifier}, CallTrace, CallTraceArena, CallTraceNode, DecodedCallData, }; use alloy_dyn_abi::{DecodedEvent, DynSolValue, EventExt, FunctionExt, JsonAbiExt}; use alloy_json_abi::{Error, Event, Function, JsonAbi}; use alloy_primitives::{ - map::{hash_map::Entry, HashMap}, + map::{hash_map::Entry, HashMap, HashSet}, Address, LogData, Selector, B256, }; use foundry_common::{ - abi::get_indexed_event, fmt::format_token, get_contract_name, ContractsByArtifact, SELECTOR_LEN, + abi::get_indexed_event, fmt::format_token, get_contract_name, selectors::SelectorKind, + ContractsByArtifact, SELECTOR_LEN, }; use foundry_evm_core::{ abi::{console, Vm}, @@ -85,7 +84,7 @@ impl CallTraceDecoderBuilder { /// Sets the signature identifier for events and functions. #[inline] - pub fn with_signature_identifier(mut self, identifier: SingleSignaturesIdentifier) -> Self { + pub fn with_signature_identifier(mut self, identifier: SignaturesIdentifier) -> Self { self.decoder.signature_identifier = Some(identifier); self } @@ -120,19 +119,22 @@ pub struct CallTraceDecoder { /// Address labels. pub labels: HashMap, /// Contract addresses that have a receive function. - pub receive_contracts: Vec

, - /// Contract addresses that have fallback functions, mapped to function sigs. - pub fallback_contracts: HashMap>, + pub receive_contracts: HashSet
, + /// Contract addresses that have fallback functions, mapped to function selectors of that + /// contract. + pub fallback_contracts: HashMap>, /// All known functions. pub functions: HashMap>, /// All known events. + /// + /// Key is: `(topics[0], topics.len() - 1)`. pub events: BTreeMap<(B256, usize), Vec>, /// Revert decoder. Contains all known custom errors. pub revert_decoder: RevertDecoder, /// A signature identifier for events and functions. - pub signature_identifier: Option, + pub signature_identifier: Option, /// Verbosity level pub verbosity: u8, @@ -211,8 +213,23 @@ impl CallTraceDecoder { /// Identify unknown addresses in the specified call trace using the specified identifier. /// /// Unknown contracts are contracts that either lack a label or an ABI. - pub fn identify(&mut self, trace: &CallTraceArena, identifier: &mut impl TraceIdentifier) { - self.collect_identities(identifier.identify_addresses(self.trace_addresses(trace))); + pub fn identify(&mut self, arena: &CallTraceArena, identifier: &mut impl TraceIdentifier) { + self.collect_identified_addresses(self.identify_addresses(arena, identifier)); + } + + /// Identify unknown addresses in the specified call trace using the specified identifier. + /// + /// Unknown contracts are contracts that either lack a label or an ABI. + pub fn identify_addresses<'a>( + &self, + arena: &CallTraceArena, + identifier: &'a mut impl TraceIdentifier, + ) -> Vec> { + let nodes = arena.nodes().iter().filter(|node| { + let address = &node.trace.address; + !self.labels.contains_key(address) || !self.contracts.contains_key(address) + }); + identifier.identify_addresses(&nodes.collect::>()) } /// Adds a single event to the decoder. @@ -242,34 +259,15 @@ impl CallTraceDecoder { self.revert_decoder.push_error(error); } - /// Returns an iterator over the trace addresses. - pub fn trace_addresses<'a>( - &'a self, - arena: &'a CallTraceArena, - ) -> impl Iterator, Option<&'a [u8]>)> + Clone + 'a { - arena - .nodes() - .iter() - .map(|node| { - ( - &node.trace.address, - node.trace.kind.is_any_create().then_some(&node.trace.output[..]), - node.trace.kind.is_any_create().then_some(&node.trace.data[..]), - ) - }) - .filter(|&(address, _, _)| { - !self.labels.contains_key(address) || !self.contracts.contains_key(address) - }) - } - - fn collect_identities(&mut self, identities: Vec>) { - // Skip logging if there are no identities. - if identities.is_empty() { + fn collect_identified_addresses(&mut self, mut addrs: Vec>) { + addrs.sort_by_key(|identity| identity.address); + addrs.dedup_by_key(|identity| identity.address); + if addrs.is_empty() { return; } - trace!(target: "evm::traces", len=identities.len(), "collecting address identities"); - for AddressIdentity { address, label, contract, abi, artifact_id: _ } in identities { + trace!(target: "evm::traces", len=addrs.len(), "collecting address identities"); + for IdentifiedAddress { address, label, contract, abi, artifact_id: _ } in addrs { let _span = trace_span!(target: "evm::traces", "identity", ?contract, ?label).entered(); if let Some(contract) = contract { @@ -281,13 +279,17 @@ impl CallTraceDecoder { } if let Some(abi) = abi { - self.collect_abi(&abi, Some(&address)); + self.collect_abi(&abi, Some(address)); } } } - fn collect_abi(&mut self, abi: &JsonAbi, address: Option<&Address>) { - trace!(target: "evm::traces", len=abi.len(), ?address, "collecting ABI"); + fn collect_abi(&mut self, abi: &JsonAbi, address: Option
) { + let len = abi.len(); + if len == 0 { + return; + } + trace!(target: "evm::traces", len, ?address, "collecting ABI"); for function in abi.functions() { self.push_function(function.clone()); } @@ -299,15 +301,12 @@ impl CallTraceDecoder { } if let Some(address) = address { if abi.receive.is_some() { - self.receive_contracts.push(*address); + self.receive_contracts.insert(address); } if abi.fallback.is_some() { - let mut functions_sig = vec![]; - for function in abi.functions() { - functions_sig.push(function.signature()); - } - self.fallback_contracts.insert(*address, functions_sig); + self.fallback_contracts + .insert(address, abi.functions().map(|f| f.selector()).collect()); } } } @@ -332,12 +331,16 @@ impl CallTraceDecoder { /// Decodes a call trace. pub async fn decode_function(&self, trace: &CallTrace) -> DecodedCallTrace { + let label = self.labels.get(&trace.address).cloned(); + + if trace.kind.is_any_create() { + return DecodedCallTrace { label, ..Default::default() }; + } + if let Some(trace) = precompiles::decode(trace, 1) { return trace; } - let label = self.labels.get(&trace.address).cloned(); - let cdata = &trace.data; if trace.address == DEFAULT_CREATE2_DEPLOYER { return DecodedCallTrace { @@ -347,16 +350,14 @@ impl CallTraceDecoder { }; } - if cdata.len() >= SELECTOR_LEN { - let selector = &cdata[..SELECTOR_LEN]; + if is_abi_call_data(cdata) { + let selector = Selector::try_from(&cdata[..SELECTOR_LEN]).unwrap(); let mut functions = Vec::new(); - let functions = match self.functions.get(selector) { + let functions = match self.functions.get(&selector) { Some(fs) => fs, None => { if let Some(identifier) = &self.signature_identifier { - if let Some(function) = - identifier.write().await.identify_function(selector).await - { + if let Some(function) = identifier.identify_function(selector).await { functions.push(function); } } @@ -366,12 +367,7 @@ impl CallTraceDecoder { let [func, ..] = &functions[..] else { return DecodedCallTrace { label, - call_data: self.fallback_contracts.get(&trace.address).map(|_| { - DecodedCallData { - signature: "fallback()".to_string(), - args: vec![cdata.to_string()], - } - }), + call_data: self.fallback_call_data(trace), return_data: self.default_return_data(trace), }; }; @@ -380,8 +376,10 @@ impl CallTraceDecoder { // If not, then replace call data signature with `fallback`. let mut call_data = self.decode_function_input(trace, func); if let Some(fallback_functions) = self.fallback_contracts.get(&trace.address) { - if !fallback_functions.contains(&func.signature()) { - call_data.signature = "fallback()".to_string(); + if !fallback_functions.contains(&selector) { + if let Some(cd) = self.fallback_call_data(trace) { + call_data.signature = cd.signature; + } } } @@ -391,14 +389,9 @@ impl CallTraceDecoder { return_data: self.decode_function_output(trace, functions), } } else { - let has_receive = self.receive_contracts.contains(&trace.address); - let signature = - if cdata.is_empty() && has_receive { "receive()" } else { "fallback()" } - .to_string(); - let args = if cdata.is_empty() { Vec::new() } else { vec![cdata.to_string()] }; DecodedCallTrace { label, - call_data: Some(DecodedCallData { signature, args }), + call_data: self.fallback_call_data(trace), return_data: self.default_return_data(trace), } } @@ -598,6 +591,21 @@ impl CallTraceDecoder { .map(Into::into) } + #[track_caller] + fn fallback_call_data(&self, trace: &CallTrace) -> Option { + let cdata = &trace.data; + let signature = if cdata.is_empty() && self.receive_contracts.contains(&trace.address) { + "receive()" + } else if self.fallback_contracts.contains_key(&trace.address) { + "fallback()" + } else { + return None; + } + .to_string(); + let args = if cdata.is_empty() { Vec::new() } else { vec![cdata.to_string()] }; + Some(DecodedCallData { signature, args }) + } + /// The default decoded return data for a trace. fn default_return_data(&self, trace: &CallTrace) -> Option { (!trace.success).then(|| self.revert_decoder.decode(&trace.output, Some(trace.status))) @@ -612,7 +620,7 @@ impl CallTraceDecoder { Some(es) => es, None => { if let Some(identifier) = &self.signature_identifier { - if let Some(event) = identifier.write().await.identify_event(&t0[..]).await { + if let Some(event) = identifier.identify_event(t0).await { events.push(get_indexed_event(event, log)); } } @@ -645,24 +653,47 @@ impl CallTraceDecoder { /// Prefetches function and event signatures into the identifier cache pub async fn prefetch_signatures(&self, nodes: &[CallTraceNode]) { let Some(identifier) = &self.signature_identifier else { return }; - - let events_it = nodes + let events = nodes .iter() - .flat_map(|node| node.logs.iter().filter_map(|log| log.raw_log.topics().first())) - .unique(); - identifier.write().await.identify_events(events_it).await; - - const DEFAULT_CREATE2_DEPLOYER_BYTES: [u8; 20] = DEFAULT_CREATE2_DEPLOYER.0 .0; - let funcs_it = nodes + .flat_map(|node| { + node.logs + .iter() + .map(|log| log.raw_log.topics()) + .filter(|&topics| { + if let Some(&first) = topics.first() { + if self.events.contains_key(&(first, topics.len() - 1)) { + return false; + } + } + true + }) + .filter_map(|topics| topics.first()) + }) + .copied(); + let functions = nodes .iter() - .filter_map(|n| match n.trace.address.0 .0 { - DEFAULT_CREATE2_DEPLOYER_BYTES => None, - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01..=0x0a] => None, - _ => n.trace.data.get(..SELECTOR_LEN), + .filter(|&n| { + // Ignore known addresses. + if n.trace.address == DEFAULT_CREATE2_DEPLOYER || + n.is_precompile() || + precompiles::is_known_precompile(n.trace.address, 1) + { + return false; + } + // Ignore non-ABI calldata. + if n.trace.kind.is_any_create() || !is_abi_call_data(&n.trace.data) { + return false; + } + true }) - .filter(|v| !self.functions.contains_key(*v)) - .unique(); - identifier.write().await.identify_functions(funcs_it).await; + .filter_map(|n| n.trace.data.first_chunk().map(Selector::from)) + .filter(|selector| !self.functions.contains_key(selector)); + let selectors = events + .map(SelectorKind::Event) + .chain(functions.map(SelectorKind::Function)) + .unique() + .collect::>(); + let _ = identifier.identify(&selectors).await; } /// Pretty-prints a value. @@ -676,6 +707,29 @@ impl CallTraceDecoder { } } +/// Returns `true` if the given function calldata (including function selector) is ABI-encoded. +/// +/// This is a simple heuristic to avoid fetching non ABI-encoded selectors. +fn is_abi_call_data(data: &[u8]) -> bool { + match data.len().cmp(&SELECTOR_LEN) { + std::cmp::Ordering::Less => false, + std::cmp::Ordering::Equal => true, + std::cmp::Ordering::Greater => is_abi_data(&data[SELECTOR_LEN..]), + } +} + +/// Returns `true` if the given data is ABI-encoded. +/// +/// See [`is_abi_call_data`] for more details. +fn is_abi_data(data: &[u8]) -> bool { + let rem = data.len() % 32; + if rem == 0 || data.is_empty() { + return true; + } + // If the length is not a multiple of 32, also accept when the last remainder bytes are all 0. + data[data.len() - rem..].iter().all(|byte| *byte == 0) +} + /// Restore the order of the params of a decoded event, /// as Alloy returns the indexed and unindexed params separately. fn reconstruct_params(event: &Event, decoded: &DecodedEvent) -> Vec { diff --git a/crates/evm/traces/src/decoder/precompiles.rs b/crates/evm/traces/src/decoder/precompiles.rs index 0719f29b77aef..508bf1e1c4320 100644 --- a/crates/evm/traces/src/decoder/precompiles.rs +++ b/crates/evm/traces/src/decoder/precompiles.rs @@ -1,5 +1,5 @@ use crate::{CallTrace, DecodedCallData}; -use alloy_primitives::{hex, B256, U256}; +use alloy_primitives::{hex, Address, B256, U256}; use alloy_sol_types::{abi, sol, SolCall}; use foundry_evm_core::precompiles::{ BLAKE_2F, EC_ADD, EC_MUL, EC_PAIRING, EC_RECOVER, IDENTITY, MOD_EXP, POINT_EVALUATION, @@ -46,9 +46,26 @@ macro_rules! tri { }; } +pub(super) fn is_known_precompile(address: Address, _chain_id: u64) -> bool { + address[..19].iter().all(|&x| x == 0) && + matches!( + address, + EC_RECOVER | + SHA_256 | + RIPEMD_160 | + IDENTITY | + MOD_EXP | + EC_ADD | + EC_MUL | + EC_PAIRING | + BLAKE_2F | + POINT_EVALUATION + ) +} + /// Tries to decode a precompile call. Returns `Some` if successful. pub(super) fn decode(trace: &CallTrace, _chain_id: u64) -> Option { - if !trace.address[..19].iter().all(|&x| x == 0) { + if !is_known_precompile(trace.address, _chain_id) { return None; } diff --git a/crates/evm/traces/src/identifier/etherscan.rs b/crates/evm/traces/src/identifier/etherscan.rs index 96e4b69667b32..64b34e2363912 100644 --- a/crates/evm/traces/src/identifier/etherscan.rs +++ b/crates/evm/traces/src/identifier/etherscan.rs @@ -1,4 +1,4 @@ -use super::{AddressIdentity, TraceIdentifier}; +use super::{IdentifiedAddress, TraceIdentifier}; use crate::debug::ContractSources; use alloy_primitives::Address; use foundry_block_explorers::{ @@ -12,6 +12,7 @@ use futures::{ stream::{FuturesUnordered, Stream, StreamExt}, task::{Context, Poll}, }; +use revm_inspectors::tracing::types::CallTraceNode; use std::{ borrow::Cow, collections::BTreeMap, @@ -92,20 +93,32 @@ impl EtherscanIdentifier { Ok(sources) } + + fn identify_from_metadata( + &self, + address: Address, + metadata: &Metadata, + ) -> IdentifiedAddress<'static> { + let label = metadata.contract_name.clone(); + let abi = metadata.abi().ok().map(Cow::Owned); + IdentifiedAddress { + address, + label: Some(label.clone()), + contract: Some(label), + abi, + artifact_id: None, + } + } } impl TraceIdentifier for EtherscanIdentifier { - fn identify_addresses<'a, A>(&mut self, addresses: A) -> Vec> - where - A: Iterator, Option<&'a [u8]>)>, - { - trace!(target: "evm::traces", "identify {:?} addresses", addresses.size_hint().1); - - if self.invalid_api_key.load(Ordering::Relaxed) { - // api key was marked as invalid + fn identify_addresses(&mut self, nodes: &[&CallTraceNode]) -> Vec> { + if self.invalid_api_key.load(Ordering::Relaxed) || nodes.is_empty() { return Vec::new() } + trace!(target: "evm::traces::etherscan", "identify {} addresses", nodes.len()); + let mut identities = Vec::new(); let mut fetcher = EtherscanFetcher::new( self.client.clone(), @@ -114,39 +127,23 @@ impl TraceIdentifier for EtherscanIdentifier { Arc::clone(&self.invalid_api_key), ); - for (addr, _, _) in addresses { - if let Some(metadata) = self.contracts.get(addr) { - let label = metadata.contract_name.clone(); - let abi = metadata.abi().ok().map(Cow::Owned); - - identities.push(AddressIdentity { - address: *addr, - label: Some(label.clone()), - contract: Some(label), - abi, - artifact_id: None, - }); + for &node in nodes { + let address = node.trace.address; + if let Some(metadata) = self.contracts.get(&address) { + identities.push(self.identify_from_metadata(address, metadata)); } else { - fetcher.push(*addr); + fetcher.push(address); } } let fetched_identities = foundry_common::block_on( fetcher .map(|(address, metadata)| { - let label = metadata.contract_name.clone(); - let abi = metadata.abi().ok().map(Cow::Owned); + let addr = self.identify_from_metadata(address, &metadata); self.contracts.insert(address, metadata); - - AddressIdentity { - address, - label: Some(label.clone()), - contract: Some(label), - abi, - artifact_id: None, - } + addr }) - .collect::>>(), + .collect::>>(), ); identities.extend(fetched_identities); diff --git a/crates/evm/traces/src/identifier/local.rs b/crates/evm/traces/src/identifier/local.rs index 718f7162fb920..dcd4c31bcaf9f 100644 --- a/crates/evm/traces/src/identifier/local.rs +++ b/crates/evm/traces/src/identifier/local.rs @@ -1,9 +1,9 @@ -use super::{AddressIdentity, TraceIdentifier}; +use super::{IdentifiedAddress, TraceIdentifier}; use alloy_dyn_abi::JsonAbiExt; use alloy_json_abi::JsonAbi; -use alloy_primitives::Address; use foundry_common::contracts::{bytecode_diff_score, ContractsByArtifact}; use foundry_compilers::ArtifactId; +use revm_inspectors::tracing::types::CallTraceNode; use std::borrow::Cow; /// A trace identifier that tries to identify addresses using local contracts. @@ -69,7 +69,7 @@ impl<'a> LocalTraceIdentifier<'a> { let score = bytecode_diff_score(bytecode, current_bytecode); if score == 0.0 { - trace!(target: "evm::traces", "found exact match"); + trace!(target: "evm::traces::local", "found exact match"); return Some((id, &contract.abi)); } if score < *min_score { @@ -114,7 +114,7 @@ impl<'a> LocalTraceIdentifier<'a> { } } - trace!(target: "evm::traces", %min_score, "no exact match found"); + trace!(target: "evm::traces::local", %min_score, "no exact match found"); // Note: the diff score can be inaccurate for small contracts so we're using a relatively // high threshold here to avoid filtering out too many contracts. @@ -141,22 +141,31 @@ impl<'a> LocalTraceIdentifier<'a> { } impl TraceIdentifier for LocalTraceIdentifier<'_> { - fn identify_addresses<'a, A>(&mut self, addresses: A) -> Vec> - where - A: Iterator, Option<&'a [u8]>)>, - { - trace!(target: "evm::traces", "identify {:?} addresses", addresses.size_hint().1); + fn identify_addresses(&mut self, nodes: &[&CallTraceNode]) -> Vec> { + if nodes.is_empty() { + return Vec::new(); + } + + trace!(target: "evm::traces::local", "identify {} addresses", nodes.len()); - addresses + nodes + .iter() + .map(|&node| { + ( + node.trace.address, + node.trace.kind.is_any_create().then_some(&node.trace.output[..]), + node.trace.kind.is_any_create().then_some(&node.trace.data[..]), + ) + }) .filter_map(|(address, runtime_code, creation_code)| { - let _span = trace_span!(target: "evm::traces", "identify", %address).entered(); + let _span = + trace_span!(target: "evm::traces::local", "identify", %address).entered(); - trace!(target: "evm::traces", "identifying"); let (id, abi) = self.identify_code(runtime_code?, creation_code?)?; - trace!(target: "evm::traces", id=%id.identifier(), "identified"); + trace!(target: "evm::traces::local", id=%id.identifier(), "identified"); - Some(AddressIdentity { - address: *address, + Some(IdentifiedAddress { + address, contract: Some(id.identifier()), label: Some(id.name.clone()), abi: Some(Cow::Borrowed(abi)), diff --git a/crates/evm/traces/src/identifier/mod.rs b/crates/evm/traces/src/identifier/mod.rs index 51f949832659f..0654b5087764f 100644 --- a/crates/evm/traces/src/identifier/mod.rs +++ b/crates/evm/traces/src/identifier/mod.rs @@ -3,6 +3,7 @@ use alloy_primitives::Address; use foundry_common::ContractsByArtifact; use foundry_compilers::ArtifactId; use foundry_config::{Chain, Config}; +use revm_inspectors::tracing::types::CallTraceNode; use std::borrow::Cow; mod local; @@ -12,19 +13,19 @@ mod etherscan; pub use etherscan::EtherscanIdentifier; mod signatures; -pub use signatures::{CachedSignatures, SignaturesIdentifier, SingleSignaturesIdentifier}; +pub use signatures::{SignaturesCache, SignaturesIdentifier}; -/// An address identity -pub struct AddressIdentity<'a> { - /// The address this identity belongs to +/// An address identified by a [`TraceIdentifier`]. +pub struct IdentifiedAddress<'a> { + /// The address. pub address: Address, - /// The label for the address + /// The label for the address. pub label: Option, - /// The contract this address represents + /// The contract this address represents. /// /// Note: This may be in the format `":"`. pub contract: Option, - /// The ABI of the contract at this address + /// The ABI of the contract at this address. pub abi: Option>, /// The artifact ID of the contract, if any. pub artifact_id: Option, @@ -33,9 +34,7 @@ pub struct AddressIdentity<'a> { /// Trace identifiers figure out what ABIs and labels belong to all the addresses of the trace. pub trait TraceIdentifier { /// Attempts to identify an address in one or more call traces. - fn identify_addresses<'a, A>(&mut self, addresses: A) -> Vec> - where - A: Iterator, Option<&'a [u8]>)> + Clone; + fn identify_addresses(&mut self, nodes: &[&CallTraceNode]) -> Vec>; } /// A collection of trace identifiers. @@ -53,16 +52,16 @@ impl Default for TraceIdentifiers<'_> { } impl TraceIdentifier for TraceIdentifiers<'_> { - fn identify_addresses<'a, A>(&mut self, addresses: A) -> Vec> - where - A: Iterator, Option<&'a [u8]>)> + Clone, - { - let mut identities = Vec::new(); + fn identify_addresses(&mut self, nodes: &[&CallTraceNode]) -> Vec> { + let mut identities = Vec::with_capacity(nodes.len()); if let Some(local) = &mut self.local { - identities.extend(local.identify_addresses(addresses.clone())); + identities.extend(local.identify_addresses(nodes)); + if identities.len() >= nodes.len() { + return identities; + } } if let Some(etherscan) = &mut self.etherscan { - identities.extend(etherscan.identify_addresses(addresses)); + identities.extend(etherscan.identify_addresses(nodes)); } identities } diff --git a/crates/evm/traces/src/identifier/signatures.rs b/crates/evm/traces/src/identifier/signatures.rs index d1c6f61aa3571..549430cf67df4 100644 --- a/crates/evm/traces/src/identifier/signatures.rs +++ b/crates/evm/traces/src/identifier/signatures.rs @@ -1,176 +1,269 @@ -use alloy_json_abi::{Error, Event, Function}; -use alloy_primitives::{hex, map::HashSet}; +use alloy_json_abi::{Error, Event, Function, JsonAbi}; +use alloy_primitives::{map::HashMap, Selector, B256}; +use eyre::Result; use foundry_common::{ abi::{get_error, get_event, get_func}, fs, - selectors::{OpenChainClient, SelectorType}, + selectors::{OpenChainClient, SelectorKind}, }; +use foundry_config::Config; use serde::{Deserialize, Serialize}; -use std::{collections::BTreeMap, path::PathBuf, sync::Arc}; +use std::{ + collections::BTreeMap, + path::{Path, PathBuf}, + sync::Arc, +}; use tokio::sync::RwLock; -pub type SingleSignaturesIdentifier = Arc>; +/// Cache for function, event and error signatures. Used by [`SignaturesIdentifier`]. +#[derive(Debug, Default, Deserialize)] +#[serde(try_from = "SignaturesDiskCache")] +pub struct SignaturesCache { + signatures: HashMap>, +} + +/// Disk representation of the signatures cache. +#[derive(Serialize, Deserialize)] +struct SignaturesDiskCache { + functions: BTreeMap, + errors: BTreeMap, + events: BTreeMap, +} + +impl From for SignaturesCache { + fn from(value: SignaturesDiskCache) -> Self { + let functions = value + .functions + .into_iter() + .map(|(selector, signature)| (SelectorKind::Function(selector), signature)); + let errors = value + .errors + .into_iter() + .map(|(selector, signature)| (SelectorKind::Error(selector), signature)); + let events = value + .events + .into_iter() + .map(|(selector, signature)| (SelectorKind::Event(selector), signature)); + Self { + signatures: functions + .chain(errors) + .chain(events) + .map(|(sel, sig)| (sel, (!sig.is_empty()).then_some(sig))) + .collect(), + } + } +} + +impl From<&SignaturesCache> for SignaturesDiskCache { + fn from(value: &SignaturesCache) -> Self { + let (functions, errors, events) = value.signatures.iter().fold( + (BTreeMap::new(), BTreeMap::new(), BTreeMap::new()), + |mut acc, (kind, signature)| { + let value = signature.clone().unwrap_or_default(); + match *kind { + SelectorKind::Function(selector) => _ = acc.0.insert(selector, value), + SelectorKind::Error(selector) => _ = acc.1.insert(selector, value), + SelectorKind::Event(selector) => _ = acc.2.insert(selector, value), + } + acc + }, + ); + Self { functions, errors, events } + } +} -#[derive(Debug, Default, Serialize, Deserialize)] -pub struct CachedSignatures { - pub errors: BTreeMap, - pub events: BTreeMap, - pub functions: BTreeMap, +impl Serialize for SignaturesCache { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + SignaturesDiskCache::from(self).serialize(serializer) + } } -impl CachedSignatures { +impl SignaturesCache { + /// Loads the cache from a file. #[instrument(target = "evm::traces")] - pub fn load(cache_path: PathBuf) -> Self { - let path = cache_path.join("signatures"); - if path.is_file() { - fs::read_json_file(&path) - .map_err( - |err| warn!(target: "evm::traces", ?path, ?err, "failed to read cache file"), - ) - .unwrap_or_default() - } else { - if let Err(err) = std::fs::create_dir_all(cache_path) { - warn!(target: "evm::traces", "could not create signatures cache dir: {:?}", err); + pub fn load(path: &Path) -> Self { + trace!(target: "evm::traces", ?path, "reading signature cache"); + fs::read_json_file(path) + .inspect_err( + |err| warn!(target: "evm::traces", ?path, ?err, "failed to read cache file"), + ) + .unwrap_or_default() + } + + /// Saves the cache to a file. + #[instrument(target = "evm::traces", skip(self))] + pub fn save(&self, path: &Path) { + if let Some(parent) = path.parent() { + if let Err(err) = std::fs::create_dir_all(parent) { + warn!(target: "evm::traces", ?parent, %err, "failed to create cache"); } - Self::default() } + if let Err(err) = fs::write_json_file(path, self) { + warn!(target: "evm::traces", %err, "failed to flush signature cache"); + } else { + trace!(target: "evm::traces", "flushed signature cache") + } + } + + /// Updates the cache from an ABI. + pub fn extend_from_abi(&mut self, abi: &JsonAbi) { + self.extend(abi.items().filter_map(|item| match item { + alloy_json_abi::AbiItem::Function(f) => { + Some((SelectorKind::Function(f.selector()), f.signature())) + } + alloy_json_abi::AbiItem::Error(e) => { + Some((SelectorKind::Error(e.selector()), e.signature())) + } + alloy_json_abi::AbiItem::Event(e) => { + Some((SelectorKind::Event(e.selector()), e.full_signature())) + } + _ => None, + })); + } + + /// Inserts a single signature into the cache. + pub fn insert(&mut self, key: SelectorKind, value: String) { + self.extend(std::iter::once((key, value))); + } + + /// Extends the cache with multiple signatures. + pub fn extend(&mut self, signatures: impl IntoIterator) { + self.signatures + .extend(signatures.into_iter().map(|(k, v)| (k, (!v.is_empty()).then_some(v)))); + } + + /// Gets a signature from the cache. + pub fn get(&self, key: &SelectorKind) -> Option> { + self.signatures.get(key).cloned() + } + + /// Returns true if the cache contains a signature. + pub fn contains_key(&self, key: &SelectorKind) -> bool { + self.signatures.contains_key(key) } } + /// An identifier that tries to identify functions and events using signatures found at /// `https://openchain.xyz` or a local cache. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct SignaturesIdentifier { /// Cached selectors for functions, events and custom errors. - cached: CachedSignatures, - /// Location where to save `CachedSignatures`. - cached_path: Option, - /// Selectors that were unavailable during the session. - unavailable: HashSet, - /// The OpenChain client to fetch signatures from. + cache: Arc>, + /// Location where to save the signature cache. + cache_path: Option, + /// The OpenChain client to fetch signatures from. `None` if disabled on construction. client: Option, } impl SignaturesIdentifier { - #[instrument(target = "evm::traces")] - pub fn new( - cache_path: Option, - offline: bool, - ) -> eyre::Result { - let client = if !offline { Some(OpenChainClient::new()?) } else { None }; - - let identifier = if let Some(cache_path) = cache_path { - let path = cache_path.join("signatures"); - trace!(target: "evm::traces", ?path, "reading signature cache"); - let cached = CachedSignatures::load(cache_path); - Self { cached, cached_path: Some(path), unavailable: HashSet::default(), client } - } else { - Self { - cached: Default::default(), - cached_path: None, - unavailable: HashSet::default(), - client, - } - }; - - Ok(Arc::new(RwLock::new(identifier))) + /// Creates a new `SignaturesIdentifier` with the default cache directory. + pub fn new(offline: bool) -> Result { + Self::new_with(Config::foundry_cache_dir().as_deref(), offline) } - #[instrument(target = "evm::traces", skip(self))] - pub fn save(&self) { - if let Some(cached_path) = &self.cached_path { - if let Some(parent) = cached_path.parent() { - if let Err(err) = std::fs::create_dir_all(parent) { - warn!(target: "evm::traces", ?parent, ?err, "failed to create cache"); - } - } - if let Err(err) = fs::write_json_file(cached_path, &self.cached) { - warn!(target: "evm::traces", ?cached_path, ?err, "failed to flush signature cache"); - } else { - trace!(target: "evm::traces", ?cached_path, "flushed signature cache") - } - } + /// Creates a new `SignaturesIdentifier` from the global configuration. + pub fn from_config(config: &Config) -> Result { + Self::new(config.offline) } -} -impl SignaturesIdentifier { - async fn identify( - &mut self, - selector_type: SelectorType, - identifiers: impl IntoIterator>, - get_type: impl Fn(&str) -> eyre::Result, - ) -> Vec> { - let cache = match selector_type { - SelectorType::Function => &mut self.cached.functions, - SelectorType::Event => &mut self.cached.events, - SelectorType::Error => &mut self.cached.errors, + /// Creates a new `SignaturesIdentifier`. + /// + /// - `cache_dir` is the cache directory to store the signatures. + /// - `offline` disables the OpenChain client. + pub fn new_with(cache_dir: Option<&Path>, offline: bool) -> Result { + let client = if !offline { Some(OpenChainClient::new()?) } else { None }; + let (cache, cache_path) = if let Some(cache_dir) = cache_dir { + let path = cache_dir.join("signatures"); + let cache = SignaturesCache::load(&path); + (cache, Some(path)) + } else { + Default::default() }; + Ok(Self { cache: Arc::new(RwLock::new(cache)), cache_path, client }) + } - let hex_identifiers: Vec = - identifiers.into_iter().map(hex::encode_prefixed).collect(); - - if let Some(client) = &self.client { - let query: Vec<_> = hex_identifiers - .iter() - .filter(|v| !cache.contains_key(v.as_str())) - .filter(|v| !self.unavailable.contains(v.as_str())) - .collect(); - - if let Ok(res) = client.decode_selectors(selector_type, query.clone()).await { - for (hex_id, selector_result) in query.into_iter().zip(res.into_iter()) { - let mut found = false; - if let Some(decoded_results) = selector_result { - if let Some(decoded_result) = decoded_results.into_iter().next() { - cache.insert(hex_id.clone(), decoded_result); - found = true; - } - } - if !found { - self.unavailable.insert(hex_id.clone()); - } - } - } + /// Saves the cache to the file system. + pub fn save(&self) { + if let Some(path) = &self.cache_path { + foundry_compilers::utils::RuntimeOrHandle::new().block_on(self.cache.read()).save(path); } - - hex_identifiers.iter().map(|v| cache.get(v).and_then(|v| get_type(v).ok())).collect() } - /// Identifies `Function`s from its cache or `https://api.openchain.xyz` + /// Identifies `Function`s. pub async fn identify_functions( - &mut self, - identifiers: impl IntoIterator>, + &self, + identifiers: impl IntoIterator, ) -> Vec> { - self.identify(SelectorType::Function, identifiers, get_func).await + self.identify_map(identifiers.into_iter().map(SelectorKind::Function), get_func).await } - /// Identifies `Function` from its cache or `https://api.openchain.xyz` - pub async fn identify_function(&mut self, identifier: &[u8]) -> Option { - self.identify_functions(&[identifier]).await.pop().unwrap() + /// Identifies a `Function`. + pub async fn identify_function(&self, identifier: Selector) -> Option { + self.identify_functions([identifier]).await.pop().unwrap() } - /// Identifies `Event`s from its cache or `https://api.openchain.xyz` + /// Identifies `Event`s. pub async fn identify_events( - &mut self, - identifiers: impl IntoIterator>, + &self, + identifiers: impl IntoIterator, ) -> Vec> { - self.identify(SelectorType::Event, identifiers, get_event).await + self.identify_map(identifiers.into_iter().map(SelectorKind::Event), get_event).await } - /// Identifies `Event` from its cache or `https://api.openchain.xyz` - pub async fn identify_event(&mut self, identifier: &[u8]) -> Option { - self.identify_events(&[identifier]).await.pop().unwrap() + /// Identifies an `Event`. + pub async fn identify_event(&self, identifier: B256) -> Option { + self.identify_events([identifier]).await.pop().unwrap() } - /// Identifies `Error`s from its cache or `https://api.openchain.xyz`. + /// Identifies `Error`s. pub async fn identify_errors( - &mut self, - identifiers: impl IntoIterator>, + &self, + identifiers: impl IntoIterator, ) -> Vec> { - self.identify(SelectorType::Error, identifiers, get_error).await + self.identify_map(identifiers.into_iter().map(SelectorKind::Error), get_error).await + } + + /// Identifies an `Error`. + pub async fn identify_error(&self, identifier: Selector) -> Option { + self.identify_errors([identifier]).await.pop().unwrap() + } + + /// Identifies a list of selectors. + pub async fn identify(&self, selectors: &[SelectorKind]) -> Vec> { + if selectors.is_empty() { + return vec![]; + } + trace!(target: "evm::traces", ?selectors, "identifying selectors"); + + let mut cache_r = self.cache.read().await; + if let Some(client) = &self.client { + let query = + selectors.iter().copied().filter(|v| !cache_r.contains_key(v)).collect::>(); + if !query.is_empty() { + drop(cache_r); + let mut cache_w = self.cache.write().await; + if let Ok(res) = client.decode_selectors(&query).await { + for (selector, signatures) in std::iter::zip(query, res) { + cache_w.signatures.insert(selector, signatures.into_iter().next()); + } + } + drop(cache_w); + cache_r = self.cache.read().await; + } + } + selectors.iter().map(|selector| cache_r.get(selector).unwrap_or_default()).collect() } - /// Identifies `Error` from its cache or `https://api.openchain.xyz`. - pub async fn identify_error(&mut self, identifier: &[u8]) -> Option { - self.identify_errors(&[identifier]).await.pop().unwrap() + async fn identify_map( + &self, + selectors: impl IntoIterator, + get_type: impl Fn(&str) -> Result, + ) -> Vec> { + let results = self.identify(&Vec::from_iter(selectors)).await; + results.into_iter().map(|r| r.and_then(|r| get_type(&r).ok())).collect() } } diff --git a/crates/evm/traces/src/lib.rs b/crates/evm/traces/src/lib.rs index 0d22352ca9e3b..2107644793463 100644 --- a/crates/evm/traces/src/lib.rs +++ b/crates/evm/traces/src/lib.rs @@ -42,7 +42,7 @@ pub use revm_inspectors::tracing::{ /// /// Identifiers figure out what ABIs and labels belong to all the addresses of the trace. pub mod identifier; -use identifier::{LocalTraceIdentifier, TraceIdentifier}; +use identifier::LocalTraceIdentifier; mod decoder; pub use decoder::{CallTraceDecoder, CallTraceDecoderBuilder}; @@ -174,14 +174,9 @@ impl DerefMut for SparsedTraceArena { /// Decode a collection of call traces. /// /// The traces will be decoded using the given decoder, if possible. -pub async fn decode_trace_arena( - arena: &mut CallTraceArena, - decoder: &CallTraceDecoder, -) -> Result<(), std::fmt::Error> { +pub async fn decode_trace_arena(arena: &mut CallTraceArena, decoder: &CallTraceDecoder) { decoder.prefetch_signatures(arena.nodes()).await; decoder.populate_traces(arena.nodes_mut()).await; - - Ok(()) } /// Render a collection of call traces to a string. @@ -260,7 +255,7 @@ pub fn load_contracts<'a>( let decoder = CallTraceDecoder::new(); let mut contracts = ContractsByAddress::new(); for trace in traces { - for address in local_identifier.identify_addresses(decoder.trace_addresses(trace)) { + for address in decoder.identify_addresses(trace, &mut local_identifier) { if let (Some(contract), Some(abi)) = (address.contract, address.abi) { contracts.insert(address.address, (contract, abi.into_owned())); } diff --git a/crates/forge/src/cmd/selectors.rs b/crates/forge/src/cmd/selectors.rs index c3d0b67eda930..5e858c9da9c58 100644 --- a/crates/forge/src/cmd/selectors.rs +++ b/crates/forge/src/cmd/selectors.rs @@ -95,7 +95,7 @@ impl SelectorsSubcommands { // compile the project to get the artifacts/abis let project = build_args.project()?; let outcome = ProjectCompiler::new().quiet(true).compile(&project)?; - cache_local_signatures(&outcome, Config::foundry_cache_dir().unwrap())? + cache_local_signatures(&outcome, &Config::foundry_cache_dir().unwrap())? } Self::Upload { contract, all, project_paths } => { let build_args = BuildOpts { diff --git a/crates/forge/src/cmd/test/mod.rs b/crates/forge/src/cmd/test/mod.rs index bf45088dc1000..a1f3e64bb574f 100644 --- a/crates/forge/src/cmd/test/mod.rs +++ b/crates/forge/src/cmd/test/mod.rs @@ -368,7 +368,7 @@ impl TestArgs { // Decode traces. let decoder = outcome.last_run_decoder.as_ref().unwrap(); - decode_trace_arena(arena, decoder).await?; + decode_trace_arena(arena, decoder).await; let mut fst = folded_stack_trace::build(arena); let label = if self.flamegraph { "flamegraph" } else { "flamechart" }; @@ -524,10 +524,8 @@ impl TestArgs { .with_verbosity(verbosity); // Signatures are of no value for gas reports. if !self.gas_report { - builder = builder.with_signature_identifier(SignaturesIdentifier::new( - Config::foundry_cache_dir(), - config.offline, - )?); + builder = + builder.with_signature_identifier(SignaturesIdentifier::from_config(&config)?); } if self.decode_internal { @@ -637,7 +635,7 @@ impl TestArgs { }; if should_include { - decode_trace_arena(arena, &decoder).await?; + decode_trace_arena(arena, &decoder).await; decoded_traces.push(render_trace_arena_inner(arena, false, verbosity > 4)); } } diff --git a/crates/forge/tests/it/config.rs b/crates/forge/tests/it/config.rs index 390735b3245ec..022303d51380f 100644 --- a/crates/forge/tests/it/config.rs +++ b/crates/forge/tests/it/config.rs @@ -77,9 +77,7 @@ impl TestConfig { let decoded_traces = join_all(result.traces.iter_mut().map(|(_, arena)| { let decoder = &call_trace_decoder; async move { - decode_trace_arena(arena, decoder) - .await - .expect("Failed to decode traces"); + decode_trace_arena(arena, decoder).await; render_trace_arena(arena) } })) diff --git a/crates/script/src/execute.rs b/crates/script/src/execute.rs index 1073f7cc6bd95..48d37cfca4329 100644 --- a/crates/script/src/execute.rs +++ b/crates/script/src/execute.rs @@ -20,7 +20,7 @@ use foundry_common::{ provider::get_http_provider, ContractsByArtifact, }; -use foundry_config::{Config, NamedChain}; +use foundry_config::NamedChain; use foundry_debugger::Debugger; use foundry_evm::{ decode::decode_console_logs, @@ -328,9 +328,8 @@ impl ExecutedState { .with_labels(self.execution_result.labeled_addresses.clone()) .with_verbosity(self.script_config.evm_opts.verbosity) .with_known_contracts(known_contracts) - .with_signature_identifier(SignaturesIdentifier::new( - Config::foundry_cache_dir(), - self.script_config.config.offline, + .with_signature_identifier(SignaturesIdentifier::from_config( + &self.script_config.config, )?) .build(); @@ -428,7 +427,7 @@ impl PreSimulationState { if should_include { let mut trace = trace.clone(); - decode_trace_arena(&mut trace, decoder).await?; + decode_trace_arena(&mut trace, decoder).await; sh_println!("{}", render_trace_arena(&trace))?; } } diff --git a/crates/script/src/simulate.rs b/crates/script/src/simulate.rs index a58b1058ebc2e..7cd23ee74bace 100644 --- a/crates/script/src/simulate.rs +++ b/crates/script/src/simulate.rs @@ -168,7 +168,7 @@ impl PreSimulationState { // Transaction will be `None`, if execution didn't pass. if tx.is_none() || self.script_config.evm_opts.verbosity > 3 { for (_, trace) in &mut traces { - decode_trace_arena(trace, &self.execution_artifacts.decoder).await?; + decode_trace_arena(trace, &self.execution_artifacts.decoder).await; sh_println!("{}", render_trace_arena(trace))?; } } diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index 17d6036ac5bcd..42d7e4f6a855e 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -774,7 +774,7 @@ pub struct TestCommand { /// The actual command we use to control the process. cmd: Command, // initial: Command, - current_dir_lock: Option>, + current_dir_lock: Option>, stdin_fun: Option>, /// If true, command output is redacted. redact_output: bool, From bfb1cb6b118b7e07a1de0fdea64a6cf44eb3a174 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 11 Apr 2025 07:36:36 +0200 Subject: [PATCH 008/244] fix: add workaround for unlinked artifacts (#10291) * fix: add workaround for unlinked artifacts * clippy --- Cargo.lock | 1 + crates/sol-macro-gen/Cargo.toml | 1 + crates/sol-macro-gen/src/sol_macro_gen.rs | 33 ++++++++++++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index c8e6545369bf6..3126a4f12d8a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3638,6 +3638,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", + "serde_json", "syn 2.0.100", ] diff --git a/crates/sol-macro-gen/Cargo.toml b/crates/sol-macro-gen/Cargo.toml index 2010fe3a569b6..79b47880f33f9 100644 --- a/crates/sol-macro-gen/Cargo.toml +++ b/crates/sol-macro-gen/Cargo.toml @@ -23,5 +23,6 @@ proc-macro2.workspace = true quote.workspace = true syn.workspace = true prettyplease.workspace = true +serde_json.workspace = true eyre.workspace = true diff --git a/crates/sol-macro-gen/src/sol_macro_gen.rs b/crates/sol-macro-gen/src/sol_macro_gen.rs index ad30580f6c3f4..133f4ed218f9b 100644 --- a/crates/sol-macro-gen/src/sol_macro_gen.rs +++ b/crates/sol-macro-gen/src/sol_macro_gen.rs @@ -15,6 +15,7 @@ use eyre::{Context, OptionExt, Result}; use foundry_common::fs; use proc_macro2::{Span, TokenStream}; use std::{ + env::temp_dir, fmt::Write, path::{Path, PathBuf}, str::FromStr, @@ -82,7 +83,37 @@ impl MultiSolMacroGen { } fn generate_binding(instance: &mut SolMacroGen, all_derives: bool) -> Result<()> { - let input = instance.get_sol_input()?.normalize_json()?; + // TODO: in `get_sol_input` we currently can't handle unlinked bytecode: + let input = match instance.get_sol_input() { + Ok(input) => input.normalize_json()?, + Err(error) => { + // TODO(mattsse): remove after + if error.to_string().contains("expected bytecode, found unlinked bytecode") { + // we attempt to do a little hack here until we have this properly supported by + // removing the bytecode objects from the json file and using a tmpfile (very + // hacky) + let content = std::fs::read_to_string(&instance.path)?; + let mut value = serde_json::from_str::(&content)?; + let obj = value.as_object_mut().expect("valid abi"); + + // clear unlinked bytecode + obj.remove("bytecode"); + obj.remove("deployedBytecode"); + + let tmpdir = temp_dir(); + let mut tmp_file = tmpdir.join(instance.path.file_name().unwrap()); + std::fs::write(&tmp_file, serde_json::to_string(&value)?)?; + + // try again + std::mem::swap(&mut tmp_file, &mut instance.path); + let input = instance.get_sol_input()?.normalize_json()?; + std::mem::swap(&mut tmp_file, &mut instance.path); + input.normalize_json()? + } else { + return Err(error) + } + } + }; let SolInput { attrs: _, path: _, kind } = input; From 8f38753bc3ae9704c69466740226f78c8003ceae Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:14:05 +0300 Subject: [PATCH 009/244] chore: bump upcoming version 1.1.0 (#10292) --- Cargo.lock | 60 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3126a4f12d8a6..88e94e4ca5bf5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -958,7 +958,7 @@ dependencies = [ [[package]] name = "anvil" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-chains", "alloy-consensus", @@ -1018,7 +1018,7 @@ dependencies = [ [[package]] name = "anvil-core" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -1042,7 +1042,7 @@ dependencies = [ [[package]] name = "anvil-rpc" -version = "1.0.0" +version = "1.1.0" dependencies = [ "serde", "serde_json", @@ -1050,7 +1050,7 @@ dependencies = [ [[package]] name = "anvil-server" -version = "1.0.0" +version = "1.1.0" dependencies = [ "anvil-rpc", "async-trait", @@ -2098,7 +2098,7 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "cast" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-chains", "alloy-consensus", @@ -2193,7 +2193,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chisel" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -3448,7 +3448,7 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "forge" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-chains", "alloy-dyn-abi", @@ -3530,7 +3530,7 @@ dependencies = [ [[package]] name = "forge-doc" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-primitives", "derive_more 2.0.1", @@ -3553,7 +3553,7 @@ dependencies = [ [[package]] name = "forge-fmt" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-primitives", "ariadne", @@ -3569,7 +3569,7 @@ dependencies = [ [[package]] name = "forge-script" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-chains", "alloy-consensus", @@ -3613,7 +3613,7 @@ dependencies = [ [[package]] name = "forge-script-sequence" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-network", "alloy-primitives", @@ -3629,7 +3629,7 @@ dependencies = [ [[package]] name = "forge-sol-macro-gen" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -3644,7 +3644,7 @@ dependencies = [ [[package]] name = "forge-verify" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -3705,7 +3705,7 @@ dependencies = [ [[package]] name = "foundry-cheatcodes" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -3752,7 +3752,7 @@ dependencies = [ [[package]] name = "foundry-cheatcodes-spec" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-sol-types", "foundry-macros", @@ -3763,7 +3763,7 @@ dependencies = [ [[package]] name = "foundry-cli" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-chains", "alloy-dyn-abi", @@ -3802,7 +3802,7 @@ dependencies = [ [[package]] name = "foundry-common" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-consensus", "alloy-contract", @@ -3857,7 +3857,7 @@ dependencies = [ [[package]] name = "foundry-common-fmt" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -3986,7 +3986,7 @@ dependencies = [ [[package]] name = "foundry-config" -version = "1.0.0" +version = "1.1.0" dependencies = [ "Inflector", "alloy-chains", @@ -4023,7 +4023,7 @@ dependencies = [ [[package]] name = "foundry-debugger" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-primitives", "crossterm", @@ -4041,7 +4041,7 @@ dependencies = [ [[package]] name = "foundry-evm" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4068,7 +4068,7 @@ dependencies = [ [[package]] name = "foundry-evm-abi" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -4080,7 +4080,7 @@ dependencies = [ [[package]] name = "foundry-evm-core" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -4114,7 +4114,7 @@ dependencies = [ [[package]] name = "foundry-evm-coverage" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-primitives", "eyre", @@ -4129,7 +4129,7 @@ dependencies = [ [[package]] name = "foundry-evm-fuzz" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4153,7 +4153,7 @@ dependencies = [ [[package]] name = "foundry-evm-traces" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4203,7 +4203,7 @@ dependencies = [ [[package]] name = "foundry-linking" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-primitives", "foundry-compilers", @@ -4213,7 +4213,7 @@ dependencies = [ [[package]] name = "foundry-macros" -version = "1.0.0" +version = "1.1.0" dependencies = [ "proc-macro-error", "proc-macro2", @@ -4223,7 +4223,7 @@ dependencies = [ [[package]] name = "foundry-test-utils" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-primitives", "alloy-provider", @@ -4246,7 +4246,7 @@ dependencies = [ [[package]] name = "foundry-wallets" -version = "1.0.0" +version = "1.1.0" dependencies = [ "alloy-consensus", "alloy-dyn-abi", diff --git a/Cargo.toml b/Cargo.toml index b7d31f092007d..33cb640551a08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ members = [ resolver = "2" [workspace.package] -version = "1.0.0" +version = "1.1.0" edition = "2021" # Remember to update clippy.toml as well rust-version = "1.83" From 2564718bbbddb59cd07fc3b9ffc775dff548c558 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Fri, 11 Apr 2025 20:49:23 +0200 Subject: [PATCH 010/244] test: add a test case for RevertDecoder (#10294) --- crates/evm/core/src/decode.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/crates/evm/core/src/decode.rs b/crates/evm/core/src/decode.rs index 2a3581360e007..7c8a03da3e300 100644 --- a/crates/evm/core/src/decode.rs +++ b/crates/evm/core/src/decode.rs @@ -245,6 +245,7 @@ fn trimmed_hex(s: &[u8]) -> String { #[cfg(test)] mod tests { use super::*; + #[test] fn test_trimmed_hex() { assert_eq!(trimmed_hex(&hex::decode("1234567890").unwrap()), "1234567890"); @@ -253,4 +254,35 @@ mod tests { "49207769736820727573742073757070…6865722d6b696e646564207479706573 (41 bytes)" ); } + + // https://github.com/foundry-rs/foundry/issues/10162 + #[test] + fn partial_decode() { + /* + error ValidationFailed(bytes); + error InvalidNonce(); + */ + let mut decoder = RevertDecoder::default(); + decoder.push_error("ValidationFailed(bytes)".parse().unwrap()); + + /* + abi.encodeWithSelector(ValidationFailed.selector, InvalidNonce.selector) + */ + let data = &hex!( + "0xe17594de" + "756688fe00000000000000000000000000000000000000000000000000000000" + ); + assert_eq!(decoder.decode(data, None), "ValidationFailed(0x)"); + + /* + abi.encodeWithSelector(ValidationFailed.selector, abi.encodeWithSelector(InvalidNonce.selector)) + */ + let data = &hex!( + "0xe17594de" + "0000000000000000000000000000000000000000000000000000000000000020" + "0000000000000000000000000000000000000000000000000000000000000004" + "756688fe00000000000000000000000000000000000000000000000000000000" + ); + assert_eq!(decoder.decode(data, None), "ValidationFailed(0x756688fe)"); + } } From f0e24fb6cfc9018d986d3136ab00aa5077994994 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 15 Apr 2025 02:29:04 +0000 Subject: [PATCH 011/244] chore(deps): weekly `cargo update` (#10297) Locking 19 packages to latest compatible versions Unchanged alloy-chains v0.1.69 (available: v0.2.0) Unchanged alloy-consensus v0.12.6 (available: v0.14.0) Unchanged alloy-contract v0.12.6 (available: v0.14.0) Unchanged alloy-dyn-abi v0.8.25 (available: v1.0.0) Unchanged alloy-eips v0.12.6 (available: v0.14.0) Unchanged alloy-genesis v0.12.6 (available: v0.14.0) Unchanged alloy-json-abi v0.8.25 (available: v1.0.0) Unchanged alloy-json-rpc v0.12.6 (available: v0.14.0) Unchanged alloy-network v0.12.6 (available: v0.14.0) Unchanged alloy-primitives v0.8.25 (available: v1.0.0) Unchanged alloy-provider v0.12.6 (available: v0.14.0) Unchanged alloy-pubsub v0.12.6 (available: v0.14.0) Unchanged alloy-rpc-client v0.12.6 (available: v0.14.0) Unchanged alloy-rpc-types v0.12.6 (available: v0.14.0) Unchanged alloy-serde v0.12.6 (available: v0.14.0) Unchanged alloy-signer v0.12.6 (available: v0.14.0) Unchanged alloy-signer-aws v0.12.6 (available: v0.14.0) Unchanged alloy-signer-gcp v0.12.6 (available: v0.14.0) Unchanged alloy-signer-ledger v0.12.6 (available: v0.14.0) Unchanged alloy-signer-local v0.12.6 (available: v0.14.0) Unchanged alloy-signer-trezor v0.12.6 (available: v0.14.0) Unchanged alloy-sol-macro-expander v0.8.25 (available: v1.0.0) Unchanged alloy-sol-macro-input v0.8.25 (available: v1.0.0) Unchanged alloy-sol-types v0.8.25 (available: v1.0.0) Unchanged alloy-transport v0.12.6 (available: v0.14.0) Unchanged alloy-transport-http v0.12.6 (available: v0.14.0) Unchanged alloy-transport-ipc v0.12.6 (available: v0.14.0) Unchanged alloy-transport-ws v0.12.6 (available: v0.14.0) Unchanged alloy-trie v0.7.9 (available: v0.8.0) Updating auto_impl v1.2.1 -> v1.3.0 Unchanged axum v0.7.9 (available: v0.8.3) Unchanged backtrace v0.3.71 (available: v0.3.74) Updating bon v3.5.1 -> v3.5.2 Updating bon-macros v3.5.1 -> v3.5.2 Updating bstr v1.11.3 -> v1.12.0 Updating cc v1.2.18 -> v1.2.19 Updating clap v4.5.35 -> v4.5.36 Updating clap_builder v4.5.35 -> v4.5.36 Unchanged crossterm v0.28.1 (available: v0.29.0) Updating data-encoding v2.8.0 -> v2.9.0 Updating fs4 v0.12.0 -> v0.13.1 Unchanged gcloud-sdk v0.26.4 (available: v0.27.0) Updating half v2.5.0 -> v2.6.0 Updating jiff v0.2.5 -> v0.2.6 Updating jiff-static v0.2.5 -> v0.2.6 Updating linux-raw-sys v0.9.3 -> v0.9.4 Updating miniz_oxide v0.8.7 -> v0.8.8 Unchanged op-alloy-consensus v0.11.4 (available: v0.13.0) Unchanged op-alloy-rpc-types v0.11.4 (available: v0.13.0) Unchanged protobuf v3.3.0 (available: v3.7.2) Unchanged protobuf-support v3.3.0 (available: v3.7.2) Unchanged rand v0.8.5 (available: v0.9.0) Unchanged revm v19.7.0 (available: v22.0.0) Unchanged revm-inspectors v0.16.0 (available: v0.19.0) Unchanged revm-primitives v15.2.0 (available: v18.0.0) Updating rustls v0.23.25 -> v0.23.26 Unchanged solang-parser v0.3.3 (available: v0.3.4) Updating svm-rs v0.5.14 -> v0.5.15 Updating svm-rs-builds v0.5.14 -> v0.5.15 Unchanged vergen v8.3.2 (available: v9.0.6) Updating which v7.0.2 -> v7.0.3 Updating winnow v0.7.4 -> v0.7.6 note: to see how you depend on a package, run `cargo tree --invert --package @` Co-authored-by: mattsse <19890894+mattsse@users.noreply.github.com> --- Cargo.lock | 96 +++++++++++++++++++++++++++--------------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 88e94e4ca5bf5..6053ca5c01566 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -161,7 +161,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "winnow 0.7.4", + "winnow 0.7.6", ] [[package]] @@ -738,7 +738,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d162f8524adfdfb0e4bd0505c734c985f3e2474eb022af32eef0d52a4f3935c" dependencies = [ "serde", - "winnow 0.7.4", + "winnow 0.7.6", ] [[package]] @@ -1346,9 +1346,9 @@ dependencies = [ [[package]] name = "auto_impl" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73" +checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", @@ -1963,9 +1963,9 @@ dependencies = [ [[package]] name = "bon" -version = "3.5.1" +version = "3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65268237be94042665b92034f979c42d431d2fd998b49809543afe3e66abad1c" +checksum = "92c5f8abc69af414cbd6f2103bb668b91e584072f2105e4b38bed79b6ad0975f" dependencies = [ "bon-macros", "rustversion", @@ -1973,9 +1973,9 @@ dependencies = [ [[package]] name = "bon-macros" -version = "3.5.1" +version = "3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "803c95b2ecf650eb10b5f87dda6b9f6a1b758cee53245e2b7b825c9b3803a443" +checksum = "b69edf39b6f321cb2699a93fc20c256adb839719c42676d03f7aa975e4e5581d" dependencies = [ "darling", "ident_case", @@ -1998,9 +1998,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.11.3" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", "regex-automata 0.4.9", @@ -2161,9 +2161,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.18" +version = "1.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" +checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" dependencies = [ "jobserver", "libc", @@ -2290,9 +2290,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.35" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" +checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04" dependencies = [ "clap_builder", "clap_derive", @@ -2310,9 +2310,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.35" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" +checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5" dependencies = [ "anstream", "anstyle", @@ -2369,7 +2369,7 @@ dependencies = [ "nix 0.29.0", "terminfo", "thiserror 2.0.12", - "which 7.0.2", + "which 7.0.3", "windows-sys 0.59.0", ] @@ -2824,9 +2824,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "dbus" @@ -3431,7 +3431,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", - "miniz_oxide 0.8.7", + "miniz_oxide 0.8.8", ] [[package]] @@ -3909,7 +3909,7 @@ dependencies = [ "thiserror 2.0.12", "tokio", "tracing", - "winnow 0.7.4", + "winnow 0.7.6", "yansi", ] @@ -4283,12 +4283,12 @@ checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619" [[package]] name = "fs4" -version = "0.12.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c29c30684418547d476f0b48e84f4821639119c483b1eccd566c8cd0cd05f521" +checksum = "8640e34b88f7652208ce9e88b1a37a2ae95227d84abec377ccd3c5cfeb141ed4" dependencies = [ - "rustix 0.38.44", - "windows-sys 0.52.0", + "rustix 1.0.5", + "windows-sys 0.59.0", ] [[package]] @@ -4789,9 +4789,9 @@ dependencies = [ [[package]] name = "half" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "cfg-if", "crunchy", @@ -5517,9 +5517,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c102670231191d07d37a35af3eb77f1f0dbf7a71be51a962dcd57ea607be7260" +checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -5532,9 +5532,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cdde31a9d349f1b1f51a0b3714a5940ac022976f4b49485fc04be052b183b4c" +checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19" dependencies = [ "proc-macro2", "quote", @@ -5774,9 +5774,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" @@ -6029,9 +6029,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] @@ -7736,15 +7736,15 @@ dependencies = [ "bitflags 2.9.0", "errno", "libc", - "linux-raw-sys 0.9.3", + "linux-raw-sys 0.9.4", "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.25" +version = "0.23.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" +checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" dependencies = [ "aws-lc-rs", "log", @@ -8844,9 +8844,9 @@ dependencies = [ [[package]] name = "svm-rs" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c86f1c4a401aa4526c0e823af56a4a967a8b445718cd1b0e87b14375e5bace8" +checksum = "039f8b5327f4c4c94384ad8596cc62fb23f58ef5e5d940945757b627fa56d0c2" dependencies = [ "const-hex", "dirs", @@ -8864,9 +8864,9 @@ dependencies = [ [[package]] name = "svm-rs-builds" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a9b30390308e3c0f7d146d87e2c798409233fe250d849a02fe57d6a9ae6810f" +checksum = "05723cae9acea48e97af3357b25cf0079277bf2ab54405fd3dd62258caae1a48" dependencies = [ "build_const", "const-hex", @@ -9321,7 +9321,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.7.4", + "winnow 0.7.6", ] [[package]] @@ -10141,13 +10141,13 @@ dependencies = [ [[package]] name = "which" -version = "7.0.2" +version = "7.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283" +checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" dependencies = [ "either", "env_home", - "rustix 0.38.44", + "rustix 1.0.5", "winsafe", ] @@ -10588,9 +10588,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" dependencies = [ "memchr", ] From 314eded9b6e801d0870b4c7c2b1d1a57f58d5203 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 15 Apr 2025 10:32:33 +0300 Subject: [PATCH 012/244] fix(forge): do not set balance as apparent value in delegate prank (#10304) --- crates/cheatcodes/src/inspector.rs | 4 +- crates/forge/tests/it/repros.rs | 3 ++ testdata/default/repros/Issue10302.t.sol | 53 ++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 testdata/default/repros/Issue10302.t.sol diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index 719b7b60a83c0..fd60fb1982a7e 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -46,7 +46,7 @@ use proptest::test_runner::{RngAlgorithm, TestRng, TestRunner}; use rand::Rng; use revm::{ interpreter::{ - opcode as op, CallInputs, CallOutcome, CallScheme, CallValue, CreateInputs, CreateOutcome, + opcode as op, CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, EOFCreateInputs, EOFCreateKind, Gas, InstructionResult, Interpreter, InterpreterAction, InterpreterResult, }, @@ -1047,8 +1047,6 @@ where { if let CallScheme::DelegateCall | CallScheme::ExtDelegateCall = call.scheme { call.target_address = prank.new_caller; call.caller = prank.new_caller; - let acc = ecx.journaled_state.account(prank.new_caller); - call.value = CallValue::Apparent(acc.info.balance); if let Some(new_origin) = prank.new_origin { ecx.env.tx.caller = new_origin; } diff --git a/crates/forge/tests/it/repros.rs b/crates/forge/tests/it/repros.rs index 8954619f79a87..550111f92d763 100644 --- a/crates/forge/tests/it/repros.rs +++ b/crates/forge/tests/it/repros.rs @@ -398,3 +398,6 @@ test_repro!(9643); // https://github.com/foundry-rs/foundry/issues/7238 test_repro!(7238); + +// https://github.com/foundry-rs/foundry/issues/10302 +test_repro!(10302); diff --git a/testdata/default/repros/Issue10302.t.sol b/testdata/default/repros/Issue10302.t.sol new file mode 100644 index 0000000000000..c47332cb2872d --- /dev/null +++ b/testdata/default/repros/Issue10302.t.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity ^0.8.18; + +import "ds-test/test.sol"; +import "cheats/Vm.sol"; + +contract A { + function foo() public pure returns (bool) { + return true; + } +} + +contract Issue10302Test is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + function testDelegateFails() external { + vm.createSelectFork("sepolia"); + A a = new A(); + vm.startPrank(0x0fe884546476dDd290eC46318785046ef68a0BA9, true); + (bool success,) = address(a).delegatecall(abi.encodeWithSelector(A.foo.selector)); + vm.stopPrank(); + require(success, "Delegate call should succeed"); + } + + function testDelegatePassesWhenBalanceSetToZero() external { + vm.createSelectFork("sepolia"); + A a = new A(); + vm.startPrank(0x0fe884546476dDd290eC46318785046ef68a0BA9, true); + vm.deal(0x0fe884546476dDd290eC46318785046ef68a0BA9, 0 ether); + (bool success,) = address(a).delegatecall(abi.encodeWithSelector(A.foo.selector)); + vm.stopPrank(); + require(success, "Delegate call should succeed"); + } + + function testDelegateCallSucceeds() external { + vm.createSelectFork("sepolia"); + A a = new A(); + vm.startPrank(0xd363339eE47775888Df411A163c586a8BdEA9dbf, true); + (bool success,) = address(a).delegatecall(abi.encodeWithSelector(A.foo.selector)); + vm.stopPrank(); + require(success, "Delegate call should succeed"); + } + + function testDelegateFailsWhenBalanceGtZero() external { + vm.createSelectFork("sepolia"); + A a = new A(); + vm.startPrank(0xd363339eE47775888Df411A163c586a8BdEA9dbf, true); + vm.deal(0xd363339eE47775888Df411A163c586a8BdEA9dbf, 1 ether); + (bool success,) = address(a).delegatecall(abi.encodeWithSelector(A.foo.selector)); + vm.stopPrank(); + require(success, "Delegate call should succeed"); + } +} From 9e43abbbaef5dc7c4b72206566f9bf5a11d83b86 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 15 Apr 2025 10:38:56 +0300 Subject: [PATCH 013/244] chore: release 1.1.0 - update last stable version (#10303) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 83124ca7e1d5f..6b2c7d5af4e70 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ env: CARGO_TERM_COLOR: always IS_NIGHTLY: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} PROFILE: maxperf - STABLE_VERSION: "v0.3.0" + STABLE_VERSION: "v1.0.0" jobs: prepare: From 8d5c36fb2e951aebac2027d40a1120f6f1769efe Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 15 Apr 2025 10:50:27 +0300 Subject: [PATCH 014/244] fix(docker): build docker aarch64 without jemalloc (#10286) --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 15c7798a2cefb..73cc92cb5c9cd 100644 --- a/Makefile +++ b/Makefile @@ -44,13 +44,13 @@ build-%: .PHONY: docker-build-push docker-build-push: docker-build-prepare ## Build and push a cross-arch Docker image tagged with DOCKER_IMAGE_NAME. - $(MAKE) build-x86_64-unknown-linux-gnu + FEATURES="jemalloc aws-kms cli asm-keccak" $(MAKE) build-x86_64-unknown-linux-gnu mkdir -p $(BIN_DIR)/amd64 for bin in anvil cast chisel forge; do \ cp $(CARGO_TARGET_DIR)/x86_64-unknown-linux-gnu/$(PROFILE)/$$bin $(BIN_DIR)/amd64/; \ done - $(MAKE) build-aarch64-unknown-linux-gnu + FEATURES="aws-kms cli asm-keccak" $(MAKE) build-aarch64-unknown-linux-gnu mkdir -p $(BIN_DIR)/arm64 for bin in anvil cast chisel forge; do \ cp $(CARGO_TARGET_DIR)/aarch64-unknown-linux-gnu/$(PROFILE)/$$bin $(BIN_DIR)/arm64/; \ From b75625abc36152b3fd205a820cd4066ea7316df5 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 15 Apr 2025 10:58:45 +0300 Subject: [PATCH 015/244] fix(forge): ensure selected fork contains init state for persisted accounts (#10301) --- crates/evm/core/src/backend/mod.rs | 8 +++ crates/forge/tests/cli/test_cmd.rs | 79 ++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index 72c6dade5da0f..24eab386ee495 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -1102,6 +1102,14 @@ impl DatabaseExt for Backend { // update the shared state and track let mut fork = self.inner.take_fork(idx); + // Make sure all persistent accounts on the newly selected fork starts from the init + // state (from setup). + for addr in &self.inner.persistent_accounts { + if let Some(account) = self.fork_init_journaled_state.state.get(addr) { + fork.journaled_state.state.insert(*addr, account.clone()); + } + } + // since all forks handle their state separately, the depth can drift // this is a handover where the target fork starts at the same depth where it was // selected. This ensures that there are no gaps in depth which would diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index 497f71f877156..91ee25070bf8c 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -3521,3 +3521,82 @@ contract InterceptInitcodeTest is DSTest { .unwrap(); cmd.args(["test", "-vvvvv"]).assert_success(); }); + +// +forgetest_init!(should_preserve_fork_state_setup, |prj, cmd| { + prj.wipe_contracts(); + prj.add_test( + "Counter.t.sol", + r#" +import "forge-std/Test.sol"; +import {StdChains} from "forge-std/StdChains.sol"; + +contract CounterTest is Test { + struct Domain { + StdChains.Chain chain; + uint256 forkId; + } + + struct Bridge { + Domain source; + Domain destination; + uint256 someVal; + } + + struct SomeStruct { + Domain domain; + Bridge[] bridges; + } + + mapping(uint256 => SomeStruct) internal data; + + function setUp() public { + StdChains.Chain memory chain1 = getChain("mainnet"); + StdChains.Chain memory chain2 = getChain("base"); + Domain memory domain1 = Domain(chain1, vm.createFork(chain1.rpcUrl, 22253716)); + Domain memory domain2 = Domain(chain2, vm.createFork(chain2.rpcUrl, 28839981)); + data[1].domain = domain1; + data[2].domain = domain2; + + vm.selectFork(domain1.forkId); + + data[2].bridges.push(Bridge(domain1, domain2, 123)); + vm.selectFork(data[2].domain.forkId); + vm.selectFork(data[1].domain.forkId); + data[2].bridges.push(Bridge(domain1, domain2, 456)); + + assertEq(data[2].bridges.length, 2); + } + + function test_assert_storage() public { + vm.selectFork(data[2].domain.forkId); + assertEq(data[2].bridges.length, 2); + } + + function test_modify_and_storage() public { + data[3].domain = Domain(getChain("base"), vm.createFork(getChain("base").rpcUrl, 28839981)); + data[3].bridges.push(Bridge(data[1].domain, data[2].domain, 123)); + data[3].bridges.push(Bridge(data[1].domain, data[2].domain, 456)); + + vm.selectFork(data[2].domain.forkId); + assertEq(data[3].bridges.length, 2); + } +} + "#, + ) + .unwrap(); + + cmd.args(["test", "--mc", "CounterTest"]).assert_success().stdout_eq(str![[r#" +[COMPILING_FILES] with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 2 tests for test/Counter.t.sol:CounterTest +[PASS] test_assert_storage() ([GAS]) +[PASS] test_modify_and_storage() ([GAS]) +Suite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests) + +"#]]); +}); From 9932680a604b4bbdfb1f2990e79a38ed9e77d5cd Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 15 Apr 2025 16:59:24 +0200 Subject: [PATCH 016/244] chore(anvil): spawn estimate on blocking task (#10307) --- crates/anvil/src/eth/api.rs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index e7ca2521e1638..406024c270672 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -2659,17 +2659,22 @@ impl EthApi { } } - self.backend - .with_database_at(Some(block_request), |mut state, block| { - if let Some(overrides) = overrides { - state = Box::new(state::apply_state_override( - overrides.into_iter().collect(), - state, - )?); - } - self.do_estimate_gas_with_state(request, &state, block) - }) - .await? + // this can be blocking for a bit, especially in forking mode + // + self.on_blocking_task(|this| async move { + this.backend + .with_database_at(Some(block_request), |mut state, block| { + if let Some(overrides) = overrides { + state = Box::new(state::apply_state_override( + overrides.into_iter().collect(), + state, + )?); + } + this.do_estimate_gas_with_state(request, &state, block) + }) + .await? + }) + .await } /// Estimates the gas usage of the `request` with the state. From a85488af8da141c74325254173baa6a4f1d18d5b Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Tue, 15 Apr 2025 23:52:57 +0800 Subject: [PATCH 017/244] chore: rm redundant clone (#10308) --- crates/script-sequence/src/reader.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/script-sequence/src/reader.rs b/crates/script-sequence/src/reader.rs index 9592795e9a203..abed5f69dd211 100644 --- a/crates/script-sequence/src/reader.rs +++ b/crates/script-sequence/src/reader.rs @@ -115,7 +115,7 @@ impl BroadcastReader { broadcast.transactions.iter().any(move |tx| { let name_filter = - tx.contract_name.clone().is_some_and(|cn| cn == self.contract_name); + tx.contract_name.as_ref().is_some_and(|cn| *cn == self.contract_name); let type_filter = self.tx_type.is_empty() || self.tx_type.contains(&tx.opcode); @@ -149,7 +149,7 @@ impl BroadcastReader { .into_iter() .filter(|tx| { let name_filter = - tx.contract_name.clone().is_some_and(|cn| cn == self.contract_name); + tx.contract_name.as_ref().is_some_and(|cn| *cn == self.contract_name); let type_filter = self.tx_type.is_empty() || self.tx_type.contains(&tx.opcode); From ac724c20f1f938676ed876310a51fe954135a9e1 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Wed, 16 Apr 2025 11:16:42 +0300 Subject: [PATCH 018/244] fix(forge): avoid preprocessor constructor args struct name conflict (#10313) --- crates/common/src/preprocessor/data.rs | 12 +++---- crates/common/src/preprocessor/deps.rs | 2 +- crates/forge/tests/cli/test_optimizer.rs | 45 ++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/crates/common/src/preprocessor/data.rs b/crates/common/src/preprocessor/data.rs index f7a31686e030a..78fe1098fcc56 100644 --- a/crates/common/src/preprocessor/data.rs +++ b/crates/common/src/preprocessor/data.rs @@ -141,13 +141,13 @@ impl ContractData { /// import "lib/openzeppelin-contracts/contracts/token/ERC20.sol"; /// /// abstract contract DeployHelper335 is ERC20 { - /// struct ConstructorArgs { + /// struct FoundryPpConstructorArgs { /// string name; /// string symbol; /// } /// } /// - /// function encodeArgs335(DeployHelper335.ConstructorArgs memory args) pure returns (bytes memory) { + /// function encodeArgs335(DeployHelper335.FoundryPpConstructorArgs memory args) pure returns (bytes memory) { /// return abi.encode(args.name, args.symbol); /// } /// ``` @@ -158,7 +158,7 @@ impl ContractData { /// ``` /// becomes /// ```solidity - /// vm.deployCode("artifact path", encodeArgs335(DeployHelper335.ConstructorArgs(name, symbol))) + /// vm.deployCode("artifact path", encodeArgs335(DeployHelper335.FoundryPpConstructorArgs(name, symbol))) /// ``` /// With named arguments: /// ```solidity @@ -166,7 +166,7 @@ impl ContractData { /// ``` /// becomes /// ```solidity - /// vm.deployCode("artifact path", encodeArgs335(DeployHelper335.ConstructorArgs({name: name, symbol: symbol}))) + /// vm.deployCode("artifact path", encodeArgs335(DeployHelper335.FoundryPpConstructorArgs({name: name, symbol: symbol}))) /// ``` pub fn build_helper(&self) -> Option { let Self { contract_id, path, name, constructor_data, artifact: _ } = self; @@ -183,12 +183,12 @@ pragma solidity >=0.4.0; import "{path}"; abstract contract DeployHelper{contract_id} is {name} {{ - struct ConstructorArgs {{ + struct FoundryPpConstructorArgs {{ {struct_fields}; }} }} -function encodeArgs{contract_id}(DeployHelper{contract_id}.ConstructorArgs memory args) pure returns (bytes memory) {{ +function encodeArgs{contract_id}(DeployHelper{contract_id}.FoundryPpConstructorArgs memory args) pure returns (bytes memory) {{ return abi.encode({abi_encode_args}); }} "#, diff --git a/crates/common/src/preprocessor/deps.rs b/crates/common/src/preprocessor/deps.rs index 2af9d76ba61af..e15e21798e9af 100644 --- a/crates/common/src/preprocessor/deps.rs +++ b/crates/common/src/preprocessor/deps.rs @@ -320,7 +320,7 @@ pub(crate) fn remove_bytecode_dependencies( update.push_str(", "); update.push_str(&format!( - "_args: encodeArgs{id}(DeployHelper{id}.ConstructorArgs", + "_args: encodeArgs{id}(DeployHelper{id}.FoundryPpConstructorArgs", id = dep.referenced_contract.get() )); if *call_args_offset > 0 { diff --git a/crates/forge/tests/cli/test_optimizer.rs b/crates/forge/tests/cli/test_optimizer.rs index ec95aa12c7cac..f5938aeda4873 100644 --- a/crates/forge/tests/cli/test_optimizer.rs +++ b/crates/forge/tests/cli/test_optimizer.rs @@ -1300,3 +1300,48 @@ Compiling 1 files with [..] "#]]); }); + +// +forgetest_init!(preprocess_contract_with_constructor_args_struct, |prj, cmd| { + prj.wipe_contracts(); + prj.update_config(|config| { + config.dynamic_test_linking = true; + }); + + prj.add_source( + "Counter.sol", + r#" +contract Counter { + struct ConstructorArgs { + uint256 _number; + } + + constructor(uint256 no) { + } +} + "#, + ) + .unwrap(); + + prj.add_test( + "Counter.t.sol", + r#" +import {Test} from "forge-std/Test.sol"; +import {Counter} from "../src/Counter.sol"; + +contract CounterTest is Test { + function test_assert_constructor_revert() public { + Counter counter = new Counter(1); + } +} + "#, + ) + .unwrap(); + // All 20 files should properly compile. + cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" +... +Compiling 20 files with [..] +... + +"#]]); +}); From 09970aa95b1bb9fa9e64cfcaff4fe2195fb01cf8 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Wed, 16 Apr 2025 11:54:34 +0300 Subject: [PATCH 019/244] chore: trigger releases on rc-* tags too (#10315) --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6b2c7d5af4e70..140988d1e1b75 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,6 +5,7 @@ on: tags: - "stable" - "rc" + - "rc-*" - "v*.*.*" schedule: - cron: "0 6 * * *" From 1da4d324652b3a61f7c7128a6d28f9d6239e8218 Mon Sep 17 00:00:00 2001 From: 0xredtrama <60705940+redtrama@users.noreply.github.com> Date: Wed, 16 Apr 2025 13:55:55 +0200 Subject: [PATCH 020/244] feat: add vm.getChain(chainAlias) (#10226) * add Chain struct * generate interface * define getChain cheatcode * add getChain(alias) implementation * add GetChain test * run fmt * fix: add alloy_chain for check chain validity --------- Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> --- Cargo.lock | 1 + crates/cheatcodes/Cargo.toml | 1 + crates/cheatcodes/assets/cheatcodes.json | 66 ++++ crates/cheatcodes/spec/src/lib.rs | 1 + crates/cheatcodes/spec/src/vm.rs | 20 + crates/cheatcodes/src/config.rs | 475 +++++++++++++++++++++++ crates/cheatcodes/src/test.rs | 49 ++- testdata/cheats/Vm.sol | 3 + testdata/default/cheats/GetChain.t.sol | 91 +++++ 9 files changed, 706 insertions(+), 1 deletion(-) create mode 100644 testdata/default/cheats/GetChain.t.sol diff --git a/Cargo.lock b/Cargo.lock index 6053ca5c01566..fac4311005343 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3707,6 +3707,7 @@ dependencies = [ name = "foundry-cheatcodes" version = "1.1.0" dependencies = [ + "alloy-chains", "alloy-consensus", "alloy-dyn-abi", "alloy-genesis", diff --git a/crates/cheatcodes/Cargo.toml b/crates/cheatcodes/Cargo.toml index 6965ebe0b646c..645426ea8bf29 100644 --- a/crates/cheatcodes/Cargo.toml +++ b/crates/cheatcodes/Cargo.toml @@ -40,6 +40,7 @@ parking_lot.workspace = true alloy-consensus = { workspace = true, features = ["k256"] } alloy-network.workspace = true alloy-rlp.workspace = true +alloy-chains.workspace = true base64.workspace = true dialoguer = "0.11" diff --git a/crates/cheatcodes/assets/cheatcodes.json b/crates/cheatcodes/assets/cheatcodes.json index e6e14c349406f..7cce924b5f60c 100644 --- a/crates/cheatcodes/assets/cheatcodes.json +++ b/crates/cheatcodes/assets/cheatcodes.json @@ -369,6 +369,32 @@ } ] }, + { + "name": "Chain", + "description": "Information about a blockchain.", + "fields": [ + { + "name": "name", + "ty": "string", + "description": "The chain name." + }, + { + "name": "chainId", + "ty": "uint256", + "description": "The chain's Chain ID." + }, + { + "name": "chainAlias", + "ty": "string", + "description": "The chain's alias. (i.e. what gets specified in `foundry.toml`)." + }, + { + "name": "rpcUrl", + "ty": "string", + "description": "A default RPC endpoint for this chain." + } + ] + }, { "name": "AccountAccess", "description": "The result of a `stopAndReturnStateDiff` call.", @@ -5928,6 +5954,46 @@ "status": "stable", "safety": "safe" }, + { + "func": { + "id": "getChain_0", + "description": "Returns a Chain struct for specific alias", + "declaration": "function getChain(string calldata chainAlias) external view returns (Chain memory chain);", + "visibility": "external", + "mutability": "view", + "signature": "getChain(string)", + "selector": "0x4cc1c2bb", + "selectorBytes": [ + 76, + 193, + 194, + 187 + ] + }, + "group": "testing", + "status": "stable", + "safety": "safe" + }, + { + "func": { + "id": "getChain_1", + "description": "Returns a Chain struct for specific chainId", + "declaration": "function getChain(uint256 chainId) external view returns (Chain memory chain);", + "visibility": "external", + "mutability": "view", + "signature": "getChain(uint256)", + "selector": "0xb6791ad4", + "selectorBytes": [ + 182, + 121, + 26, + 212 + ] + }, + "group": "testing", + "status": "stable", + "safety": "safe" + }, { "func": { "id": "getCode", diff --git a/crates/cheatcodes/spec/src/lib.rs b/crates/cheatcodes/spec/src/lib.rs index b7c44f3284b47..7d1dbe33ac9e6 100644 --- a/crates/cheatcodes/spec/src/lib.rs +++ b/crates/cheatcodes/spec/src/lib.rs @@ -83,6 +83,7 @@ impl Cheatcodes<'static> { Vm::Wallet::STRUCT.clone(), Vm::FfiResult::STRUCT.clone(), Vm::ChainInfo::STRUCT.clone(), + Vm::Chain::STRUCT.clone(), Vm::AccountAccess::STRUCT.clone(), Vm::StorageAccess::STRUCT.clone(), Vm::Gas::STRUCT.clone(), diff --git a/crates/cheatcodes/spec/src/vm.rs b/crates/cheatcodes/spec/src/vm.rs index 1aa5f7890833a..c0481569af296 100644 --- a/crates/cheatcodes/spec/src/vm.rs +++ b/crates/cheatcodes/spec/src/vm.rs @@ -207,6 +207,18 @@ interface Vm { uint256 chainId; } + /// Information about a blockchain. + struct Chain { + /// The chain name. + string name; + /// The chain's Chain ID. + uint256 chainId; + /// The chain's alias. (i.e. what gets specified in `foundry.toml`). + string chainAlias; + /// A default RPC endpoint for this chain. + string rpcUrl; + } + /// The storage accessed during an `AccountAccess`. struct StorageAccess { /// The account whose storage was accessed. @@ -967,6 +979,14 @@ interface Vm { #[cheatcode(group = Testing, safety = Safe)] function rpcUrlStructs() external view returns (Rpc[] memory urls); + /// Returns a Chain struct for specific alias + #[cheatcode(group = Testing, safety = Safe)] + function getChain(string calldata chainAlias) external view returns (Chain memory chain); + + /// Returns a Chain struct for specific chainId + #[cheatcode(group = Testing, safety = Safe)] + function getChain(uint256 chainId) external view returns (Chain memory chain); + /// Suspends execution of the main thread for `duration` milliseconds. #[cheatcode(group = Testing, safety = Safe)] function sleep(uint256 duration) external; diff --git a/crates/cheatcodes/src/config.rs b/crates/cheatcodes/src/config.rs index 3ab70f6e053fb..210c76553cba7 100644 --- a/crates/cheatcodes/src/config.rs +++ b/crates/cheatcodes/src/config.rs @@ -9,6 +9,7 @@ use foundry_config::{ }; use foundry_evm_core::opts::EvmOpts; use std::{ + collections::HashMap, path::{Path, PathBuf}, time::Duration, }; @@ -56,6 +57,18 @@ pub struct CheatsConfig { pub seed: Option, /// Whether to allow `expectRevert` to work for internal calls. pub internal_expect_revert: bool, + /// Mapping of chain aliases to chain data + pub chains: HashMap, + /// Mapping of chain IDs to their aliases + pub chain_id_to_alias: HashMap, +} + +/// Chain data for getChain cheatcodes +#[derive(Clone, Debug)] +pub struct ChainData { + pub name: String, + pub chain_id: u64, + pub default_rpc_url: String, // Store default RPC URL } impl CheatsConfig { @@ -96,6 +109,8 @@ impl CheatsConfig { assertions_revert: config.assertions_revert, seed: config.fuzz.seed, internal_expect_revert: config.allow_internal_expect_revert, + chains: HashMap::new(), + chain_id_to_alias: HashMap::new(), } } @@ -203,6 +218,77 @@ impl CheatsConfig { } Ok(urls) } + + /// Initialize default chain data (similar to initializeStdChains in Solidity) + pub fn initialize_chain_data(&mut self) { + if !self.chains.is_empty() { + return; // Already initialized + } + + // Use the same function to create chains + let chains = create_default_chains(); + + // Add all chains to the config + for (alias, data) in chains { + self.set_chain_with_default_rpc_url(&alias, data); + } + } + + /// Set chain with default RPC URL (similar to setChainWithDefaultRpcUrl in Solidity) + pub fn set_chain_with_default_rpc_url(&mut self, alias: &str, data: ChainData) { + // Store the default RPC URL is already stored in the data + // No need to clone it separately + + // Add chain data + self.set_chain_data(alias, data); + } + + /// Set chain data for a specific alias + pub fn set_chain_data(&mut self, alias: &str, data: ChainData) { + // Remove old chain ID mapping if it exists + if let Some(old_data) = self.chains.get(alias) { + self.chain_id_to_alias.remove(&old_data.chain_id); + } + + // Add new mappings + self.chain_id_to_alias.insert(data.chain_id, alias.to_string()); + self.chains.insert(alias.to_string(), data); + } + + /// Get chain data by alias + pub fn get_chain_data_by_alias_non_mut(&self, alias: &str) -> Result { + // Initialize chains if not already done + if self.chains.is_empty() { + // Create a temporary copy with initialized chains + // This is inefficient but handles the edge case + let temp_chains = create_default_chains(); + + if let Some(data) = temp_chains.get(alias) { + return Ok(data.clone()); + } + } else { + // Normal path - chains are initialized + if let Some(data) = self.chains.get(alias) { + return Ok(data.clone()); + } + } + + // Chain not found in either case + Err(fmt_err!("vm.getChain: Chain with alias \"{}\" not found", alias)) + } + + /// Get RPC URL for an alias + pub fn get_rpc_url_non_mut(&self, alias: &str) -> Result { + // Try to get from config first + match self.rpc_endpoint(alias) { + Ok(endpoint) => Ok(endpoint.url()?), + Err(_) => { + // If not in config, try to get default URL + let chain_data = self.get_chain_data_by_alias_non_mut(alias)?; + Ok(chain_data.default_rpc_url) + } + } + } } impl Default for CheatsConfig { @@ -226,10 +312,399 @@ impl Default for CheatsConfig { assertions_revert: true, seed: None, internal_expect_revert: false, + chains: HashMap::new(), + chain_id_to_alias: HashMap::new(), } } } +// Helper function to set default chains +fn create_default_chains() -> HashMap { + let mut chains = HashMap::new(); + + // Define all chains in one place + chains.insert( + "anvil".to_string(), + ChainData { + name: "Anvil".to_string(), + chain_id: 31337, + default_rpc_url: "http://127.0.0.1:8545".to_string(), + }, + ); + + chains.insert( + "mainnet".to_string(), + ChainData { + name: "Mainnet".to_string(), + chain_id: 1, + default_rpc_url: "https://eth.llamarpc.com".to_string(), + }, + ); + + chains.insert( + "sepolia".to_string(), + ChainData { + name: "Sepolia".to_string(), + chain_id: 11155111, + default_rpc_url: "https://sepolia.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001" + .to_string(), + }, + ); + + chains.insert( + "holesky".to_string(), + ChainData { + name: "Holesky".to_string(), + chain_id: 17000, + default_rpc_url: "https://rpc.holesky.ethpandaops.io".to_string(), + }, + ); + + chains.insert( + "optimism".to_string(), + ChainData { + name: "Optimism".to_string(), + chain_id: 10, + default_rpc_url: "https://mainnet.optimism.io".to_string(), + }, + ); + + chains.insert( + "optimism_sepolia".to_string(), + ChainData { + name: "Optimism Sepolia".to_string(), + chain_id: 11155420, + default_rpc_url: "https://sepolia.optimism.io".to_string(), + }, + ); + + chains.insert( + "arbitrum_one".to_string(), + ChainData { + name: "Arbitrum One".to_string(), + chain_id: 42161, + default_rpc_url: "https://arb1.arbitrum.io/rpc".to_string(), + }, + ); + + chains.insert( + "arbitrum_one_sepolia".to_string(), + ChainData { + name: "Arbitrum One Sepolia".to_string(), + chain_id: 421614, + default_rpc_url: "https://sepolia-rollup.arbitrum.io/rpc".to_string(), + }, + ); + + chains.insert( + "arbitrum_nova".to_string(), + ChainData { + name: "Arbitrum Nova".to_string(), + chain_id: 42170, + default_rpc_url: "https://nova.arbitrum.io/rpc".to_string(), + }, + ); + + chains.insert( + "polygon".to_string(), + ChainData { + name: "Polygon".to_string(), + chain_id: 137, + default_rpc_url: "https://polygon-rpc.com".to_string(), + }, + ); + + chains.insert( + "polygon_amoy".to_string(), + ChainData { + name: "Polygon Amoy".to_string(), + chain_id: 80002, + default_rpc_url: "https://rpc-amoy.polygon.technology".to_string(), + }, + ); + + chains.insert( + "avalanche".to_string(), + ChainData { + name: "Avalanche".to_string(), + chain_id: 43114, + default_rpc_url: "https://api.avax.network/ext/bc/C/rpc".to_string(), + }, + ); + + chains.insert( + "avalanche_fuji".to_string(), + ChainData { + name: "Avalanche Fuji".to_string(), + chain_id: 43113, + default_rpc_url: "https://api.avax-test.network/ext/bc/C/rpc".to_string(), + }, + ); + + chains.insert( + "bnb_smart_chain".to_string(), + ChainData { + name: "BNB Smart Chain".to_string(), + chain_id: 56, + default_rpc_url: "https://bsc-dataseed1.binance.org".to_string(), + }, + ); + + chains.insert( + "bnb_smart_chain_testnet".to_string(), + ChainData { + name: "BNB Smart Chain Testnet".to_string(), + chain_id: 97, + default_rpc_url: "https://rpc.ankr.com/bsc_testnet_chapel".to_string(), + }, + ); + + chains.insert( + "gnosis_chain".to_string(), + ChainData { + name: "Gnosis Chain".to_string(), + chain_id: 100, + default_rpc_url: "https://rpc.gnosischain.com".to_string(), + }, + ); + + chains.insert( + "moonbeam".to_string(), + ChainData { + name: "Moonbeam".to_string(), + chain_id: 1284, + default_rpc_url: "https://rpc.api.moonbeam.network".to_string(), + }, + ); + + chains.insert( + "moonriver".to_string(), + ChainData { + name: "Moonriver".to_string(), + chain_id: 1285, + default_rpc_url: "https://rpc.api.moonriver.moonbeam.network".to_string(), + }, + ); + + chains.insert( + "moonbase".to_string(), + ChainData { + name: "Moonbase".to_string(), + chain_id: 1287, + default_rpc_url: "https://rpc.testnet.moonbeam.network".to_string(), + }, + ); + + chains.insert( + "base_sepolia".to_string(), + ChainData { + name: "Base Sepolia".to_string(), + chain_id: 84532, + default_rpc_url: "https://sepolia.base.org".to_string(), + }, + ); + + chains.insert( + "base".to_string(), + ChainData { + name: "Base".to_string(), + chain_id: 8453, + default_rpc_url: "https://mainnet.base.org".to_string(), + }, + ); + + chains.insert( + "blast_sepolia".to_string(), + ChainData { + name: "Blast Sepolia".to_string(), + chain_id: 168587773, + default_rpc_url: "https://sepolia.blast.io".to_string(), + }, + ); + + chains.insert( + "blast".to_string(), + ChainData { + name: "Blast".to_string(), + chain_id: 81457, + default_rpc_url: "https://rpc.blast.io".to_string(), + }, + ); + + chains.insert( + "fantom_opera".to_string(), + ChainData { + name: "Fantom Opera".to_string(), + chain_id: 250, + default_rpc_url: "https://rpc.ankr.com/fantom/".to_string(), + }, + ); + + chains.insert( + "fantom_opera_testnet".to_string(), + ChainData { + name: "Fantom Opera Testnet".to_string(), + chain_id: 4002, + default_rpc_url: "https://rpc.ankr.com/fantom_testnet/".to_string(), + }, + ); + + chains.insert( + "fraxtal".to_string(), + ChainData { + name: "Fraxtal".to_string(), + chain_id: 252, + default_rpc_url: "https://rpc.frax.com".to_string(), + }, + ); + + chains.insert( + "fraxtal_testnet".to_string(), + ChainData { + name: "Fraxtal Testnet".to_string(), + chain_id: 2522, + default_rpc_url: "https://rpc.testnet.frax.com".to_string(), + }, + ); + + chains.insert( + "berachain_bartio_testnet".to_string(), + ChainData { + name: "Berachain bArtio Testnet".to_string(), + chain_id: 80084, + default_rpc_url: "https://bartio.rpc.berachain.com".to_string(), + }, + ); + + chains.insert( + "flare".to_string(), + ChainData { + name: "Flare".to_string(), + chain_id: 14, + default_rpc_url: "https://flare-api.flare.network/ext/C/rpc".to_string(), + }, + ); + + chains.insert( + "flare_coston2".to_string(), + ChainData { + name: "Flare Coston2".to_string(), + chain_id: 114, + default_rpc_url: "https://coston2-api.flare.network/ext/C/rpc".to_string(), + }, + ); + + chains.insert( + "mode".to_string(), + ChainData { + name: "Mode".to_string(), + chain_id: 34443, + default_rpc_url: "https://mode.drpc.org".to_string(), + }, + ); + + chains.insert( + "mode_sepolia".to_string(), + ChainData { + name: "Mode Sepolia".to_string(), + chain_id: 919, + default_rpc_url: "https://sepolia.mode.network".to_string(), + }, + ); + + chains.insert( + "zora".to_string(), + ChainData { + name: "Zora".to_string(), + chain_id: 7777777, + default_rpc_url: "https://zora.drpc.org".to_string(), + }, + ); + + chains.insert( + "zora_sepolia".to_string(), + ChainData { + name: "Zora Sepolia".to_string(), + chain_id: 999999999, + default_rpc_url: "https://sepolia.rpc.zora.energy".to_string(), + }, + ); + + chains.insert( + "race".to_string(), + ChainData { + name: "Race".to_string(), + chain_id: 6805, + default_rpc_url: "https://racemainnet.io".to_string(), + }, + ); + + chains.insert( + "race_sepolia".to_string(), + ChainData { + name: "Race Sepolia".to_string(), + chain_id: 6806, + default_rpc_url: "https://racemainnet.io".to_string(), + }, + ); + + chains.insert( + "metal".to_string(), + ChainData { + name: "Metal".to_string(), + chain_id: 1750, + default_rpc_url: "https://metall2.drpc.org".to_string(), + }, + ); + + chains.insert( + "metal_sepolia".to_string(), + ChainData { + name: "Metal Sepolia".to_string(), + chain_id: 1740, + default_rpc_url: "https://testnet.rpc.metall2.com".to_string(), + }, + ); + + chains.insert( + "binary".to_string(), + ChainData { + name: "Binary".to_string(), + chain_id: 624, + default_rpc_url: "https://rpc.zero.thebinaryholdings.com".to_string(), + }, + ); + + chains.insert( + "binary_sepolia".to_string(), + ChainData { + name: "Binary Sepolia".to_string(), + chain_id: 625, + default_rpc_url: "https://rpc.zero.thebinaryholdings.com".to_string(), + }, + ); + + chains.insert( + "orderly".to_string(), + ChainData { + name: "Orderly".to_string(), + chain_id: 291, + default_rpc_url: "https://rpc.orderly.network".to_string(), + }, + ); + + chains.insert( + "orderly_sepolia".to_string(), + ChainData { + name: "Orderly Sepolia".to_string(), + chain_id: 4460, + default_rpc_url: "https://testnet-rpc.orderly.org".to_string(), + }, + ); + + chains +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/cheatcodes/src/test.rs b/crates/cheatcodes/src/test.rs index c12f4609bdef2..9a59430a9264c 100644 --- a/crates/cheatcodes/src/test.rs +++ b/crates/cheatcodes/src/test.rs @@ -1,10 +1,12 @@ //! Implementations of [`Testing`](spec::Group::Testing) cheatcodes. use crate::{Cheatcode, Cheatcodes, CheatsCtxt, Result, Vm::*}; -use alloy_primitives::Address; +use alloy_chains::Chain as AlloyChain; +use alloy_primitives::{Address, U256}; use alloy_sol_types::SolValue; use foundry_common::version::SEMVER_VERSION; use foundry_evm_core::constants::MAGIC_SKIP; +use std::str::FromStr; pub(crate) mod assert; pub(crate) mod assume; @@ -84,6 +86,22 @@ impl Cheatcode for skip_1Call { } } +impl Cheatcode for getChain_0Call { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { chainAlias } = self; + get_chain(state, chainAlias) + } +} + +impl Cheatcode for getChain_1Call { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { chainId } = self; + // Convert the chainId to a string and use the existing get_chain function + let chain_id_str = chainId.to_string(); + get_chain(state, &chain_id_str) + } +} + /// 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(); @@ -100,3 +118,32 @@ fn breakpoint(state: &mut Cheatcodes, caller: &Address, s: &str, add: bool) -> R Ok(Default::default()) } + +/// Gets chain information for the given alias. +fn get_chain(state: &mut Cheatcodes, chain_alias: &str) -> Result { + // Parse the chain alias - works for both chain names and IDs + let alloy_chain = AlloyChain::from_str(chain_alias) + .map_err(|_| fmt_err!("invalid chain alias: {chain_alias}"))?; + + // Check if this is an unknown chain ID by comparing the name to the chain ID + // When a numeric ID is passed for an unknown chain, alloy_chain.to_string() will return the ID + // So if they match, it's likely an unknown chain ID + if alloy_chain.to_string() == alloy_chain.id().to_string() { + return Err(fmt_err!("invalid chain alias: {chain_alias}")); + } + + // First, try to get RPC URL from the user's config in foundry.toml + let rpc_url = state.config.rpc_endpoint(chain_alias).ok().and_then(|e| e.url().ok()); + + // If we couldn't get a URL from config, return an empty string + let rpc_url = rpc_url.unwrap_or_default(); + + let chain_struct = Chain { + name: alloy_chain.to_string(), + chainId: U256::from(alloy_chain.id()), + chainAlias: chain_alias.to_string(), + rpcUrl: rpc_url, + }; + + Ok(chain_struct.abi_encode()) +} diff --git a/testdata/cheats/Vm.sol b/testdata/cheats/Vm.sol index 7128dae391ed1..b3a447cc5e1dc 100644 --- a/testdata/cheats/Vm.sol +++ b/testdata/cheats/Vm.sol @@ -18,6 +18,7 @@ interface Vm { struct Wallet { address addr; uint256 publicKeyX; uint256 publicKeyY; uint256 privateKey; } struct FfiResult { int32 exitCode; bytes stdout; bytes stderr; } struct ChainInfo { uint256 forkId; uint256 chainId; } + struct Chain { string name; uint256 chainId; string chainAlias; string rpcUrl; } struct AccountAccess { ChainInfo chainInfo; AccountAccessKind kind; address account; address accessor; bool initialized; uint256 oldBalance; uint256 newBalance; bytes deployedCode; uint256 value; bytes data; bool reverted; StorageAccess[] storageAccesses; uint64 depth; } struct StorageAccess { address account; bytes32 slot; bool isWrite; bytes32 previousValue; bytes32 newValue; bool reverted; } struct Gas { uint64 gasLimit; uint64 gasTotalUsed; uint64 gasMemoryUsed; int64 gasRefunded; uint64 gasRemaining; } @@ -290,6 +291,8 @@ interface Vm { function getBroadcast(string calldata contractName, uint64 chainId, BroadcastTxType txType) external view returns (BroadcastTxSummary memory); function getBroadcasts(string calldata contractName, uint64 chainId, BroadcastTxType txType) external view returns (BroadcastTxSummary[] memory); function getBroadcasts(string calldata contractName, uint64 chainId) external view returns (BroadcastTxSummary[] memory); + function getChain(string calldata chainAlias) external view returns (Chain memory chain); + function getChain(uint256 chainId) external view returns (Chain memory chain); function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode); function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode); function getDeployment(string calldata contractName) external view returns (address deployedAddress); diff --git a/testdata/default/cheats/GetChain.t.sol b/testdata/default/cheats/GetChain.t.sol new file mode 100644 index 0000000000000..856a6b8a75712 --- /dev/null +++ b/testdata/default/cheats/GetChain.t.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "ds-test/test.sol"; +import "cheats/Vm.sol"; + +contract GetChainTest is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + function testGetMainnet() public { + // Test mainnet + Vm.Chain memory mainnet = vm.getChain("mainnet"); + assertEq(mainnet.name, "mainnet"); + assertEq(mainnet.chainId, 1); + assertEq(mainnet.chainAlias, "mainnet"); + } + + function testGetSepolia() public { + // Test Sepolia + Vm.Chain memory sepolia = vm.getChain("sepolia"); + assertEq(sepolia.name, "sepolia"); + assertEq(sepolia.chainId, 11155111); + assertEq(sepolia.chainAlias, "sepolia"); + } + + function testGetOptimism() public { + // Test Optimism + Vm.Chain memory optimism = vm.getChain("optimism"); + assertEq(optimism.name, "optimism"); + assertEq(optimism.chainId, 10); + assertEq(optimism.chainAlias, "optimism"); + } + + function testGetByChainId() public { + // Test getting a chain by its ID + vm._expectCheatcodeRevert("invalid chain alias:"); + Vm.Chain memory arbitrum = vm.getChain("42161222"); + } + + function testEmptyAlias() public { + // Test empty string + vm._expectCheatcodeRevert("invalid chain alias:"); + vm.getChain(""); + } + + function testInvalidAlias() public { + // Test invalid alias + vm._expectCheatcodeRevert("invalid chain alias: nonexistent_chain"); + vm.getChain("nonexistent_chain"); + } + + // Tests for the numeric chainId version of getChain + + function testGetMainnetById() public { + // Test mainnet using chain ID + Vm.Chain memory mainnet = vm.getChain(1); + assertEq(mainnet.name, "mainnet"); + assertEq(mainnet.chainId, 1); + assertEq(mainnet.chainAlias, "1"); + } + + function testGetSepoliaById() public { + // Test Sepolia using chain ID + Vm.Chain memory sepolia = vm.getChain(11155111); + assertEq(sepolia.name, "sepolia"); + assertEq(sepolia.chainId, 11155111); + assertEq(sepolia.chainAlias, "11155111"); + } + + function testGetOptimismById() public { + // Test Optimism using chain ID + Vm.Chain memory optimism = vm.getChain(10); + assertEq(optimism.name, "optimism"); + assertEq(optimism.chainId, 10); + assertEq(optimism.chainAlias, "10"); + } + + function testGetArbitrumById() public { + // Test Arbitrum using chain ID + Vm.Chain memory arbitrum = vm.getChain(42161); + assertEq(arbitrum.name, "arbitrum"); + assertEq(arbitrum.chainId, 42161); + assertEq(arbitrum.chainAlias, "42161"); + } + + function testInvalidChainId() public { + // Test invalid chain ID (using a value that's unlikely to be a valid chain) + vm._expectCheatcodeRevert("invalid chain alias: 12345678"); + vm.getChain(12345678); + } +} From 23b1cbd6ef131838629be51ad8f5f9391239eb4d Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Thu, 17 Apr 2025 13:05:59 +0530 Subject: [PATCH 021/244] feat(`cast`): getTransactionBySenderAndNonce (#10323) * feat(`cast`): getTransactionBySenderAndNonce * fix doc-test --- crates/cast/src/args.rs | 7 ++++-- crates/cast/src/lib.rs | 42 ++++++++++++++++++++++++++--------- crates/cast/src/opts.rs | 10 ++++++++- crates/cast/tests/cli/main.rs | 38 +++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 14 deletions(-) diff --git a/crates/cast/src/args.rs b/crates/cast/src/args.rs index 78ca1d3076a63..a1803eda251fe 100644 --- a/crates/cast/src/args.rs +++ b/crates/cast/src/args.rs @@ -482,14 +482,17 @@ pub async fn run_command(args: CastArgs) -> Result<()> { } CastSubcommand::Run(cmd) => cmd.run().await?, CastSubcommand::SendTx(cmd) => cmd.run().await?, - CastSubcommand::Tx { tx_hash, field, raw, rpc } => { + CastSubcommand::Tx { tx_hash, from, nonce, field, raw, rpc } => { let config = rpc.load_config()?; let provider = utils::get_provider(&config)?; // Can use either --raw or specify raw as a field let raw = raw || field.as_ref().is_some_and(|f| f == "raw"); - sh_println!("{}", Cast::new(&provider).transaction(tx_hash, field, raw).await?)? + sh_println!( + "{}", + Cast::new(&provider).transaction(tx_hash, from, nonce, field, raw).await? + )? } // 4Byte diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index f369c5de03f46..a83e67ef2183f 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -5,11 +5,11 @@ use alloy_consensus::TxEnvelope; use alloy_dyn_abi::{DynSolType, DynSolValue, FunctionExt}; use alloy_json_abi::Function; -use alloy_network::AnyNetwork; +use alloy_network::{AnyNetwork, AnyRpcTransaction}; use alloy_primitives::{ hex, utils::{keccak256, ParseUnits, Unit}, - Address, Keccak256, Selector, TxHash, TxKind, B256, I256, U256, + Address, Keccak256, Selector, TxHash, TxKind, B256, I256, U256, U64, }; use alloy_provider::{ network::eip2718::{Decodable2718, Encodable2718}, @@ -26,6 +26,7 @@ use foundry_block_explorers::Client; use foundry_common::{ abi::{encode_function_args, get_func}, compile::etherscan_project, + ens::NameOrAddress, fmt::*, fs, get_pretty_tx_receipt_attr, shell, TransactionReceiptWithRevertReason, }; @@ -731,26 +732,45 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let tx_hash = "0xf8d1713ea15a81482958fb7ddf884baee8d3bcc478c5f2f604e008dc788ee4fc"; - /// let tx = cast.transaction(tx_hash.to_string(), None, false).await?; + /// let tx = cast.transaction(Some(tx_hash.to_string()), None, None, None, false).await?; /// println!("{}", tx); /// # Ok(()) /// # } /// ``` pub async fn transaction( &self, - tx_hash: String, + tx_hash: Option, + from: Option, + nonce: Option, field: Option, raw: bool, ) -> Result { - let tx_hash = TxHash::from_str(&tx_hash).wrap_err("invalid tx hash")?; - let tx = self - .provider - .get_transaction_by_hash(tx_hash) - .await? - .ok_or_else(|| eyre::eyre!("tx not found: {:?}", tx_hash))?; + let tx = if let Some(tx_hash) = tx_hash { + let tx_hash = TxHash::from_str(&tx_hash).wrap_err("invalid tx hash")?; + self.provider + .get_transaction_by_hash(tx_hash) + .await? + .ok_or_else(|| eyre::eyre!("tx not found: {:?}", tx_hash))? + } else if let Some(from) = from { + // If nonce is not provided, uses 0. + let nonce = U64::from(nonce.unwrap_or_default()); + let from = from.resolve(self.provider.root()).await?; + + self.provider + .raw_request::<_, Option>( + "eth_getTransactionBySenderAndNonce".into(), + (from, nonce), + ) + .await? + .ok_or_else(|| { + eyre::eyre!("tx not found for sender {from} and nonce {:?}", nonce.to::()) + })? + } else { + eyre::bail!("tx hash or from address is required") + }; Ok(if raw { format!("0x{}", hex::encode(tx.inner.inner.encoded_2718())) diff --git a/crates/cast/src/opts.rs b/crates/cast/src/opts.rs index 8ffb6326c025e..da789f830cda4 100644 --- a/crates/cast/src/opts.rs +++ b/crates/cast/src/opts.rs @@ -446,7 +446,15 @@ pub enum CastSubcommand { #[command(visible_alias = "t")] Tx { /// The transaction hash. - tx_hash: String, + tx_hash: Option, + + /// The sender of the transaction. + #[arg(long, value_parser = NameOrAddress::from_str)] + from: Option, + + /// Nonce of the transaction. + #[arg(long)] + nonce: Option, /// If specified, only get the given field of the transaction. If "raw", the RLP encoded /// transaction will be printed. diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 5e511256f88cd..c37ea2bbed221 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -1265,6 +1265,44 @@ casttest!(tx_raw, |_prj, cmd| { "#]]); }); +casttest!(tx_using_sender_and_nonce, |_prj, cmd| { + let rpc = "https://reth-ethereum.ithaca.xyz/rpc"; + // + let args = vec![ + "tx", + "--from", + "0x4648451b5F87FF8F0F7D622bD40574bb97E25980", + "--nonce", + "113642", + "--rpc-url", + rpc, + ]; + cmd.args(args).assert_success().stdout_eq(str![[r#" + +blockHash 0x29518c1cea251b1bda5949a9b039722604ec1fb99bf9d8124cfe001c95a50bdc +blockNumber 22287055 +from 0x4648451b5F87FF8F0F7D622bD40574bb97E25980 +transactionIndex 230 +effectiveGasPrice 363392048 + +accessList [] +chainId 1 +gasLimit 350000 +hash 0x5bcd22734cca2385dc25b2d38a3d33a640c5961bd46d390dff184c894204b594 +input 0xa9059cbb000000000000000000000000568766d218d82333dd4dae933ddfcda5da26625000000000000000000000000000000000000000000000000000000000cc3ed109 +maxFeePerGas 675979146 +maxPriorityFeePerGas 1337 +nonce 113642 +r 0x1e92d3e1ca69109a1743fc4b3cf9dff58630bc9f429cea3c3fe311506264e36c +s 0x793947d4bbdce56a1a5b2b3525c46f01569414a22355f4883b5429668ab0f51a +to 0xdAC17F958D2ee523a2206206994597C13D831ec7 +type 2 +value 0 +yParity 1 +... +"#]]); +}); + // ensure receipt or code is required casttest!(send_requires_to, |_prj, cmd| { cmd.args([ From 709f266ff6a26264ac4fc8c06cc40964861c7ebb Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 17 Apr 2025 15:19:44 +0200 Subject: [PATCH 022/244] fix: force install default crypto provider (#10327) * fix: force install default crypto provider * Fix tests and cargo deny --------- Co-authored-by: grandizzy --- Cargo.lock | 1 + Cargo.toml | 3 +++ crates/anvil/src/args.rs | 1 + crates/cast/Cargo.toml | 2 +- crates/cast/src/args.rs | 1 + crates/chisel/src/args.rs | 1 + crates/cli/Cargo.toml | 1 + crates/cli/src/utils/mod.rs | 17 +++++++++++++++++ crates/forge/src/args.rs | 1 + crates/forge/tests/it/test_helpers.rs | 2 ++ crates/wallets/Cargo.toml | 4 ++-- deny.toml | 1 + 12 files changed, 32 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fac4311005343..21e660b9c767b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3789,6 +3789,7 @@ dependencies = [ "itertools 0.14.0", "rayon", "regex", + "rustls", "serde", "serde_json", "strsim", diff --git a/Cargo.toml b/Cargo.toml index 33cb640551a08..840b4c9fa1fe1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -259,6 +259,8 @@ thiserror = "2" # misc auto_impl = "1" +aws-config = { version = "1", default-features = true } +aws-sdk-kms = { version = "1", default-features = false } bytes = "1.8" walkdir = "2" prettyplease = "0.2" @@ -293,6 +295,7 @@ reqwest = { version = "0.12", default-features = false, features = [ "rustls-tls", "rustls-tls-native-roots", ] } +rustls = "0.23" semver = "1" serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["arbitrary_precision"] } diff --git a/crates/anvil/src/args.rs b/crates/anvil/src/args.rs index 065ab216c81a5..336c42742e6cb 100644 --- a/crates/anvil/src/args.rs +++ b/crates/anvil/src/args.rs @@ -16,6 +16,7 @@ pub fn run() -> Result<()> { /// Setup the exception handler and other utilities. pub fn setup() -> Result<()> { + utils::install_crypto_provider(); handler::install(); utils::load_dotenv(); utils::enable_paint(); diff --git a/crates/cast/Cargo.toml b/crates/cast/Cargo.toml index e3042bcc54c8d..91dc55544b8cf 100644 --- a/crates/cast/Cargo.toml +++ b/crates/cast/Cargo.toml @@ -61,7 +61,7 @@ serde_json.workspace = true serde.workspace = true # aws-kms -aws-sdk-kms = { version = "1", default-features = false, optional = true } +aws-sdk-kms = { workspace = true, default-features = false, optional = true } # bin foundry-cli.workspace = true diff --git a/crates/cast/src/args.rs b/crates/cast/src/args.rs index a1803eda251fe..d0cf7400b287a 100644 --- a/crates/cast/src/args.rs +++ b/crates/cast/src/args.rs @@ -38,6 +38,7 @@ pub fn run() -> Result<()> { /// Setup the global logger and other utilities. pub fn setup() -> Result<()> { + utils::install_crypto_provider(); handler::install(); utils::load_dotenv(); utils::subscriber(); diff --git a/crates/chisel/src/args.rs b/crates/chisel/src/args.rs index 19b63efedd617..3837953b5f3b2 100644 --- a/crates/chisel/src/args.rs +++ b/crates/chisel/src/args.rs @@ -35,6 +35,7 @@ pub fn run() -> Result<()> { /// Setup the global logger and other utilities. pub fn setup() -> Result<()> { + utils::install_crypto_provider(); handler::install(); utils::subscriber(); utils::load_dotenv(); diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 5a082590d4f1f..a3a510f03cb1a 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -47,6 +47,7 @@ tokio = { workspace = true, features = ["macros"] } tracing-subscriber = { workspace = true, features = ["registry", "env-filter"] } tracing.workspace = true yansi.workspace = true +rustls = { workspace = true, features = ["ring"] } tracing-tracy = { version = "0.11", optional = true } diff --git a/crates/cli/src/utils/mod.rs b/crates/cli/src/utils/mod.rs index 13d312b8a079d..30c984c960f14 100644 --- a/crates/cli/src/utils/mod.rs +++ b/crates/cli/src/utils/mod.rs @@ -205,6 +205,23 @@ pub fn enable_paint() { yansi::whenever(yansi::Condition::cached(enable)); } +/// This force installs the default crypto provider. +/// +/// This is necessary in case there are more than one available backends enabled in rustls (ring, +/// aws-lc-rs). +/// +/// This should be called high in the main fn. +/// +/// See also: +/// +/// +pub fn install_crypto_provider() { + // https://github.com/snapview/tokio-tungstenite/issues/353 + rustls::crypto::ring::default_provider() + .install_default() + .expect("Failed to install default rustls crypto provider"); +} + /// Useful extensions to [`std::process::Command`]. pub trait CommandUtils { /// Returns the command's output if execution is successful, otherwise, throws an error. diff --git a/crates/forge/src/args.rs b/crates/forge/src/args.rs index 88928a63b1cda..92922155c5775 100644 --- a/crates/forge/src/args.rs +++ b/crates/forge/src/args.rs @@ -21,6 +21,7 @@ pub fn run() -> Result<()> { /// Setup the global logger and other utilities. pub fn setup() -> Result<()> { + utils::install_crypto_provider(); handler::install(); utils::load_dotenv(); utils::subscriber(); diff --git a/crates/forge/tests/it/test_helpers.rs b/crates/forge/tests/it/test_helpers.rs index 89f26382a867a..c6ac80c114608 100644 --- a/crates/forge/tests/it/test_helpers.rs +++ b/crates/forge/tests/it/test_helpers.rs @@ -3,6 +3,7 @@ use alloy_chains::NamedChain; use alloy_primitives::U256; use forge::{revm::primitives::SpecId, MultiContractRunner, MultiContractRunnerBuilder}; +use foundry_cli::utils::install_crypto_provider; use foundry_compilers::{ artifacts::{EvmVersion, Libraries, Settings}, compilers::multi::MultiCompiler, @@ -172,6 +173,7 @@ impl ForgeTestData { /// /// Uses [get_compiled] to lazily compile the project. pub fn new(profile: ForgeTestProfile) -> Self { + install_crypto_provider(); init_tracing(); let config = Arc::new(profile.config()); let mut project = config.project().unwrap(); diff --git a/crates/wallets/Cargo.toml b/crates/wallets/Cargo.toml index b1310b98e86a8..856779e6d99c8 100644 --- a/crates/wallets/Cargo.toml +++ b/crates/wallets/Cargo.toml @@ -27,8 +27,8 @@ alloy-dyn-abi.workspace = true # aws-kms alloy-signer-aws = { workspace = true, features = ["eip712"], optional = true } -aws-config = { version = "1", default-features = true, optional = true } -aws-sdk-kms = { version = "1", default-features = false, optional = true } +aws-config = { workspace = true, default-features = true, optional = true } +aws-sdk-kms = { workspace = true, default-features = false, optional = true } # gcp-kms alloy-signer-gcp = { workspace = true, features = ["eip712"], optional = true } diff --git a/deny.toml b/deny.toml index b724ef3accdd8..8f6d7d9f0c1d9 100644 --- a/deny.toml +++ b/deny.toml @@ -56,6 +56,7 @@ allow = [ "MPL-2.0", "CDDL-1.0", "Zlib", + "OpenSSL", ] # Allow 1 or more licenses on a per-crate basis, so that particular licenses From 8d52dde7b47c02581671a2e5f73143e94d64c727 Mon Sep 17 00:00:00 2001 From: morito Date: Fri, 18 Apr 2025 18:20:31 +0900 Subject: [PATCH 023/244] Support the `gcp` option in `cast wallet list` (#8232) * Support gcp option in `cast wallet list` * implement `gcp_sugners` to `MultiWalletOpts` * add comment * Make gcp option infallible if the env vars are missing * align version with Alloy --------- Co-authored-by: evalir Co-authored-by: zerosnacks Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- Cargo.lock | 1 + crates/cast/Cargo.toml | 6 +++- crates/cast/src/cmd/wallet/list.rs | 18 +++++++++++- crates/wallets/Cargo.toml | 2 +- crates/wallets/src/multi_wallet.rs | 44 ++++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 21e660b9c767b..f9ef655f3f68a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2135,6 +2135,7 @@ dependencies = [ "foundry-test-utils", "foundry-wallets", "futures", + "gcloud-sdk", "itertools 0.14.0", "rand 0.8.5", "rayon", diff --git a/crates/cast/Cargo.toml b/crates/cast/Cargo.toml index 91dc55544b8cf..0f23a854f653b 100644 --- a/crates/cast/Cargo.toml +++ b/crates/cast/Cargo.toml @@ -42,7 +42,7 @@ alloy-provider = { workspace = true, features = [ "ws", "ipc", "trace-api", - "txpool-api" + "txpool-api", ] } alloy-rlp.workspace = true alloy-rpc-types = { workspace = true, features = ["eth", "trace"] } @@ -63,6 +63,9 @@ serde.workspace = true # aws-kms aws-sdk-kms = { workspace = true, default-features = false, optional = true } +# gcp-kms +gcloud-sdk = { version = "0.26.4", default-features = false, optional = true } + # bin foundry-cli.workspace = true @@ -93,4 +96,5 @@ default = ["jemalloc"] asm-keccak = ["alloy-primitives/asm-keccak"] jemalloc = ["dep:tikv-jemallocator"] aws-kms = ["foundry-wallets/aws-kms", "dep:aws-sdk-kms"] +gcp-kms = ["foundry-wallets/gcp-kms", "dep:gcloud-sdk"] isolate-by-default = ["foundry-config/isolate-by-default"] diff --git a/crates/cast/src/cmd/wallet/list.rs b/crates/cast/src/cmd/wallet/list.rs index be29cb22bde98..fd3551be79b5b 100644 --- a/crates/cast/src/cmd/wallet/list.rs +++ b/crates/cast/src/cmd/wallet/list.rs @@ -1,5 +1,6 @@ use clap::Parser; use eyre::Result; +use std::env; use foundry_common::{fs, sh_err, sh_println}; use foundry_config::Config; @@ -25,6 +26,10 @@ pub struct ListArgs { #[arg(long, hide = !cfg!(feature = "aws-kms"))] aws: bool, + /// List accounts from Google Cloud KMS. + #[arg(long, hide = !cfg!(feature = "gcp-kms"))] + gcp: bool, + /// List all configured accounts. #[arg(long, group = "hw-wallets")] all: bool, @@ -37,7 +42,10 @@ pub struct ListArgs { impl ListArgs { pub async fn run(self) -> Result<()> { // list local accounts as files in keystore dir, no need to unlock / provide password - if self.dir.is_some() || self.all || (!self.ledger && !self.trezor && !self.aws) { + if self.dir.is_some() || + self.all || + (!self.ledger && !self.trezor && !self.aws && !self.gcp) + { let _ = self.list_local_senders(); } @@ -47,6 +55,7 @@ impl ListArgs { .mnemonic_indexes(Some(vec![0])) .trezor(self.trezor || self.all) .aws(self.aws || self.all) + .gcp(self.gcp || (self.all && gcp_env_vars_set())) .interactives(0) .build() .expect("build multi wallet"); @@ -108,3 +117,10 @@ impl ListArgs { Ok(()) } } + +fn gcp_env_vars_set() -> bool { + let required_vars = + ["GCP_PROJECT_ID", "GCP_LOCATION", "GCP_KEY_RING", "GCP_KEY_NAME", "GCP_KEY_VERSION"]; + + required_vars.iter().all(|&var| env::var(var).is_ok()) +} diff --git a/crates/wallets/Cargo.toml b/crates/wallets/Cargo.toml index 856779e6d99c8..0efad83cfbf5f 100644 --- a/crates/wallets/Cargo.toml +++ b/crates/wallets/Cargo.toml @@ -32,7 +32,7 @@ aws-sdk-kms = { workspace = true, default-features = false, optional = true } # gcp-kms alloy-signer-gcp = { workspace = true, features = ["eip712"], optional = true } -gcloud-sdk = { version = "0.26", features = [ +gcloud-sdk = { version = "0.26.4", features = [ "google-cloud-kms-v1", "google-longrunning", ], optional = true } diff --git a/crates/wallets/src/multi_wallet.rs b/crates/wallets/src/multi_wallet.rs index f70b39d5d671e..39ba6fefa1480 100644 --- a/crates/wallets/src/multi_wallet.rs +++ b/crates/wallets/src/multi_wallet.rs @@ -221,6 +221,10 @@ pub struct MultiWalletOpts { /// Use AWS Key Management Service. #[arg(long, help_heading = "Wallet options - remote", hide = !cfg!(feature = "aws-kms"))] pub aws: bool, + + /// Use Google Cloud Key Management Service. + #[arg(long, help_heading = "Wallet options - remote", hide = !cfg!(feature = "gcp-kms"))] + pub gcp: bool, } impl MultiWalletOpts { @@ -238,6 +242,9 @@ impl MultiWalletOpts { if let Some(aws_signers) = self.aws_signers().await? { signers.extend(aws_signers); } + if let Some(gcp_signer) = self.gcp_signers().await? { + signers.extend(gcp_signer); + } if let Some((pending_keystores, unlocked)) = self.keystores()? { pending.extend(pending_keystores); signers.extend(unlocked); @@ -397,6 +404,43 @@ impl MultiWalletOpts { Ok(None) } + + /// Returns a list of GCP signers if the GCP flag is set. + /// + /// The GCP signers are created from the following environment variables: + /// - GCP_PROJECT_ID: The GCP project ID. e.g. `my-project-123456`. + /// - GCP_LOCATION: The GCP location. e.g. `us-central1`. + /// - GCP_KEY_RING: The GCP key ring name. e.g. `my-key-ring`. + /// - GCP_KEY_NAME: The GCP key name. e.g. `my-key`. + /// - GCP_KEY_VERSION: The GCP key version. e.g. `1`. + /// + /// For more information on GCP KMS, see the [official documentation](https://cloud.google.com/kms/docs). + pub async fn gcp_signers(&self) -> Result>> { + #[cfg(feature = "gcp-kms")] + if self.gcp { + let mut wallets = vec![]; + + let project_id = std::env::var("GCP_PROJECT_ID")?; + let location = std::env::var("GCP_LOCATION")?; + let key_ring = std::env::var("GCP_KEY_RING")?; + let key_names = std::env::var("GCP_KEY_NAME")?; + let key_version = std::env::var("GCP_KEY_VERSION")?; + + let gcp_signer = WalletSigner::from_gcp( + project_id, + location, + key_ring, + key_names, + key_version.parse()?, + ) + .await?; + wallets.push(gcp_signer); + + return Ok(Some(wallets)); + } + + Ok(None) + } } #[cfg(test)] From 41506cadeb4b1c609dfa5ab77348c285346b0464 Mon Sep 17 00:00:00 2001 From: 0xcomfycat <140531986+0xcomfycat@users.noreply.github.com> Date: Fri, 18 Apr 2025 16:32:56 +0700 Subject: [PATCH 024/244] feat: add serde derive to forge bind (#10332) feat: add serde derive --- crates/sol-macro-gen/src/sol_macro_gen.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/sol-macro-gen/src/sol_macro_gen.rs b/crates/sol-macro-gen/src/sol_macro_gen.rs index 133f4ed218f9b..2aa6e7fefd3b4 100644 --- a/crates/sol-macro-gen/src/sol_macro_gen.rs +++ b/crates/sol-macro-gen/src/sol_macro_gen.rs @@ -119,8 +119,15 @@ impl MultiSolMacroGen { let tokens = match kind { SolInputKind::Sol(mut file) => { - let sol_attr: syn::Attribute = syn::parse_quote! { - #[sol(rpc, alloy_sol_types = alloy::sol_types, alloy_contract = alloy::contract, all_derives = #all_derives)] + let sol_attr: syn::Attribute = if all_derives { + syn::parse_quote! { + #[sol(rpc, alloy_sol_types = alloy::sol_types, alloy_contract = + alloy::contract, all_derives = true, extra_derives(serde::Serialize, + serde::Deserialize))] } + } else { + syn::parse_quote! { + #[sol(rpc, alloy_sol_types = alloy::sol_types, alloy_contract = + alloy::contract)] } }; file.attrs.push(sol_attr); expand(file).wrap_err("failed to expand")? From f76309dad7dddc0917755d3f3d17e1ad9d02c6b8 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Fri, 18 Apr 2025 20:24:30 +0300 Subject: [PATCH 025/244] fix(forge): avoid panic on internal decoding of linked tests (#10333) Failing tests related to etherscan sepolia migration --- crates/evm/traces/src/debug/mod.rs | 7 +++ crates/forge/tests/cli/test_optimizer.rs | 66 ++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/crates/evm/traces/src/debug/mod.rs b/crates/evm/traces/src/debug/mod.rs index 1f3fb0b2faedd..0e6521a7f5a8c 100644 --- a/crates/evm/traces/src/debug/mod.rs +++ b/crates/evm/traces/src/debug/mod.rs @@ -200,6 +200,13 @@ impl<'a> DebugStepsWalker<'a> { fn parse_function_from_loc(source: &SourceData, loc: &SourceElement) -> Option { let start = loc.offset() as usize; let end = start + loc.length() as usize; + let src_len = source.source.len(); + + // Handle special case of preprocessed test sources. + if start > src_len || end > src_len { + return None; + } + let source_part = &source.source[start..end]; if !source_part.starts_with("function") { return None; diff --git a/crates/forge/tests/cli/test_optimizer.rs b/crates/forge/tests/cli/test_optimizer.rs index f5938aeda4873..6caa03412aa37 100644 --- a/crates/forge/tests/cli/test_optimizer.rs +++ b/crates/forge/tests/cli/test_optimizer.rs @@ -1345,3 +1345,69 @@ Compiling 20 files with [..] "#]]); }); + +// Test preprocessed contracts with decode internal fns. +forgetest_init!(preprocess_contract_with_decode_internal, |prj, cmd| { + prj.update_config(|config| { + config.dynamic_test_linking = true; + }); + + prj.add_test( + "Counter.t.sol", + r#" +import {Test} from "forge-std/Test.sol"; +import {Counter} from "../src/Counter.sol"; + +contract CounterTest is Test { + Counter public counter; + + function setUp() public { + create_counter(0); + } + + function test_Increment() public { + create_counter(0); + counter.increment(); + assertEq(counter.number(), 1); + } + + function create_counter(uint256 number) internal { + counter = new Counter(); + counter.setNumber(number); + } +} + "#, + ) + .unwrap(); + + cmd.args(["test", "--decode-internal", "-vvvv"]).assert_success().stdout_eq(str![[r#" +[COMPILING_FILES] with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 1 test for test/Counter.t.sol:CounterTest +[PASS] test_Increment() ([GAS]) +Traces: + [..] CounterTest::test_Increment() + ├─ [0] VM::deployCode("src/Counter.sol:Counter") + │ ├─ [96345] → new Counter@0x2e234DAe75C793f67A35089C9d99245E1C58470b + │ │ └─ ← [Return] 481 bytes of code + │ └─ ← [Return] Counter: [0x2e234DAe75C793f67A35089C9d99245E1C58470b] + ├─ [..] Counter::setNumber(0) + │ └─ ← [Stop] + ├─ [..] Counter::increment() + │ └─ ← [Stop] + ├─ [..] Counter::number() [staticcall] + │ └─ ← [Return] 1 + ├─ [..] StdAssertions::assertEq(1, 1) + │ ├─ [0] VM::assertEq(1, 1) [staticcall] + │ │ └─ ← [Return] + │ └─ ← + └─ ← [Stop] + +Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) + +"#]]); +}); From 1ae64e38a1c69bda45343947875f7c86bad00038 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 20 Apr 2025 11:03:39 +0000 Subject: [PATCH 026/244] chore(deps): weekly `cargo update` (#10339) Locking 25 packages to latest compatible versions Unchanged alloy-chains v0.1.69 (available: v0.2.0) Unchanged alloy-consensus v0.12.6 (available: v0.14.0) Unchanged alloy-contract v0.12.6 (available: v0.14.0) Unchanged alloy-dyn-abi v0.8.25 (available: v1.0.0) Unchanged alloy-eips v0.12.6 (available: v0.14.0) Unchanged alloy-genesis v0.12.6 (available: v0.14.0) Unchanged alloy-json-abi v0.8.25 (available: v1.0.0) Unchanged alloy-json-rpc v0.12.6 (available: v0.14.0) Unchanged alloy-network v0.12.6 (available: v0.14.0) Unchanged alloy-primitives v0.8.25 (available: v1.0.0) Unchanged alloy-provider v0.12.6 (available: v0.14.0) Unchanged alloy-pubsub v0.12.6 (available: v0.14.0) Unchanged alloy-rpc-client v0.12.6 (available: v0.14.0) Unchanged alloy-rpc-types v0.12.6 (available: v0.14.0) Unchanged alloy-serde v0.12.6 (available: v0.14.0) Unchanged alloy-signer v0.12.6 (available: v0.14.0) Unchanged alloy-signer-aws v0.12.6 (available: v0.14.0) Unchanged alloy-signer-gcp v0.12.6 (available: v0.14.0) Unchanged alloy-signer-ledger v0.12.6 (available: v0.14.0) Unchanged alloy-signer-local v0.12.6 (available: v0.14.0) Unchanged alloy-signer-trezor v0.12.6 (available: v0.14.0) Unchanged alloy-sol-macro-expander v0.8.25 (available: v1.0.0) Unchanged alloy-sol-macro-input v0.8.25 (available: v1.0.0) Unchanged alloy-sol-types v0.8.25 (available: v1.0.0) Unchanged alloy-transport v0.12.6 (available: v0.14.0) Unchanged alloy-transport-http v0.12.6 (available: v0.14.0) Unchanged alloy-transport-ipc v0.12.6 (available: v0.14.0) Unchanged alloy-transport-ws v0.12.6 (available: v0.14.0) Unchanged alloy-trie v0.7.9 (available: v0.8.1) Updating anyhow v1.0.97 -> v1.0.98 Updating aws-lc-sys v0.28.0 -> v0.28.1 Unchanged axum v0.7.9 (available: v0.8.3) Unchanged backtrace v0.3.71 (available: v0.3.74) Updating bon v3.5.2 -> v3.6.1 Updating bon-macros v3.5.2 -> v3.6.1 Updating clap v4.5.36 -> v4.5.37 Updating clap_builder v4.5.36 -> v4.5.37 Unchanged crossterm v0.28.1 (available: v0.29.0) Updating der v0.7.9 -> v0.7.10 Updating foundry-block-explorers v0.13.0 -> v0.13.1 Updating foundry-compilers v0.14.0 -> v0.14.1 Updating foundry-compilers-artifacts v0.14.0 -> v0.14.1 Updating foundry-compilers-artifacts-solc v0.14.0 -> v0.14.1 Updating foundry-compilers-artifacts-vyper v0.14.0 -> v0.14.1 Updating foundry-compilers-core v0.14.0 -> v0.14.1 Unchanged gcloud-sdk v0.26.4 (available: v0.27.0) Updating h2 v0.4.8 -> v0.4.9 Updating jiff v0.2.6 -> v0.2.9 Updating jiff-static v0.2.6 -> v0.2.9 Updating libc v0.2.171 -> v0.2.172 Removing lockfree-object-pool v0.1.6 Removing md-5 v0.10.6 Unchanged op-alloy-consensus v0.11.4 (available: v0.14.1) Unchanged op-alloy-rpc-types v0.11.4 (available: v0.14.1) Updating proc-macro2 v1.0.94 -> v1.0.95 Updating prodash v29.0.1 -> v29.0.2 Unchanged protobuf v3.3.0 (available: v3.7.2) Unchanged protobuf-support v3.3.0 (available: v3.7.2) Updating rand v0.9.0 -> v0.9.1 Unchanged rand v0.8.5 (available: v0.9.1) Unchanged revm v19.7.0 (available: v22.0.1) Unchanged revm-inspectors v0.16.0 (available: v0.19.1) Unchanged revm-primitives v15.2.0 (available: v18.0.0) Updating rtoolbox v0.0.2 -> v0.0.3 Updating scc v2.3.3 -> v2.3.4 Updating signal-hook-registry v1.4.2 -> v1.4.4 Unchanged solang-parser v0.3.3 (available: v0.3.4) Unchanged vergen v8.3.2 (available: v9.0.6) Adding xxhash-rust v0.8.15 Updating zopfli v0.8.1 -> v0.8.2 note: to see how you depend on a package, run `cargo tree --invert --package @` Co-authored-by: mattsse <19890894+mattsse@users.noreply.github.com> --- Cargo.lock | 132 ++++++++++++++++++++++++----------------------------- 1 file changed, 59 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9ef655f3f68a..43d0cbcd56ae6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1071,9 +1071,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "arbitrary" @@ -1415,9 +1415,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f7720b74ed28ca77f90769a71fd8c637a0137f6fae4ae947e1050229cff57f" +checksum = "0ddeb19ee86cb16ecfc871e5b0660aff6285760957aaedda6284cf0e790d3769" dependencies = [ "bindgen", "cc", @@ -1963,9 +1963,9 @@ dependencies = [ [[package]] name = "bon" -version = "3.5.2" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c5f8abc69af414cbd6f2103bb668b91e584072f2105e4b38bed79b6ad0975f" +checksum = "94054366e2ff97b455acdd4fdb03913f717febc57b7bbd1741b2c3b87efae030" dependencies = [ "bon-macros", "rustversion", @@ -1973,9 +1973,9 @@ dependencies = [ [[package]] name = "bon-macros" -version = "3.5.2" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69edf39b6f321cb2699a93fc20c256adb839719c42676d03f7aa975e4e5581d" +checksum = "542a990e676ce0a0a895ae54b2d94afd012434f2228a85b186c6bc1a7056cdc6" dependencies = [ "darling", "ident_case", @@ -2291,9 +2291,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.36" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04" +checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" dependencies = [ "clap_builder", "clap_derive", @@ -2311,9 +2311,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.36" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5" +checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" dependencies = [ "anstream", "anstyle", @@ -2842,9 +2842,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", "pem-rfc7468", @@ -3688,9 +3688,9 @@ dependencies = [ [[package]] name = "foundry-block-explorers" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f13025e2bf7b3975b34190a7e0fb66b6a5df61e29e54d1da093938073e06ad10" +checksum = "001678abc9895502532c8c4a1a225079c580655fc82a194e78b06dcf99f49b8c" dependencies = [ "alloy-chains", "alloy-json-abi", @@ -3880,9 +3880,9 @@ dependencies = [ [[package]] name = "foundry-compilers" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cc93d4e235ddde616d9fc532bac2cf9840203c3432e24fa48d827a4eb51b35c" +checksum = "94bb4155f53d4b05642a1398ad105dc04d44b368a7932b85f6ed012af48768b7" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -3896,7 +3896,6 @@ dependencies = [ "futures-util", "home", "itertools 0.14.0", - "md-5", "path-slash", "rand 0.8.5", "rayon", @@ -3918,9 +3917,9 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ce306d3199cbea0805df69b62feb4311d5cbcfe0b2d0fe02819a7300e5c42b" +checksum = "f8239fe85061cdb35b8041ef84918e657099fe26f41b016ab8d2560ae6413183" dependencies = [ "foundry-compilers-artifacts-solc", "foundry-compilers-artifacts-vyper", @@ -3928,15 +3927,14 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-solc" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8217869394db052366fc6ed03475929e5c844222885c76d5dfcbb95fecf2640b" +checksum = "99d5c80fda7c4fde0d2964b329b22d09718838da0c940e5df418f2c1db14fd24" dependencies = [ "alloy-json-abi", "alloy-primitives", "foundry-compilers-core", "futures-util", - "md-5", "path-slash", "rayon", "semver 1.0.26", @@ -3952,9 +3950,9 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-vyper" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750e309e1ec20a4fd73617bdbf25529688ff75ae54c79b17b6428e2ce54ca6e" +checksum = "2eaf3cad3dd7bd9eae02736e98f55aaf00ee31fbc0a367613436c2fb01c43914" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -3967,9 +3965,9 @@ dependencies = [ [[package]] name = "foundry-compilers-core" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a0f2673de9b861d8d7f21a48182f3cb724354e17be084655b5b84d4446f41fc" +checksum = "5ac5a1aef4083544309765a1a10c310dffde8c9b8bcfda79b7c2bcfde32f3be3" dependencies = [ "alloy-primitives", "cfg-if", @@ -3985,6 +3983,7 @@ dependencies = [ "thiserror 2.0.12", "tokio", "walkdir", + "xxhash-rust", ] [[package]] @@ -4773,9 +4772,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" +checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" dependencies = [ "atomic-waker", "bytes", @@ -5520,9 +5519,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488" +checksum = "59ec30f7142be6fe14e1b021f50b85db8df2d4324ea6e91ec3e5dcde092021d0" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -5535,9 +5534,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19" +checksum = "526b834d727fd59d37b076b0c3236d9adde1b1729a4361e20b2026f738cc1dbe" dependencies = [ "proc-macro2", "quote", @@ -5716,9 +5715,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libdbus-sys" @@ -5797,12 +5796,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "lockfree-object-pool" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" - [[package]] name = "log" version = "0.4.27" @@ -5901,16 +5894,6 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest 0.10.7", -] - [[package]] name = "mdbook" version = "0.4.48" @@ -6940,9 +6923,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -6976,9 +6959,9 @@ dependencies = [ [[package]] name = "prodash" -version = "29.0.1" +version = "29.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee7ce24c980b976607e2d6ae4aae92827994d23fed71659c3ede3f92528b58b" +checksum = "f04bb108f648884c23b98a0e940ebc2c93c0c3b89f04dbaf7eb8256ce617d1bc" dependencies = [ "log", "parking_lot", @@ -7163,7 +7146,7 @@ checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc" dependencies = [ "bytes", "getrandom 0.3.2", - "rand 0.9.0", + "rand 0.9.1", "ring", "rustc-hash 2.1.1", "rustls", @@ -7234,13 +7217,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", - "zerocopy 0.8.24", ] [[package]] @@ -7620,12 +7602,12 @@ dependencies = [ [[package]] name = "rtoolbox" -version = "0.0.2" +version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" +checksum = "a7cc970b249fbe527d6e02e0a227762c9108b2f49d81094fe357ffc6d14d7f6f" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -7648,7 +7630,7 @@ dependencies = [ "primitive-types", "proptest", "rand 0.8.5", - "rand 0.9.0", + "rand 0.9.1", "rlp", "ruint-macro", "serde", @@ -7876,9 +7858,9 @@ dependencies = [ [[package]] name = "scc" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea091f6cac2595aa38993f04f4ee692ed43757035c36e67c180b6828356385b1" +checksum = "22b2d775fb28f245817589471dd49c5edf64237f4a19d10ce9a92ff4651a27f4" dependencies = [ "sdd", ] @@ -8311,9 +8293,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "a1ee1aca2bc74ef9589efa7ccaa0f3752751399940356209b3fd80c078149b5e" dependencies = [ "libc", ] @@ -9616,7 +9598,7 @@ dependencies = [ "http 1.3.1", "httparse", "log", - "rand 0.9.0", + "rand 0.9.1", "rustls", "rustls-pki-types", "sha1", @@ -10659,6 +10641,12 @@ version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" +[[package]] +name = "xxhash-rust" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + [[package]] name = "yansi" version = "1.0.1" @@ -10824,14 +10812,12 @@ dependencies = [ [[package]] name = "zopfli" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" +checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" dependencies = [ "bumpalo", "crc32fast", - "lockfree-object-pool", "log", - "once_cell", "simd-adler32", ] From 8690fefcce1e77e01cd03c3d91c5e5a9f0723abc Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 22 Apr 2025 15:23:16 +0300 Subject: [PATCH 027/244] fix(forge): run git submodule sync when installing (#10347) --- crates/cli/src/utils/mod.rs | 4 ++++ crates/forge/src/cmd/install.rs | 3 +++ 2 files changed, 7 insertions(+) diff --git a/crates/cli/src/utils/mod.rs b/crates/cli/src/utils/mod.rs index 30c984c960f14..68cb49a6891fd 100644 --- a/crates/cli/src/utils/mod.rs +++ b/crates/cli/src/utils/mod.rs @@ -575,6 +575,10 @@ ignore them in the `.gitignore` file." self.cmd().stderr(self.stderr()).args(["submodule", "init"]).exec().map(drop) } + pub fn submodule_sync(self) -> Result<()> { + self.cmd().stderr(self.stderr()).args(["submodule", "sync"]).exec().map(drop) + } + pub fn cmd(self) -> Command { let mut cmd = Self::cmd_no_root(); cmd.current_dir(self.root); diff --git a/crates/forge/src/cmd/install.rs b/crates/forge/src/cmd/install.rs index 7672787ce26f6..0a88c6eca7ab1 100644 --- a/crates/forge/src/cmd/install.rs +++ b/crates/forge/src/cmd/install.rs @@ -276,6 +276,9 @@ impl Installer<'_> { std::iter::empty::(), )?; + // sync submodules config with changes in .gitmodules, see + self.git.root(path).submodule_sync()?; + if self.commit { self.git.add(Some(path))?; } From 1af5f85f22c8e02234888497558b618f861f208d Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Tue, 22 Apr 2025 16:33:27 +0200 Subject: [PATCH 028/244] chore(`release`): add `gcp-kms` flag to default release workflow (#10346) add gcp kms flag to workflow --- .github/workflows/release.yml | 4 ++-- Dockerfile | 2 +- Makefile | 8 ++++---- crates/forge/Cargo.toml | 1 + 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 140988d1e1b75..8d96287ebb22c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -159,7 +159,7 @@ jobs: run: | set -eo pipefail flags=(--target $TARGET --profile $PROFILE --bins - --no-default-features --features aws-kms,cli,asm-keccak) + --no-default-features --features aws-kms,gcp-kms,cli,asm-keccak) # `jemalloc` is not fully supported on MSVC or aarch64 Linux. if [[ "$TARGET" != *msvc* && "$TARGET" != "aarch64-unknown-linux-gnu" ]]; then @@ -293,7 +293,7 @@ jobs: issue: name: Open an issue runs-on: ubuntu-latest - needs: [ prepare, release-docker, release, cleanup ] + needs: [prepare, release-docker, release, cleanup] if: failure() steps: - uses: actions/checkout@v4 diff --git a/Dockerfile b/Dockerfile index 08b997d369050..57983fe283b4d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,7 @@ COPY . . RUN git update-index --force-write-index RUN --mount=type=cache,target=/root/.cargo/registry --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/opt/foundry/target \ - source $HOME/.profile && cargo build --release --features cast/aws-kms,forge/aws-kms \ + source $HOME/.profile && cargo build --release --features cast/aws-kms,cast/gcp-kms,forge/aws-kms,forge/gcp-kms \ && mkdir out \ && mv target/release/forge out/forge \ && mv target/release/cast out/cast \ diff --git a/Makefile b/Makefile index 73cc92cb5c9cd..24431a88458a7 100644 --- a/Makefile +++ b/Makefile @@ -13,9 +13,9 @@ CARGO_TARGET_DIR ?= target # List of features to use when building. Can be overridden via the environment. # No jemalloc on Windows ifeq ($(OS),Windows_NT) - FEATURES ?= aws-kms cli asm-keccak + FEATURES ?= aws-kms gcp-kms cli asm-keccak else - FEATURES ?= jemalloc aws-kms cli asm-keccak + FEATURES ?= jemalloc aws-kms gcp-kms cli asm-keccak endif ##@ Help @@ -44,13 +44,13 @@ build-%: .PHONY: docker-build-push docker-build-push: docker-build-prepare ## Build and push a cross-arch Docker image tagged with DOCKER_IMAGE_NAME. - FEATURES="jemalloc aws-kms cli asm-keccak" $(MAKE) build-x86_64-unknown-linux-gnu + FEATURES="jemalloc aws-kms gcp-kms cli asm-keccak" $(MAKE) build-x86_64-unknown-linux-gnu mkdir -p $(BIN_DIR)/amd64 for bin in anvil cast chisel forge; do \ cp $(CARGO_TARGET_DIR)/x86_64-unknown-linux-gnu/$(PROFILE)/$$bin $(BIN_DIR)/amd64/; \ done - FEATURES="aws-kms cli asm-keccak" $(MAKE) build-aarch64-unknown-linux-gnu + FEATURES="aws-kms gcp-kms cli asm-keccak" $(MAKE) build-aarch64-unknown-linux-gnu mkdir -p $(BIN_DIR)/arm64 for bin in anvil cast chisel forge; do \ cp $(CARGO_TARGET_DIR)/aarch64-unknown-linux-gnu/$(PROFILE)/$$bin $(BIN_DIR)/arm64/; \ diff --git a/crates/forge/Cargo.toml b/crates/forge/Cargo.toml index f2265703f879e..ffcb88fdf0351 100644 --- a/crates/forge/Cargo.toml +++ b/crates/forge/Cargo.toml @@ -118,4 +118,5 @@ default = ["jemalloc"] asm-keccak = ["alloy-primitives/asm-keccak"] jemalloc = ["dep:tikv-jemallocator"] aws-kms = ["foundry-wallets/aws-kms"] +gcp-kms = ["foundry-wallets/gcp-kms"] isolate-by-default = ["foundry-config/isolate-by-default"] From e9888937e032b3b4729b2e902c1eaf51f84a9948 Mon Sep 17 00:00:00 2001 From: 0xcomfycat <140531986+0xcomfycat@users.noreply.github.com> Date: Tue, 22 Apr 2025 21:41:08 +0700 Subject: [PATCH 029/244] feat(forge): add new cheatcode `attachBlob` to send EIP-4844 transaction (#10336) * feat: add new cheatcode attachBlob * fix: lint * fix: build fail due to missing feature flag --------- Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> --- crates/cheatcodes/Cargo.toml | 2 +- crates/cheatcodes/assets/cheatcodes.json | 20 +++++++++ crates/cheatcodes/spec/src/vm.rs | 4 ++ crates/cheatcodes/src/inspector.rs | 34 ++++++++++++-- crates/cheatcodes/src/script.rs | 18 +++++++- testdata/cheats/Vm.sol | 1 + testdata/default/cheats/AttachBlob.t.sol | 56 ++++++++++++++++++++++++ 7 files changed, 129 insertions(+), 6 deletions(-) create mode 100644 testdata/default/cheats/AttachBlob.t.sol diff --git a/crates/cheatcodes/Cargo.toml b/crates/cheatcodes/Cargo.toml index 645426ea8bf29..49611dcca071c 100644 --- a/crates/cheatcodes/Cargo.toml +++ b/crates/cheatcodes/Cargo.toml @@ -37,7 +37,7 @@ alloy-signer-local = { workspace = true, features = [ "keystore", ] } parking_lot.workspace = true -alloy-consensus = { workspace = true, features = ["k256"] } +alloy-consensus = { workspace = true, features = ["k256", "kzg"] } alloy-network.workspace = true alloy-rlp.workspace = true alloy-chains.workspace = true diff --git a/crates/cheatcodes/assets/cheatcodes.json b/crates/cheatcodes/assets/cheatcodes.json index 7cce924b5f60c..59c5bab3cb457 100644 --- a/crates/cheatcodes/assets/cheatcodes.json +++ b/crates/cheatcodes/assets/cheatcodes.json @@ -3230,6 +3230,26 @@ "status": "stable", "safety": "safe" }, + { + "func": { + "id": "attachBlob", + "description": "Attach an EIP-4844 blob to the next call", + "declaration": "function attachBlob(bytes calldata blob) external;", + "visibility": "external", + "mutability": "", + "signature": "attachBlob(bytes)", + "selector": "0x10cb385c", + "selectorBytes": [ + 16, + 203, + 56, + 92 + ] + }, + "group": "scripting", + "status": "stable", + "safety": "safe" + }, { "func": { "id": "attachDelegation", diff --git a/crates/cheatcodes/spec/src/vm.rs b/crates/cheatcodes/spec/src/vm.rs index c0481569af296..00f3b8004a96c 100644 --- a/crates/cheatcodes/spec/src/vm.rs +++ b/crates/cheatcodes/spec/src/vm.rs @@ -2236,6 +2236,10 @@ interface Vm { #[cheatcode(group = Scripting)] function signAndAttachDelegation(address implementation, uint256 privateKey, uint64 nonce) external returns (SignedDelegation memory signedDelegation); + /// Attach an EIP-4844 blob to the next call + #[cheatcode(group = Scripting)] + function attachBlob(bytes calldata blob) external; + /// Returns addresses of available unlocked wallets in the script environment. #[cheatcode(group = Scripting)] function getWallets() external returns (address[] memory wallets); diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index fd60fb1982a7e..251210113c4e6 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -21,6 +21,8 @@ use crate::{ CheatsConfig, CheatsCtxt, DynCheatcode, Error, Result, Vm::{self, AccountAccess}, }; +use alloy_consensus::BlobTransactionSidecar; +use alloy_network::TransactionBuilder4844; use alloy_primitives::{ hex, map::{AddressHashMap, HashMap, HashSet}, @@ -393,6 +395,9 @@ pub struct Cheatcodes { /// transaction construction. pub active_delegation: Option, + /// The active EIP-4844 blob that will be attached to the next call. + pub active_blob_sidecar: Option, + /// The gas price. /// /// Used in the cheatcode handler to overwrite the gas price separately from the gas price @@ -526,6 +531,7 @@ impl Cheatcodes { config, block: Default::default(), active_delegation: Default::default(), + active_blob_sidecar: Default::default(), gas_price: Default::default(), pranks: Default::default(), expected_revert: Default::default(), @@ -1127,10 +1133,30 @@ where { ..Default::default() }; - if let Some(auth_list) = self.active_delegation.take() { - tx_req.authorization_list = Some(vec![auth_list]); - } else { - tx_req.authorization_list = None; + match (self.active_delegation.take(), self.active_blob_sidecar.take()) { + (Some(_), Some(_)) => { + let msg = "both delegation and blob are active; `attachBlob` and `attachDelegation` are not compatible"; + return Some(CallOutcome { + result: InterpreterResult { + result: InstructionResult::Revert, + output: Error::encode(msg), + gas, + }, + memory_offset: call.return_memory_offset.clone(), + }); + } + (Some(auth_list), None) => { + tx_req.authorization_list = Some(vec![auth_list]); + tx_req.sidecar = None; + } + (None, Some(blob_sidecar)) => { + tx_req.set_blob_sidecar(blob_sidecar); + tx_req.authorization_list = None; + } + (None, None) => { + tx_req.sidecar = None; + tx_req.authorization_list = None; + } } self.broadcastable_transactions.push_back(BroadcastableTransaction { diff --git a/crates/cheatcodes/src/script.rs b/crates/cheatcodes/src/script.rs index d940cb438b8af..dc80b7021ab04 100644 --- a/crates/cheatcodes/src/script.rs +++ b/crates/cheatcodes/src/script.rs @@ -1,6 +1,7 @@ //! Implementations of [`Scripting`](spec::Group::Scripting) cheatcodes. use crate::{Cheatcode, CheatsCtxt, Result, Vm::*}; +use alloy_consensus::{SidecarBuilder, SimpleCoder}; use alloy_primitives::{Address, Uint, B256, U256}; use alloy_rpc_types::Authorization; use alloy_signer::SignerSync; @@ -8,7 +9,7 @@ use alloy_signer_local::PrivateKeySigner; use alloy_sol_types::SolValue; use foundry_wallets::{multi_wallet::MultiWallet, WalletSigner}; use parking_lot::Mutex; -use revm::primitives::{Bytecode, SignedAuthorization}; +use revm::primitives::{Bytecode, SignedAuthorization, SpecId}; use std::sync::Arc; impl Cheatcode for broadcast_0Call { @@ -133,6 +134,21 @@ fn write_delegation(ccx: &mut CheatsCtxt, auth: SignedAuthorization) -> Result<( Ok(()) } +impl Cheatcode for attachBlobCall { + fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { + let Self { blob } = self; + ensure!( + ccx.ecx.spec_id() >= SpecId::CANCUN, + "`attachBlob` is not supported before the Cancun hard fork; \ + see EIP-4844: https://eips.ethereum.org/EIPS/eip-4844" + ); + let sidecar: SidecarBuilder = SidecarBuilder::from_slice(blob); + let sidecar = sidecar.build().map_err(|e| format!("{e}"))?; + ccx.state.active_blob_sidecar = Some(sidecar); + Ok(Default::default()) + } +} + impl Cheatcode for startBroadcast_0Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self {} = self; diff --git a/testdata/cheats/Vm.sol b/testdata/cheats/Vm.sol index b3a447cc5e1dc..adf6733ba9424 100644 --- a/testdata/cheats/Vm.sol +++ b/testdata/cheats/Vm.sol @@ -155,6 +155,7 @@ interface Vm { function assumeNoRevert() external pure; function assumeNoRevert(PotentialRevert calldata potentialRevert) external pure; function assumeNoRevert(PotentialRevert[] calldata potentialReverts) external pure; + function attachBlob(bytes calldata blob) external; function attachDelegation(SignedDelegation calldata signedDelegation) external; function blobBaseFee(uint256 newBlobBaseFee) external; function blobhashes(bytes32[] calldata hashes) external; diff --git a/testdata/default/cheats/AttachBlob.t.sol b/testdata/default/cheats/AttachBlob.t.sol new file mode 100644 index 0000000000000..db17c1fae5f4c --- /dev/null +++ b/testdata/default/cheats/AttachBlob.t.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity ^0.8.25; + +import "ds-test/test.sol"; +import "cheats/Vm.sol"; + +contract Counter { + uint256 public counter; + + function increment() public { + counter++; + } +} + +contract AttachBlobTest is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + uint256 bobPk = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d; + address bob = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8; + + Counter public counter; + + function setUp() public { + counter = new Counter(); + } + + function testAttachBlob() public { + bytes memory blob = abi.encode("Blob the Builder"); + vm.attachBlob(blob); + + vm.broadcast(bobPk); + counter.increment(); + } + + function testAttachBlobWithCreateTx() public { + bytes memory blob = abi.encode("Blob the Builder"); + vm.attachBlob(blob); + + vm.broadcast(bobPk); + new Counter(); + + // blob is attached with this tx instead + vm.broadcast(bobPk); + counter.increment(); + } + + /// forge-config: default.allow_internal_expect_revert = true + function testRevertAttachBlobWithDelegation() public { + bytes memory blob = abi.encode("Blob the Builder"); + vm.attachBlob(blob); + vm.signAndAttachDelegation(address(0), bobPk); + + vm.broadcast(bobPk); + vm.expectRevert("both delegation and blob are active; `attachBlob` and `attachDelegation` are not compatible"); + counter.increment(); + } +} From 055b0ea4311254f89d1b3274eddb07bfac288f6c Mon Sep 17 00:00:00 2001 From: Maximilian Hubert <64627729+gap-editor@users.noreply.github.com> Date: Wed, 23 Apr 2025 08:23:57 +0200 Subject: [PATCH 030/244] feat(script): revert if address(this) used (#10295) * Update stack.rs * Update lib.rs * Update lib.rs * Update stack.rs * Create ScriptAddressWarn.t.sol * Update mod.rs * Update stack.rs * Update lib.rs * Create script.rs * Fix compilation, cleanup, add new test in script tests * Set and check current address is script address * Update stack.rs * Allow calls to external libraries * changes after review: use sh_err --------- Co-authored-by: grandizzy Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> --- crates/evm/evm/src/executors/mod.rs | 5 ++++ crates/evm/evm/src/inspectors/mod.rs | 3 ++ crates/evm/evm/src/inspectors/script.rs | 37 +++++++++++++++++++++++++ crates/evm/evm/src/inspectors/stack.rs | 22 +++++++++++++-- crates/forge/tests/cli/script.rs | 25 +++++++++++++++++ crates/script/src/runner.rs | 3 ++ testdata/default/cheats/Broadcast.t.sol | 7 ----- 7 files changed, 92 insertions(+), 10 deletions(-) create mode 100644 crates/evm/evm/src/inspectors/script.rs diff --git a/crates/evm/evm/src/executors/mod.rs b/crates/evm/evm/src/executors/mod.rs index 5c26a6d6cdc5d..9c4b27e0377dc 100644 --- a/crates/evm/evm/src/executors/mod.rs +++ b/crates/evm/evm/src/executors/mod.rs @@ -257,6 +257,11 @@ impl Executor { self } + #[inline] + pub fn set_script(&mut self, script_address: Address) { + self.inspector_mut().script(script_address); + } + #[inline] pub fn set_trace_printer(&mut self, trace_printer: bool) -> &mut Self { self.inspector_mut().print(trace_printer); diff --git a/crates/evm/evm/src/inspectors/mod.rs b/crates/evm/evm/src/inspectors/mod.rs index 41008397a1cbc..914bf460e5e44 100644 --- a/crates/evm/evm/src/inspectors/mod.rs +++ b/crates/evm/evm/src/inspectors/mod.rs @@ -13,5 +13,8 @@ pub use chisel_state::ChiselState; mod logs; pub use logs::LogCollector; +mod script; +pub use script::ScriptExecutionInspector; + mod stack; pub use stack::{InspectorData, InspectorStack, InspectorStackBuilder}; diff --git a/crates/evm/evm/src/inspectors/script.rs b/crates/evm/evm/src/inspectors/script.rs new file mode 100644 index 0000000000000..57fa7b209b162 --- /dev/null +++ b/crates/evm/evm/src/inspectors/script.rs @@ -0,0 +1,37 @@ +use alloy_primitives::Address; +use foundry_common::sh_err; +use revm::{ + interpreter::{opcode::ADDRESS, InstructionResult, Interpreter}, + Database, EvmContext, Inspector, +}; + +/// An inspector that enforces certain rules during script execution. +/// +/// Currently, it only warns if the `ADDRESS` opcode is used within the script's main contract. +#[derive(Clone, Debug, Default)] +pub struct ScriptExecutionInspector { + /// The address of the script contract being executed. + pub script_address: Address, +} + +impl Inspector for ScriptExecutionInspector { + #[inline] + fn step(&mut self, interpreter: &mut Interpreter, _ecx: &mut EvmContext) { + // Check if both target and bytecode address are the same as script contract address + // (allow calling external libraries when bytecode address is different). + if interpreter.current_opcode() == ADDRESS && + interpreter.contract.target_address == self.script_address && + interpreter.contract.bytecode_address.unwrap_or_default() == self.script_address + { + // Log the reason for revert + let _ = sh_err!( + "Usage of `address(this)` detected in script contract. Script contracts are ephemeral and their addresses should not be relied upon." + ); + // Set the instruction result to Revert to stop execution + interpreter.instruction_result = InstructionResult::Revert; + } + // Note: We don't return anything here as step returns void. + // The original check returned InstructionResult::Continue, but that's the default + // behavior. + } +} diff --git a/crates/evm/evm/src/inspectors/stack.rs b/crates/evm/evm/src/inspectors/stack.rs index e23adfcae0661..773730d6cc136 100644 --- a/crates/evm/evm/src/inspectors/stack.rs +++ b/crates/evm/evm/src/inspectors/stack.rs @@ -1,6 +1,6 @@ use super::{ Cheatcodes, CheatsConfig, ChiselState, CoverageCollector, Fuzzer, LogCollector, - TracingInspector, + ScriptExecutionInspector, TracingInspector, }; use alloy_primitives::{map::AddressHashMap, Address, Bytes, Log, TxKind, U256}; use foundry_cheatcodes::{CheatcodesExecutor, Wallets}; @@ -199,6 +199,7 @@ impl InspectorStackBuilder { if let Some(chisel_state) = chisel_state { stack.set_chisel(chisel_state); } + stack.collect_coverage(coverage.unwrap_or(false)); stack.collect_logs(logs.unwrap_or(true)); stack.print(print.unwrap_or(false)); @@ -290,6 +291,7 @@ pub struct InspectorStackInner { pub log_collector: Option, pub printer: Option, pub tracer: Option, + pub script_execution_inspector: Option, pub enable_isolation: bool, pub odyssey: bool, pub create2_deployer: Address, @@ -437,6 +439,13 @@ impl InspectorStack { } } + /// Set whether to enable script execution inspector. + #[inline] + pub fn script(&mut self, script_address: Address) { + self.script_execution_inspector.get_or_insert_with(Default::default).script_address = + script_address; + } + /// Collects all the data gathered during inspection into a single struct. #[inline] pub fn collect(self) -> InspectorData { @@ -757,7 +766,13 @@ impl Inspector<&mut dyn DatabaseExt> for InspectorStackRefMut<'_> { ecx: &mut EvmContext<&mut dyn DatabaseExt>, ) { call_inspectors!( - [&mut self.coverage, &mut self.tracer, &mut self.cheatcodes, &mut self.printer], + [ + &mut self.coverage, + &mut self.tracer, + &mut self.cheatcodes, + &mut self.script_execution_inspector, + &mut self.printer + ], |inspector| inspector.initialize_interp(interpreter, ecx), ); } @@ -769,7 +784,8 @@ impl Inspector<&mut dyn DatabaseExt> for InspectorStackRefMut<'_> { &mut self.tracer, &mut self.coverage, &mut self.cheatcodes, - &mut self.printer, + &mut self.script_execution_inspector, + &mut self.printer ], |inspector| inspector.step(interpreter, ecx), ); diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index 371a87fdc94ab..8f0df538e9636 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -2645,3 +2645,28 @@ Script ran successfully. "#]]); }); + +// Tests that script reverts if it uses `address(this)`. +forgetest_init!(should_revert_on_address_opcode, |prj, cmd| { + prj.add_script( + "ScriptWithAddress.s.sol", + r#" + import {Script, console} from "forge-std/Script.sol"; + + contract ScriptWithAddress is Script { + function run() public view { + console.log("script address", address(this)); + } + } + "#, + ) + .unwrap(); + + cmd.arg("script").arg("ScriptWithAddress").assert_failure().stderr_eq(str![[r#" +... +Error: Usage of `address(this)` detected in script contract. Script contracts are ephemeral and their addresses should not be relied upon. +Error: script failed: +... + +"#]]); +}); diff --git a/crates/script/src/runner.rs b/crates/script/src/runner.rs index 2d58e381f6356..d45a97139dae4 100644 --- a/crates/script/src/runner.rs +++ b/crates/script/src/runner.rs @@ -157,6 +157,9 @@ impl ScriptRunner { self.executor.set_nonce(self.evm_opts.sender, prev_sender_nonce)?; } + // set script address to be used by execution inspector + self.executor.set_script(address); + traces.extend(constructor_traces.map(|traces| (TraceKind::Deployment, traces))); // Optionally call the `setUp` function diff --git a/testdata/default/cheats/Broadcast.t.sol b/testdata/default/cheats/Broadcast.t.sol index 6486049b03b3e..9916ca0efc799 100644 --- a/testdata/default/cheats/Broadcast.t.sol +++ b/testdata/default/cheats/Broadcast.t.sol @@ -112,8 +112,6 @@ contract BroadcastTest is DSTest { vm.stopBroadcast(); - require(test.echoSender() == address(this)); - vm.broadcast(ACCOUNT_B); Test tmptest2 = new Test(); @@ -577,11 +575,6 @@ contract ScriptSign is DSTest { vm.startBroadcast(); (uint8 v, bytes32 r, bytes32 s) = vm.sign(digest); - vm._expectCheatcodeRevert( - bytes(string.concat("signer with address ", vm.toString(address(this)), " is not available")) - ); - vm.sign(address(this), digest); - SignatureTester tester = new SignatureTester(); (, address caller,) = vm.readCallers(); assertEq(tester.owner(), caller); From 77aec5998edc1ba4d72bd66c09a8df7d206e09d4 Mon Sep 17 00:00:00 2001 From: Nnamdi Aninye Date: Wed, 23 Apr 2025 15:05:03 +0100 Subject: [PATCH 031/244] feat(cast): Include recover_authority when logging SignedAuthorization (#10349) * add recover_authority when logging signed_authority * add error handling and test for signed_authorization formatting * update naming * update formatting --------- Co-authored-by: Nnamdi Aninye --- crates/common/fmt/src/ui.rs | 45 ++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/crates/common/fmt/src/ui.rs b/crates/common/fmt/src/ui.rs index 64e342c497b01..16600324bcb0f 100644 --- a/crates/common/fmt/src/ui.rs +++ b/crates/common/fmt/src/ui.rs @@ -12,6 +12,7 @@ use alloy_rpc_types::{ AccessListItem, Block, BlockTransactions, Header, Log, Transaction, TransactionReceipt, }; use alloy_serde::{OtherFields, WithOtherFields}; +use revm_primitives::SignedAuthorization; use serde::Deserialize; /// length of the name column for pretty formatting `{:>20}{value}` @@ -443,8 +444,9 @@ yParity {}", .pretty(), self.authorization_list() .as_ref() - .map(|l| serde_json::to_string(&l).unwrap()) - .unwrap_or_default(), + .map(|l| l.iter().collect::>()) + .unwrap_or_default() + .pretty(), self.chain_id().pretty(), self.gas_limit().pretty(), self.tx_hash().pretty(), @@ -675,8 +677,9 @@ yParity {}", .pretty(), self.authorization_list() .as_ref() - .map(|l| serde_json::to_string(&l).unwrap()) - .unwrap_or_default(), + .map(|l| l.iter().collect::>()) + .unwrap_or_default() + .pretty(), self.block_hash.pretty(), self.block_number.pretty(), self.chain_id().pretty(), @@ -808,6 +811,21 @@ impl UIfmt for EthValue { } } +impl UIfmt for SignedAuthorization { + fn pretty(&self) -> String { + let signed_authorization = serde_json::to_string(self).unwrap_or("".to_string()); + + match self.recover_authority() { + Ok(authority) => format!( + "{{recoveredAuthority: {authority}, signedAuthority: {signed_authorization}}}", + ), + Err(e) => format!( + "{{recoveredAuthority: , signedAuthority: {signed_authorization}}}", + ), + } + } +} + /// Returns the `UiFmt::pretty()` formatted attribute of the transactions pub fn get_pretty_tx_attr(transaction: &Transaction, attr: &str) -> Option { let sig = match &transaction.inner.inner() { @@ -867,7 +885,7 @@ pub fn get_pretty_block_attr(block: &AnyRpcBlock, attr: &str) -> Option other => { if let Some(value) = block.other.get(other) { let val = EthValue::from(value.clone()); - return Some(val.pretty()) + return Some(val.pretty()); } None } @@ -970,6 +988,7 @@ requestsHash {}", mod tests { use super::*; use alloy_primitives::B256; + use alloy_rpc_types::Authorization; use similar_asserts::assert_eq; use std::str::FromStr; @@ -1473,4 +1492,20 @@ l1GasUsed 1600 assert_eq!(formatted.trim(), expected.trim()); } + + #[test] + fn test_uifmt_for_signed_authorization() { + let inner = Authorization { + chain_id: U256::from(1), + address: "0x000000000000000000000000000000000000dead".parse::

().unwrap(), + nonce: 42, + }; + let signed_authorization = + SignedAuthorization::new_unchecked(inner, 1, U256::from(20), U256::from(30)); + + assert_eq!( + signed_authorization.pretty(), + r#"{recoveredAuthority: 0xf3eaBD0de6Ca1aE7fC4D81FfD6C9a40e5D5D7e30, signedAuthority: {"chainId":"0x1","address":"0x000000000000000000000000000000000000dead","nonce":"0x2a","yParity":"0x1","r":"0x14","s":"0x1e"}}"# + ); + } } From 70ded2b35f95ee9b4ee94f5e44961914d30a87f7 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Wed, 23 Apr 2025 19:41:48 +0300 Subject: [PATCH 032/244] chore: fix isolate tests (#10344) --- crates/forge/tests/cli/test_optimizer.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/forge/tests/cli/test_optimizer.rs b/crates/forge/tests/cli/test_optimizer.rs index 6caa03412aa37..f196746490ece 100644 --- a/crates/forge/tests/cli/test_optimizer.rs +++ b/crates/forge/tests/cli/test_optimizer.rs @@ -1347,6 +1347,7 @@ Compiling 20 files with [..] }); // Test preprocessed contracts with decode internal fns. +#[cfg(not(feature = "isolate-by-default"))] forgetest_init!(preprocess_contract_with_decode_internal, |prj, cmd| { prj.update_config(|config| { config.dynamic_test_linking = true; From 55802bad5f9068d969df4273b5c2a960332e8e42 Mon Sep 17 00:00:00 2001 From: Tushar Jain <54453857+tushar994@users.noreply.github.com> Date: Thu, 24 Apr 2025 00:01:49 +0530 Subject: [PATCH 033/244] Add state overrides flags to cast call (#10255) * add initial implementation * modify flag names * minor change: fix cargo clipy * fix docs * fix docs * minor fix * fix cargo fmt * Revert "fix cargo fmt" This reverts commit e7712694339203ef7c23435d18d15089fc654794. * add test * fix tests * use alloys Accountoverride * move get_state_overrides to self * minor fixes * remove parse_address_value_for_nonce and use a general function. use get_or_insert_default. remove clones(). * use regex for address slot value parsing * make all override flags options * Fmt and clippy * Use StateOverridesBuilder, nit * Fix docs * Add better tests for state, code and balance overrides --------- Co-authored-by: grandizzy Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> --- crates/cast/src/cmd/call.rs | 189 +++++++++++++++++++++++++++++++--- crates/cast/src/lib.rs | 29 ++++-- crates/cast/tests/cli/main.rs | 126 +++++++++++++++++++++++ 3 files changed, 324 insertions(+), 20 deletions(-) diff --git a/crates/cast/src/cmd/call.rs b/crates/cast/src/cmd/call.rs index 053bad5d2c664..65ee4c068c17b 100644 --- a/crates/cast/src/cmd/call.rs +++ b/crates/cast/src/cmd/call.rs @@ -3,8 +3,11 @@ use crate::{ tx::{CastTxBuilder, SenderKind}, Cast, }; -use alloy_primitives::{TxKind, U256}; -use alloy_rpc_types::{BlockId, BlockNumberOrTag}; +use alloy_primitives::{Address, Bytes, TxKind, U256}; +use alloy_rpc_types::{ + state::{StateOverride, StateOverridesBuilder}, + BlockId, BlockNumberOrTag, +}; use clap::Parser; use eyre::Result; use foundry_cli::{ @@ -26,9 +29,35 @@ use foundry_evm::{ opts::EvmOpts, traces::{InternalTraceMode, TraceMode}, }; -use std::str::FromStr; +use regex::Regex; +use std::{str::FromStr, sync::LazyLock}; + +// matches override pattern
:: +// e.g. 0x123:0x1:0x1234 +static OVERRIDE_PATTERN: LazyLock = + LazyLock::new(|| Regex::new(r"^([^:]+):([^:]+):([^:]+)$").unwrap()); /// CLI arguments for `cast call`. +/// +/// ## State Override Flags +/// +/// The following flags can be used to override the state for the call: +/// +/// * `--override-balance
:` - Override the balance of an account +/// * `--override-nonce
:` - Override the nonce of an account +/// * `--override-code
:` - Override the code of an account +/// * `--override-state
::` - Override a storage slot of an account +/// +/// Multiple overrides can be specified for the same account. For example: +/// +/// ```bash +/// cast call 0x... "transfer(address,uint256)" 0x... 100 \ +/// --override-balance 0x123:0x1234 \ +/// --override-nonce 0x123:1 \ +/// --override-code 0x123:0x1234 \ +/// --override-state 0x123:0x1:0x1234 +/// --override-state-diff 0x123:0x1:0x1234 +/// ``` #[derive(Debug, Parser)] pub struct CallArgs { /// The destination of the transaction. @@ -92,6 +121,31 @@ pub struct CallArgs { /// Use current project artifacts for trace decoding. #[arg(long, visible_alias = "la")] pub with_local_artifacts: bool, + + /// Override the balance of an account. + /// Format: address:balance + #[arg(long = "override-balance", value_name = "ADDRESS:BALANCE")] + pub balance_overrides: Option>, + + /// Override the nonce of an account. + /// Format: address:nonce + #[arg(long = "override-nonce", value_name = "ADDRESS:NONCE")] + pub nonce_overrides: Option>, + + /// Override the code of an account. + /// Format: address:code + #[arg(long = "override-code", value_name = "ADDRESS:CODE")] + pub code_overrides: Option>, + + /// Override the state of an account. + /// Format: address:slot:value + #[arg(long = "override-state", value_name = "ADDRESS:SLOT:VALUE")] + pub state_overrides: Option>, + + /// Override the state diff of an account. + /// Format: address:slot:value + #[arg(long = "override-state-diff", value_name = "ADDRESS:SLOT:VALUE")] + pub state_diff_overrides: Option>, } #[derive(Debug, Parser)] @@ -123,6 +177,7 @@ impl CallArgs { let figment = Into::::into(&self.eth).merge(&self); let evm_opts = figment.extract::()?; let mut config = Config::from_provider(figment)?.sanitized(); + let state_overrides = self.get_state_overrides()?; let Self { to, @@ -236,10 +291,54 @@ impl CallArgs { return Ok(()); } - sh_println!("{}", Cast::new(provider).call(&tx, func.as_ref(), block).await?)?; + sh_println!( + "{}", + Cast::new(provider).call(&tx, func.as_ref(), block, state_overrides).await? + )?; Ok(()) } + /// Parse state overrides from command line arguments + pub fn get_state_overrides(&self) -> eyre::Result { + let mut state_overrides_builder = StateOverridesBuilder::default(); + + // Parse balance overrides + for override_str in self.balance_overrides.iter().flatten() { + let (addr, balance) = address_value_override(override_str)?; + state_overrides_builder = + state_overrides_builder.with_balance(addr.parse()?, balance.parse()?); + } + + // Parse nonce overrides + for override_str in self.nonce_overrides.iter().flatten() { + let (addr, nonce) = address_value_override(override_str)?; + state_overrides_builder = + state_overrides_builder.with_nonce(addr.parse()?, nonce.parse()?); + } + + // Parse code overrides + for override_str in self.code_overrides.iter().flatten() { + let (addr, code_str) = address_value_override(override_str)?; + state_overrides_builder = + state_overrides_builder.with_code(addr.parse()?, Bytes::from_str(code_str)?); + } + + // Parse state overrides + for override_str in self.state_overrides.iter().flatten() { + let (addr, slot, value) = address_slot_value_override(override_str)?; + state_overrides_builder = + state_overrides_builder.with_state(addr, [(slot.into(), value.into())]); + } + + // Parse state diff overrides + for override_str in self.state_diff_overrides.iter().flatten() { + let (addr, slot, value) = address_slot_value_override(override_str)?; + state_overrides_builder = + state_overrides_builder.with_state_diff(addr, [(slot.into(), value.into())]); + } + + Ok(state_overrides_builder.build()) + } } impl figment::Provider for CallArgs { @@ -262,10 +361,30 @@ impl figment::Provider for CallArgs { } } +/// Parse an override string in the format address:value. +fn address_value_override(address_override: &str) -> Result<(&str, &str)> { + address_override.split_once(':').ok_or_else(|| { + eyre::eyre!("Invalid override {address_override}. Expected
:") + }) +} + +/// Parse an override string in the format address:slot:value. +fn address_slot_value_override(address_override: &str) -> Result<(Address, U256, U256)> { + let captures = OVERRIDE_PATTERN.captures(address_override).ok_or_else(|| { + eyre::eyre!("Invalid override {address_override}. Expected
::") + })?; + + Ok(( + captures[1].parse()?, // Address + captures[2].parse()?, // Slot (U256) + captures[3].parse()?, // Value (U256) + )) +} + #[cfg(test)] mod tests { use super::*; - use alloy_primitives::{hex, Address}; + use alloy_primitives::hex; #[test] fn can_parse_call_data() { @@ -279,17 +398,59 @@ mod tests { } #[test] - fn call_sig_and_data_exclusive() { - let data = hex::encode("hello"); - let to = Address::ZERO; - let args = CallArgs::try_parse_from([ + fn can_parse_state_overrides() { + let args = CallArgs::parse_from([ + "foundry-cli", + "--override-balance", + "0x123:0x1234", + "--override-nonce", + "0x123:1", + "--override-code", + "0x123:0x1234", + "--override-state", + "0x123:0x1:0x1234", + ]); + + assert_eq!(args.balance_overrides, Some(vec!["0x123:0x1234".to_string()])); + assert_eq!(args.nonce_overrides, Some(vec!["0x123:1".to_string()])); + assert_eq!(args.code_overrides, Some(vec!["0x123:0x1234".to_string()])); + assert_eq!(args.state_overrides, Some(vec!["0x123:0x1:0x1234".to_string()])); + } + + #[test] + fn can_parse_multiple_state_overrides() { + let args = CallArgs::parse_from([ "foundry-cli", - to.to_string().as_str(), - "signature", - "--data", - format!("0x{data}").as_str(), + "--override-balance", + "0x123:0x1234", + "--override-balance", + "0x456:0x5678", + "--override-nonce", + "0x123:1", + "--override-nonce", + "0x456:2", + "--override-code", + "0x123:0x1234", + "--override-code", + "0x456:0x5678", + "--override-state", + "0x123:0x1:0x1234", + "--override-state", + "0x456:0x2:0x5678", ]); - assert!(args.is_err()); + assert_eq!( + args.balance_overrides, + Some(vec!["0x123:0x1234".to_string(), "0x456:0x5678".to_string()]) + ); + assert_eq!(args.nonce_overrides, Some(vec!["0x123:1".to_string(), "0x456:2".to_string()])); + assert_eq!( + args.code_overrides, + Some(vec!["0x123:0x1234".to_string(), "0x456:0x5678".to_string()]) + ); + assert_eq!( + args.state_overrides, + Some(vec!["0x123:0x1:0x1234".to_string(), "0x456:0x2:0x5678".to_string()]) + ); } } diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index a83e67ef2183f..66a0abc75f78f 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -16,7 +16,9 @@ use alloy_provider::{ PendingTransactionBuilder, Provider, }; use alloy_rlp::Decodable; -use alloy_rpc_types::{BlockId, BlockNumberOrTag, Filter, TransactionRequest}; +use alloy_rpc_types::{ + state::StateOverride, BlockId, BlockNumberOrTag, Filter, TransactionRequest, +}; use alloy_serde::WithOtherFields; use alloy_sol_types::sol; use base::{Base, NumberWithBase, ToBase}; @@ -107,11 +109,12 @@ impl> Cast

{ /// /// ``` /// use alloy_primitives::{Address, U256, Bytes}; - /// use alloy_rpc_types::{TransactionRequest}; + /// use alloy_rpc_types::{TransactionRequest, state::{StateOverride, AccountOverride}}; /// use alloy_serde::WithOtherFields; /// use cast::Cast; /// use alloy_provider::{RootProvider, ProviderBuilder, network::AnyNetwork}; - /// use std::str::FromStr; + /// use std::{str::FromStr, collections::HashMap}; + /// use alloy_rpc_types::state::StateOverridesBuilder; /// use alloy_sol_types::{sol, SolCall}; /// /// sol!( @@ -119,14 +122,22 @@ impl> Cast

{ /// ); /// /// # async fn foo() -> eyre::Result<()> { - /// let alloy_provider = ProviderBuilder::<_,_, AnyNetwork>::default().on_builtin("http://localhost:8545").await?;; + /// let alloy_provider = ProviderBuilder::<_,_, AnyNetwork>::default().connect("http://localhost:8545").await?;; /// let to = Address::from_str("0xB3C95ff08316fb2F2e3E52Ee82F8e7b605Aa1304")?; /// let greeting = greetingCall { i: U256::from(5) }.abi_encode(); /// let bytes = Bytes::from_iter(greeting.iter()); /// let tx = TransactionRequest::default().to(to).input(bytes.into()); /// let tx = WithOtherFields::new(tx); + /// + /// // Create state overrides + /// let mut state_override = StateOverride::default(); + /// let mut account_override = AccountOverride::default(); + /// account_override.balance = Some(U256::from(1000)); + /// state_override.insert(to, account_override); + /// let state_override_object = StateOverridesBuilder::default().build(); + /// /// let cast = Cast::new(alloy_provider); - /// let data = cast.call(&tx, None, None).await?; + /// let data = cast.call(&tx, None, None, state_override_object).await?; /// println!("{}", data); /// # Ok(()) /// # } @@ -136,8 +147,14 @@ impl> Cast

{ req: &WithOtherFields, func: Option<&Function>, block: Option, + state_override: StateOverride, ) -> Result { - let res = self.provider.call(req.clone()).block(block.unwrap_or_default()).await?; + let res = self + .provider + .call(req.clone()) + .block(block.unwrap_or_default()) + .overrides(state_override) + .await?; let mut decoded = vec![]; diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index c37ea2bbed221..be2e9a7ed7101 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -2257,6 +2257,132 @@ forgetest_async!(cast_call_custom_chain_id, |_prj, cmd| { .assert_success(); }); +// https://github.com/foundry-rs/foundry/issues/10189 +forgetest_async!(cast_call_custom_override, |prj, cmd| { + let (_, handle) = anvil::spawn(NodeConfig::test()).await; + + foundry_test_utils::util::initialize(prj.root()); + prj.add_source( + "Counter", + r#" +contract Counter { + uint256 public number; + + function getBalance(address target) public returns (uint256) { + return target.balance; + } +} + "#, + ) + .unwrap(); + + // Deploy counter contract. + cmd.args([ + "script", + "--private-key", + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + "--rpc-url", + &handle.http_endpoint(), + "--broadcast", + "CounterScript", + ]) + .assert_success(); + + // Override state, `number()` should return overridden value. + cmd.cast_fuse() + .args([ + "call", + "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "--rpc-url", + &handle.http_endpoint(), + "--override-state", + "0x5FbDB2315678afecb367f032d93F642f64180aa3:0x0:0x1234", + "number()(uint256)", + ]) + .assert_success() + .stdout_eq(str![[r#" +4660 + +"#]]); + + // Override balance, `getBalance()` should return overridden value. + cmd.cast_fuse() + .args([ + "call", + "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "--rpc-url", + &handle.http_endpoint(), + "--override-balance", + "0x5FbDB2315678afecb367f032d93F642f64180aa3:0x1111", + "getBalance(address)(uint256)", + "0x5FbDB2315678afecb367f032d93F642f64180aa3", + ]) + .assert_success() + .stdout_eq(str![[r#" +4369 + +"#]]); + + // Override code with + // contract Counter { + // uint256 public number1; + // } + // Calling `number()` should fail. + cmd.cast_fuse() + .args([ + "call", + "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "--rpc-url", + &handle.http_endpoint(), + "--override-code", + "0x5FbDB2315678afecb367f032d93F642f64180aa3:0x6080604052348015600e575f5ffd5b50600436106026575f3560e01c8063c223a39e14602a575b5f5ffd5b60306044565b604051603b9190605f565b60405180910390f35b5f5481565b5f819050919050565b6059816049565b82525050565b5f60208201905060705f8301846052565b9291505056fea26469706673582212202a0acfb9083efed3e0e9f27177b090731d4392cf196d58e27e05088f59008d0964736f6c634300081d0033", + "number()(uint256)", + ]) + .assert_failure() + .stderr_eq(str![[r#" +Error: server returned an error response: error code 3: execution reverted, data: "0x" + +"#]]); + + // Calling `number1()` with overridden state should return new value. + cmd.cast_fuse() + .args([ + "call", + "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "--rpc-url", + &handle.http_endpoint(), + "--override-code", + "0x5FbDB2315678afecb367f032d93F642f64180aa3:0x6080604052348015600e575f5ffd5b50600436106026575f3560e01c8063c223a39e14602a575b5f5ffd5b60306044565b604051603b9190605f565b60405180910390f35b5f5481565b5f819050919050565b6059816049565b82525050565b5f60208201905060705f8301846052565b9291505056fea26469706673582212202a0acfb9083efed3e0e9f27177b090731d4392cf196d58e27e05088f59008d0964736f6c634300081d0033", + "--override-state", + "0x5FbDB2315678afecb367f032d93F642f64180aa3:0x0:0x2222", + "number1()(uint256)", + ]) + .assert_success() + .stdout_eq(str![[r#" +8738 + +"#]]); + + // Calling `number1()` with overridden state should return new value. + cmd.cast_fuse() + .args([ + "call", + "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "--rpc-url", + &handle.http_endpoint(), + "--override-code", + "0x5FbDB2315678afecb367f032d93F642f64180aa3:0x6080604052348015600e575f5ffd5b50600436106026575f3560e01c8063c223a39e14602a575b5f5ffd5b60306044565b604051603b9190605f565b60405180910390f35b5f5481565b5f819050919050565b6059816049565b82525050565b5f60208201905060705f8301846052565b9291505056fea26469706673582212202a0acfb9083efed3e0e9f27177b090731d4392cf196d58e27e05088f59008d0964736f6c634300081d0033", + "--override-state-diff", + "0x5FbDB2315678afecb367f032d93F642f64180aa3:0x0:0x2222", + "number1()(uint256)", + ]) + .assert_success() + .stdout_eq(str![[r#" +8738 + +"#]]); +}); + // https://github.com/foundry-rs/foundry/issues/9541 forgetest_async!(cast_run_impersonated_tx, |_prj, cmd| { let (_api, handle) = anvil::spawn( From 7af634be5ad48e5c6f4f58fa5189086da557041d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 27 Apr 2025 13:22:28 +0000 Subject: [PATCH 034/244] chore(deps): weekly `cargo update` (#10381) * chore(deps): weekly `cargo update` Locking 46 packages to latest compatible versions Unchanged alloy-chains v0.1.69 (available: v0.2.0) Unchanged alloy-consensus v0.12.6 (available: v0.15.6) Unchanged alloy-contract v0.12.6 (available: v0.15.6) Unchanged alloy-dyn-abi v0.8.25 (available: v1.0.0) Unchanged alloy-eips v0.12.6 (available: v0.15.6) Unchanged alloy-genesis v0.12.6 (available: v0.15.6) Unchanged alloy-json-abi v0.8.25 (available: v1.0.0) Unchanged alloy-json-rpc v0.12.6 (available: v0.15.6) Unchanged alloy-network v0.12.6 (available: v0.15.6) Unchanged alloy-primitives v0.8.25 (available: v1.0.0) Unchanged alloy-provider v0.12.6 (available: v0.15.6) Unchanged alloy-pubsub v0.12.6 (available: v0.15.6) Unchanged alloy-rpc-client v0.12.6 (available: v0.15.6) Unchanged alloy-rpc-types v0.12.6 (available: v0.15.6) Unchanged alloy-serde v0.12.6 (available: v0.15.6) Unchanged alloy-signer v0.12.6 (available: v0.15.6) Unchanged alloy-signer-aws v0.12.6 (available: v0.15.6) Unchanged alloy-signer-gcp v0.12.6 (available: v0.15.6) Unchanged alloy-signer-ledger v0.12.6 (available: v0.15.6) Unchanged alloy-signer-local v0.12.6 (available: v0.15.6) Unchanged alloy-signer-trezor v0.12.6 (available: v0.15.6) Unchanged alloy-sol-macro-expander v0.8.25 (available: v1.0.0) Unchanged alloy-sol-macro-input v0.8.25 (available: v1.0.0) Unchanged alloy-sol-types v0.8.25 (available: v1.0.0) Unchanged alloy-transport v0.12.6 (available: v0.15.6) Unchanged alloy-transport-http v0.12.6 (available: v0.15.6) Unchanged alloy-transport-ipc v0.12.6 (available: v0.15.6) Unchanged alloy-transport-ws v0.12.6 (available: v0.15.6) Unchanged alloy-trie v0.7.9 (available: v0.8.1) Updating ammonia v4.0.0 -> v4.1.0 Updating async-compression v0.4.22 -> v0.4.23 Updating aws-config v1.6.1 -> v1.6.2 Updating aws-credential-types v1.2.2 -> v1.2.3 Updating aws-lc-sys v0.28.1 -> v0.28.2 Updating aws-runtime v1.5.6 -> v1.5.7 Updating aws-sdk-kms v1.65.0 -> v1.66.0 Updating aws-sdk-sso v1.64.0 -> v1.65.0 Updating aws-sdk-ssooidc v1.65.0 -> v1.66.0 Updating aws-sdk-sts v1.65.0 -> v1.66.0 Updating aws-sigv4 v1.3.0 -> v1.3.1 Updating aws-smithy-http v0.62.0 -> v0.62.1 Updating aws-smithy-observability v0.1.2 -> v0.1.3 Updating aws-smithy-runtime v1.8.1 -> v1.8.3 Updating aws-smithy-runtime-api v1.7.4 -> v1.8.0 Updating aws-smithy-types v1.3.0 -> v1.3.1 Updating aws-types v1.3.6 -> v1.3.7 Unchanged axum v0.7.9 (available: v0.8.3) Unchanged backtrace v0.3.71 (available: v0.3.74) Updating bon v3.6.1 -> v3.6.3 Updating bon-macros v3.6.1 -> v3.6.3 Updating cc v1.2.19 -> v1.2.20 Unchanged crossterm v0.28.1 (available: v0.29.0) Adding cssparser v0.35.0 Adding cssparser-macros v0.6.1 Adding dtoa v1.0.10 Adding dtoa-short v0.3.5 Unchanged gcloud-sdk v0.26.4 (available: v0.27.0) Updating getrandom v0.2.15 -> v0.2.16 Updating gix-path v0.10.15 -> v0.10.17 Adding gix-validate v0.10.0 Updating html5ever v0.27.0 -> v0.31.0 Updating jiff v0.2.9 -> v0.2.10 Updating jiff-static v0.2.9 -> v0.2.10 Updating libm v0.2.11 -> v0.2.13 Updating markup5ever v0.12.1 -> v0.16.1 Adding match_token v0.1.0 Unchanged op-alloy-consensus v0.11.4 (available: v0.15.1) Unchanged op-alloy-rpc-types v0.11.4 (available: v0.15.1) Unchanged protobuf v3.3.0 (available: v3.7.2) Unchanged protobuf-support v3.3.0 (available: v3.7.2) Updating quinn-proto v0.11.10 -> v0.11.11 Unchanged rand v0.8.5 (available: v0.9.1) Unchanged revm v19.7.0 (available: v22.0.1) Unchanged revm-inspectors v0.16.0 (available: v0.20.0) Unchanged revm-primitives v15.2.0 (available: v18.0.0) Updating rpassword v7.3.1 -> v7.4.0 Updating signal-hook-registry v1.4.4 -> v1.4.5 Unchanged solang-parser v0.3.3 (available: v0.3.4) Updating syn v2.0.100 -> v2.0.101 Updating tokio-util v0.7.14 -> v0.7.15 Updating toml v0.8.20 -> v0.8.21 Updating toml_datetime v0.6.8 -> v0.6.9 Updating toml_edit v0.22.24 -> v0.22.25 Adding toml_write v0.1.0 Unchanged vergen v8.3.2 (available: v9.0.6) Adding web_atoms v0.1.0 Removing windows-sys v0.48.0 Removing windows-targets v0.48.5 Removing windows_aarch64_gnullvm v0.48.5 Removing windows_aarch64_msvc v0.48.5 Removing windows_i686_gnu v0.48.5 Removing windows_i686_msvc v0.48.5 Removing windows_x86_64_gnu v0.48.5 Removing windows_x86_64_gnullvm v0.48.5 Removing windows_x86_64_msvc v0.48.5 Updating winnow v0.7.6 -> v0.7.7 Updating zerocopy v0.8.24 -> v0.8.25 Updating zerocopy-derive v0.8.24 -> v0.8.25 note: to see how you depend on a package, run `cargo tree --invert --package @` * chore: clippy * test --------- Co-authored-by: mattsse <19890894+mattsse@users.noreply.github.com> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> --- Cargo.lock | 497 +++++++++--------- crates/cheatcodes/src/test/revert_handlers.rs | 2 +- .../evm/evm/src/executors/invariant/error.rs | 2 +- crates/forge/tests/cli/config.rs | 8 +- 4 files changed, 256 insertions(+), 253 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 43d0cbcd56ae6..74292c6950ddc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,7 +51,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "once_cell", "version_check", "zerocopy 0.7.35", @@ -161,7 +161,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "winnow 0.7.6", + "winnow 0.7.7", ] [[package]] @@ -318,7 +318,7 @@ dependencies = [ "derive_arbitrary", "derive_more 2.0.1", "foldhash", - "getrandom 0.2.15", + "getrandom 0.2.16", "hashbrown 0.15.2", "indexmap 2.9.0", "itoa", @@ -416,7 +416,7 @@ checksum = "a40e1ef334153322fd878d07e86af7a529bcb86b2439525920a88eba87bcf943" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -691,7 +691,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -708,7 +708,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "syn-solidity", "tiny-keccak", ] @@ -727,7 +727,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.100", + "syn 2.0.101", "syn-solidity", ] @@ -738,7 +738,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d162f8524adfdfb0e4bd0505c734c985f3e2474eb022af32eef0d52a4f3935c" dependencies = [ "serde", - "winnow 0.7.6", + "winnow 0.7.7", ] [[package]] @@ -847,13 +847,13 @@ dependencies = [ [[package]] name = "ammonia" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459" +checksum = "3ada2ee439075a3e70b6992fce18ac4e407cd05aea9ca3f75d2c0b0c20bbb364" dependencies = [ + "cssparser", "html5ever", "maplit", - "once_cell", "tendril", "url", ] @@ -1238,9 +1238,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a194f9d963d8099596278594b3107448656ba73831c9d8c783e613ce86da64" +checksum = "b37fc50485c4f3f736a4fb14199f6d5f5ba008d7f28fe710306c92780f004c07" dependencies = [ "flate2", "futures-core", @@ -1266,7 +1266,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1288,7 +1288,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1299,7 +1299,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1352,7 +1352,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1363,9 +1363,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-config" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c39646d1a6b51240a1a23bb57ea4eebede7e16fbc237fdc876980233dcecb4f" +checksum = "b6fcc63c9860579e4cb396239570e979376e70aab79e496621748a09913f8b36" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1393,9 +1393,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4471bef4c22a06d2c7a1b6492493d3fdf24a805323109d6874f9c94d5906ac14" +checksum = "687bc16bc431a8533fe0097c7f0182874767f920989d7260950172ae8e3c4465" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -1415,9 +1415,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.28.1" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ddeb19ee86cb16ecfc871e5b0660aff6285760957aaedda6284cf0e790d3769" +checksum = "bfa9b6986f250236c27e5a204062434a773a13243d2ffc2955f37bdba4c5c6a1" dependencies = [ "bindgen", "cc", @@ -1428,9 +1428,9 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.5.6" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aff45ffe35196e593ea3b9dd65b320e51e2dda95aff4390bc459e461d09c6ad" +checksum = "6c4063282c69991e57faab9e5cb21ae557e59f5b0fb285c196335243df8dc25c" dependencies = [ "aws-credential-types", "aws-sigv4", @@ -1444,7 +1444,6 @@ dependencies = [ "fastrand", "http 0.2.12", "http-body 0.4.6", - "once_cell", "percent-encoding", "pin-project-lite", "tracing", @@ -1453,9 +1452,9 @@ dependencies = [ [[package]] name = "aws-sdk-kms" -version = "1.65.0" +version = "1.66.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5325c5e2badf4148e850017cc56cc205888c6e0b52c9e29d3501ec577005230" +checksum = "655097cd83ab1f15575890943135192560f77097413c6dd1733fdbdc453e81ac" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1476,9 +1475,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.64.0" +version = "1.65.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d4bdb0e5f80f0689e61c77ab678b2b9304af329616af38aef5b6b967b8e736" +checksum = "8efec445fb78df585327094fcef4cad895b154b58711e504db7a93c41aa27151" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1499,9 +1498,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.65.0" +version = "1.66.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbbb3ce8da257aedbccdcb1aadafbbb6a5fe9adf445db0e1ea897bdc7e22d08" +checksum = "5e49cca619c10e7b002dc8e66928ceed66ab7f56c1a3be86c5437bf2d8d89bba" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1522,9 +1521,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.65.0" +version = "1.66.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a78a8f50a1630db757b60f679c8226a8a70ee2ab5f5e6e51dc67f6c61c7cfd" +checksum = "7420479eac0a53f776cc8f0d493841ffe58ad9d9783f3947be7265784471b47a" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1546,9 +1545,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d03c3c05ff80d54ff860fe38c726f6f494c639ae975203a101335f223386db" +checksum = "3503af839bd8751d0bdc5a46b9cac93a003a353e635b0c12cf2376b5b53e41ea" dependencies = [ "aws-credential-types", "aws-smithy-http", @@ -1560,7 +1559,6 @@ dependencies = [ "hmac", "http 0.2.12", "http 1.3.1", - "once_cell", "percent-encoding", "sha2", "time", @@ -1580,9 +1578,9 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.62.0" +version = "0.62.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5949124d11e538ca21142d1fba61ab0a2a2c1bc3ed323cdb3e4b878bfb83166" +checksum = "99335bec6cdc50a346fda1437f9fefe33abf8c99060739a546a16457f2862ca9" dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", @@ -1592,7 +1590,6 @@ dependencies = [ "http 0.2.12", "http 1.3.1", "http-body 0.4.6", - "once_cell", "percent-encoding", "pin-project-lite", "pin-utils", @@ -1633,12 +1630,11 @@ dependencies = [ [[package]] name = "aws-smithy-observability" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445d065e76bc1ef54963db400319f1dd3ebb3e0a74af20f7f7630625b0cc7cc0" +checksum = "9364d5989ac4dd918e5cc4c4bdcc61c9be17dcd2586ea7f69e348fc7c6cab393" dependencies = [ "aws-smithy-runtime-api", - "once_cell", ] [[package]] @@ -1653,9 +1649,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.8.1" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0152749e17ce4d1b47c7747bdfec09dac1ccafdcbc741ebf9daa2a373356730f" +checksum = "14302f06d1d5b7d333fd819943075b13d27c7700b414f574c3c35859bfb55d5e" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -1669,7 +1665,6 @@ dependencies = [ "http 1.3.1", "http-body 0.4.6", "http-body 1.0.1", - "once_cell", "pin-project-lite", "pin-utils", "tokio", @@ -1678,9 +1673,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.7.4" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da37cf5d57011cb1753456518ec76e31691f1f474b73934a284eb2a1c76510f" +checksum = "a1e5d9e3a80a18afa109391fb5ad09c3daf887b516c6fd805a157c6ea7994a57" dependencies = [ "aws-smithy-async", "aws-smithy-types", @@ -1695,9 +1690,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836155caafba616c0ff9b07944324785de2ab016141c3550bd1c07882f8cee8f" +checksum = "40076bd09fadbc12d5e026ae080d0930defa606856186e31d83ccc6a255eeaf3" dependencies = [ "base64-simd", "bytes", @@ -1727,9 +1722,9 @@ dependencies = [ [[package]] name = "aws-types" -version = "1.3.6" +version = "1.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3873f8deed8927ce8d04487630dc9ff73193bab64742a61d050e57a68dec4125" +checksum = "8a322fec39e4df22777ed3ad8ea868ac2f94cd15e1a55f6ee8d8d6305057689a" dependencies = [ "aws-credential-types", "aws-smithy-async", @@ -1877,7 +1872,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.100", + "syn 2.0.101", "which 4.4.2", ] @@ -1963,9 +1958,9 @@ dependencies = [ [[package]] name = "bon" -version = "3.6.1" +version = "3.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94054366e2ff97b455acdd4fdb03913f717febc57b7bbd1741b2c3b87efae030" +checksum = "ced38439e7a86a4761f7f7d5ded5ff009135939ecb464a24452eaa4c1696af7d" dependencies = [ "bon-macros", "rustversion", @@ -1973,9 +1968,9 @@ dependencies = [ [[package]] name = "bon-macros" -version = "3.6.1" +version = "3.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "542a990e676ce0a0a895ae54b2d94afd012434f2228a85b186c6bc1a7056cdc6" +checksum = "0ce61d2d3844c6b8d31b2353d9f66cf5e632b3e9549583fe3cac2f4f6136725e" dependencies = [ "darling", "ident_case", @@ -1983,7 +1978,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -2162,9 +2157,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.19" +version = "1.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" dependencies = [ "jobserver", "libc", @@ -2352,7 +2347,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -2467,7 +2462,7 @@ dependencies = [ "byteorder", "cfg-if", "const-hex", - "getrandom 0.2.15", + "getrandom 0.2.16", "hidapi-rusb", "js-sys", "log", @@ -2755,6 +2750,29 @@ dependencies = [ "typenum", ] +[[package]] +name = "cssparser" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e901edd733a1472f944a45116df3f846f54d37e67e68640ac8bb69689aca2aa" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.101", +] + [[package]] name = "ctr" version = "0.9.2" @@ -2795,7 +2813,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -2806,7 +2824,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -2880,7 +2898,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -2901,7 +2919,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -2911,7 +2929,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -2940,7 +2958,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "unicode-xid", ] @@ -2953,7 +2971,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "unicode-xid", ] @@ -3041,7 +3059,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -3062,6 +3080,21 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" +[[package]] +name = "dtoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + [[package]] name = "dunce" version = "1.0.5" @@ -3182,7 +3215,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -3390,7 +3423,7 @@ dependencies = [ "pear", "serde", "tempfile", - "toml 0.8.20", + "toml 0.8.21", "uncased", "version_check", ] @@ -3519,7 +3552,7 @@ dependencies = [ "thiserror 2.0.12", "tikv-jemallocator", "tokio", - "toml 0.8.20", + "toml 0.8.21", "toml_edit", "tower-http", "tracing", @@ -3548,7 +3581,7 @@ dependencies = [ "serde_json", "solang-parser", "thiserror 2.0.12", - "toml 0.8.20", + "toml 0.8.21", "tracing", ] @@ -3563,7 +3596,7 @@ dependencies = [ "similar-asserts", "solang-parser", "thiserror 2.0.12", - "toml 0.8.20", + "toml 0.8.21", "tracing", "tracing-subscriber", ] @@ -3640,7 +3673,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -3747,7 +3780,7 @@ dependencies = [ "serde", "serde_json", "thiserror 2.0.12", - "toml 0.8.20", + "toml 0.8.21", "tracing", "walkdir", ] @@ -3911,7 +3944,7 @@ dependencies = [ "thiserror 2.0.12", "tokio", "tracing", - "winnow 0.7.6", + "winnow 0.7.7", "yansi", ] @@ -4016,7 +4049,7 @@ dependencies = [ "solar-parse", "tempfile", "thiserror 2.0.12", - "toml 0.8.20", + "toml 0.8.21", "toml_edit", "tracing", "walkdir", @@ -4220,7 +4253,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -4380,7 +4413,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -4473,9 +4506,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "js-sys", @@ -4648,7 +4681,7 @@ dependencies = [ "gix-hashtable", "gix-path", "gix-utils", - "gix-validate", + "gix-validate 0.9.4", "itoa", "smallvec", "thiserror 2.0.12", @@ -4657,12 +4690,13 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.15" +version = "0.10.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f910668e2f6b2a55ff35a1f04df88a1a049f7b868507f4cbeeaa220eaba7be87" +checksum = "c091d2e887e02c3462f52252c5ea61150270c0f2657b642e8d0d6df56c16e642" dependencies = [ "bstr", "gix-trace", + "gix-validate 0.10.0", "home", "once_cell", "thiserror 2.0.12", @@ -4683,7 +4717,7 @@ dependencies = [ "gix-path", "gix-tempfile", "gix-utils", - "gix-validate", + "gix-validate 0.9.4", "memmap2", "thiserror 2.0.12", "winnow 0.6.26", @@ -4740,6 +4774,16 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "gix-validate" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77b9e00cacde5b51388d28ed746c493b18a6add1f19b5e01d686b3b9ece66d4d" +dependencies = [ + "bstr", + "thiserror 2.0.12", +] + [[package]] name = "glob" version = "0.3.2" @@ -4911,16 +4955,14 @@ dependencies = [ [[package]] name = "html5ever" -version = "0.27.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" +checksum = "953cbbe631aae7fc0a112702ad5d3aaf09da38beaf45ea84610d6e1c358f569c" dependencies = [ "log", "mac", "markup5ever", - "proc-macro2", - "quote", - "syn 2.0.100", + "match_token", ] [[package]] @@ -5225,7 +5267,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -5307,7 +5349,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -5425,7 +5467,7 @@ dependencies = [ "indoc", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -5519,9 +5561,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ec30f7142be6fe14e1b021f50b85db8df2d4324ea6e91ec3e5dcde092021d0" +checksum = "5a064218214dc6a10fbae5ec5fa888d80c45d611aba169222fc272072bf7aef6" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -5534,13 +5576,13 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "526b834d727fd59d37b076b0c3236d9adde1b1729a4361e20b2026f738cc1dbe" +checksum = "199b7932d97e325aff3a7030e141eafe7f2c6268e1d1b24859b753a627f45254" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -5741,9 +5783,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" [[package]] name = "libredox" @@ -5850,7 +5892,7 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -5861,16 +5903,13 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "markup5ever" -version = "0.12.1" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45" +checksum = "d0a8096766c229e8c88a3900c9b44b7e06aa7f7343cc229158c3e58ef8f9973a" dependencies = [ "log", - "phf", - "phf_codegen", - "string_cache", - "string_cache_codegen", "tendril", + "web_atoms", ] [[package]] @@ -5879,6 +5918,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" +[[package]] +name = "match_token" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "matchers" version = "0.1.0" @@ -5979,7 +6029,7 @@ checksum = "bf45bf44ab49be92fd1227a3be6fc6f617f1a337c06af54981048574d8783147" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6057,7 +6107,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6307,7 +6357,7 @@ checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6478,7 +6528,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6561,7 +6611,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6620,7 +6670,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6694,7 +6744,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6743,7 +6793,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6801,7 +6851,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.24", + "zerocopy 0.8.25", ] [[package]] @@ -6843,7 +6893,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" dependencies = [ "proc-macro2", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6918,7 +6968,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6938,7 +6988,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "version_check", "yansi", ] @@ -7006,7 +7056,7 @@ checksum = "4ee1c9ac207483d5e7db4940700de86a9aae46ef90c48b57f99fe7edb8345e49" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -7029,7 +7079,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -7140,9 +7190,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.10" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc" +checksum = "bcbafbbdbb0f638fe3f35f3c56739f77a8a1d070cb25603226c83339b391472b" dependencies = [ "bytes", "getrandom 0.3.2", @@ -7251,7 +7301,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -7334,7 +7384,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror 1.0.69", ] @@ -7345,7 +7395,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror 2.0.12", ] @@ -7564,7 +7614,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -7591,13 +7641,13 @@ dependencies = [ [[package]] name = "rpassword" -version = "7.3.1" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" +checksum = "66d4c8b64f049c6721ec8ccec37ddfc3d641c4a7fca57e8f2a89de509c73df39" dependencies = [ "libc", "rtoolbox", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -7895,7 +7945,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -8048,7 +8098,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -8059,7 +8109,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -8112,7 +8162,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -8163,7 +8213,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -8198,7 +8248,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -8293,9 +8343,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.4" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ee1aca2bc74ef9589efa7ccaa0f3752751399940356209b3fd80c078149b5e" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] @@ -8509,7 +8559,7 @@ checksum = "ca2c9ff6e00eeeff12eac9d589f1f20413d3b71b9c0c292d1eefbd34787e0836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -8714,7 +8764,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -8727,7 +8777,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -8873,9 +8923,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -8891,7 +8941,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -8911,7 +8961,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -9041,7 +9091,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -9052,7 +9102,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -9187,7 +9237,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -9254,9 +9304,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", @@ -9276,9 +9326,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "900f6c86a685850b1bc9f6223b20125115ee3f31e01207d81655bbcc0aea9231" dependencies = [ "indexmap 2.9.0", "serde", @@ -9289,26 +9339,33 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "10558ed0bd2a1562e630926a2d1f0b98c827da99fabd3fe20920a59642504485" dependencies = [ "indexmap 2.9.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.7.6", + "toml_write", + "winnow 0.7.7", ] +[[package]] +name = "toml_write" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28391a4201ba7eb1984cfeb6862c0b3ea2cfe23332298967c749dddc0d6cd976" + [[package]] name = "tonic" version = "0.12.3" @@ -9453,7 +9510,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -9784,7 +9841,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "serde", ] @@ -9944,7 +10001,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "wasm-bindgen-shared", ] @@ -9979,7 +10036,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -10103,6 +10160,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web_atoms" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "954c5a41f2bcb7314344079d0891505458cc2f4b422bdea1d5bfbe6d1a04903b" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + [[package]] name = "webpki-roots" version = "0.26.8" @@ -10240,7 +10309,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -10251,7 +10320,7 @@ checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -10262,7 +10331,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -10273,7 +10342,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -10284,7 +10353,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -10350,15 +10419,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -10377,21 +10437,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -10424,12 +10469,6 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -10442,12 +10481,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -10460,12 +10493,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -10490,12 +10517,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -10508,12 +10529,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -10526,12 +10541,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -10544,12 +10553,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -10573,9 +10576,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" dependencies = [ "memchr", ] @@ -10676,7 +10679,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "synstructure", ] @@ -10691,11 +10694,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "zerocopy-derive 0.8.24", + "zerocopy-derive 0.8.25", ] [[package]] @@ -10706,18 +10709,18 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -10737,7 +10740,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "synstructure", ] @@ -10758,7 +10761,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -10780,7 +10783,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] diff --git a/crates/cheatcodes/src/test/revert_handlers.rs b/crates/cheatcodes/src/test/revert_handlers.rs index e8f713dcc7144..2dfd4b014fa6f 100644 --- a/crates/cheatcodes/src/test/revert_handlers.rs +++ b/crates/cheatcodes/src/test/revert_handlers.rs @@ -100,7 +100,7 @@ fn handle_revert( Ok(()) } else { let (actual, expected) = if let Some(contracts) = known_contracts { - let decoder = RevertDecoder::new().with_abis(contracts.iter().map(|(_, c)| &c.abi)); + let decoder = RevertDecoder::new().with_abis(contracts.values().map(|c| &c.abi)); ( &decoder.decode(actual_revert.as_slice(), Some(status)), &decoder.decode(expected_reason, Some(status)), diff --git a/crates/evm/evm/src/executors/invariant/error.rs b/crates/evm/evm/src/executors/invariant/error.rs index f5eef18ed7529..0ff4b4c52f962 100644 --- a/crates/evm/evm/src/executors/invariant/error.rs +++ b/crates/evm/evm/src/executors/invariant/error.rs @@ -78,7 +78,7 @@ impl FailedInvariantCaseData { ) -> Self { // Collect abis of fuzzed and invariant contracts to decode custom error. let revert_reason = RevertDecoder::new() - .with_abis(targeted_contracts.targets.lock().iter().map(|(_, c)| &c.abi)) + .with_abis(targeted_contracts.targets.lock().values().map(|c| &c.abi)) .with_abi(invariant_contract.abi) .decode(call_result.result.as_ref(), Some(call_result.exit_reason)); diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index 5308a2918a6aa..46dd731df9e45 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -1042,14 +1042,14 @@ eof = false additional_compiler_profiles = [] compilation_restrictions = [] -[[profile.default.fs_permissions]] -access = "read" -path = "out" - [profile.default.rpc_storage_caching] chains = "all" endpoints = "all" +[[profile.default.fs_permissions]] +access = "read" +path = "out" + [fmt] line_length = 120 tab_width = 4 From 8ee5205e47a3c4e631b584613a9c556157d53449 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sun, 27 Apr 2025 15:57:44 +0200 Subject: [PATCH 035/244] chore(deps): replace inflector with heck (#10386) --- Cargo.lock | 12 +----------- crates/config/Cargo.toml | 2 +- crates/config/src/etherscan.rs | 2 +- crates/config/src/providers/ext.rs | 2 +- 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74292c6950ddc..73c777be4c949 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,16 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - [[package]] name = "addr2line" version = "0.21.0" @@ -4023,7 +4013,6 @@ dependencies = [ name = "foundry-config" version = "1.1.0" dependencies = [ - "Inflector", "alloy-chains", "alloy-primitives", "dirs", @@ -4034,6 +4023,7 @@ dependencies = [ "foundry-compilers", "glob", "globset", + "heck", "itertools 0.14.0", "mesc", "number_prefix", diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml index 2d2b80b4ad695..c432cceb04ac0 100644 --- a/crates/config/Cargo.toml +++ b/crates/config/Cargo.toml @@ -29,7 +29,7 @@ eyre.workspace = true figment = { workspace = true, features = ["toml", "env"] } glob = "0.3" globset = "0.4" -Inflector = "0.11" +heck = "0.5" itertools.workspace = true mesc.workspace = true number_prefix = "0.4" diff --git a/crates/config/src/etherscan.rs b/crates/config/src/etherscan.rs index 9dde4b733a543..099dc0e344c2f 100644 --- a/crates/config/src/etherscan.rs +++ b/crates/config/src/etherscan.rs @@ -9,7 +9,7 @@ use figment::{ value::{Dict, Map}, Error, Metadata, Profile, Provider, }; -use inflector::Inflector; +use heck::ToKebabCase; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::{ collections::BTreeMap, diff --git a/crates/config/src/providers/ext.rs b/crates/config/src/providers/ext.rs index aac50f3140e4f..64c99c771ba38 100644 --- a/crates/config/src/providers/ext.rs +++ b/crates/config/src/providers/ext.rs @@ -5,7 +5,7 @@ use figment::{ Error, Figment, Metadata, Profile, Provider, }; use foundry_compilers::ProjectPathsConfig; -use inflector::Inflector; +use heck::ToSnakeCase; use std::path::{Path, PathBuf}; pub(crate) trait ProviderExt: Provider + Sized { From ef27f1c3e091170e107e304c471bce29d9e530fc Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sun, 27 Apr 2025 16:00:47 +0200 Subject: [PATCH 036/244] chore(deps): switch to proc-macro-error2 (#10387) --- Cargo.lock | 26 +------------------------- crates/macros/Cargo.toml | 2 +- crates/macros/src/lib.rs | 3 +-- deny.toml | 4 +--- 4 files changed, 4 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 73c777be4c949..ca08eb415ed49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4240,7 +4240,7 @@ dependencies = [ name = "foundry-macros" version = "1.1.0" dependencies = [ - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", "syn 2.0.101", @@ -6915,30 +6915,6 @@ dependencies = [ "toml_edit", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro-error-attr2" version = "2.0.0" diff --git a/crates/macros/Cargo.toml b/crates/macros/Cargo.toml index 98dc669f137e8..de1872973f755 100644 --- a/crates/macros/Cargo.toml +++ b/crates/macros/Cargo.toml @@ -22,4 +22,4 @@ doc = false proc-macro2.workspace = true quote.workspace = true syn.workspace = true -proc-macro-error = "1" +proc-macro-error2 = "2" diff --git a/crates/macros/src/lib.rs b/crates/macros/src/lib.rs index dbdaa208ce726..375434f82d246 100644 --- a/crates/macros/src/lib.rs +++ b/crates/macros/src/lib.rs @@ -6,10 +6,9 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #[macro_use] -extern crate proc_macro_error; +extern crate proc_macro_error2; use proc_macro::TokenStream; -use proc_macro_error::proc_macro_error; use syn::{parse_macro_input, DeriveInput, Error}; mod cheatcodes; diff --git a/deny.toml b/deny.toml index 8f6d7d9f0c1d9..5cc729a2c121e 100644 --- a/deny.toml +++ b/deny.toml @@ -5,14 +5,12 @@ version = 2 yanked = "warn" ignore = [ - # proc-macro-error is unmaintained - "RUSTSEC-2024-0370", # https://rustsec.org/advisories/RUSTSEC-2024-0436 paste! is unmaintained "RUSTSEC-2024-0436", # https://rustsec.org/advisories/RUSTSEC-2024-0437 protobuf! Crash due to uncontrolled recursion in protobuf crate. "RUSTSEC-2024-0437", # https://rustsec.org/advisories/RUSTSEC-2025-0021 gitoxide uses SHA-1 hash implementations without any collision detection, leaving it vulnerable to hash collision attacks. - "RUSTSEC-2025-0021" + "RUSTSEC-2025-0021", ] # This section is considered when running `cargo deny check bans`. From d8814d3cefcf6a292be3f82eaac7c275f907eb1d Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sun, 27 Apr 2025 16:16:57 +0200 Subject: [PATCH 037/244] chore(deps): remove serde_regex (#10389) --- Cargo.lock | 11 ----------- crates/config/Cargo.toml | 1 - crates/config/src/lib.rs | 24 +++++++++++++++++++++++- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ca08eb415ed49..4a26b77acfaaf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4034,7 +4034,6 @@ dependencies = [ "semver 1.0.26", "serde", "serde_json", - "serde_regex", "similar-asserts", "solar-parse", "tempfile", @@ -8110,16 +8109,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_regex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf" -dependencies = [ - "regex", - "serde", -] - [[package]] name = "serde_repr" version = "0.1.20" diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml index c432cceb04ac0..8c8fc70bb3fa8 100644 --- a/crates/config/Cargo.toml +++ b/crates/config/Cargo.toml @@ -37,7 +37,6 @@ regex.workspace = true reqwest.workspace = true semver = { workspace = true, features = ["serde"] } serde_json.workspace = true -serde_regex = "1" serde.workspace = true thiserror.workspace = true toml = { workspace = true, features = ["preserve_order"] } diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 94c445991b887..6318d4b63f064 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -2163,7 +2163,7 @@ impl FigmentProviders { } } -/// Wrapper type for `regex::Regex` that implements `PartialEq` +/// Wrapper type for [`regex::Regex`] that implements [`PartialEq`] and [`serde`] traits. #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(transparent)] pub struct RegexWrapper { @@ -2185,6 +2185,8 @@ impl std::cmp::PartialEq for RegexWrapper { } } +impl Eq for RegexWrapper {} + impl From for regex::Regex { fn from(wrapper: RegexWrapper) -> Self { wrapper.inner @@ -2197,6 +2199,26 @@ impl From for RegexWrapper { } } +mod serde_regex { + use regex::Regex; + use serde::{Deserialize, Deserializer, Serializer}; + + pub(crate) fn serialize(value: &Regex, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(value.as_str()) + } + + pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + Regex::new(&s).map_err(serde::de::Error::custom) + } +} + /// Ser/de `globset::Glob` explicitly to handle `Option` properly pub(crate) mod from_opt_glob { use serde::{Deserialize, Deserializer, Serializer}; From a914bb5e499ff354440bd42006de894e9b82ef6e Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sun, 27 Apr 2025 16:26:01 +0200 Subject: [PATCH 038/244] chore(deps): use unicode-rs as the idna backend (#10390) --- Cargo.lock | 272 ++++------------------------------- Cargo.toml | 5 + crates/test-utils/Cargo.toml | 3 + crates/test-utils/src/lib.rs | 3 + 4 files changed, 38 insertions(+), 245 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4a26b77acfaaf..8d8e4c679794b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3041,17 +3041,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "doctest-file" version = "1.0.0" @@ -4257,6 +4246,7 @@ dependencies = [ "foundry-common", "foundry-compilers", "foundry-config", + "idna_adapter", "parking_lot", "rand 0.8.5", "regex", @@ -5141,124 +5131,6 @@ dependencies = [ "cc", ] -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -5278,12 +5150,22 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "279259b0ac81c89d11c290495fdcfa96ea3643b7df311c138b6fe8ca5237f0f8" dependencies = [ - "icu_normalizer", - "icu_properties", + "idna_mapping", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna_mapping" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5422cc5bc64289a77dbb45e970b86b5e9a04cb500abc7240505aedc1bf40f38" +dependencies = [ + "unicode-joining-type", ] [[package]] @@ -5811,12 +5693,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" -[[package]] -name = "litemap" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" - [[package]] name = "lock_api" version = "0.4.12" @@ -8908,17 +8784,6 @@ dependencies = [ "futures-core", ] -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "system-configuration" version = "0.6.1" @@ -9141,16 +9006,6 @@ dependencies = [ "crunchy", ] -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - [[package]] name = "tinyvec" version = "1.9.0" @@ -9675,6 +9530,12 @@ version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + [[package]] name = "unicode-bom" version = "2.0.3" @@ -9687,6 +9548,12 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "unicode-joining-type" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f8cb47ccb8bc750808755af3071da4a10dcd147b68fc874b7ae4b12543f6f5" + [[package]] name = "unicode-linebreak" version = "0.1.5" @@ -9766,12 +9633,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8-width" version = "0.1.7" @@ -10553,18 +10414,6 @@ dependencies = [ "bitflags 2.9.0", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - [[package]] name = "ws_stream_wasm" version = "0.7.4" @@ -10614,30 +10463,6 @@ dependencies = [ "is-terminal", ] -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", - "synstructure", -] - [[package]] name = "zerocopy" version = "0.7.35" @@ -10678,27 +10503,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", - "synstructure", -] - [[package]] name = "zeroize" version = "1.8.1" @@ -10719,28 +10523,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "zip" version = "2.6.1" diff --git a/Cargo.toml b/Cargo.toml index 840b4c9fa1fe1..a5e1cfaef6317 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -315,6 +315,11 @@ vergen = { version = "8", default-features = false } yansi = { version = "1.0", features = ["detect-tty", "detect-env"] } path-slash = "0.2" +# Use unicode-rs which has a smaller binary size than the default ICU4X as the IDNA backend, used +# by the `url` crate. +# See the `idna_adapter` README.md for more details: https://docs.rs/crate/idna_adapter/latest +idna_adapter = "=1.1.0" + [patch.crates-io] ## alloy-core # alloy-dyn-abi = { path = "../../alloy-rs/core/crates/dyn-abi" } diff --git a/crates/test-utils/Cargo.toml b/crates/test-utils/Cargo.toml index f4234189e61e6..b9d7b1ce5f2f6 100644 --- a/crates/test-utils/Cargo.toml +++ b/crates/test-utils/Cargo.toml @@ -33,6 +33,9 @@ rand.workspace = true snapbox = { version = "0.6", features = ["json", "regex", "term-svg"] } tempfile.workspace = true +# See /Cargo.toml. +idna_adapter.workspace = true + [dev-dependencies] tokio.workspace = true foundry-block-explorers.workspace = true diff --git a/crates/test-utils/src/lib.rs b/crates/test-utils/src/lib.rs index 2fda786c5deaf..c1f717f2c118f 100644 --- a/crates/test-utils/src/lib.rs +++ b/crates/test-utils/src/lib.rs @@ -10,6 +10,9 @@ #[macro_use] extern crate tracing; +// See /Cargo.toml. +use idna_adapter as _; + // Macros useful for testing. mod macros; From 7ed7e16323ff4edbffde7ec2196346f93f4567b3 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sun, 27 Apr 2025 16:57:02 +0200 Subject: [PATCH 039/244] test(anvil): fix flaky test (#10391) --- crates/anvil/tests/it/anvil_api.rs | 10 ++++--- crates/test-utils/src/rpc.rs | 43 +++++++++++++++++------------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/crates/anvil/tests/it/anvil_api.rs b/crates/anvil/tests/it/anvil_api.rs index 215625b28c24f..22179d505a9b6 100644 --- a/crates/anvil/tests/it/anvil_api.rs +++ b/crates/anvil/tests/it/anvil_api.rs @@ -1028,14 +1028,18 @@ async fn test_mine_blks_with_same_timestamp() { blk_futs.push(provider.get_block(i.into()).into_future()); } - let blks = futures::future::join_all(blk_futs) + let timestamps = futures::future::join_all(blk_futs) .await .into_iter() .map(|blk| blk.unwrap().unwrap().header.timestamp) .collect::>(); - // timestamps should be equal - assert_eq!(blks, vec![init_timestamp; 4]); + // All timestamps should be equal. Allow for 1 second difference. + assert!(timestamps.windows(2).all(|w| w[0] == w[1]), "{timestamps:#?}"); + assert!( + timestamps[0] == init_timestamp || timestamps[0] == init_timestamp + 1, + "{timestamps:#?} != {init_timestamp}" + ); } // diff --git a/crates/test-utils/src/rpc.rs b/crates/test-utils/src/rpc.rs index 6c39c75a54f6a..70e3c87534f95 100644 --- a/crates/test-utils/src/rpc.rs +++ b/crates/test-utils/src/rpc.rs @@ -10,35 +10,40 @@ use std::sync::{ LazyLock, }; +fn shuffled(mut vec: Vec) -> Vec { + vec.shuffle(&mut rand::thread_rng()); + vec +} + // List of public archive reth nodes to use static RETH_ARCHIVE_HOSTS: LazyLock> = LazyLock::new(|| { - let mut hosts = vec!["reth-ethereum.ithaca.xyz"]; - hosts.shuffle(&mut rand::thread_rng()); - hosts + shuffled(vec![ + // + "reth-ethereum.ithaca.xyz", + ]) }); // List of public reth nodes to use (archive and non archive) static RETH_HOSTS: LazyLock> = LazyLock::new(|| { - let mut hosts = vec!["reth-ethereum.ithaca.xyz", "reth-ethereum-full.ithaca.xyz"]; - hosts.shuffle(&mut rand::thread_rng()); - hosts + shuffled(vec![ + // + "reth-ethereum.ithaca.xyz", + "reth-ethereum-full.ithaca.xyz", + ]) }); // List of general purpose DRPC keys to rotate through static DRPC_KEYS: LazyLock> = LazyLock::new(|| { - let mut keys = vec![ + shuffled(vec![ + // "Agc9NK9-6UzYh-vQDDM80Tv0A5UnBkUR8I3qssvAG40d", "AjUPUPonSEInt2CZ_7A-ai3hMyxxBlsR8I4EssvAG40d", - ]; - - keys.shuffle(&mut rand::thread_rng()); - - keys + ]) }); // List of etherscan keys for mainnet static ETHERSCAN_MAINNET_KEYS: LazyLock> = LazyLock::new(|| { - let mut keys = vec![ + shuffled(vec![ "MCAUM7WPE9XP5UQMZPCKIBUJHPM1C24FP6", "JW6RWCG2C5QF8TANH4KC7AYIF1CX7RB5D1", "ZSMDY6BI2H55MBE3G9CUUQT4XYUDBB6ZSK", @@ -51,14 +56,16 @@ static ETHERSCAN_MAINNET_KEYS: LazyLock> = LazyLock::new(|| { "ZUB97R31KSYX7NYVW6224Q6EYY6U56H591", // Optimism // "JQNGFHINKS1W7Y5FRXU4SPBYF43J3NYK46", - ]; - keys.shuffle(&mut rand::thread_rng()); - keys + ]) }); // List of etherscan keys for Optimism. -static ETHERSCAN_OPTIMISM_KEYS: LazyLock> = - LazyLock::new(|| vec!["JQNGFHINKS1W7Y5FRXU4SPBYF43J3NYK46"]); +static ETHERSCAN_OPTIMISM_KEYS: LazyLock> = LazyLock::new(|| { + shuffled(vec![ + // + "JQNGFHINKS1W7Y5FRXU4SPBYF43J3NYK46", + ]) +}); /// Returns the next index to use. fn next_idx() -> usize { From f9d8b9c53a431154bb48beac7f4496aed77fc95c Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sun, 27 Apr 2025 17:29:34 +0200 Subject: [PATCH 040/244] test: move serial_tests to nextest test groups (#10392) --- .config/nextest.toml | 7 +++++++ Cargo.lock | 26 -------------------------- crates/chisel/Cargo.toml | 1 - crates/chisel/tests/cache.rs | 10 ---------- 4 files changed, 7 insertions(+), 37 deletions(-) diff --git a/.config/nextest.toml b/.config/nextest.toml index a90da8b186e19..1de244ff846d7 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -1,3 +1,6 @@ +[test-groups] +chisel-serial = { max-threads = 1 } + [profile.default] retries = { backoff = "exponential", count = 2, delay = "3s", jitter = true } slow-timeout = { period = "1m", terminate-after = 3 } @@ -9,3 +12,7 @@ slow-timeout = { period = "5m", terminate-after = 4 } [[profile.default.overrides]] filter = "package(foundry-cheatcodes-spec)" retries = 0 + +[[profile.default.overrides]] +filter = "package(chisel)" +test-group = "chisel-serial" diff --git a/Cargo.lock b/Cargo.lock index 8d8e4c679794b..112351887f28b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2200,7 +2200,6 @@ dependencies = [ "semver 1.0.26", "serde", "serde_json", - "serial_test", "solang-parser", "solar-parse", "strum 0.27.1", @@ -8057,31 +8056,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serial_test" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" -dependencies = [ - "futures", - "log", - "once_cell", - "parking_lot", - "scc", - "serial_test_derive", -] - -[[package]] -name = "serial_test_derive" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "sha1" version = "0.10.6" diff --git a/crates/chisel/Cargo.toml b/crates/chisel/Cargo.toml index 78acd8faaa62b..2e40c92e9f99d 100644 --- a/crates/chisel/Cargo.toml +++ b/crates/chisel/Cargo.toml @@ -61,7 +61,6 @@ walkdir.workspace = true tikv-jemallocator = { workspace = true, optional = true } [dev-dependencies] -serial_test = "3" tracing-subscriber.workspace = true [features] diff --git a/crates/chisel/tests/cache.rs b/crates/chisel/tests/cache.rs index 7016bce09c76e..75da9683f6d8d 100644 --- a/crates/chisel/tests/cache.rs +++ b/crates/chisel/tests/cache.rs @@ -1,11 +1,9 @@ use chisel::session::ChiselSession; use foundry_compilers::artifacts::EvmVersion; use foundry_config::Config; -use serial_test::serial; use std::path::Path; #[test] -#[serial] fn test_cache_directory() { // Get the cache dir // Should be ~/.foundry/cache/chisel @@ -17,7 +15,6 @@ fn test_cache_directory() { } #[test] -#[serial] fn test_create_cache_directory() { // Get the cache dir let cache_dir = ChiselSession::cache_dir().unwrap(); @@ -30,7 +27,6 @@ fn test_create_cache_directory() { } #[test] -#[serial] fn test_write_session() { // Create the cache directory if it doesn't exist let cache_dir = ChiselSession::cache_dir().unwrap(); @@ -58,7 +54,6 @@ fn test_write_session() { } #[test] -#[serial] fn test_write_session_with_name() { // Create the cache directory if it doesn't exist let cache_dir = ChiselSession::cache_dir().unwrap(); @@ -83,7 +78,6 @@ fn test_write_session_with_name() { } #[test] -#[serial] fn test_clear_cache() { // Create a session to validate clearing a non-empty cache directory let cache_dir = ChiselSession::cache_dir().unwrap(); @@ -108,7 +102,6 @@ fn test_clear_cache() { } #[test] -#[serial] fn test_list_sessions() { // Create and clear the cache directory ChiselSession::create_cache_dir().unwrap(); @@ -135,7 +128,6 @@ fn test_list_sessions() { } #[test] -#[serial] fn test_load_cache() { // Create and clear the cache directory ChiselSession::create_cache_dir().unwrap(); @@ -163,7 +155,6 @@ fn test_load_cache() { } #[test] -#[serial] fn test_write_same_session_multiple_times() { // Create and clear the cache directory ChiselSession::create_cache_dir().unwrap(); @@ -186,7 +177,6 @@ fn test_write_same_session_multiple_times() { } #[test] -#[serial] fn test_load_latest_cache() { // Create and clear the cache directory ChiselSession::create_cache_dir().unwrap(); From 9ef405335ccc1f48bd10aff2baf6e1825c535ee3 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Mon, 28 Apr 2025 09:35:35 +0200 Subject: [PATCH 041/244] chore: metadata hash extraction cleanup (#10396) --- crates/verify/src/bytecode.rs | 4 ++-- crates/verify/src/utils.rs | 31 +++++++++++++------------------ 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/crates/verify/src/bytecode.rs b/crates/verify/src/bytecode.rs index c3ddd3c4df867..66e95c7e790b3 100644 --- a/crates/verify/src/bytecode.rs +++ b/crates/verify/src/bytecode.rs @@ -291,7 +291,7 @@ impl VerifyBytecodeArgs { .await?; let match_type = crate::utils::match_bytecodes( - &deployed_bytecode.original_bytes(), + deployed_bytecode.original_byte_slice(), &onchain_runtime_code, &constructor_args, true, @@ -501,7 +501,7 @@ impl VerifyBytecodeArgs { // Compare the onchain runtime bytecode with the runtime code from the fork. let match_type = crate::utils::match_bytecodes( - &fork_runtime_code.original_bytes(), + fork_runtime_code.original_byte_slice(), &onchain_runtime_code, &constructor_args, true, diff --git a/crates/verify/src/utils.rs b/crates/verify/src/utils.rs index f79f2dfce52f8..714fe4eee0e36 100644 --- a/crates/verify/src/utils.rs +++ b/crates/verify/src/utils.rs @@ -197,29 +197,24 @@ fn is_partial_match( } fn try_extract_and_compare_bytecode(mut local_bytecode: &[u8], mut bytecode: &[u8]) -> bool { - local_bytecode = extract_metadata_hash(local_bytecode); - bytecode = extract_metadata_hash(bytecode); + local_bytecode = ignore_metadata_hash(local_bytecode); + bytecode = ignore_metadata_hash(bytecode); // Now compare the local code and bytecode local_bytecode == bytecode } -/// @dev This assumes that the metadata is at the end of the bytecode -fn extract_metadata_hash(bytecode: &[u8]) -> &[u8] { - // Get the last two bytes of the bytecode to find the length of CBOR metadata - let metadata_len = &bytecode[bytecode.len() - 2..]; - let metadata_len = u16::from_be_bytes([metadata_len[0], metadata_len[1]]); - - if metadata_len as usize <= bytecode.len() { - if ciborium::from_reader::( - &bytecode[bytecode.len() - 2 - metadata_len as usize..bytecode.len() - 2], - ) - .is_ok() - { - &bytecode[..bytecode.len() - 2 - metadata_len as usize] - } else { - bytecode - } +/// This assumes that the metadata is at the end of the bytecode. +fn ignore_metadata_hash(bytecode: &[u8]) -> &[u8] { + // Get the last two bytes of the bytecode to find the length of CBOR metadata. + let Some((rest, metadata_len_bytes)) = bytecode.split_last_chunk() else { return bytecode }; + let metadata_len = u16::from_be_bytes(*metadata_len_bytes) as usize; + if metadata_len > rest.len() { + return bytecode; + } + let (rest, metadata) = rest.split_at(rest.len() - metadata_len); + if ciborium::from_reader::(metadata).is_ok() { + rest } else { bytecode } From 272e409f8f4fe6cb1bad87b0cddab37af7f31f73 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Mon, 28 Apr 2025 10:43:03 +0200 Subject: [PATCH 042/244] chore(deps): replace humantime with jiff (#10395) * chore(deps): replace humantime with jiff * tests --- Cargo.lock | 18 +-------------- Cargo.toml | 1 + crates/common/Cargo.toml | 5 +++-- crates/common/src/serde_helpers.rs | 22 +++++++++++++++++++ crates/forge/Cargo.toml | 1 - crates/forge/src/result.rs | 3 ++- .../SimpleContractTestNonVerbose.json | 5 +---- .../fixtures/SimpleContractTestVerbose.json | 5 +---- 8 files changed, 31 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 112351887f28b..cb611f7e66c36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3502,7 +3502,6 @@ dependencies = [ "foundry-wallets", "futures", "globset", - "humantime-serde", "indicatif", "inferno", "itertools 0.14.0", @@ -3850,6 +3849,7 @@ dependencies = [ "foundry-compilers", "foundry-config", "itertools 0.14.0", + "jiff", "num-format", "path-slash", "reqwest", @@ -5017,22 +5017,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "humantime" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" - -[[package]] -name = "humantime-serde" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c" -dependencies = [ - "humantime", - "serde", -] - [[package]] name = "hyper" version = "1.6.0" diff --git a/Cargo.toml b/Cargo.toml index a5e1cfaef6317..07b78ee1b99d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -314,6 +314,7 @@ url = "2" vergen = { version = "8", default-features = false } yansi = { version = "1.0", features = ["detect-tty", "detect-env"] } path-slash = "0.2" +jiff = "0.2" # Use unicode-rs which has a smaller binary size than the default ICU4X as the IDNA backend, used # by the `url` crate. diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index 11e67174b65be..393946c33d934 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -56,18 +56,19 @@ comfy-table.workspace = true dunce.workspace = true eyre.workspace = true itertools.workspace = true +jiff.workspace = true num-format.workspace = true +path-slash.workspace = true reqwest.workspace = true semver.workspace = true -serde_json.workspace = true serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true thiserror.workspace = true tokio.workspace = true tracing.workspace = true url.workspace = true walkdir.workspace = true yansi.workspace = true -path-slash.workspace = true anstream.workspace = true anstyle.workspace = true diff --git a/crates/common/src/serde_helpers.rs b/crates/common/src/serde_helpers.rs index a7cc8bee12308..90634de397424 100644 --- a/crates/common/src/serde_helpers.rs +++ b/crates/common/src/serde_helpers.rs @@ -125,3 +125,25 @@ where Ok(num) } + +pub mod duration { + use serde::{Deserialize, Deserializer}; + use std::time::Duration; + + pub fn serialize(duration: &Duration, serializer: S) -> Result + where + S: serde::Serializer, + { + let d = jiff::SignedDuration::try_from(*duration).map_err(serde::ser::Error::custom)?; + serializer.serialize_str(&format!("{d:#}")) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + let d = s.parse::().map_err(serde::de::Error::custom)?; + d.try_into().map_err(serde::de::Error::custom) + } +} diff --git a/crates/forge/Cargo.toml b/crates/forge/Cargo.toml index ffcb88fdf0351..4f8a20e86c9ad 100644 --- a/crates/forge/Cargo.toml +++ b/crates/forge/Cargo.toml @@ -35,7 +35,6 @@ rayon.workspace = true serde.workspace = true tracing.workspace = true yansi.workspace = true -humantime-serde = "1.1.1" chrono.workspace = true # bin diff --git a/crates/forge/src/result.rs b/crates/forge/src/result.rs index f221ad7ebac3d..90447fc26bfa0 100644 --- a/crates/forge/src/result.rs +++ b/crates/forge/src/result.rs @@ -205,7 +205,7 @@ impl TestOutcome { #[derive(Clone, Debug, Serialize)] pub struct SuiteResult { /// Wall clock time it took to execute all tests in this suite. - #[serde(with = "humantime_serde")] + #[serde(with = "foundry_common::serde_helpers::duration")] pub duration: Duration, /// Individual test results: `test fn signature -> TestResult`. pub test_results: BTreeMap, @@ -409,6 +409,7 @@ pub struct TestResult { /// Labeled addresses pub labeled_addresses: AddressHashMap, + #[serde(with = "foundry_common::serde_helpers::duration")] pub duration: Duration, /// pc breakpoint char map diff --git a/crates/forge/tests/fixtures/SimpleContractTestNonVerbose.json b/crates/forge/tests/fixtures/SimpleContractTestNonVerbose.json index b4e396863dc68..e9d992751b868 100644 --- a/crates/forge/tests/fixtures/SimpleContractTestNonVerbose.json +++ b/crates/forge/tests/fixtures/SimpleContractTestNonVerbose.json @@ -15,10 +15,7 @@ }, "traces": [], "labeled_addresses": {}, - "duration": { - "secs": "{...}", - "nanos": "{...}" - }, + "duration": "{...}", "breakpoints": {}, "gas_snapshots": {} } diff --git a/crates/forge/tests/fixtures/SimpleContractTestVerbose.json b/crates/forge/tests/fixtures/SimpleContractTestVerbose.json index 20324950fc240..8659312887de6 100644 --- a/crates/forge/tests/fixtures/SimpleContractTestVerbose.json +++ b/crates/forge/tests/fixtures/SimpleContractTestVerbose.json @@ -204,10 +204,7 @@ ] ], "labeled_addresses": {}, - "duration": { - "secs": "{...}", - "nanos": "{...}" - }, + "duration": "{...}", "breakpoints": {}, "gas_snapshots": {} } From 1a5ff59ac6a09472c10cf6cbd1918aa024ebea3b Mon Sep 17 00:00:00 2001 From: Ayush Dubey <61616662+Ayushdubey86@users.noreply.github.com> Date: Mon, 28 Apr 2025 21:27:29 +0530 Subject: [PATCH 043/244] feat(forge): script warn if no transactions to broadcast (#10384) * warn if no transactions to broadcast * Update revert_handlers.rs * Update error.rs * moving to sh_warn from warn * Adding tc for "no tx to broadcast" * fmt * Move and fix test --------- Co-authored-by: grandizzy --- crates/forge/tests/cli/script.rs | 39 ++++++++++++++++++++++++++++++++ crates/script/src/lib.rs | 4 ++++ 2 files changed, 43 insertions(+) diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index 8f0df538e9636..607158d571bb9 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -2670,3 +2670,42 @@ Error: script failed: "#]]); }); + +// Tests that script warns if no tx to broadcast. +// +forgetest_async!(warns_if_no_transactions_to_broadcast, |prj, cmd| { + let (_api, handle) = spawn(NodeConfig::test()).await; + foundry_test_utils::util::initialize(prj.root()); + prj.add_script( + "NoTxScript.s.sol", + r#" + import {Script} from "forge-std/Script.sol"; + + contract NoTxScript is Script { + function run() public { + vm.startBroadcast(); + // No real tx created + vm.stopBroadcast(); + } + } + "#, + ) + .unwrap(); + + cmd.args([ + "script", + "--private-key", + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + "--rpc-url", + &handle.http_endpoint(), + "--broadcast", + "NoTxScript", + ]) + .assert_success() + .stderr_eq(str![ + r#" +Warning: No transactions to broadcast. + +"# + ]); +}); diff --git a/crates/script/src/lib.rs b/crates/script/src/lib.rs index 3016784d180c7..fbbb52398a837 100644 --- a/crates/script/src/lib.rs +++ b/crates/script/src/lib.rs @@ -279,6 +279,10 @@ impl ScriptArgs { .as_ref() .is_none_or(|txs| txs.is_empty()) { + if pre_simulation.args.broadcast { + sh_warn!("No transactions to broadcast.")?; + } + return Ok(()); } From d4d2cc8c6609038e24a37233e3e7d4f0f08c1d49 Mon Sep 17 00:00:00 2001 From: m4rio <92288535+mario-eth@users.noreply.github.com> Date: Mon, 28 Apr 2025 12:10:58 -0700 Subject: [PATCH 044/244] Update to soldeer 0.5.4 (#10399) * Update to release 0.5.4 * refactor: use soldeer_core structs where possible * fix(config): soldeer import * style: format --------- Co-authored-by: beeb <703631+beeb@users.noreply.github.com> --- Cargo.lock | 9 +++-- Cargo.toml | 3 +- crates/config/Cargo.toml | 1 + crates/config/src/lib.rs | 2 +- crates/config/src/soldeer.rs | 72 +++++++-------------------------- crates/forge/src/cmd/soldeer.rs | 19 ++------- 6 files changed, 28 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cb611f7e66c36..583a27613a16d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4024,6 +4024,7 @@ dependencies = [ "serde_json", "similar-asserts", "solar-parse", + "soldeer-core", "tempfile", "thiserror 2.0.12", "toml 0.8.21", @@ -8403,9 +8404,9 @@ dependencies = [ [[package]] name = "soldeer-commands" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f88020cde2fb2ace7acb636e7fe9cfc5b0ea26b3751533f574227ca01acff54" +checksum = "7d5234cb6edcb3ac81b73c4554391e47c78d5493ac17c59115d2e72b87746816" dependencies = [ "bon", "clap", @@ -8422,9 +8423,9 @@ dependencies = [ [[package]] name = "soldeer-core" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc58b150e6ab9407038329da2b904f795faa2a5eb1b5c2c61b016ca07ecd1b2c" +checksum = "a67f45108aec81281be2c23000bde114d568ac3899026779f21656bbc3d85671" dependencies = [ "bon", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 07b78ee1b99d2..f364649b9f9ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -300,7 +300,8 @@ semver = "1" serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["arbitrary_precision"] } similar-asserts = "1.6" -soldeer-commands = "=0.5.3" +soldeer-commands = "=0.5.4" +soldeer-core = { version = "=0.5.4", features = ["serde"] } strum = "0.27" tempfile = "3.13" tikv-jemallocator = "0.6" diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml index 8c8fc70bb3fa8..816f06054734f 100644 --- a/crates/config/Cargo.toml +++ b/crates/config/Cargo.toml @@ -38,6 +38,7 @@ reqwest.workspace = true semver = { workspace = true, features = ["serde"] } serde_json.workspace = true serde.workspace = true +soldeer-core.workspace = true thiserror.workspace = true toml = { workspace = true, features = ["preserve_order"] } toml_edit = "0.22" diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 6318d4b63f064..b7d3f0f7e5c0d 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -2575,7 +2575,7 @@ mod tests { vyper::VyperOptimizationMode, ModelCheckerEngine, YulDetails, }; use similar_asserts::assert_eq; - use soldeer::RemappingsLocation; + use soldeer_core::remappings::RemappingsLocation; use std::{collections::BTreeMap, fs::File, io::Write}; use tempfile::tempdir; use NamedChain::Moonbeam; diff --git a/crates/config/src/soldeer.rs b/crates/config/src/soldeer.rs index 75ee96c2c0fee..24ecce0955f12 100644 --- a/crates/config/src/soldeer.rs +++ b/crates/config/src/soldeer.rs @@ -1,8 +1,7 @@ //! Configuration specific to the `forge soldeer` command and the `forge_soldeer` package - -use std::collections::BTreeMap; - use serde::{Deserialize, Serialize}; +pub use soldeer_core::config::SoldeerConfig; +use std::collections::BTreeMap; /// Soldeer dependencies config structure when it's defined as a map #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] @@ -14,9 +13,21 @@ pub struct MapDependency { #[serde(default, skip_serializing_if = "Option::is_none")] pub url: Option, - /// The commit in case git is used as dependency retrieval + /// The git URL for the source repo + #[serde(default, skip_serializing_if = "Option::is_none")] + pub git: Option, + + /// The commit in case git is used as dependency source #[serde(default, skip_serializing_if = "Option::is_none")] pub rev: Option, + + /// The branch in case git is used as dependency source + #[serde(default, skip_serializing_if = "Option::is_none")] + pub branch: Option, + + /// The git tag in case git is used as dependency source + #[serde(default, skip_serializing_if = "Option::is_none")] + pub tag: Option, } /// Type for Soldeer configs, under dependencies tag in the foundry.toml @@ -39,56 +50,3 @@ pub enum SoldeerDependencyValue { Map(MapDependency), Str(String), } - -/// Location where to store the remappings, either in `remappings.txt` or in the `foundry.toml` -#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Default)] -#[serde(rename_all = "lowercase")] -pub enum RemappingsLocation { - #[default] - Txt, - Config, -} - -fn default_true() -> bool { - true -} - -/// Type for Soldeer configs, under soldeer tag in the foundry.toml -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] -pub struct SoldeerConfig { - #[serde(default = "default_true")] - pub remappings_generate: bool, - - #[serde(default)] - pub remappings_regenerate: bool, - - #[serde(default = "default_true")] - pub remappings_version: bool, - - #[serde(default)] - pub remappings_prefix: String, - - #[serde(default)] - pub remappings_location: RemappingsLocation, - - #[serde(default)] - pub recursive_deps: bool, -} - -impl AsRef for SoldeerConfig { - fn as_ref(&self) -> &Self { - self - } -} -impl Default for SoldeerConfig { - fn default() -> Self { - Self { - remappings_generate: true, - remappings_regenerate: false, - remappings_version: true, - remappings_prefix: String::new(), - remappings_location: Default::default(), - recursive_deps: false, - } - } -} diff --git a/crates/forge/src/cmd/soldeer.rs b/crates/forge/src/cmd/soldeer.rs index 3f42481c2b753..6ca70758ce7f6 100644 --- a/crates/forge/src/cmd/soldeer.rs +++ b/crates/forge/src/cmd/soldeer.rs @@ -2,23 +2,12 @@ use clap::Parser; use eyre::Result; use foundry_common::shell; use soldeer_commands::{Command, Verbosity}; -// CLI arguments for `forge soldeer`. -// The following list of commands and their actions: -// -// forge soldeer install: looks up the config file and install all the dependencies that are present -// there forge soldeer install package~version: looks up on https://soldeer.xyz and if the package>version is there then add to config+lockfile and install new dependency. Replaces existing entry if version is different. -// forge soldeer install package~version url: same behavior as install but instead of looking at https://soldeer.xyz it choses the URL, which can be git or custom zip url -// forge soldeer update: same behavior as install looks up the config file and install all the -// dependencies that are present there. This will change in the future forge soldeer login: logs in into https://soldeer.xyz account -// forge soldeer push package~version: pushes files to the central repository -// forge soldeer version: checks soldeer version -// forge soldeer init: initializes a new project with minimal dependency for foundry setup, install -// latest forge-std version forge soldeer uninstall dependency: uninstalls a dependency, removes -// artifacts and configs +/// Available subcommands for Soldeer, see +/// for more information #[derive(Clone, Debug, Parser)] #[command( - override_usage = "Native Solidity Package Manager, `run forge soldeer [COMMAND] --help` for more details" + override_usage = "Native Solidity Package Manager, run `forge soldeer [COMMAND] --help` for more details" )] pub struct SoldeerArgs { /// Command must be one of the following init/install/login/push/uninstall/update/version. @@ -31,7 +20,7 @@ impl SoldeerArgs { let verbosity = Verbosity::new(shell::verbosity(), if shell::is_quiet() { 1 } else { 0 }); match soldeer_commands::run(self.command, verbosity).await { Ok(_) => Ok(()), - Err(err) => Err(eyre::eyre!("Failed to run soldeer {}", err)), + Err(err) => Err(eyre::eyre!("Failed to run soldeer: {err}")), } } } From 96f6ffe0750dfbd5639034f95e0c974d93d6f369 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 29 Apr 2025 05:00:55 +0300 Subject: [PATCH 045/244] fix(forge): do not use bytecode metadata in fuzz dict (#10402) fix(forge): do not use metadata in fuzzing --- Cargo.lock | 2 +- Cargo.toml | 1 + crates/common/Cargo.toml | 1 + crates/common/src/utils.rs | 17 +++++++++++++++++ crates/evm/fuzz/src/strategies/state.rs | 3 ++- crates/forge/tests/it/invariant.rs | 18 +++++++++--------- crates/verify/Cargo.toml | 2 -- crates/verify/src/utils.rs | 21 ++++----------------- 8 files changed, 35 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 583a27613a16d..9fec46ff7e011 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3663,7 +3663,6 @@ dependencies = [ "alloy-provider", "alloy-rpc-types", "async-trait", - "ciborium", "clap", "eyre", "foundry-block-explorers", @@ -3840,6 +3839,7 @@ dependencies = [ "async-trait", "axum", "chrono", + "ciborium", "clap", "comfy-table", "dunce", diff --git a/Cargo.toml b/Cargo.toml index f364649b9f9ef..2d8aeadaa72f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -270,6 +270,7 @@ chrono = { version = "0.4", default-features = false, features = [ "std", ] } axum = "0.7" +ciborium = "0.2" color-eyre = "0.6" comfy-table = "7" dirs = "6" diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index 393946c33d934..0b81ac057e94e 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -73,6 +73,7 @@ yansi.workspace = true anstream.workspace = true anstyle.workspace = true terminal_size.workspace = true +ciborium.workspace = true [build-dependencies] chrono.workspace = true diff --git a/crates/common/src/utils.rs b/crates/common/src/utils.rs index 8fc612c2d6197..a655d1e3d713f 100644 --- a/crates/common/src/utils.rs +++ b/crates/common/src/utils.rs @@ -37,3 +37,20 @@ pub fn erc7201(id: &str) -> B256 { let x = U256::from_be_bytes(keccak256(id).0) - U256::from(1); keccak256(x.to_be_bytes::<32>()) & B256::from(!U256::from(0xff)) } + +/// Utility function to ignore metadata hash of the given bytecode. +/// This assumes that the metadata is at the end of the bytecode. +pub fn ignore_metadata_hash(bytecode: &[u8]) -> &[u8] { + // Get the last two bytes of the bytecode to find the length of CBOR metadata. + let Some((rest, metadata_len_bytes)) = bytecode.split_last_chunk() else { return bytecode }; + let metadata_len = u16::from_be_bytes(*metadata_len_bytes) as usize; + if metadata_len > rest.len() { + return bytecode; + } + let (rest, metadata) = rest.split_at(rest.len() - metadata_len); + if ciborium::from_reader::(metadata).is_ok() { + rest + } else { + bytecode + } +} diff --git a/crates/evm/fuzz/src/strategies/state.rs b/crates/evm/fuzz/src/strategies/state.rs index 9bcca6aa16d2e..c598ada0accab 100644 --- a/crates/evm/fuzz/src/strategies/state.rs +++ b/crates/evm/fuzz/src/strategies/state.rs @@ -5,6 +5,7 @@ use alloy_primitives::{ map::{AddressIndexSet, B256IndexSet, HashMap}, Address, Bytes, Log, B256, U256, }; +use foundry_common::ignore_metadata_hash; use foundry_config::FuzzDictionaryConfig; use foundry_evm_core::utils::StateChangeset; use parking_lot::{lock_api::RwLockReadGuard, RawRwLock, RwLock}; @@ -248,7 +249,7 @@ impl FuzzDictionary { // Insert push bytes if let Some(code) = &account_info.code { self.insert_address(*address); - self.collect_push_bytes(code.bytes_slice()); + self.collect_push_bytes(ignore_metadata_hash(code.original_byte_slice())); } } } diff --git a/crates/forge/tests/it/invariant.rs b/crates/forge/tests/it/invariant.rs index 43db084d06df3..5a072cedb7195 100644 --- a/crates/forge/tests/it/invariant.rs +++ b/crates/forge/tests/it/invariant.rs @@ -1114,9 +1114,9 @@ Encountered 1 failing test in test/InvariantSequenceLenTest.t.sol:InvariantSeque [FAIL: invariant increment failure] [Sequence] (original: 4, shrunk: 4) sender=0x00000000000000000000000000000000000018dE addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[1931387396117645594923 [1.931e21]] - sender=0x00000000000000000000000000000000000009d5 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] - sender=0x0000000000000000000000000000000000000105 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] - sender=0x00000000000000000000000000000000000009B2 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[996881781832960761274744263729582347 [9.968e35]] + sender=0x0000000000000000000000000000000000000C37 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] + sender=0x0000000000000000000000000000000000000106 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] + sender=0x0000000000000000000000000000000000001684 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[996881781832960761274744263729582347 [9.968e35]] invariant_increment() (runs: 0, calls: 0, reverts: 0) Encountered a total of 1 failing tests, 0 tests succeeded @@ -1138,11 +1138,11 @@ Encountered 1 failing test in test/InvariantSequenceLenTest.t.sol:InvariantSeque [Sequence] (original: 4, shrunk: 4) vm.prank(0x00000000000000000000000000000000000018dE); Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).setNumber(1931387396117645594923); - vm.prank(0x00000000000000000000000000000000000009d5); + vm.prank(0x0000000000000000000000000000000000000C37); Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).increment(); - vm.prank(0x0000000000000000000000000000000000000105); + vm.prank(0x0000000000000000000000000000000000000106); Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).increment(); - vm.prank(0x00000000000000000000000000000000000009B2); + vm.prank(0x0000000000000000000000000000000000001684); Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).setNumber(996881781832960761274744263729582347); invariant_increment() (runs: 0, calls: 0, reverts: 0) @@ -1163,9 +1163,9 @@ Encountered 1 failing test in test/InvariantSequenceLenTest.t.sol:InvariantSeque [FAIL: invariant_increment replay failure] [Sequence] (original: 4, shrunk: 4) sender=0x00000000000000000000000000000000000018dE addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[1931387396117645594923 [1.931e21]] - sender=0x00000000000000000000000000000000000009d5 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] - sender=0x0000000000000000000000000000000000000105 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] - sender=0x00000000000000000000000000000000000009B2 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[996881781832960761274744263729582347 [9.968e35]] + sender=0x0000000000000000000000000000000000000C37 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] + sender=0x0000000000000000000000000000000000000106 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] + sender=0x0000000000000000000000000000000000001684 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[996881781832960761274744263729582347 [9.968e35]] invariant_increment() (runs: 1, calls: 1, reverts: 1) Encountered a total of 1 failing tests, 0 tests succeeded diff --git a/crates/verify/Cargo.toml b/crates/verify/Cargo.toml index 443d44cc110a4..8e2ec24f7d4d4 100644 --- a/crates/verify/Cargo.toml +++ b/crates/verify/Cargo.toml @@ -40,8 +40,6 @@ regex = { workspace = true, default-features = false } yansi.workspace = true itertools.workspace = true -ciborium = "0.2" - [dev-dependencies] tokio = { workspace = true, features = ["macros"] } foundry-test-utils.workspace = true diff --git a/crates/verify/src/utils.rs b/crates/verify/src/utils.rs index 714fe4eee0e36..81defa05d0f7b 100644 --- a/crates/verify/src/utils.rs +++ b/crates/verify/src/utils.rs @@ -9,7 +9,10 @@ use foundry_block_explorers::{ contract::{ContractCreationData, ContractMetadata, Metadata}, errors::EtherscanError, }; -use foundry_common::{abi::encode_args, compile::ProjectCompiler, provider::RetryProvider, shell}; +use foundry_common::{ + abi::encode_args, compile::ProjectCompiler, ignore_metadata_hash, provider::RetryProvider, + shell, +}; use foundry_compilers::artifacts::{BytecodeHash, CompactContractBytecode, EvmVersion}; use foundry_config::Config; use foundry_evm::{ @@ -204,22 +207,6 @@ fn try_extract_and_compare_bytecode(mut local_bytecode: &[u8], mut bytecode: &[u local_bytecode == bytecode } -/// This assumes that the metadata is at the end of the bytecode. -fn ignore_metadata_hash(bytecode: &[u8]) -> &[u8] { - // Get the last two bytes of the bytecode to find the length of CBOR metadata. - let Some((rest, metadata_len_bytes)) = bytecode.split_last_chunk() else { return bytecode }; - let metadata_len = u16::from_be_bytes(*metadata_len_bytes) as usize; - if metadata_len > rest.len() { - return bytecode; - } - let (rest, metadata) = rest.split_at(rest.len() - metadata_len); - if ciborium::from_reader::(metadata).is_ok() { - rest - } else { - bytecode - } -} - fn find_mismatch_in_settings( etherscan_settings: &Metadata, local_settings: &Config, From d5860bd2b4bbc3772ca7ff4452e1cf776d96a3b4 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 29 Apr 2025 13:27:19 +0300 Subject: [PATCH 046/244] chore: fix anvil immutable fork test (#10409) --- crates/anvil/tests/it/fork.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/anvil/tests/it/fork.rs b/crates/anvil/tests/it/fork.rs index e00b7be42d406..0add43733bf39 100644 --- a/crates/anvil/tests/it/fork.rs +++ b/crates/anvil/tests/it/fork.rs @@ -1335,7 +1335,7 @@ async fn test_immutable_fork_transaction_hash() { fork_config() .with_blocktime(Some(Duration::from_millis(500))) .with_fork_transaction_hash(Some(fork_tx_hash)) - .with_eth_rpc_url(Some("https://rpc.immutable.com".to_string())), + .with_eth_rpc_url(Some("https://immutable-zkevm.drpc.org".to_string())), ) .await; From c7008516045ea6d127e21a45c3bc4f966c519e23 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 29 Apr 2025 22:05:04 +0300 Subject: [PATCH 047/244] chore(tests): bump forge-std version (#10406) * chore: bump forge-std version used for tests * fix tests - additional file in forge-std * Fix precompile label test --------- Co-authored-by: DaniPopes Co-authored-by: grandizzy Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> --- crates/forge/tests/cli/script.rs | 4 ++-- crates/forge/tests/cli/test_cmd.rs | 14 ++++++------- crates/forge/tests/cli/test_optimizer.rs | 26 ++++++++++++------------ testdata/forge-std-rev | 2 +- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index 607158d571bb9..7c7461dfe9f61 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -1952,7 +1952,7 @@ contract SimpleScript is Script { ]) .assert_success() .stdout_eq(str![[r#" -{"logs":[],"returns":{"success":{"internal_type":"bool","value":"true"}},"success":true,"raw_logs":[],"traces":[["Deployment",{"arena":[{"parent":null,"children":[],"idx":0,"trace":{"depth":0,"success":true,"caller":"0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38","address":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","maybe_precompile":false,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CREATE","value":"0x0","data":"[..]","output":"[..]","gas_used":"{...}","gas_limit":"{...}","status":"Return","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[]}]}],["Execution",{"arena":[{"parent":null,"children":[1,2],"idx":0,"trace":{"depth":0,"success":true,"caller":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","address":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc0406226","output":"0x0000000000000000000000000000000000000000000000000000000000000001","gas_used":"{...}","gas_limit":1073720760,"status":"Return","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[{"Call":0},{"Call":1}]},{"parent":0,"children":[],"idx":1,"trace":{"depth":1,"success":true,"caller":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x7fb5297f","output":"0x","gas_used":"{...}","gas_limit":1056940994,"status":"Return","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":2,"trace":{"depth":1,"success":true,"caller":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","address":"0x0000000000000000000000000000000000000000","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x","output":"0x","gas_used":"{...}","gas_limit":1056940645,"status":"Stop","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[]}]}]],"gas_used":"{...}","labeled_addresses":{},"returned":"0x0000000000000000000000000000000000000000000000000000000000000001","address":null} +{"logs":[],"returns":{"success":{"internal_type":"bool","value":"true"}},"success":true,"raw_logs":[],"traces":[["Deployment",{"arena":[{"parent":null,"children":[],"idx":0,"trace":{"depth":0,"success":true,"caller":"0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38","address":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","maybe_precompile":false,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CREATE","value":"0x0","data":"[..]","output":"[..]","gas_used":"{...}","gas_limit":"{...}","status":"Return","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[]}]}],["Execution",{"arena":[{"parent":null,"children":[1,2],"idx":0,"trace":{"depth":0,"success":true,"caller":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","address":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc0406226","output":"0x0000000000000000000000000000000000000000000000000000000000000001","gas_used":"{...}","gas_limit":1073720760,"status":"Return","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[{"Call":0},{"Call":1}]},{"parent":0,"children":[],"idx":1,"trace":{"depth":1,"success":true,"caller":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x7fb5297f","output":"0x","gas_used":"{...}","gas_limit":1056940999,"status":"Return","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":2,"trace":{"depth":1,"success":true,"caller":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","address":"0x0000000000000000000000000000000000000000","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x","output":"0x","gas_used":"{...}","gas_limit":1056940650,"status":"Stop","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[]}]}]],"gas_used":"{...}","labeled_addresses":{},"returned":"0x0000000000000000000000000000000000000000000000000000000000000001","address":null} {"chain":31337,"estimated_gas_price":"{...}","estimated_total_gas_used":"{...}","estimated_amount_required":"{...}","token_symbol":"ETH"} {"chain":"anvil-hardhat","status":"success","tx_hash":"0x4f78afe915fceb282c7625a68eb350bc0bf78acb59ad893e5c62b710a37f3156","contract_address":null,"block_number":1,"gas_used":"{...}","gas_price":"{...}"} {"status":"success","transactions":"[..]/broadcast/Foo.sol/31337/run-latest.json","sensitive":"[..]/cache/Foo.sol/31337/run-latest.json"} @@ -2575,7 +2575,7 @@ Chain 31337 accessList [] chainId 31337 -gasLimit 228247 +gasLimit 228231 gasPrice input [..] maxFeePerBlobGas diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index 91ee25070bf8c..fb2e990f28984 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -997,7 +997,7 @@ Compiler run successful! Ran 1 test for test/Contract.t.sol:PrecompileLabelsTest [PASS] testPrecompileLabels() ([GAS]) Traces: - [14048] PrecompileLabelsTest::testPrecompileLabels() + [..] PrecompileLabelsTest::testPrecompileLabels() ├─ [0] VM::deal(VM: [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D], 1000000000000000000 [1e18]) │ └─ ← [Return] ├─ [0] VM::deal(console: [0x000000000000000000636F6e736F6c652e6c6f67], 1000000000000000000 [1e18]) @@ -1451,10 +1451,10 @@ contract ATest is Test { cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... -[PASS] testNormalGas() (gas: 3153) -[PASS] testWeirdGas1() (gas: 2991) -[PASS] testWeirdGas2() (gas: 3218) -[PASS] testWithAssembly() (gas: 3034) +[PASS] testNormalGas() (gas: 3148) +[PASS] testWeirdGas1() (gas: 2986) +[PASS] testWeirdGas2() (gas: 3213) +[PASS] testWithAssembly() (gas: 3029) ... "#]]); }); @@ -1547,9 +1547,9 @@ Traces: │ └─ ← [Stop] └─ ← [Stop] -[PASS] test_GasMeter() (gas: 53102) +[PASS] test_GasMeter() (gas: 53097) Traces: - [53102] ATest::test_GasMeter() + [53097] ATest::test_GasMeter() ├─ [0] VM::pauseGasMetering() │ └─ ← [Return] ├─ [0] VM::resumeGasMetering() diff --git a/crates/forge/tests/cli/test_optimizer.rs b/crates/forge/tests/cli/test_optimizer.rs index f196746490ece..8b522e5c95862 100644 --- a/crates/forge/tests/cli/test_optimizer.rs +++ b/crates/forge/tests/cli/test_optimizer.rs @@ -8,7 +8,7 @@ forgetest_init!(toggle_invalidate_cache_on_build, |prj, cmd| { // All files are built with optimized tests. cmd.args(["build"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... -Compiling 22 files with [..] +Compiling 23 files with [..] ... "#]]); @@ -27,7 +27,7 @@ No files changed, compilation skipped // All files are rebuilt with preprocessed cache false. cmd.with_no_redact().assert_success().stdout_eq(str![[r#" ... -Compiling 22 files with [..] +Compiling 23 files with [..] ... "#]]); @@ -41,7 +41,7 @@ forgetest_init!(toggle_invalidate_cache_on_test, |prj, cmd| { // All files are built with optimized tests. cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... -Compiling 20 files with [..] +Compiling 21 files with [..] ... "#]]); @@ -60,7 +60,7 @@ No files changed, compilation skipped // All files are rebuilt with preprocessed cache false. cmd.with_no_redact().assert_success().stdout_eq(str![[r#" ... -Compiling 20 files with [..] +Compiling 21 files with [..] ... "#]]); @@ -126,7 +126,7 @@ contract CounterTest is Test { // All 20 files are compiled on first run. cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... -Compiling 20 files with [..] +Compiling 21 files with [..] ... "#]]); @@ -268,7 +268,7 @@ contract CounterTest is Test { // All 21 files are compiled on first run. cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... -Compiling 21 files with [..] +Compiling 22 files with [..] ... "#]]); @@ -417,7 +417,7 @@ contract CounterTest is Test { // 20 files plus one mock file are compiled on first run. cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... -Compiling 21 files with [..] +Compiling 22 files with [..] ... "#]]); @@ -560,7 +560,7 @@ contract CounterTest is Test { // 20 files plus one mock file are compiled on first run. cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... -Compiling 21 files with [..] +Compiling 22 files with [..] ... "#]]); @@ -699,7 +699,7 @@ contract CounterTest is Test { // 20 files plus one mock file are compiled on first run. cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... -Compiling 21 files with [..] +Compiling 22 files with [..] ... "#]]); @@ -874,7 +874,7 @@ contract CounterTest is Test { // 22 files plus one mock file are compiled on first run. cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... -Compiling 23 files with [..] +Compiling 24 files with [..] ... [PASS] test_Increment_In_Counter() (gas: [..]) [PASS] test_Increment_In_Counter_A() (gas: [..]) @@ -1091,7 +1091,7 @@ contract CounterTest is Test { cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... -Compiling 21 files with [..] +Compiling 22 files with [..] ... [PASS] test_Increment_In_Counter() (gas: [..]) [PASS] test_Increment_In_Counter_With_Salt() (gas: [..]) @@ -1214,7 +1214,7 @@ contract CounterTest is Test { // All 20 files are compiled on first run. cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... -Compiling 20 files with [..] +Compiling 21 files with [..] ... "#]]); @@ -1340,7 +1340,7 @@ contract CounterTest is Test { // All 20 files should properly compile. cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... -Compiling 20 files with [..] +Compiling 21 files with [..] ... "#]]); diff --git a/testdata/forge-std-rev b/testdata/forge-std-rev index ac11c37c7c648..893b927f82be2 100644 --- a/testdata/forge-std-rev +++ b/testdata/forge-std-rev @@ -1 +1 @@ -3b20d60d14b343ee4f908cb8079495c07f5e8981 \ No newline at end of file +77041d2ce690e692d6e03cc812b57d1ddaa4d505 \ No newline at end of file From 47cd8569d7881b0cbf974ea874698cbc474528e0 Mon Sep 17 00:00:00 2001 From: Tronica Date: Wed, 30 Apr 2025 01:03:49 +0200 Subject: [PATCH 048/244] chore: update `std::process::exit(0)` calls in `ProjectCompiler::compile` (#10328) * Update compile.rs * Update compile.rs * Update compile.rs * Update compile.rs * Reverted changes in compile.rs * Added TODO comments in compile.rs * return result --------- Co-authored-by: Matthias Seitz Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> --- crates/common/src/compile.rs | 47 +++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index ecae238cabb1d..9d7f3735c5227 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -157,10 +157,14 @@ impl ProjectCompiler { { self.project_root = project.root().to_path_buf(); - // TODO: Avoid process::exit + // TODO: Avoid using std::process::exit(0). + // Replacing this with a return (e.g., Ok(ProjectCompileOutput::default())) would be more + // idiomatic, but it currently requires a `Default` bound on `C::Language`, which + // breaks compatibility with downstream crates like `foundry-cli`. This would need a + // broader refactor across the call chain. Leaving it as-is for now until a larger + // refactor is feasible. if !project.paths.has_input_files() && self.files.is_empty() { sh_println!("Nothing to compile")?; - // nothing to do here std::process::exit(0); } @@ -204,7 +208,7 @@ impl ProjectCompiler { let quiet = self.quiet.unwrap_or(false); let bail = self.bail.unwrap_or(true); - let output = with_compilation_reporter(self.quiet.unwrap_or(false), || { + let output = with_compilation_reporter(quiet, || { tracing::debug!("compiling project"); let timer = Instant::now(); @@ -229,7 +233,7 @@ impl ProjectCompiler { } } - self.handle_output(&output); + self.handle_output(&output)?; } Ok(output) @@ -239,7 +243,7 @@ impl ProjectCompiler { fn handle_output>( &self, output: &ProjectCompileOutput, - ) { + ) -> Result<()> { let print_names = self.print_names.unwrap_or(false); let print_sizes = self.print_sizes.unwrap_or(false); @@ -251,17 +255,17 @@ impl ProjectCompiler { } if shell::is_json() { - let _ = sh_println!("{}", serde_json::to_string(&artifacts).unwrap()); + sh_println!("{}", serde_json::to_string(&artifacts).unwrap())?; } else { for (version, names) in artifacts { - let _ = sh_println!( + sh_println!( " compiler version: {}.{}.{}", version.major, version.minor, version.patch - ); + )?; for name in names { - let _ = sh_println!(" - {name}"); + sh_println!(" - {name}")?; } } } @@ -270,7 +274,7 @@ impl ProjectCompiler { if print_sizes { // add extra newline if names were already printed if print_names && !shell::is_json() { - let _ = sh_println!(); + sh_println!()?; } let mut size_report = @@ -317,19 +321,22 @@ impl ProjectCompiler { } } - let _ = sh_println!("{size_report}"); - - // TODO: avoid process::exit - // exit with error if any contract exceeds the size limit, excluding test contracts. - if size_report.exceeds_runtime_size_limit() { - std::process::exit(1); - } + sh_println!("{size_report}")?; + eyre::ensure!( + !size_report.exceeds_runtime_size_limit(), + "some contracts exceed the runtime size limit \ + (EIP-170: {CONTRACT_RUNTIME_SIZE_LIMIT} bytes)" + ); // Check size limits only if not ignoring EIP-3860 - if !self.ignore_eip_3860 && size_report.exceeds_initcode_size_limit() { - std::process::exit(1); - } + eyre::ensure!( + self.ignore_eip_3860 || !size_report.exceeds_initcode_size_limit(), + "some contracts exceed the initcode size limit \ + (EIP-3860: {CONTRACT_INITCODE_SIZE_LIMIT} bytes)" + ); } + + Ok(()) } } From f3b9eafdc6145287a865fe0adfac2ae0627046b0 Mon Sep 17 00:00:00 2001 From: 0xdapper <94534135+0xdapper@users.noreply.github.com> Date: Wed, 30 Apr 2025 04:42:24 +0530 Subject: [PATCH 049/244] fix(anvil): trace_filter same to and from block range is valid (#10400) * fix(anvil): trace_filter same to and from block range is valid * Update crates/anvil/src/eth/backend/mem/mod.rs --------- Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> --- crates/anvil/src/eth/backend/mem/mod.rs | 7 ++++--- crates/anvil/tests/it/traces.rs | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 5e2ac34cd9505..2f295ed3311b9 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -2519,14 +2519,15 @@ impl Backend { ) -> Result, BlockchainError> { let matcher = filter.matcher(); let start = filter.from_block.unwrap_or(0); - let end = filter.to_block.unwrap_or(self.best_number()); + let end = filter.to_block.unwrap_or_else(|| self.best_number()); - let dist = end.saturating_sub(start); - if dist == 0 { + if start > end { return Err(BlockchainError::RpcError(RpcError::invalid_params( "invalid block range, ensure that to block is greater than from block".to_string(), ))); } + + let dist = end - start; if dist > 300 { return Err(BlockchainError::RpcError(RpcError::invalid_params( "block range too large, currently limited to 300".to_string(), diff --git a/crates/anvil/tests/it/traces.rs b/crates/anvil/tests/it/traces.rs index 79448ad836921..297f188f7ddbd 100644 --- a/crates/anvil/tests/it/traces.rs +++ b/crates/anvil/tests/it/traces.rs @@ -873,6 +873,21 @@ async fn test_trace_filter() { let traces = api.trace_filter(tracer).await; assert!(traces.is_err()); + // Test same from and to block is valid + let latest = provider.get_block_number().await.unwrap(); + let tracer = TraceFilter { + from_block: Some(latest), + to_block: Some(latest), + from_address: vec![], + to_address: vec![], + mode: TraceFilterMode::Union, + after: None, + count: None, + }; + + let traces = api.trace_filter(tracer).await; + assert!(traces.is_ok()); + // Test invalid block range let latest = provider.get_block_number().await.unwrap(); let tracer = TraceFilter { From fa55caa48ea767ad615874b745f06d3f7442e547 Mon Sep 17 00:00:00 2001 From: Kristofer Peterson Date: Wed, 30 Apr 2025 00:15:21 +0100 Subject: [PATCH 050/244] Apply access list to tracing executor for 'cast call --trace' (#10161) Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> --- crates/cast/src/cmd/call.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/cast/src/cmd/call.rs b/crates/cast/src/cmd/call.rs index 65ee4c068c17b..b005a8af0f8c8 100644 --- a/crates/cast/src/cmd/call.rs +++ b/crates/cast/src/cmd/call.rs @@ -266,6 +266,10 @@ impl CallArgs { let input = tx.inner.input.into_input().unwrap_or_default(); let tx_kind = tx.inner.to.expect("set by builder"); + if let Some(access_list) = tx.inner.access_list { + executor.env_mut().tx.access_list = access_list.0 + } + let trace = match tx_kind { TxKind::Create => { let deploy_result = executor.deploy(from, input, value, None); From a63dbe2936f9b1303a64f43bca3e9fa4c196f016 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Wed, 30 Apr 2025 01:26:24 +0200 Subject: [PATCH 051/244] chore: minor changes (#10415) --- .github/workflows/nextest.yml | 2 +- crates/anvil/src/cmd.rs | 2 +- crates/anvil/src/config.rs | 6 +++--- crates/anvil/tests/it/transaction.rs | 2 +- crates/cast/src/cmd/find_block.rs | 2 +- crates/cheatcodes/src/evm/prank.rs | 2 +- crates/chisel/src/executor.rs | 2 +- crates/doc/src/writer/buf_writer.rs | 2 +- crates/fmt/README.md | 2 +- crates/fmt/src/formatter.rs | 2 +- crates/forge/tests/it/core.rs | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/nextest.yml b/.github/workflows/nextest.yml index 48ad9307b200b..d50953871eaf5 100644 --- a/.github/workflows/nextest.yml +++ b/.github/workflows/nextest.yml @@ -75,7 +75,7 @@ jobs: run: pip --version && pip install vyper==0.4.0 - name: Forge RPC cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.foundry/cache diff --git a/crates/anvil/src/cmd.rs b/crates/anvil/src/cmd.rs index 6753c6c7475f5..4b89f0a6dfb89 100644 --- a/crates/anvil/src/cmd.rs +++ b/crates/anvil/src/cmd.rs @@ -438,7 +438,7 @@ pub struct AnvilEvmArgs { /// Fetch state from a specific block number over a remote endpoint. /// - /// If a negative the the given value is subtracted from the `latest` block number. + /// If negative, the given value is subtracted from the `latest` block number. /// /// See --fork-url. #[arg( diff --git a/crates/anvil/src/config.rs b/crates/anvil/src/config.rs index 0db12e2fe559c..43ae552adaf3f 100644 --- a/crates/anvil/src/config.rs +++ b/crates/anvil/src/config.rs @@ -1420,14 +1420,14 @@ async fn derive_block_and_transactions( } } -/// Fork delimiter used to specify which block or transaction to fork from +/// Fork delimiter used to specify which block or transaction to fork from. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ForkChoice { /// Block number to fork from. /// - /// f a negative the the given value is subtracted from the `latest` block number. + /// If negative, the given value is subtracted from the `latest` block number. Block(i128), - /// Transaction hash to fork from + /// Transaction hash to fork from. Transaction(TxHash), } diff --git a/crates/anvil/tests/it/transaction.rs b/crates/anvil/tests/it/transaction.rs index 88dd95bb468d6..fc049614e3bdd 100644 --- a/crates/anvil/tests/it/transaction.rs +++ b/crates/anvil/tests/it/transaction.rs @@ -872,7 +872,7 @@ async fn test_tx_receipt() { let tx = WithOtherFields::new(tx); let tx = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap(); - // `to` field is none if it's a contract creation transaction: https://ethereum.org/developers/docs/apis/json-rpc/#eth_gettransactionreceipt + // `to` field is none if it's a contract creation transaction: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionreceipt assert!(tx.to.is_none()); assert!(tx.contract_address.is_some()); } diff --git a/crates/cast/src/cmd/find_block.rs b/crates/cast/src/cmd/find_block.rs index 53da3e9686080..19aa9e3ff6abb 100644 --- a/crates/cast/src/cmd/find_block.rs +++ b/crates/cast/src/cmd/find_block.rs @@ -45,7 +45,7 @@ impl FindBlockArgs { let mut high_block = last_block_num; let mut matching_block = None; while high_block > low_block && matching_block.is_none() { - // Get timestamp of middle block (this approach approach to avoids overflow) + // Get timestamp of middle block (this approach to avoids overflow) let high_minus_low_over_2 = high_block .checked_sub(low_block) .ok_or_else(|| eyre::eyre!("unexpected underflow")) diff --git a/crates/cheatcodes/src/evm/prank.rs b/crates/cheatcodes/src/evm/prank.rs index 4fdaede8b5d98..195760e702f46 100644 --- a/crates/cheatcodes/src/evm/prank.rs +++ b/crates/cheatcodes/src/evm/prank.rs @@ -16,7 +16,7 @@ pub struct Prank { pub depth: u64, /// Whether the prank stops by itself after the next call pub single_call: bool, - /// Whether the prank should be be applied to delegate call + /// Whether the prank should be applied to delegate call pub delegate_call: bool, /// Whether the prank has been used yet (false if unused) pub used: bool, diff --git a/crates/chisel/src/executor.rs b/crates/chisel/src/executor.rs index 658a18f461823..b490cdfc77c72 100644 --- a/crates/chisel/src/executor.rs +++ b/crates/chisel/src/executor.rs @@ -1036,7 +1036,7 @@ impl Type { } // Check if the first element of the custom type is a known contract. If it is, begin - // our recursion on on that contract's definitions. + // our recursion on that contract's definitions. let name = custom_type.last().unwrap(); let contract = intermediate.intermediate_contracts.get(name); if contract.is_some() { diff --git a/crates/doc/src/writer/buf_writer.rs b/crates/doc/src/writer/buf_writer.rs index e6109c338c03f..4bb7f9612db47 100644 --- a/crates/doc/src/writer/buf_writer.rs +++ b/crates/doc/src/writer/buf_writer.rs @@ -104,7 +104,7 @@ impl BufWriter { self.write_list_item(&link.as_doc()?, depth) } - /// Writes a solidity code block block to the buffer. + /// Writes a solidity code block to the buffer. pub fn write_code(&mut self, code: &str) -> fmt::Result { writeln!(self.buf, "{}", Markdown::CodeBlock(SOLIDITY, code)) } diff --git a/crates/fmt/README.md b/crates/fmt/README.md index 1fc2712ad6e0e..f38eed245eaf9 100644 --- a/crates/fmt/README.md +++ b/crates/fmt/README.md @@ -53,7 +53,7 @@ To insert the comments into the appropriate areas, strings get converted to chun before being written to the buffer. A chunk is any string that cannot be split by whitespace. A chunk also carries with it the surrounding comment information. Thereby when writing the chunk the comments can be added before and after the chunk as well -as any any whitespace surrounding. +as any whitespace surrounding. To construct a chunk, the string and the location of the string is given to the Formatter and the pre-parsed comments before the start and end of the string are diff --git a/crates/fmt/src/formatter.rs b/crates/fmt/src/formatter.rs index aee9eee91db12..98a2adcef86c5 100644 --- a/crates/fmt/src/formatter.rs +++ b/crates/fmt/src/formatter.rs @@ -3252,7 +3252,7 @@ impl Visitor for Formatter<'_, W> { let is_constructor = self.context.is_constructor_function(); // we can't make any decisions here regarding trailing `()` because we'd need to // find out if the `base` is a solidity modifier or an - // interface/contract therefore we we its raw content. + // interface/contract therefore we use its raw content. // we can however check if the contract `is` the `base`, this however also does // not cover all cases diff --git a/crates/forge/tests/it/core.rs b/crates/forge/tests/it/core.rs index 3d08812f9d68e..50208854a536d 100644 --- a/crates/forge/tests/it/core.rs +++ b/crates/forge/tests/it/core.rs @@ -752,7 +752,7 @@ async fn test_trace() { assert_eq!( execution_traces.count(), 1, - "Test {test_name} did not not have exactly 1 execution trace." + "Test {test_name} did not have exactly 1 execution trace." ); } } From 378ded105929fefac358d5c0a3d7d2870ddb3ae5 Mon Sep 17 00:00:00 2001 From: Tushar Jain <54453857+tushar994@users.noreply.github.com> Date: Wed, 30 Apr 2025 11:39:29 +0530 Subject: [PATCH 052/244] feat(forge): add `vm.stopRecord` (#10370) * add initial implementation of StopRecord cheatcode * modify command to be stopRecordAndReturnAccesses instead * improve documentation and lint fixes * lint changes in integration tests * implement resetRecord and stopRecord * clippy fix * minor formatting changes * chore: cleanup, rm reset --------- Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> --- crates/cheatcodes/assets/cheatcodes.json | 22 ++++++++++++- crates/cheatcodes/spec/src/vm.rs | 7 ++++- crates/cheatcodes/src/evm.rs | 30 +++++++++++------- crates/cheatcodes/src/inspector.rs | 10 ++++-- testdata/cheats/Vm.sol | 1 + testdata/default/cheats/Record.t.sol | 40 ++++++++++++++++++++++++ 6 files changed, 94 insertions(+), 16 deletions(-) diff --git a/crates/cheatcodes/assets/cheatcodes.json b/crates/cheatcodes/assets/cheatcodes.json index 59c5bab3cb457..5d46978a4fdb9 100644 --- a/crates/cheatcodes/assets/cheatcodes.json +++ b/crates/cheatcodes/assets/cheatcodes.json @@ -8499,7 +8499,7 @@ { "func": { "id": "record", - "description": "Records all storage reads and writes.", + "description": "Records all storage reads and writes. Use `accesses` to get the recorded data.\nSubsequent calls to `record` will clear the previous data.", "declaration": "function record() external;", "visibility": "external", "mutability": "", @@ -10422,6 +10422,26 @@ "status": "stable", "safety": "unsafe" }, + { + "func": { + "id": "stopRecord", + "description": "Stops recording storage reads and writes.", + "declaration": "function stopRecord() external;", + "visibility": "external", + "mutability": "", + "signature": "stopRecord()", + "selector": "0x996be76d", + "selectorBytes": [ + 153, + 107, + 231, + 109 + ] + }, + "group": "evm", + "status": "stable", + "safety": "safe" + }, { "func": { "id": "stopSnapshotGas_0", diff --git a/crates/cheatcodes/spec/src/vm.rs b/crates/cheatcodes/spec/src/vm.rs index 00f3b8004a96c..afb687894f863 100644 --- a/crates/cheatcodes/spec/src/vm.rs +++ b/crates/cheatcodes/spec/src/vm.rs @@ -399,10 +399,15 @@ interface Vm { // -------- Record Storage -------- - /// Records all storage reads and writes. + /// Records all storage reads and writes. Use `accesses` to get the recorded data. + /// Subsequent calls to `record` will clear the previous data. #[cheatcode(group = Evm, safety = Safe)] function record() external; + /// Stops recording storage reads and writes. + #[cheatcode(group = Evm, safety = Safe)] + function stopRecord() external; + /// Gets all accessed reads and write slot from a `vm.record` session, for a given address. #[cheatcode(group = Evm, safety = Safe)] function accesses(address target) external returns (bytes32[] memory readSlots, bytes32[] memory writeSlots); diff --git a/crates/cheatcodes/src/evm.rs b/crates/cheatcodes/src/evm.rs index 52d246958436b..8b7d714d3dd8f 100644 --- a/crates/cheatcodes/src/evm.rs +++ b/crates/cheatcodes/src/evm.rs @@ -56,6 +56,12 @@ impl RecordAccess { self.record_read(target, slot); self.writes.entry(target).or_default().push(slot); } + + /// Clears the recorded reads and writes. + pub fn clear(&mut self) { + // Also frees memory. + *self = Default::default(); + } } /// Records the `snapshotGas*` cheatcodes. @@ -280,7 +286,15 @@ impl Cheatcode for dumpStateCall { impl Cheatcode for recordCall { fn apply(&self, state: &mut Cheatcodes) -> Result { let Self {} = self; - state.accesses = Some(Default::default()); + state.recording_accesses = true; + state.accesses.clear(); + Ok(Default::default()) + } +} + +impl Cheatcode for stopRecordCall { + fn apply(&self, state: &mut Cheatcodes) -> Result { + state.recording_accesses = false; Ok(Default::default()) } } @@ -288,16 +302,10 @@ impl Cheatcode for recordCall { impl Cheatcode for accessesCall { fn apply(&self, state: &mut Cheatcodes) -> Result { let Self { target } = *self; - let result = state - .accesses - .as_mut() - .map(|accesses| { - ( - &accesses.reads.entry(target).or_default()[..], - &accesses.writes.entry(target).or_default()[..], - ) - }) - .unwrap_or_default(); + let result = ( + state.accesses.reads.entry(target).or_default().as_slice(), + state.accesses.writes.entry(target).or_default().as_slice(), + ); Ok(result.abi_encode_params()) } } diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index 251210113c4e6..517b1ffbe72d7 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -420,7 +420,10 @@ pub struct Cheatcodes { pub fork_revert_diagnostic: Option, /// Recorded storage reads and writes - pub accesses: Option, + pub accesses: RecordAccess, + + /// Whether storage access recording is currently active + pub recording_accesses: bool, /// Recorded account accesses (calls, creates) organized by relative call depth, where the /// topmost vector corresponds to accesses at the depth at which account access recording @@ -538,6 +541,7 @@ impl Cheatcodes { assume_no_revert: Default::default(), fork_revert_diagnostic: Default::default(), accesses: Default::default(), + recording_accesses: Default::default(), recorded_account_diffs_stack: Default::default(), recorded_logs: Default::default(), record_debug_steps_info: Default::default(), @@ -1332,7 +1336,7 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { } // `record`: record storage reads and writes. - if self.accesses.is_some() { + if self.recording_accesses { self.record_accesses(interpreter); } @@ -1945,7 +1949,7 @@ impl Cheatcodes { /// Records storage slots reads and writes. #[cold] fn record_accesses(&mut self, interpreter: &mut Interpreter) { - let Some(access) = &mut self.accesses else { return }; + let access = &mut self.accesses; match interpreter.current_opcode() { op::SLOAD => { let key = try_or_return!(interpreter.stack().peek(0)); diff --git a/testdata/cheats/Vm.sol b/testdata/cheats/Vm.sol index adf6733ba9424..c043d29489763 100644 --- a/testdata/cheats/Vm.sol +++ b/testdata/cheats/Vm.sol @@ -514,6 +514,7 @@ interface Vm { function stopExpectSafeMemory() external; function stopMappingRecording() external; function stopPrank() external; + function stopRecord() external; function stopSnapshotGas() external returns (uint256 gasUsed); function stopSnapshotGas(string calldata name) external returns (uint256 gasUsed); function stopSnapshotGas(string calldata group, string calldata name) external returns (uint256 gasUsed); diff --git a/testdata/default/cheats/Record.t.sol b/testdata/default/cheats/Record.t.sol index c2907ebb84316..c3029d5f54205 100644 --- a/testdata/default/cheats/Record.t.sol +++ b/testdata/default/cheats/Record.t.sol @@ -53,4 +53,44 @@ contract RecordTest is DSTest { assertEq(innerWrites.length, 1, "number of nested writes is incorrect"); assertEq(innerWrites[0], bytes32(uint256(2)), "key for nested write is incorrect"); } + + function testStopRecordAccess() public { + RecordAccess target = new RecordAccess(); + + // Start recording + vm.record(); + NestedRecordAccess inner = target.record(); + + // Verify Records + (bytes32[] memory reads, bytes32[] memory writes) = vm.accesses(address(target)); + + assertEq(reads.length, 2, "number of reads is incorrect"); + assertEq(reads[0], bytes32(uint256(1)), "key for read 0 is incorrect"); + assertEq(reads[1], bytes32(uint256(1)), "key for read 1 is incorrect"); + + assertEq(writes.length, 1, "number of writes is incorrect"); + assertEq(writes[0], bytes32(uint256(1)), "key for write is incorrect"); + + vm.stopRecord(); + inner = target.record(); + + // Verify that there are no new Records + (reads, writes) = vm.accesses(address(target)); + + assertEq(reads.length, 2, "number of reads is incorrect"); + assertEq(reads[0], bytes32(uint256(1)), "key for read 0 is incorrect"); + assertEq(reads[1], bytes32(uint256(1)), "key for read 1 is incorrect"); + + assertEq(writes.length, 1, "number of writes is incorrect"); + assertEq(writes[0], bytes32(uint256(1)), "key for write is incorrect"); + + vm.record(); + vm.stopRecord(); + + // verify reset all records + (reads, writes) = vm.accesses(address(target)); + + assertEq(reads.length, 0, "number of reads is incorrect"); + assertEq(writes.length, 0, "number of writes is incorrect"); + } } From 497b6ee597a6a8042fc91c361f77eee22aed0cb2 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Wed, 30 Apr 2025 16:43:20 +0300 Subject: [PATCH 053/244] feat(forge): add script execution protection config (#10408) * feat(forge): add script execution protection config * Update crates/config/src/lib.rs Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> --------- Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> --- crates/config/src/lib.rs | 4 ++++ crates/evm/evm/src/executors/mod.rs | 2 +- crates/forge/tests/cli/config.rs | 5 ++++- crates/forge/tests/cli/script.rs | 11 +++++++++++ crates/script/src/execute.rs | 3 +-- crates/script/src/runner.rs | 12 +++++++----- 6 files changed, 28 insertions(+), 9 deletions(-) diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index b7d3f0f7e5c0d..c78bde6d8d8e7 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -523,6 +523,9 @@ pub struct Config { #[serde(default)] pub compilation_restrictions: Vec, + /// Whether to enable script execution protection. + pub script_execution_protection: bool, + /// PRIVATE: This structure may grow, As such, constructing this structure should /// _always_ be done using a public constructor or update syntax: /// @@ -2412,6 +2415,7 @@ impl Default for Config { additional_compiler_profiles: Default::default(), compilation_restrictions: Default::default(), eof: false, + script_execution_protection: true, _non_exhaustive: (), } } diff --git a/crates/evm/evm/src/executors/mod.rs b/crates/evm/evm/src/executors/mod.rs index 9c4b27e0377dc..5937912e17601 100644 --- a/crates/evm/evm/src/executors/mod.rs +++ b/crates/evm/evm/src/executors/mod.rs @@ -258,7 +258,7 @@ impl Executor { } #[inline] - pub fn set_script(&mut self, script_address: Address) { + pub fn set_script_execution(&mut self, script_address: Address) { self.inspector_mut().script(script_address); } diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index 46dd731df9e45..799365fcd1b03 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -169,6 +169,7 @@ forgetest!(can_extract_config_values, |prj, cmd| { additional_compiler_profiles: Default::default(), compilation_restrictions: Default::default(), eof: false, + script_execution_protection: true, _non_exhaustive: (), }; prj.write_config(input.clone()); @@ -1041,6 +1042,7 @@ transaction_timeout = 120 eof = false additional_compiler_profiles = [] compilation_restrictions = [] +script_execution_protection = true [profile.default.rpc_storage_caching] chains = "all" @@ -1298,7 +1300,8 @@ exclude = [] "transaction_timeout": 120, "eof": false, "additional_compiler_profiles": [], - "compilation_restrictions": [] + "compilation_restrictions": [], + "script_execution_protection": true } "#]]); diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index 7c7461dfe9f61..1b1180e793015 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -2668,6 +2668,17 @@ Error: Usage of `address(this)` detected in script contract. Script contracts ar Error: script failed: ... +"#]]); + + // Disable script protection. + prj.update_config(|config| { + config.script_execution_protection = false; + }); + cmd.assert_success().stdout_eq(str![[r#" +... +Script ran successfully. +... + "#]]); }); diff --git a/crates/script/src/execute.rs b/crates/script/src/execute.rs index 48d37cfca4329..9317381a91632 100644 --- a/crates/script/src/execute.rs +++ b/crates/script/src/execute.rs @@ -144,9 +144,8 @@ impl PreExecutionState { &self.build_data.predeploy_libraries, self.execution_data.bytecode.clone(), needs_setup(&self.execution_data.abi), - self.script_config.sender_nonce, + &self.script_config, self.args.broadcast, - self.script_config.evm_opts.fork_url.is_none(), )?; if setup_result.success { diff --git a/crates/script/src/runner.rs b/crates/script/src/runner.rs index d45a97139dae4..b568cbce28632 100644 --- a/crates/script/src/runner.rs +++ b/crates/script/src/runner.rs @@ -1,4 +1,4 @@ -use super::ScriptResult; +use super::{ScriptConfig, ScriptResult}; use crate::build::ScriptPredeployLibraries; use alloy_eips::eip7702::SignedAuthorization; use alloy_primitives::{Address, Bytes, TxKind, U256}; @@ -33,9 +33,8 @@ impl ScriptRunner { libraries: &ScriptPredeployLibraries, code: Bytes, setup: bool, - sender_nonce: u64, + script_config: &ScriptConfig, is_broadcast: bool, - need_create2_deployer: bool, ) -> Result<(Address, ScriptResult)> { trace!(target: "script", "executing setUP()"); @@ -45,11 +44,12 @@ impl ScriptRunner { self.executor.set_balance(self.evm_opts.sender, U256::MAX)?; } - if need_create2_deployer { + if script_config.evm_opts.fork_url.is_none() { self.executor.deploy_create2_deployer()?; } } + let sender_nonce = script_config.sender_nonce; self.executor.set_nonce(self.evm_opts.sender, sender_nonce)?; // We max out their balance so that they can deploy and make calls. @@ -158,7 +158,9 @@ impl ScriptRunner { } // set script address to be used by execution inspector - self.executor.set_script(address); + if script_config.config.script_execution_protection { + self.executor.set_script_execution(address); + } traces.extend(constructor_traces.map(|traces| (TraceKind::Deployment, traces))); From 96c40b6ad6ca444e52520d1ee5e7e84d8aa08b22 Mon Sep 17 00:00:00 2001 From: daramir <4935829+daramir@users.noreply.github.com> Date: Thu, 1 May 2025 00:44:40 +1000 Subject: [PATCH 054/244] feat: add Alpine Linux support to foundryup (#10257) * feat: add Alpine Linux support to foundryup This change adds Alpine Linux as a supported platform in `foundryup` script, enabling straightforward installation on Alpine systems. Alpine binaries (which use MUSL instead of GNU libc) have been available in nightly builds since PR #10086. This commit makes Alpine a first-class supported platform alongside existing ones. This benefits teams working in lightweight Alpine-based environments (e.g. CI, containers) and other systems that favor MUSL's smaller footprint. * Bump foundryup version --------- Co-authored-by: grandizzy Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> --- foundryup/foundryup | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/foundryup/foundryup b/foundryup/foundryup index a3a6d1bb58823..9379ca5183729 100755 --- a/foundryup/foundryup +++ b/foundryup/foundryup @@ -4,7 +4,7 @@ set -eo pipefail # NOTE: if you make modifications to this script, please increment the version number. # Major / minor: incremented for each stable release of Foundry. # Patch: incremented for each change between stable releases. -FOUNDRYUP_INSTALLER_VERSION="1.0.1" +FOUNDRYUP_INSTALLER_VERSION="1.1.0" BASE_DIR=${XDG_CONFIG_HOME:-$HOME} FOUNDRY_DIR=${FOUNDRY_DIR:-"$BASE_DIR/.foundry"} @@ -118,7 +118,7 @@ main() { PLATFORM=$(tolower "${FOUNDRYUP_PLATFORM:-$uname_s}") EXT="tar.gz" case $PLATFORM in - linux) ;; + linux|alpine) ;; darwin|mac*) PLATFORM="darwin" ;; @@ -272,7 +272,7 @@ OPTIONS: -p, --path Build and install a local repository -j, --jobs Number of CPUs to use for building Foundry (default: all CPUs) --arch Install a specific architecture (supports amd64 and arm64) - --platform Install a specific platform (supports win32, linux, and darwin) + --platform Install a specific platform (supports win32, linux, darwin and alpine) EOF } From b28c2b210450232b5a5cf649926398985306a750 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Thu, 1 May 2025 13:42:16 +0300 Subject: [PATCH 055/244] fix(forge): show lcov hits for do while statements (#10423) --- crates/forge/src/coverage.rs | 14 ++++--- crates/forge/tests/cli/coverage.rs | 66 ++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/crates/forge/src/coverage.rs b/crates/forge/src/coverage.rs index 22c1bbb0701d1..b446fccc94b79 100644 --- a/crates/forge/src/coverage.rs +++ b/crates/forge/src/coverage.rs @@ -1,6 +1,6 @@ //! Coverage reports. -use alloy_primitives::map::HashMap; +use alloy_primitives::map::{HashMap, HashSet}; use comfy_table::{modifiers::UTF8_ROUND_CORNERS, Attribute, Cell, Color, Row, Table}; use evm_disassembler::disassemble_bytes; use foundry_common::fs; @@ -118,6 +118,8 @@ impl CoverageReporter for LcovReporter { writeln!(out, "TN:")?; writeln!(out, "SF:{}", path.display())?; + let mut recorded_lines = HashSet::new(); + for item in items { let line = item.loc.lines.start; // `lines` is half-open, so we need to subtract 1 to get the last included line. @@ -140,8 +142,11 @@ impl CoverageReporter for LcovReporter { writeln!(out, "FNDA:{hits},{name}")?; } } - CoverageItemKind::Line => { - writeln!(out, "DA:{line},{hits}")?; + // Add lines / statement hits only once. + CoverageItemKind::Line | CoverageItemKind::Statement => { + if recorded_lines.insert(line) { + writeln!(out, "DA:{line},{hits}")?; + } } CoverageItemKind::Branch { branch_id, path_id, .. } => { writeln!( @@ -150,9 +155,6 @@ impl CoverageReporter for LcovReporter { if hits == 0 { "-".to_string() } else { hits.to_string() } )?; } - // Statements are not in the LCOV format. - // We don't add them in order to avoid doubling line hits. - CoverageItemKind::Statement => {} } } diff --git a/crates/forge/tests/cli/coverage.rs b/crates/forge/tests/cli/coverage.rs index 5f8ad1e873b95..43896c7c3623b 100644 --- a/crates/forge/tests/cli/coverage.rs +++ b/crates/forge/tests/cli/coverage.rs @@ -1845,6 +1845,72 @@ contract ArrayConditionTest is DSTest { "#]]); }); +// +// Test that line hits are properly recorded in lcov report. +forgetest!(do_while_lcov, |prj, cmd| { + prj.insert_ds_test(); + prj.add_source( + "Counter.sol", + r#" +contract Counter { + uint256 public number = 21; + + function increment() public { + uint256 i = 0; + do { + number++; + if (number > 20) { + number -= 2; + } + } while (++i < 10); + } +} + "#, + ) + .unwrap(); + + prj.add_source( + "Counter.t.sol", + r#" +import "./test.sol"; +import "./Counter.sol"; + +contract CounterTest is DSTest { + function test_do_while() public { + Counter counter = new Counter(); + counter.increment(); + } +} + "#, + ) + .unwrap(); + + assert_lcov( + cmd.arg("coverage"), + str![[r#" +TN: +SF:src/Counter.sol +DA:7,1 +FN:7,Counter.increment +FNDA:1,Counter.increment +DA:8,1 +DA:14,10 +DA:10,10 +DA:11,10 +BRDA:11,0,0,6 +DA:12,6 +FNF:1 +FNH:1 +LF:3 +LH:3 +BRF:1 +BRH:1 +end_of_record + +"#]], + ); +}); + #[track_caller] fn assert_lcov(cmd: &mut TestCommand, data: impl IntoData) { cmd.args(["--report=lcov", "--report-file"]).assert_file(data.into_data()); From 33cb8d2faf6787ddecde2af7343ee472bdf829ee Mon Sep 17 00:00:00 2001 From: Ayush Dubey <61616662+Ayushdubey86@users.noreply.github.com> Date: Fri, 2 May 2025 16:14:49 +0530 Subject: [PATCH 056/244] feat: Add file option for calldata input (#10397) * Update opts.rs * Update args.rs * Update args-> final_args * Update crates/cast/src/opts.rs Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> * test case * fmt * splitting the string * fmt --------- Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> --- crates/cast/src/args.rs | 15 +++++++++++++-- crates/cast/src/opts.rs | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/crates/cast/src/args.rs b/crates/cast/src/args.rs index d0cf7400b287a..fc6df76364a82 100644 --- a/crates/cast/src/args.rs +++ b/crates/cast/src/args.rs @@ -195,8 +195,19 @@ pub async fn run_command(args: CastArgs) -> Result<()> { let tokens = SimpleCast::calldata_decode(&sig, &calldata, true)?; print_tokens(&tokens); } - CastSubcommand::CalldataEncode { sig, args } => { - sh_println!("{}", SimpleCast::calldata_encode(sig, &args)?)?; + CastSubcommand::CalldataEncode { sig, args, file } => { + let final_args = if let Some(file_path) = file { + let contents = fs::read_to_string(file_path)?; + contents + .lines() + .map(str::trim) + .filter(|line| !line.is_empty()) + .map(String::from) + .collect() + } else { + args + }; + sh_println!("{}", SimpleCast::calldata_encode(sig, &final_args)?)?; } CastSubcommand::DecodeString { data } => { let tokens = SimpleCast::calldata_decode("Any(string)", &data, true)?; diff --git a/crates/cast/src/opts.rs b/crates/cast/src/opts.rs index da789f830cda4..7594d0fe23fc5 100644 --- a/crates/cast/src/opts.rs +++ b/crates/cast/src/opts.rs @@ -391,6 +391,10 @@ pub enum CastSubcommand { /// The arguments to encode. #[arg(allow_hyphen_values = true)] args: Vec, + + // Path to file containing arguments to encode. + #[arg(long, value_name = "PATH")] + file: Option, }, /// Get the symbolic name of the current chain. @@ -1147,6 +1151,19 @@ mod tests { }; } + #[test] + fn parse_call_data_with_file() { + let args: Cast = Cast::parse_from(["foundry-cli", "calldata", "f()", "--file", "test.txt"]); + match args.cmd { + CastSubcommand::CalldataEncode { sig, file, args } => { + assert_eq!(sig, "f()".to_string()); + assert_eq!(file, Some(PathBuf::from("test.txt"))); + assert!(args.is_empty()); + } + _ => unreachable!(), + }; + } + // #[test] fn parse_signature() { From cc3a3f8ced82ff2df8317592b8c016bf8759d592 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Mon, 5 May 2025 10:42:04 +0300 Subject: [PATCH 057/244] chore: update immutable forked test (#10439) --- crates/anvil/tests/it/fork.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/anvil/tests/it/fork.rs b/crates/anvil/tests/it/fork.rs index 0add43733bf39..422bd2514cf6d 100644 --- a/crates/anvil/tests/it/fork.rs +++ b/crates/anvil/tests/it/fork.rs @@ -1329,7 +1329,7 @@ async fn test_immutable_fork_transaction_hash() { // Fork to a block with a specific transaction let fork_tx_hash = - TxHash::from_str("39d64ebf9eb3f07ede37f8681bc3b61928817276c4c4680b6ef9eac9f88b6786") + TxHash::from_str("2ac736ce725d628ef20569a1bb501726b42b33f9d171f60b92b69de3ce705845") .unwrap(); let (api, _) = spawn( fork_config() @@ -1339,7 +1339,7 @@ async fn test_immutable_fork_transaction_hash() { ) .await; - let fork_block_number = 8521008; + let fork_block_number = 21824325; // Make sure the fork starts from previous block let mut block_number = api.block_number().unwrap().to::(); @@ -1356,26 +1356,26 @@ async fn test_immutable_fork_transaction_hash() { .await .unwrap() .unwrap(); - assert_eq!(block.transactions.len(), 14); + assert_eq!(block.transactions.len(), 6); let block = api .block_by_number_full(BlockNumberOrTag::Number(fork_block_number)) .await .unwrap() .unwrap(); - assert_eq!(block.transactions.len(), 3); + assert!(!block.transactions.is_empty()); // Validate the transactions preceding the target transaction exist let expected_transactions = [ - TxHash::from_str("1bfe33136edc3d26bd01ce75c8f5ae14fffe8b142d30395cb4b6d3dc3043f400") + TxHash::from_str("c900784c993221ba192c53a3ff9996f6af83a951100ceb93e750f7ef86bd43d5") .unwrap(), - TxHash::from_str("8c0ce5fb9ec2c8e03f7fcc69c7786393c691ce43b58a06d74d6733679308fc01") + TxHash::from_str("f86f001bbdf69f8f64ff8a4a5fc3e684cf3a7706f204eba8439752f6f67cd2c4") .unwrap(), fork_tx_hash, ]; for expected in [ - (expected_transactions[0], address!("0x8C1aB379E7263d37049505626D2F975288F5dF12")), - (expected_transactions[1], address!("0xdf918d9D02d5C7Df6825a7046dBF3D10F705Aa76")), - (expected_transactions[2], address!("0x5Be88952ce249024613e0961eB437f5E9424A90c")), + (expected_transactions[0], address!("0x0a02a416f87a13626dda0ad386859497565222aa")), + (expected_transactions[1], address!("0x0a02a416f87a13626dda0ad386859497565222aa")), + (expected_transactions[2], address!("0x4f07d669d76ed9a17799fc4c04c4005196240940")), ] { let tx = api.backend.mined_transaction_by_hash(expected.0).unwrap(); assert_eq!(tx.inner.inner.signer(), expected.1); From 97724afac2dc61ed8eace9e9c114f2fc80cc0264 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 09:03:22 +0000 Subject: [PATCH 058/244] chore(deps): weekly `cargo update` (#10433) * chore(deps): weekly `cargo update` Locking 27 packages to latest compatible versions Updating addr2line v0.21.0 -> v0.24.2 Removing adler v1.0.2 Unchanged alloy-chains v0.1.69 (available: v0.2.0) Unchanged alloy-consensus v0.12.6 (available: v0.15.8) Unchanged alloy-contract v0.12.6 (available: v0.15.8) Unchanged alloy-dyn-abi v0.8.25 (available: v1.1.0) Unchanged alloy-eips v0.12.6 (available: v0.15.8) Unchanged alloy-genesis v0.12.6 (available: v0.15.8) Unchanged alloy-json-abi v0.8.25 (available: v1.1.0) Unchanged alloy-json-rpc v0.12.6 (available: v0.15.8) Unchanged alloy-network v0.12.6 (available: v0.15.8) Unchanged alloy-primitives v0.8.25 (available: v1.1.0) Unchanged alloy-provider v0.12.6 (available: v0.15.8) Unchanged alloy-pubsub v0.12.6 (available: v0.15.8) Unchanged alloy-rpc-client v0.12.6 (available: v0.15.8) Unchanged alloy-rpc-types v0.12.6 (available: v0.15.8) Unchanged alloy-serde v0.12.6 (available: v0.15.8) Unchanged alloy-signer v0.12.6 (available: v0.15.8) Unchanged alloy-signer-aws v0.12.6 (available: v0.15.8) Unchanged alloy-signer-gcp v0.12.6 (available: v0.15.8) Unchanged alloy-signer-ledger v0.12.6 (available: v0.15.8) Unchanged alloy-signer-local v0.12.6 (available: v0.15.8) Unchanged alloy-signer-trezor v0.12.6 (available: v0.15.8) Unchanged alloy-sol-macro-expander v0.8.25 (available: v1.1.0) Unchanged alloy-sol-macro-input v0.8.25 (available: v1.1.0) Unchanged alloy-sol-types v0.8.25 (available: v1.1.0) Unchanged alloy-transport v0.12.6 (available: v0.15.8) Unchanged alloy-transport-http v0.12.6 (available: v0.15.8) Unchanged alloy-transport-ipc v0.12.6 (available: v0.15.8) Unchanged alloy-transport-ws v0.12.6 (available: v0.15.8) Unchanged alloy-trie v0.7.9 (available: v0.8.1) Unchanged axum v0.7.9 (available: v0.8.4) Updating backtrace v0.3.71 -> v0.3.74 Updating bytemuck v1.22.0 -> v1.23.0 Updating cc v1.2.20 -> v1.2.21 Updating chrono v0.4.40 -> v0.4.41 Updating clap_complete v4.5.47 -> v4.5.48 Updating color-eyre v0.6.3 -> v0.6.4 Updating color-spantrace v0.2.1 -> v0.2.2 Unchanged crossterm v0.28.1 (available: v0.29.0) Unchanged gcloud-sdk v0.26.4 (available: v0.27.0) Updating gimli v0.28.1 -> v0.31.1 Updating hashbrown v0.15.2 -> v0.15.3 Unchanged idna_adapter v1.1.0 (available: v1.2.0) Updating jiff v0.2.10 -> v0.2.12 Updating jiff-static v0.2.10 -> v0.2.12 Updating miette v7.5.0 -> v7.6.0 Updating miette-derive v7.5.0 -> v7.6.0 Removing miniz_oxide v0.7.4 Updating object v0.32.2 -> v0.36.7 Unchanged op-alloy-consensus v0.11.4 (available: v0.15.2) Unchanged op-alloy-rpc-types v0.11.4 (available: v0.15.2) Updating owo-colors v3.5.0 -> v4.2.0 Unchanged protobuf v3.3.0 (available: v3.7.2) Unchanged protobuf-support v3.3.0 (available: v3.7.2) Updating quick-xml v0.37.4 -> v0.37.5 Updating quinn-udp v0.5.11 -> v0.5.12 Unchanged rand v0.8.5 (available: v0.9.1) Updating redox_syscall v0.5.11 -> v0.5.12 Unchanged revm v19.7.0 (available: v22.0.1) Unchanged revm-inspectors v0.16.0 (available: v0.20.1) Unchanged revm-primitives v15.2.0 (available: v18.0.0) Updating rustix v1.0.5 -> v1.0.7 Updating sha2 v0.10.8 -> v0.10.9 Unchanged solang-parser v0.3.3 (available: v0.3.4) Updating toml v0.8.21 -> v0.8.22 Updating toml_edit v0.22.25 -> v0.22.26 Updating toml_write v0.1.0 -> v0.1.1 Unchanged vergen v8.3.2 (available: v9.0.6) Updating web_atoms v0.1.0 -> v0.1.1 Updating webpki-roots v0.26.8 -> v0.26.10 Updating winnow v0.7.7 -> v0.7.9 note: to see how you depend on a package, run `cargo tree --invert --package @` * Allow CDLA-Permissive-2.0 --------- Co-authored-by: mattsse <19890894+mattsse@users.noreply.github.com> Co-authored-by: grandizzy --- Cargo.lock | 174 ++++++++++++++++++++++++----------------------------- deny.toml | 1 + 2 files changed, 80 insertions(+), 95 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9fec46ff7e011..97154acb8607a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,19 +4,13 @@ version = 4 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -151,7 +145,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "winnow 0.7.7", + "winnow 0.7.9", ] [[package]] @@ -309,7 +303,7 @@ dependencies = [ "derive_more 2.0.1", "foldhash", "getrandom 0.2.16", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "indexmap 2.9.0", "itoa", "k256", @@ -728,7 +722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d162f8524adfdfb0e4bd0505c734c985f3e2474eb022af32eef0d52a4f3935c" dependencies = [ "serde", - "winnow 0.7.7", + "winnow 0.7.9", ] [[package]] @@ -1784,17 +1778,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -2012,9 +2006,9 @@ checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] name = "bytemuck" -version = "1.22.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" [[package]] name = "byteorder" @@ -2147,9 +2141,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.20" +version = "1.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" +checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" dependencies = [ "jobserver", "libc", @@ -2214,9 +2208,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -2310,9 +2304,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.47" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06f5378ea264ad4f82bbc826628b5aad714a75abf6ece087e923010eb937fb6" +checksum = "be8c97f3a6f02b9e24cadc12aaba75201d18754b53ea0a9d99642f806ccdb4c9" dependencies = [ "clap", ] @@ -2466,9 +2460,9 @@ dependencies = [ [[package]] name = "color-eyre" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" +checksum = "e6e1761c0e16f8883bbbb8ce5990867f4f06bf11a0253da6495a04ce4b6ef0ec" dependencies = [ "backtrace", "color-spantrace", @@ -2481,9 +2475,9 @@ dependencies = [ [[package]] name = "color-spantrace" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5" dependencies = [ "once_cell", "owo-colors", @@ -3366,7 +3360,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" dependencies = [ "cfg-if", - "rustix 1.0.5", + "rustix 1.0.7", "windows-sys 0.59.0", ] @@ -3401,7 +3395,7 @@ dependencies = [ "pear", "serde", "tempfile", - "toml 0.8.21", + "toml 0.8.22", "uncased", "version_check", ] @@ -3443,7 +3437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", - "miniz_oxide 0.8.8", + "miniz_oxide", ] [[package]] @@ -3529,7 +3523,7 @@ dependencies = [ "thiserror 2.0.12", "tikv-jemallocator", "tokio", - "toml 0.8.21", + "toml 0.8.22", "toml_edit", "tower-http", "tracing", @@ -3558,7 +3552,7 @@ dependencies = [ "serde_json", "solang-parser", "thiserror 2.0.12", - "toml 0.8.21", + "toml 0.8.22", "tracing", ] @@ -3573,7 +3567,7 @@ dependencies = [ "similar-asserts", "solang-parser", "thiserror 2.0.12", - "toml 0.8.21", + "toml 0.8.22", "tracing", "tracing-subscriber", ] @@ -3756,7 +3750,7 @@ dependencies = [ "serde", "serde_json", "thiserror 2.0.12", - "toml 0.8.21", + "toml 0.8.22", "tracing", "walkdir", ] @@ -3922,7 +3916,7 @@ dependencies = [ "thiserror 2.0.12", "tokio", "tracing", - "winnow 0.7.7", + "winnow 0.7.9", "yansi", ] @@ -4027,7 +4021,7 @@ dependencies = [ "soldeer-core", "tempfile", "thiserror 2.0.12", - "toml 0.8.21", + "toml 0.8.22", "toml_edit", "tracing", "walkdir", @@ -4301,7 +4295,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8640e34b88f7652208ce9e88b1a37a2ae95227d84abec377ccd3c5cfeb141ed4" dependencies = [ - "rustix 1.0.5", + "rustix 1.0.7", "windows-sys 0.59.0", ] @@ -4512,9 +4506,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "gix-actor" @@ -4856,9 +4850,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ "allocator-api2", "equivalent", @@ -5238,7 +5232,7 @@ checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "arbitrary", "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "serde", ] @@ -5272,7 +5266,7 @@ dependencies = [ "log", "num-format", "once_cell", - "quick-xml 0.37.4", + "quick-xml 0.37.5", "rgb", "str_stack", ] @@ -5416,9 +5410,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a064218214dc6a10fbae5ec5fa888d80c45d611aba169222fc272072bf7aef6" +checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -5431,9 +5425,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "199b7932d97e325aff3a7030e141eafe7f2c6268e1d1b24859b753a627f45254" +checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300" dependencies = [ "proc-macro2", "quote", @@ -5715,7 +5709,7 @@ version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.15.3", ] [[package]] @@ -5724,7 +5718,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.15.3", ] [[package]] @@ -5860,21 +5854,20 @@ dependencies = [ [[package]] name = "miette" -version = "7.5.0" +version = "7.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a955165f87b37fd1862df2a59547ac542c77ef6d17c666f619d1ad22dd89484" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" dependencies = [ "cfg-if", "miette-derive", - "thiserror 1.0.69", "unicode-width 0.1.14", ] [[package]] name = "miette-derive" -version = "7.5.0" +version = "7.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf45bf44ab49be92fd1227a3be6fc6f617f1a337c06af54981048574d8783147" +checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" dependencies = [ "proc-macro2", "quote", @@ -5903,15 +5896,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.8" @@ -6239,9 +6223,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -6259,7 +6243,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bd2cae3bec3936bbed1ccc5a3343b3738858182419f9c0522c7260c80c430b0" dependencies = [ "ahash", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "parking_lot", "stable_deref_trait", ] @@ -6336,9 +6320,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "owo-colors" -version = "3.5.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564" [[package]] name = "p256" @@ -6969,7 +6953,7 @@ dependencies = [ "chrono", "indexmap 2.9.0", "newtype-uuid", - "quick-xml 0.37.4", + "quick-xml 0.37.5", "strip-ansi-escapes", "thiserror 2.0.12", "uuid 1.16.0", @@ -6986,9 +6970,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.37.4" +version = "0.37.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ce8c88de324ff838700f36fb6ab86c96df0e3c4ab6ef3a9b2044465cce1369" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" dependencies = [ "memchr", ] @@ -7035,9 +7019,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5" +checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" dependencies = [ "cfg_aliases", "libc", @@ -7196,9 +7180,9 @@ checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ "bitflags 2.9.0", ] @@ -7589,9 +7573,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ "bitflags 2.9.0", "errno", @@ -8060,9 +8044,9 @@ checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -8779,7 +8763,7 @@ dependencies = [ "fastrand", "getrandom 0.3.2", "once_cell", - "rustix 1.0.5", + "rustix 1.0.7", "windows-sys 0.59.0", ] @@ -8811,7 +8795,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" dependencies = [ - "rustix 1.0.5", + "rustix 1.0.7", "windows-sys 0.59.0", ] @@ -9095,9 +9079,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900f6c86a685850b1bc9f6223b20125115ee3f31e01207d81655bbcc0aea9231" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "indexmap 2.9.0", "serde", @@ -9117,23 +9101,23 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.25" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10558ed0bd2a1562e630926a2d1f0b98c827da99fabd3fe20920a59642504485" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap 2.9.0", "serde", "serde_spanned", "toml_datetime", "toml_write", - "winnow 0.7.7", + "winnow 0.7.9", ] [[package]] name = "toml_write" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28391a4201ba7eb1984cfeb6862c0b3ea2cfe23332298967c749dddc0d6cd976" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" [[package]] name = "tonic" @@ -9937,9 +9921,9 @@ dependencies = [ [[package]] name = "web_atoms" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "954c5a41f2bcb7314344079d0891505458cc2f4b422bdea1d5bfbe6d1a04903b" +checksum = "08bcbdcad8fb2e316072ba6bbe09419afdb550285668ac2534f4230a6f2da0ee" dependencies = [ "phf", "phf_codegen", @@ -9949,9 +9933,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.8" +version = "0.26.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" +checksum = "37493cadf42a2a939ed404698ded7fb378bf301b5011f973361779a3a74f8c93" dependencies = [ "rustls-pki-types", ] @@ -9976,7 +9960,7 @@ checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" dependencies = [ "either", "env_home", - "rustix 1.0.5", + "rustix 1.0.7", "winsafe", ] @@ -10351,9 +10335,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.7" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" +checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" dependencies = [ "memchr", ] diff --git a/deny.toml b/deny.toml index 5cc729a2c121e..16d88e50ba78f 100644 --- a/deny.toml +++ b/deny.toml @@ -55,6 +55,7 @@ allow = [ "CDDL-1.0", "Zlib", "OpenSSL", + "CDLA-Permissive-2.0", ] # Allow 1 or more licenses on a per-crate basis, so that particular licenses From a34f4c989b94f572497631ff5c85909d674c23a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?katsumata=EF=BC=88TK=EF=BC=89?= <12413150+winor30@users.noreply.github.com> Date: Tue, 6 May 2025 22:44:26 +0900 Subject: [PATCH 059/244] fix(forge): remove `strategy` section from workflow template to simplify (#10434) Simplify workflow configuration for Foundry project - Refactor the Foundry project workflow for improved clarity and efficiency. - Remove the `fail-fast` option to ensure all checks run regardless of failures. - Streamline job configurations for better maintainability and readability. Signed-off-by: katsumata <12413150+winor30@users.noreply.github.com> --- crates/forge/assets/workflowTemplate.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/crates/forge/assets/workflowTemplate.yml b/crates/forge/assets/workflowTemplate.yml index 34a4a527be6f9..4481ec6a8b2de 100644 --- a/crates/forge/assets/workflowTemplate.yml +++ b/crates/forge/assets/workflowTemplate.yml @@ -10,9 +10,6 @@ env: jobs: check: - strategy: - fail-fast: true - name: Foundry project runs-on: ubuntu-latest steps: From c2c4b773826ea57ded74a63f1b4addd1afac5aa5 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Wed, 7 May 2025 15:57:46 +0200 Subject: [PATCH 060/244] core: sprinkle some traces (#10456) --- crates/anvil/src/config.rs | 4 +++- crates/anvil/src/eth/backend/mem/mod.rs | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/anvil/src/config.rs b/crates/anvil/src/config.rs index 43ae552adaf3f..f9606eeeb08fd 100644 --- a/crates/anvil/src/config.rs +++ b/crates/anvil/src/config.rs @@ -1149,7 +1149,7 @@ impl NodeConfig { env: &mut EnvWithHandlerCfg, fees: &FeeManager, ) -> Result<(ForkedDatabase, ClientForkConfig)> { - // TODO make provider agnostic + debug!(target: "node", ?eth_rpc_url, "setting up fork db"); let provider = Arc::new( ProviderBuilder::new(ð_rpc_url) .timeout(self.fork_request_timeout) @@ -1328,6 +1328,8 @@ latest block number: {latest_block}" force_transactions, }; + debug!(target: "node", fork_number=config.block_number, fork_hash=%config.block_hash, "set up fork db"); + let mut db = ForkedDatabase::new(backend, block_chain_db); // need to insert the forked block's hash diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 2f295ed3311b9..2f5aa321080bc 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -449,6 +449,9 @@ impl Backend { let db = self.db.write().await; // apply the genesis.json alloc self.genesis.apply_genesis_json_alloc(db)?; + + trace!(target: "backend", "set genesis balances"); + Ok(()) } @@ -599,6 +602,8 @@ impl Backend { self.apply_genesis().await?; + trace!(target: "backend", "reset fork"); + Ok(()) } else { Err(RpcError::invalid_params("Forking not enabled").into()) From 0f8746073a26301da8622bb9ed2542642b1c79ca Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Thu, 8 May 2025 09:28:48 +0300 Subject: [PATCH 061/244] feat: Etherscan V2 support (#10440) * Adding support to etherscanv2 * clippy+fmt * Adding default for v2 and updating configuration to parse etherscan api version from config * Updating api_version to use new variable and fix merge * Use block explorer rev, fix fmt * fix api version parsing * fix fmt * Simplify Etherscan provider option, default v2 * Use released version * Updates, fix script --verify * Clone api version, cast * Cast fixes * Tests nits * configs for verify check * Simplify, use EtherscanApiVersion enum --------- Co-authored-by: Iain Nash --- Cargo.lock | 6 +- Cargo.toml | 2 +- crates/anvil/tests/it/fork.rs | 1 + crates/cast/src/cmd/artifact.rs | 10 +- crates/cast/src/cmd/constructor_args.rs | 7 +- crates/cast/src/cmd/creation_code.rs | 13 +- crates/cast/src/cmd/interface.rs | 3 +- crates/cast/src/cmd/run.rs | 4 + crates/cast/src/cmd/storage.rs | 3 +- crates/cast/src/tx.rs | 7 + crates/cast/tests/cli/main.rs | 26 ++-- crates/cli/Cargo.toml | 1 + crates/cli/src/opts/rpc.rs | 16 +++ crates/cli/src/utils/abi.rs | 4 +- crates/common/src/abi.rs | 7 +- crates/config/src/etherscan.rs | 112 ++++++++++----- crates/config/src/lib.rs | 99 ++++++++++++-- crates/forge/src/cmd/clone.rs | 8 +- crates/forge/src/cmd/create.rs | 7 +- crates/forge/src/cmd/test/mod.rs | 9 ++ crates/forge/tests/cli/cmd.rs | 12 +- crates/forge/tests/cli/config.rs | 2 + crates/forge/tests/cli/verify_bytecode.rs | 8 +- crates/script/Cargo.toml | 1 + crates/script/src/lib.rs | 8 ++ crates/test-utils/src/rpc.rs | 62 +++++---- crates/verify/src/bytecode.rs | 13 +- crates/verify/src/etherscan/mod.rs | 159 ++++++++++++++-------- crates/verify/src/verify.rs | 25 +++- 29 files changed, 449 insertions(+), 186 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 97154acb8607a..c52b0803a0009 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3593,6 +3593,7 @@ dependencies = [ "eyre", "forge-script-sequence", "forge-verify", + "foundry-block-explorers", "foundry-cheatcodes", "foundry-cli", "foundry-common", @@ -3691,9 +3692,9 @@ dependencies = [ [[package]] name = "foundry-block-explorers" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "001678abc9895502532c8c4a1a225079c580655fc82a194e78b06dcf99f49b8c" +checksum = "8025385c52416bf14e5bb28d21eb5efe2490dd6fb001a49b87f1825a626b4909" dependencies = [ "alloy-chains", "alloy-json-abi", @@ -3782,6 +3783,7 @@ dependencies = [ "dotenvy", "eyre", "forge-fmt", + "foundry-block-explorers", "foundry-common", "foundry-compilers", "foundry-config", diff --git a/Cargo.toml b/Cargo.toml index 2d8aeadaa72f2..e76ac670d7cf7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -188,7 +188,7 @@ foundry-wallets = { path = "crates/wallets" } foundry-linking = { path = "crates/linking" } # solc & compilation utilities -foundry-block-explorers = { version = "0.13.0", default-features = false } +foundry-block-explorers = { version = "0.13.3", default-features = false } foundry-compilers = { version = "0.14.0", default-features = false } foundry-fork-db = "0.12" solang-parser = "=0.3.3" diff --git a/crates/anvil/tests/it/fork.rs b/crates/anvil/tests/it/fork.rs index 422bd2514cf6d..cda5fc805cf8c 100644 --- a/crates/anvil/tests/it/fork.rs +++ b/crates/anvil/tests/it/fork.rs @@ -1324,6 +1324,7 @@ async fn test_fork_execution_reverted() { // #[tokio::test(flavor = "multi_thread")] +#[ignore] async fn test_immutable_fork_transaction_hash() { use std::str::FromStr; diff --git a/crates/cast/src/cmd/artifact.rs b/crates/cast/src/cmd/artifact.rs index dc83cb2aea211..79ec880d34cfd 100644 --- a/crates/cast/src/cmd/artifact.rs +++ b/crates/cast/src/cmd/artifact.rs @@ -1,12 +1,11 @@ use super::{ - creation_code::{fetch_creation_code, parse_code_output}, + creation_code::{fetch_creation_code_from_etherscan, parse_code_output}, interface::{fetch_abi_from_etherscan, load_abi_from_file}, }; use alloy_primitives::Address; use alloy_provider::Provider; use clap::{command, Parser}; use eyre::Result; -use foundry_block_explorers::Client; use foundry_cli::{ opts::{EtherscanOpts, RpcOpts}, utils::{self, LoadConfig}, @@ -46,15 +45,12 @@ pub struct ArtifactArgs { impl ArtifactArgs { pub async fn run(self) -> Result<()> { - let Self { contract, etherscan, rpc, output: output_location, abi_path } = self; + let Self { contract, mut etherscan, rpc, output: output_location, abi_path } = self; - let mut etherscan = etherscan; let config = rpc.load_config()?; let provider = utils::get_provider(&config)?; - let api_key = etherscan.key().unwrap_or_default(); let chain = provider.get_chain_id().await?; etherscan.chain = Some(chain.into()); - let client = Client::new(chain.into(), api_key)?; let abi = if let Some(ref abi_path) = abi_path { load_abi_from_file(abi_path, None)? @@ -64,7 +60,7 @@ impl ArtifactArgs { let (abi, _) = abi.first().ok_or_else(|| eyre::eyre!("No ABI found"))?; - let bytecode = fetch_creation_code(contract, client, provider).await?; + let bytecode = fetch_creation_code_from_etherscan(contract, ðerscan, provider).await?; let bytecode = parse_code_output(bytecode, contract, ðerscan, abi_path.as_deref(), true, false) .await?; diff --git a/crates/cast/src/cmd/constructor_args.rs b/crates/cast/src/cmd/constructor_args.rs index 2775e2e99ecfd..3d60673857f37 100644 --- a/crates/cast/src/cmd/constructor_args.rs +++ b/crates/cast/src/cmd/constructor_args.rs @@ -1,5 +1,5 @@ use super::{ - creation_code::fetch_creation_code, + creation_code::fetch_creation_code_from_etherscan, interface::{fetch_abi_from_etherscan, load_abi_from_file}, }; use alloy_dyn_abi::DynSolType; @@ -7,7 +7,6 @@ use alloy_primitives::{Address, Bytes}; use alloy_provider::Provider; use clap::{command, Parser}; use eyre::{eyre, OptionExt, Result}; -use foundry_block_explorers::Client; use foundry_cli::{ opts::{EtherscanOpts, RpcOpts}, utils::{self, LoadConfig}, @@ -37,12 +36,10 @@ impl ConstructorArgsArgs { let config = rpc.load_config()?; let provider = utils::get_provider(&config)?; - let api_key = etherscan.key().unwrap_or_default(); let chain = provider.get_chain_id().await?; etherscan.chain = Some(chain.into()); - let client = Client::new(chain.into(), api_key)?; - let bytecode = fetch_creation_code(contract, client, provider).await?; + let bytecode = fetch_creation_code_from_etherscan(contract, ðerscan, provider).await?; let args_arr = parse_constructor_args(bytecode, contract, ðerscan, abi_path).await?; for arg in args_arr { diff --git a/crates/cast/src/cmd/creation_code.rs b/crates/cast/src/cmd/creation_code.rs index 9967f38fde9bb..db47b1bdec523 100644 --- a/crates/cast/src/cmd/creation_code.rs +++ b/crates/cast/src/cmd/creation_code.rs @@ -50,12 +50,10 @@ impl CreationCodeArgs { let config = rpc.load_config()?; let provider = utils::get_provider(&config)?; - let api_key = etherscan.key().unwrap_or_default(); let chain = provider.get_chain_id().await?; etherscan.chain = Some(chain.into()); - let client = Client::new(chain.into(), api_key)?; - let bytecode = fetch_creation_code(contract, client, provider).await?; + let bytecode = fetch_creation_code_from_etherscan(contract, ðerscan, provider).await?; let bytecode = parse_code_output( bytecode, @@ -131,11 +129,16 @@ pub async fn parse_code_output( } /// Fetches the creation code of a contract from Etherscan and RPC. -pub async fn fetch_creation_code( +pub async fn fetch_creation_code_from_etherscan( contract: Address, - client: Client, + etherscan: &EtherscanOpts, provider: RetryProvider, ) -> Result { + let config = etherscan.load_config()?; + let chain = config.chain.unwrap_or_default(); + let api_version = config.get_etherscan_api_version(Some(chain)); + let api_key = config.get_etherscan_api_key(Some(chain)).unwrap_or_default(); + let client = Client::new_with_api_version(chain, api_key, api_version)?; let creation_data = client.contract_creation_data(contract).await?; let creation_tx_hash = creation_data.transaction_hash; let tx_data = provider.get_transaction_by_hash(creation_tx_hash).await?; diff --git a/crates/cast/src/cmd/interface.rs b/crates/cast/src/cmd/interface.rs index f37f92864e534..992f5b833eac3 100644 --- a/crates/cast/src/cmd/interface.rs +++ b/crates/cast/src/cmd/interface.rs @@ -143,8 +143,9 @@ pub async fn fetch_abi_from_etherscan( ) -> Result> { let config = etherscan.load_config()?; let chain = config.chain.unwrap_or_default(); + let api_version = config.get_etherscan_api_version(Some(chain)); let api_key = config.get_etherscan_api_key(Some(chain)).unwrap_or_default(); - let client = Client::new(chain, api_key)?; + let client = Client::new_with_api_version(chain, api_key, api_version)?; let source = client.contract_source_code(address).await?; source.items.into_iter().map(|item| Ok((item.abi()?, item.contract_name))).collect() } diff --git a/crates/cast/src/cmd/run.rs b/crates/cast/src/cmd/run.rs index 947704a2df5a1..90470ef31ed97 100644 --- a/crates/cast/src/cmd/run.rs +++ b/crates/cast/src/cmd/run.rs @@ -299,6 +299,10 @@ impl figment::Provider for RunArgs { map.insert("etherscan_api_key".into(), api_key.as_str().into()); } + if let Some(api_version) = &self.etherscan.api_version { + map.insert("etherscan_api_version".into(), api_version.to_string().into()); + } + if let Some(evm_version) = self.evm_version { map.insert("evm_version".into(), figment::value::Value::serialize(evm_version)?); } diff --git a/crates/cast/src/cmd/storage.rs b/crates/cast/src/cmd/storage.rs index 7f75b61fb146f..b477ebf2b2637 100644 --- a/crates/cast/src/cmd/storage.rs +++ b/crates/cast/src/cmd/storage.rs @@ -135,8 +135,9 @@ impl StorageArgs { } let chain = utils::get_chain(config.chain, &provider).await?; + let api_version = config.get_etherscan_api_version(Some(chain)); let api_key = config.get_etherscan_api_key(Some(chain)).unwrap_or_default(); - let client = Client::new(chain, api_key)?; + let client = Client::new_with_api_version(chain, api_key, api_version)?; let source = if let Some(proxy) = self.proxy { find_source(client, proxy.resolve(&provider).await?).await? } else { diff --git a/crates/cast/src/tx.rs b/crates/cast/src/tx.rs index 1097da794e15f..36b14807b98cd 100644 --- a/crates/cast/src/tx.rs +++ b/crates/cast/src/tx.rs @@ -13,6 +13,7 @@ use alloy_serde::WithOtherFields; use alloy_signer::Signer; use alloy_transport::TransportError; use eyre::Result; +use foundry_block_explorers::EtherscanApiVersion; use foundry_cli::{ opts::{CliAuthorizationList, TransactionOpts}, utils::{self, parse_function_args}, @@ -141,6 +142,7 @@ pub struct CastTxBuilder { auth: Option, chain: Chain, etherscan_api_key: Option, + etherscan_api_version: EtherscanApiVersion, access_list: Option>, state: S, } @@ -152,6 +154,7 @@ impl> CastTxBuilder { let mut tx = WithOtherFields::::default(); let chain = utils::get_chain(config.chain, &provider).await?; + let etherscan_api_version = config.get_etherscan_api_version(Some(chain)); let etherscan_api_key = config.get_etherscan_api_key(Some(chain)); let legacy = tx_opts.legacy || chain.is_legacy(); @@ -192,6 +195,7 @@ impl> CastTxBuilder { blob: tx_opts.blob, chain, etherscan_api_key, + etherscan_api_version, auth: tx_opts.auth, access_list: tx_opts.access_list, state: InitState, @@ -208,6 +212,7 @@ impl> CastTxBuilder { blob: self.blob, chain: self.chain, etherscan_api_key: self.etherscan_api_key, + etherscan_api_version: self.etherscan_api_version, auth: self.auth, access_list: self.access_list, state: ToState { to }, @@ -233,6 +238,7 @@ impl> CastTxBuilder { self.chain, &self.provider, self.etherscan_api_key.as_deref(), + self.etherscan_api_version, ) .await? } else { @@ -264,6 +270,7 @@ impl> CastTxBuilder { blob: self.blob, chain: self.chain, etherscan_api_key: self.etherscan_api_key, + etherscan_api_version: self.etherscan_api_version, auth: self.auth, access_list: self.access_list, state: InputState { kind: self.state.to.into(), input, func }, diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index be2e9a7ed7101..a661c432df1c5 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -9,7 +9,7 @@ use anvil::{EthereumHardfork, NodeConfig}; use foundry_test_utils::{ rpc::{ next_etherscan_api_key, next_http_archive_rpc_url, next_http_rpc_endpoint, - next_mainnet_etherscan_api_key, next_rpc_endpoint, next_ws_rpc_endpoint, + next_rpc_endpoint, next_ws_rpc_endpoint, }, str, util::OutputExt, @@ -1378,7 +1378,7 @@ casttest!(storage_layout_simple, |_prj, cmd| { "--block", "21034138", "--etherscan-api-key", - next_mainnet_etherscan_api_key().as_str(), + next_etherscan_api_key().as_str(), "0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2", ]) .assert_success() @@ -1405,7 +1405,7 @@ casttest!(storage_layout_simple_json, |_prj, cmd| { "--block", "21034138", "--etherscan-api-key", - next_mainnet_etherscan_api_key().as_str(), + next_etherscan_api_key().as_str(), "0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2", "--json", ]) @@ -1422,7 +1422,7 @@ casttest!(storage_layout_complex, |_prj, cmd| { "--block", "21034138", "--etherscan-api-key", - next_mainnet_etherscan_api_key().as_str(), + next_etherscan_api_key().as_str(), "0xBA12222222228d8Ba445958a75a0704d566BF2C8", ]) .assert_success() @@ -1470,7 +1470,7 @@ casttest!(storage_layout_complex_proxy, |_prj, cmd| { "--block", "7857852", "--etherscan-api-key", - next_mainnet_etherscan_api_key().as_str(), + next_etherscan_api_key().as_str(), "0xE2588A9CAb7Ea877206E35f615a39f84a64A7A3b", "--proxy", "0x29fcb43b46531bca003ddc8fcb67ffe91900c762" @@ -1512,7 +1512,7 @@ casttest!(storage_layout_complex_json, |_prj, cmd| { "--block", "21034138", "--etherscan-api-key", - next_mainnet_etherscan_api_key().as_str(), + next_etherscan_api_key().as_str(), "0xBA12222222228d8Ba445958a75a0704d566BF2C8", "--json", ]) @@ -1601,7 +1601,7 @@ casttest!(fetch_weth_interface_from_etherscan, |_prj, cmd| { cmd.args([ "interface", "--etherscan-api-key", - &next_mainnet_etherscan_api_key(), + &next_etherscan_api_key(), "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", ]) .assert_success() @@ -1880,7 +1880,7 @@ casttest!(fetch_creation_code_from_etherscan, |_prj, cmd| { cmd.args([ "creation-code", "--etherscan-api-key", - &next_mainnet_etherscan_api_key(), + &next_etherscan_api_key(), "0x0923cad07f06b2d0e5e49e63b8b35738d4156b95", "--rpc-url", eth_rpc_url.as_str(), @@ -1899,7 +1899,7 @@ casttest!(fetch_creation_code_only_args_from_etherscan, |_prj, cmd| { cmd.args([ "creation-code", "--etherscan-api-key", - &next_mainnet_etherscan_api_key(), + &next_etherscan_api_key(), "0x6982508145454ce325ddbe47a25d4ec3d2311933", "--rpc-url", eth_rpc_url.as_str(), @@ -1919,7 +1919,7 @@ casttest!(fetch_constructor_args_from_etherscan, |_prj, cmd| { cmd.args([ "constructor-args", "--etherscan-api-key", - &next_mainnet_etherscan_api_key(), + &next_etherscan_api_key(), "0x6982508145454ce325ddbe47a25d4ec3d2311933", "--rpc-url", eth_rpc_url.as_str(), @@ -1940,7 +1940,7 @@ casttest!(test_non_mainnet_traces, |prj, cmd| { "--rpc-url", next_rpc_endpoint(NamedChain::Optimism).as_str(), "--etherscan-api-key", - next_etherscan_api_key(NamedChain::Optimism).as_str(), + next_etherscan_api_key().as_str(), ]) .assert_success() .stdout_eq(str![[r#" @@ -1963,7 +1963,7 @@ casttest!(fetch_artifact_from_etherscan, |_prj, cmd| { cmd.args([ "artifact", "--etherscan-api-key", - &next_mainnet_etherscan_api_key(), + &next_etherscan_api_key(), "0x0923cad07f06b2d0e5e49e63b8b35738d4156b95", "--rpc-url", eth_rpc_url.as_str(), @@ -2444,7 +2444,7 @@ contract WETH9 { casttest!(fetch_src_default, |_prj, cmd| { let weth = address!("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"); - let etherscan_api_key = next_mainnet_etherscan_api_key(); + let etherscan_api_key = next_etherscan_api_key(); cmd.args(["source", &weth.to_string(), "--flatten", "--etherscan-api-key", ðerscan_api_key]) .assert_success() diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index a3a510f03cb1a..b9dfd5f83d67f 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -21,6 +21,7 @@ foundry-evm.workspace = true foundry-wallets.workspace = true foundry-compilers = { workspace = true, features = ["full"] } +foundry-block-explorers.workspace = true alloy-eips.workspace = true alloy-dyn-abi.workspace = true diff --git a/crates/cli/src/opts/rpc.rs b/crates/cli/src/opts/rpc.rs index 344efe73e8514..2b508720a81a1 100644 --- a/crates/cli/src/opts/rpc.rs +++ b/crates/cli/src/opts/rpc.rs @@ -2,6 +2,7 @@ use crate::opts::ChainValueParser; use alloy_chains::ChainKind; use clap::Parser; use eyre::Result; +use foundry_block_explorers::EtherscanApiVersion; use foundry_config::{ figment::{ self, @@ -114,6 +115,16 @@ pub struct EtherscanOpts { #[serde(rename = "etherscan_api_key", skip_serializing_if = "Option::is_none")] pub key: Option, + /// The Etherscan API version. + #[arg( + short, + long = "etherscan-api-version", + alias = "api-version", + env = "ETHERSCAN_API_VERSION" + )] + #[serde(rename = "etherscan_api_version", skip_serializing_if = "Option::is_none")] + pub api_version: Option, + /// The chain name or EIP-155 chain ID. #[arg( short, @@ -154,6 +165,11 @@ impl EtherscanOpts { if let Some(key) = self.key() { dict.insert("etherscan_api_key".into(), key.into()); } + + if let Some(api_version) = &self.api_version { + dict.insert("etherscan_api_version".into(), api_version.to_string().into()); + } + if let Some(chain) = self.chain { if let ChainKind::Id(id) = chain.kind() { dict.insert("chain_id".into(), (*id).into()); diff --git a/crates/cli/src/utils/abi.rs b/crates/cli/src/utils/abi.rs index c7f4d260416d7..c037fd1e17961 100644 --- a/crates/cli/src/utils/abi.rs +++ b/crates/cli/src/utils/abi.rs @@ -3,6 +3,7 @@ use alloy_json_abi::Function; use alloy_primitives::{hex, Address}; use alloy_provider::{network::AnyNetwork, Provider}; use eyre::{OptionExt, Result}; +use foundry_block_explorers::EtherscanApiVersion; use foundry_common::{ abi::{encode_function_args, get_func, get_func_etherscan}, ens::NameOrAddress, @@ -31,6 +32,7 @@ pub async fn parse_function_args>( chain: Chain, provider: &P, etherscan_api_key: Option<&str>, + etherscan_api_version: EtherscanApiVersion, ) -> Result<(Vec, Option)> { if sig.trim().is_empty() { eyre::bail!("Function signature or calldata must be provided.") @@ -50,7 +52,7 @@ pub async fn parse_function_args>( "If you wish to fetch function data from Etherscan, please provide an Etherscan API key.", )?; let to = to.ok_or_eyre("A 'to' address must be provided to fetch function data.")?; - get_func_etherscan(sig, to, &args, chain, etherscan_api_key).await? + get_func_etherscan(sig, to, &args, chain, etherscan_api_key, etherscan_api_version).await? }; Ok((encode_function_args(&func, &args)?, Some(func))) diff --git a/crates/common/src/abi.rs b/crates/common/src/abi.rs index fa9f241719fdb..28824925cacda 100644 --- a/crates/common/src/abi.rs +++ b/crates/common/src/abi.rs @@ -4,7 +4,9 @@ use alloy_dyn_abi::{DynSolType, DynSolValue, FunctionExt, JsonAbiExt}; use alloy_json_abi::{Error, Event, Function, Param}; use alloy_primitives::{hex, Address, LogData}; use eyre::{Context, ContextCompat, Result}; -use foundry_block_explorers::{contract::ContractMetadata, errors::EtherscanError, Client}; +use foundry_block_explorers::{ + contract::ContractMetadata, errors::EtherscanError, Client, EtherscanApiVersion, +}; use foundry_config::Chain; use std::{future::Future, pin::Pin}; @@ -120,8 +122,9 @@ pub async fn get_func_etherscan( args: &[String], chain: Chain, etherscan_api_key: &str, + etherscan_api_version: EtherscanApiVersion, ) -> Result { - let client = Client::new(chain, etherscan_api_key)?; + let client = Client::new_with_api_version(chain, etherscan_api_key, etherscan_api_version)?; let source = find_source(client, contract).await?; let metadata = source.items.first().wrap_err("etherscan returned empty metadata")?; diff --git a/crates/config/src/etherscan.rs b/crates/config/src/etherscan.rs index 099dc0e344c2f..76d50b09bc934 100644 --- a/crates/config/src/etherscan.rs +++ b/crates/config/src/etherscan.rs @@ -9,6 +9,7 @@ use figment::{ value::{Dict, Map}, Error, Metadata, Profile, Provider, }; +use foundry_block_explorers::EtherscanApiVersion; use heck::ToKebabCase; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::{ @@ -83,13 +84,13 @@ impl EtherscanConfigs { } /// Returns all (alias -> url) pairs - pub fn resolved(self) -> ResolvedEtherscanConfigs { + pub fn resolved(self, default_api_version: EtherscanApiVersion) -> ResolvedEtherscanConfigs { ResolvedEtherscanConfigs { configs: self .configs .into_iter() .map(|(name, e)| { - let resolved = e.resolve(Some(&name)); + let resolved = e.resolve(Some(&name), default_api_version); (name, resolved) }) .collect(), @@ -173,6 +174,9 @@ pub struct EtherscanConfig { /// Etherscan API URL #[serde(default, skip_serializing_if = "Option::is_none")] pub url: Option, + /// Etherscan API Version. Defaults to v2 + #[serde(default, alias = "api-version", skip_serializing_if = "Option::is_none")] + pub api_version: Option, /// The etherscan API KEY that's required to make requests pub key: EtherscanApiKey, } @@ -187,8 +191,11 @@ impl EtherscanConfig { pub fn resolve( self, alias: Option<&str>, + default_api_version: EtherscanApiVersion, ) -> Result { - let Self { chain, mut url, key } = self; + let Self { chain, mut url, key, api_version } = self; + + let api_version = api_version.unwrap_or(default_api_version); if let Some(url) = &mut url { *url = interpolate(url)?; @@ -219,17 +226,23 @@ impl EtherscanConfig { match (chain, url) { (Some(chain), Some(api_url)) => Ok(ResolvedEtherscanConfig { api_url, + api_version, browser_url: chain.etherscan_urls().map(|(_, url)| url.to_string()), key, chain: Some(chain), }), - (Some(chain), None) => ResolvedEtherscanConfig::create(key, chain).ok_or_else(|| { - let msg = alias.map(|a| format!(" `{a}`")).unwrap_or_default(); - EtherscanConfigError::UnknownChain(msg, chain) + (Some(chain), None) => ResolvedEtherscanConfig::create(key, chain, api_version) + .ok_or_else(|| { + let msg = alias.map(|a| format!(" `{a}`")).unwrap_or_default(); + EtherscanConfigError::UnknownChain(msg, chain) + }), + (None, Some(api_url)) => Ok(ResolvedEtherscanConfig { + api_url, + browser_url: None, + key, + chain: None, + api_version, }), - (None, Some(api_url)) => { - Ok(ResolvedEtherscanConfig { api_url, browser_url: None, key, chain: None }) - } (None, None) => { let msg = alias .map(|a| format!(" for Etherscan config with unknown alias `{a}`")) @@ -251,6 +264,9 @@ pub struct ResolvedEtherscanConfig { pub browser_url: Option, /// The resolved API key. pub key: String, + /// Etherscan API Version. + #[serde(default)] + pub api_version: EtherscanApiVersion, /// The chain name or EIP-155 chain ID. #[serde(default, skip_serializing_if = "Option::is_none")] pub chain: Option, @@ -258,11 +274,16 @@ pub struct ResolvedEtherscanConfig { impl ResolvedEtherscanConfig { /// Creates a new instance using the api key and chain - pub fn create(api_key: impl Into, chain: impl Into) -> Option { + pub fn create( + api_key: impl Into, + chain: impl Into, + api_version: EtherscanApiVersion, + ) -> Option { let chain = chain.into(); let (api_url, browser_url) = chain.etherscan_urls()?; Some(Self { api_url: api_url.to_string(), + api_version, browser_url: Some(browser_url.to_string()), key: api_key.into(), chain: Some(chain), @@ -294,13 +315,10 @@ impl ResolvedEtherscanConfig { self, ) -> Result { - let Self { api_url, browser_url, key: api_key, chain } = self; - let (mainnet_api, mainnet_url) = NamedChain::Mainnet.etherscan_urls().expect("exist; qed"); + let Self { api_url, browser_url, key: api_key, chain, api_version } = self; - let cache = chain - // try to match against mainnet, which is usually the most common target - .or_else(|| (api_url == mainnet_api).then(Chain::mainnet)) - .and_then(Config::foundry_etherscan_chain_cache_dir); + let chain = chain.unwrap_or_default(); + let cache = Config::foundry_etherscan_chain_cache_dir(chain); if let Some(cache_path) = &cache { // we also create the `sources` sub dir here @@ -314,15 +332,15 @@ impl ResolvedEtherscanConfig { .user_agent(ETHERSCAN_USER_AGENT) .tls_built_in_root_certs(api_url.scheme() == "https") .build()?; - foundry_block_explorers::Client::builder() + let mut client_builder = foundry_block_explorers::Client::builder() .with_client(client) + .with_api_version(api_version) .with_api_key(api_key) - .with_api_url(api_url)? - // the browser url is not used/required by the client so we can simply set the - // mainnet browser url here - .with_url(browser_url.as_deref().unwrap_or(mainnet_url))? - .with_cache(cache, Duration::from_secs(24 * 60 * 60)) - .build() + .with_cache(cache, Duration::from_secs(24 * 60 * 60)); + if let Some(browser_url) = browser_url { + client_builder = client_builder.with_url(browser_url)?; + } + client_builder.chain(chain)?.build() } } @@ -423,12 +441,36 @@ mod tests { chain: Some(Mainnet.into()), url: None, key: EtherscanApiKey::Key("ABCDEFG".to_string()), + api_version: None, }, ); - let mut resolved = configs.resolved(); + let mut resolved = configs.resolved(EtherscanApiVersion::V2); let config = resolved.remove("mainnet").unwrap().unwrap(); - let _ = config.into_client().unwrap(); + // None version = None + assert_eq!(config.api_version, EtherscanApiVersion::V2); + let client = config.into_client().unwrap(); + assert_eq!(*client.etherscan_api_version(), EtherscanApiVersion::V2); + } + + #[test] + fn can_create_v1_client_via_chain() { + let mut configs = EtherscanConfigs::default(); + configs.insert( + "mainnet".to_string(), + EtherscanConfig { + chain: Some(Mainnet.into()), + url: None, + api_version: Some(EtherscanApiVersion::V1), + key: EtherscanApiKey::Key("ABCDEG".to_string()), + }, + ); + + let mut resolved = configs.resolved(EtherscanApiVersion::V2); + let config = resolved.remove("mainnet").unwrap().unwrap(); + assert_eq!(config.api_version, EtherscanApiVersion::V1); + let client = config.into_client().unwrap(); + assert_eq!(*client.etherscan_api_version(), EtherscanApiVersion::V1); } #[test] @@ -440,10 +482,11 @@ mod tests { chain: Some(Mainnet.into()), url: Some("https://api.etherscan.io/api".to_string()), key: EtherscanApiKey::Key("ABCDEFG".to_string()), + api_version: None, }, ); - let mut resolved = configs.resolved(); + let mut resolved = configs.resolved(EtherscanApiVersion::V2); let config = resolved.remove("mainnet").unwrap().unwrap(); let _ = config.into_client().unwrap(); } @@ -457,20 +500,22 @@ mod tests { EtherscanConfig { chain: Some(Mainnet.into()), url: Some("https://api.etherscan.io/api".to_string()), + api_version: None, key: EtherscanApiKey::Env(format!("${{{env}}}")), }, ); - let mut resolved = configs.clone().resolved(); + let mut resolved = configs.clone().resolved(EtherscanApiVersion::V2); let config = resolved.remove("mainnet").unwrap(); assert!(config.is_err()); std::env::set_var(env, "ABCDEFG"); - let mut resolved = configs.resolved(); + let mut resolved = configs.resolved(EtherscanApiVersion::V2); let config = resolved.remove("mainnet").unwrap().unwrap(); assert_eq!(config.key, "ABCDEFG"); - let _ = config.into_client().unwrap(); + let client = config.into_client().unwrap(); + assert_eq!(*client.etherscan_api_version(), EtherscanApiVersion::V2); std::env::remove_var(env); } @@ -484,10 +529,11 @@ mod tests { chain: None, url: Some("https://api.etherscan.io/api".to_string()), key: EtherscanApiKey::Key("ABCDEFG".to_string()), + api_version: None, }, ); - let mut resolved = configs.clone().resolved(); + let mut resolved = configs.clone().resolved(EtherscanApiVersion::V2); let config = resolved.remove("blast_sepolia").unwrap().unwrap(); assert_eq!(config.chain, Some(Chain::blast_sepolia())); } @@ -498,11 +544,13 @@ mod tests { chain: None, url: Some("https://api.etherscan.io/api".to_string()), key: EtherscanApiKey::Key("ABCDEFG".to_string()), + api_version: None, }; - let resolved = config.clone().resolve(Some("base_sepolia")).unwrap(); + let resolved = + config.clone().resolve(Some("base_sepolia"), EtherscanApiVersion::V2).unwrap(); assert_eq!(resolved.chain, Some(Chain::base_sepolia())); - let resolved = config.resolve(Some("base-sepolia")).unwrap(); + let resolved = config.resolve(Some("base-sepolia"), EtherscanApiVersion::V2).unwrap(); assert_eq!(resolved.chain, Some(Chain::base_sepolia())); } } diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index c78bde6d8d8e7..2abb5a04cb233 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -96,6 +96,7 @@ pub mod fix; // reexport so cli types can implement `figment::Provider` to easily merge compiler arguments pub use alloy_chains::{Chain, NamedChain}; pub use figment; +use foundry_block_explorers::EtherscanApiVersion; pub mod providers; pub use providers::Remappings; @@ -281,6 +282,8 @@ pub struct Config { pub eth_rpc_headers: Option>, /// etherscan API key, or alias for an `EtherscanConfig` in `etherscan` table pub etherscan_api_key: Option, + /// etherscan API version + pub etherscan_api_version: Option, /// Multiple etherscan api configs and their aliases #[serde(default, skip_serializing_if = "EtherscanConfigs::is_empty")] pub etherscan: EtherscanConfigs, @@ -1377,17 +1380,23 @@ impl Config { &self, chain: Option, ) -> Result, EtherscanConfigError> { + let default_api_version = self.etherscan_api_version.unwrap_or_default(); + if let Some(maybe_alias) = self.etherscan_api_key.as_ref().or(self.eth_rpc_url.as_ref()) { if self.etherscan.contains_key(maybe_alias) { - return self.etherscan.clone().resolved().remove(maybe_alias).transpose(); + return self + .etherscan + .clone() + .resolved(default_api_version) + .remove(maybe_alias) + .transpose(); } } // try to find by comparing chain IDs after resolving - if let Some(res) = chain - .or(self.chain) - .and_then(|chain| self.etherscan.clone().resolved().find_chain(chain)) - { + if let Some(res) = chain.or(self.chain).and_then(|chain| { + self.etherscan.clone().resolved(default_api_version).find_chain(chain) + }) { match (res, self.etherscan_api_key.as_ref()) { (Ok(mut config), Some(key)) => { // we update the key, because if an etherscan_api_key is set, it should take @@ -1405,8 +1414,11 @@ impl Config { // etherscan fallback via API key if let Some(key) = self.etherscan_api_key.as_ref() { - let chain = chain.or(self.chain).unwrap_or_default(); - return Ok(ResolvedEtherscanConfig::create(key, chain)); + return Ok(ResolvedEtherscanConfig::create( + key, + chain.or(self.chain).unwrap_or_default(), + default_api_version, + )); } Ok(None) @@ -1421,6 +1433,17 @@ impl Config { self.get_etherscan_config_with_chain(chain).ok().flatten().map(|c| c.key) } + /// Helper function to get the API version. + /// + /// See also [Self::get_etherscan_config_with_chain] + pub fn get_etherscan_api_version(&self, chain: Option) -> EtherscanApiVersion { + self.get_etherscan_config_with_chain(chain) + .ok() + .flatten() + .map(|c| c.api_version) + .unwrap_or_default() + } + /// Returns the remapping for the project's _src_ directory /// /// **Note:** this will add an additional `/=` remapping here so imports that @@ -2369,6 +2392,7 @@ impl Default for Config { eth_rpc_timeout: None, eth_rpc_headers: None, etherscan_api_key: None, + etherscan_api_version: None, verbosity: 0, remappings: vec![], auto_detect_remappings: true, @@ -3063,11 +3087,66 @@ mod tests { let config = Config::load().unwrap(); - assert!(config.etherscan.clone().resolved().has_unresolved()); + assert!(config.etherscan.clone().resolved(EtherscanApiVersion::V2).has_unresolved()); + + jail.set_env("_CONFIG_ETHERSCAN_MOONBEAM", "123456789"); + + let configs = config.etherscan.resolved(EtherscanApiVersion::V2); + assert!(!configs.has_unresolved()); + + let mb_urls = Moonbeam.etherscan_urls().unwrap(); + let mainnet_urls = NamedChain::Mainnet.etherscan_urls().unwrap(); + assert_eq!( + configs, + ResolvedEtherscanConfigs::new([ + ( + "mainnet", + ResolvedEtherscanConfig { + api_url: mainnet_urls.0.to_string(), + chain: Some(NamedChain::Mainnet.into()), + browser_url: Some(mainnet_urls.1.to_string()), + api_version: EtherscanApiVersion::V2, + key: "FX42Z3BBJJEWXWGYV2X1CIPRSCN".to_string(), + } + ), + ( + "moonbeam", + ResolvedEtherscanConfig { + api_url: mb_urls.0.to_string(), + chain: Some(Moonbeam.into()), + browser_url: Some(mb_urls.1.to_string()), + api_version: EtherscanApiVersion::V2, + key: "123456789".to_string(), + } + ), + ]) + ); + + Ok(()) + }); + } + + #[test] + fn test_resolve_etherscan_with_versions() { + figment::Jail::expect_with(|jail| { + jail.create_file( + "foundry.toml", + r#" + [profile.default] + + [etherscan] + mainnet = { key = "FX42Z3BBJJEWXWGYV2X1CIPRSCN", api_version = "v2" } + moonbeam = { key = "${_CONFIG_ETHERSCAN_MOONBEAM}", api_version = "v1" } + "#, + )?; + + let config = Config::load().unwrap(); + + assert!(config.etherscan.clone().resolved(EtherscanApiVersion::V2).has_unresolved()); jail.set_env("_CONFIG_ETHERSCAN_MOONBEAM", "123456789"); - let configs = config.etherscan.resolved(); + let configs = config.etherscan.resolved(EtherscanApiVersion::V2); assert!(!configs.has_unresolved()); let mb_urls = Moonbeam.etherscan_urls().unwrap(); @@ -3081,6 +3160,7 @@ mod tests { api_url: mainnet_urls.0.to_string(), chain: Some(NamedChain::Mainnet.into()), browser_url: Some(mainnet_urls.1.to_string()), + api_version: EtherscanApiVersion::V2, key: "FX42Z3BBJJEWXWGYV2X1CIPRSCN".to_string(), } ), @@ -3090,6 +3170,7 @@ mod tests { api_url: mb_urls.0.to_string(), chain: Some(Moonbeam.into()), browser_url: Some(mb_urls.1.to_string()), + api_version: EtherscanApiVersion::V1, key: "123456789".to_string(), } ), diff --git a/crates/forge/src/cmd/clone.rs b/crates/forge/src/cmd/clone.rs index aaf157637c9e7..a5bc4b2aa4676 100644 --- a/crates/forge/src/cmd/clone.rs +++ b/crates/forge/src/cmd/clone.rs @@ -101,8 +101,10 @@ impl CloneArgs { // step 0. get the chain and api key from the config let config = etherscan.load_config()?; let chain = config.chain.unwrap_or_default(); + let etherscan_api_version = config.get_etherscan_api_version(Some(chain)); let etherscan_api_key = config.get_etherscan_api_key(Some(chain)).unwrap_or_default(); - let client = Client::new(chain, etherscan_api_key.clone())?; + let client = + Client::new_with_api_version(chain, etherscan_api_key.clone(), etherscan_api_version)?; // step 1. get the metadata from client sh_println!("Downloading the source code of {address} from Etherscan...")?; @@ -630,7 +632,7 @@ mod tests { use super::*; use alloy_primitives::hex; use foundry_compilers::CompilerContract; - use foundry_test_utils::rpc::next_mainnet_etherscan_api_key; + use foundry_test_utils::rpc::next_etherscan_api_key; use std::collections::BTreeMap; #[expect(clippy::disallowed_macros)] @@ -709,7 +711,7 @@ mod tests { // create folder if not exists std::fs::create_dir_all(&data_folder).unwrap(); // create metadata.json and creation_data.json - let client = Client::new(Chain::mainnet(), next_mainnet_etherscan_api_key()).unwrap(); + let client = Client::new(Chain::mainnet(), next_etherscan_api_key()).unwrap(); let meta = client.contract_source_code(address).await.unwrap(); // dump json let json = serde_json::to_string_pretty(&meta).unwrap(); diff --git a/crates/forge/src/cmd/create.rs b/crates/forge/src/cmd/create.rs index 744c38d71d977..5cffad23b9141 100644 --- a/crates/forge/src/cmd/create.rs +++ b/crates/forge/src/cmd/create.rs @@ -228,6 +228,7 @@ impl CreateArgs { num_of_optimizations: None, etherscan: EtherscanOpts { key: self.eth.etherscan.key.clone(), + api_version: self.eth.etherscan.api_version, chain: Some(chain.into()), }, rpc: Default::default(), @@ -416,7 +417,11 @@ impl CreateArgs { constructor_args, constructor_args_path: None, num_of_optimizations, - etherscan: EtherscanOpts { key: self.eth.etherscan.key(), chain: Some(chain.into()) }, + etherscan: EtherscanOpts { + key: self.eth.etherscan.key(), + api_version: self.eth.etherscan.api_version, + chain: Some(chain.into()), + }, rpc: Default::default(), flatten: false, force: false, diff --git a/crates/forge/src/cmd/test/mod.rs b/crates/forge/src/cmd/test/mod.rs index a1f3e64bb574f..9e8a4b2d26643 100644 --- a/crates/forge/src/cmd/test/mod.rs +++ b/crates/forge/src/cmd/test/mod.rs @@ -16,6 +16,7 @@ use alloy_primitives::U256; use chrono::Utc; use clap::{Parser, ValueHint}; use eyre::{bail, Context, OptionExt, Result}; +use foundry_block_explorers::EtherscanApiVersion; use foundry_cli::{ opts::{BuildOpts, GlobalArgs}, utils::{self, LoadConfig}, @@ -146,6 +147,10 @@ pub struct TestArgs { #[arg(long, env = "ETHERSCAN_API_KEY", value_name = "KEY")] etherscan_api_key: Option, + /// The Etherscan API version. + #[arg(long, env = "ETHERSCAN_API_VERSION", value_name = "VERSION")] + etherscan_api_version: Option, + /// List tests instead of running them. #[arg(long, short, conflicts_with_all = ["show_progress", "decode_internal", "summary"], help_heading = "Display options")] list: bool, @@ -873,6 +878,10 @@ impl Provider for TestArgs { dict.insert("etherscan_api_key".to_string(), etherscan_api_key.to_string().into()); } + if let Some(api_version) = &self.etherscan_api_version { + dict.insert("etherscan_api_version".to_string(), api_version.to_string().into()); + } + if self.show_progress { dict.insert("show_progress".to_string(), true.into()); } diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index f845981bda592..cd34f4d646237 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -7,7 +7,7 @@ use foundry_config::{ }; use foundry_test_utils::{ foundry_compilers::PathStyle, - rpc::next_mainnet_etherscan_api_key, + rpc::next_etherscan_api_key, snapbox::IntoData, util::{pretty_err, read_string, OutputExt, TestCommand}, }; @@ -619,7 +619,7 @@ forgetest!(can_clone, |prj, cmd| { cmd.args([ "clone", "--etherscan-api-key", - next_mainnet_etherscan_api_key().as_str(), + next_etherscan_api_key().as_str(), "0x044b75f554b886A065b9567891e45c79542d7357", ]) .arg(prj.root()) @@ -648,7 +648,7 @@ forgetest!(can_clone_quiet, |prj, cmd| { cmd.args([ "clone", "--etherscan-api-key", - next_mainnet_etherscan_api_key().as_str(), + next_etherscan_api_key().as_str(), "--quiet", "0xDb53f47aC61FE54F456A4eb3E09832D08Dd7BEec", ]) @@ -666,7 +666,7 @@ forgetest!(can_clone_no_remappings_txt, |prj, cmd| { cmd.args([ "clone", "--etherscan-api-key", - next_mainnet_etherscan_api_key().as_str(), + next_etherscan_api_key().as_str(), "--no-remappings-txt", "0x33e690aEa97E4Ef25F0d140F1bf044d663091DAf", ]) @@ -701,7 +701,7 @@ forgetest!(can_clone_keep_directory_structure, |prj, cmd| { .args([ "clone", "--etherscan-api-key", - next_mainnet_etherscan_api_key().as_str(), + next_etherscan_api_key().as_str(), "--keep-directory-structure", "0x33e690aEa97E4Ef25F0d140F1bf044d663091DAf", ]) @@ -739,7 +739,7 @@ forgetest!(can_clone_with_node_modules, |prj, cmd| { cmd.args([ "clone", "--etherscan-api-key", - next_mainnet_etherscan_api_key().as_str(), + next_etherscan_api_key().as_str(), "0xA3E217869460bEf59A1CfD0637e2875F9331e823", ]) .arg(prj.root()) diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index 799365fcd1b03..41db96842d0ef 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -119,6 +119,7 @@ forgetest!(can_extract_config_values, |prj, cmd| { eth_rpc_timeout: None, eth_rpc_headers: None, etherscan_api_key: None, + etherscan_api_version: None, etherscan: Default::default(), verbosity: 4, remappings: vec![Remapping::from_str("forge-std/=lib/forge-std/").unwrap().into()], @@ -1161,6 +1162,7 @@ exclude = [] "eth_rpc_timeout": null, "eth_rpc_headers": null, "etherscan_api_key": null, + "etherscan_api_version": null, "ignored_error_codes": [ "license", "code-size", diff --git a/crates/forge/tests/cli/verify_bytecode.rs b/crates/forge/tests/cli/verify_bytecode.rs index 2b61e4e847cdb..9ef4d6ddf4606 100644 --- a/crates/forge/tests/cli/verify_bytecode.rs +++ b/crates/forge/tests/cli/verify_bytecode.rs @@ -2,7 +2,7 @@ use foundry_compilers::artifacts::{BytecodeHash, EvmVersion}; use foundry_config::Config; use foundry_test_utils::{ forgetest_async, - rpc::{next_http_archive_rpc_url, next_mainnet_etherscan_api_key}, + rpc::{next_etherscan_api_key, next_http_archive_rpc_url}, util::OutputExt, TestCommand, TestProject, }; @@ -19,7 +19,7 @@ fn test_verify_bytecode( verifier_url: &str, expected_matches: (&str, &str), ) { - let etherscan_key = next_mainnet_etherscan_api_key(); + let etherscan_key = next_etherscan_api_key(); let rpc_url = next_http_archive_rpc_url(); // fetch and flatten source code @@ -33,7 +33,7 @@ fn test_verify_bytecode( prj.add_source(contract_name, &source_code).unwrap(); prj.write_config(config); - let etherscan_key = next_mainnet_etherscan_api_key(); + let etherscan_key = next_etherscan_api_key(); let mut args = vec![ "verify-bytecode", addr, @@ -74,7 +74,7 @@ fn test_verify_bytecode_with_ignore( ignore: &str, chain: &str, ) { - let etherscan_key = next_mainnet_etherscan_api_key(); + let etherscan_key = next_etherscan_api_key(); let rpc_url = next_http_archive_rpc_url(); // fetch and flatten source code diff --git a/crates/script/Cargo.toml b/crates/script/Cargo.toml index b3307f6b44ece..b258da28d02f4 100644 --- a/crates/script/Cargo.toml +++ b/crates/script/Cargo.toml @@ -23,6 +23,7 @@ foundry-debugger.workspace = true foundry-cheatcodes.workspace = true foundry-wallets.workspace = true foundry-linking.workspace = true +foundry-block-explorers.workspace = true forge-script-sequence.workspace = true serde.workspace = true diff --git a/crates/script/src/lib.rs b/crates/script/src/lib.rs index fbbb52398a837..ee6762ed01944 100644 --- a/crates/script/src/lib.rs +++ b/crates/script/src/lib.rs @@ -26,6 +26,7 @@ use dialoguer::Confirm; use eyre::{ContextCompat, Result}; use forge_script_sequence::{AdditionalContract, NestedValue}; use forge_verify::{RetryArgs, VerifierArgs}; +use foundry_block_explorers::EtherscanApiVersion; use foundry_cli::{ opts::{BuildOpts, GlobalArgs}, utils::LoadConfig, @@ -182,6 +183,10 @@ pub struct ScriptArgs { #[arg(long, env = "ETHERSCAN_API_KEY", value_name = "KEY")] pub etherscan_api_key: Option, + /// The Etherscan API version. + #[arg(long, env = "ETHERSCAN_API_VERSION", value_name = "VERSION")] + pub etherscan_api_version: Option, + /// Verifies all the contracts found in the receipts of a script, if any. #[arg(long)] pub verify: bool, @@ -496,6 +501,9 @@ impl Provider for ScriptArgs { figment::value::Value::from(etherscan_api_key.to_string()), ); } + if let Some(api_version) = &self.etherscan_api_version { + dict.insert("etherscan_api_version".to_string(), api_version.to_string().into()); + } if let Some(timeout) = self.timeout { dict.insert("transaction_timeout".to_string(), timeout.into()); } diff --git a/crates/test-utils/src/rpc.rs b/crates/test-utils/src/rpc.rs index 70e3c87534f95..056a2adc578bf 100644 --- a/crates/test-utils/src/rpc.rs +++ b/crates/test-utils/src/rpc.rs @@ -41,8 +41,8 @@ static DRPC_KEYS: LazyLock> = LazyLock::new(|| { ]) }); -// List of etherscan keys for mainnet -static ETHERSCAN_MAINNET_KEYS: LazyLock> = LazyLock::new(|| { +// List of etherscan keys. +static ETHERSCAN_KEYS: LazyLock> = LazyLock::new(|| { shuffled(vec![ "MCAUM7WPE9XP5UQMZPCKIBUJHPM1C24FP6", "JW6RWCG2C5QF8TANH4KC7AYIF1CX7RB5D1", @@ -54,16 +54,6 @@ static ETHERSCAN_MAINNET_KEYS: LazyLock> = LazyLock::new(|| { "A15KZUMZXXCK1P25Y1VP1WGIVBBHIZDS74", "3IA6ASNQXN8WKN7PNFX7T72S9YG56X9FPG", "ZUB97R31KSYX7NYVW6224Q6EYY6U56H591", - // Optimism - // "JQNGFHINKS1W7Y5FRXU4SPBYF43J3NYK46", - ]) -}); - -// List of etherscan keys for Optimism. -static ETHERSCAN_OPTIMISM_KEYS: LazyLock> = LazyLock::new(|| { - shuffled(vec![ - // - "JQNGFHINKS1W7Y5FRXU4SPBYF43J3NYK46", ]) }); @@ -145,19 +135,10 @@ fn archive_urls(is_ws: bool) -> &'static [String] { } } -/// Returns the next etherscan api key -pub fn next_mainnet_etherscan_api_key() -> String { - next_etherscan_api_key(NamedChain::Mainnet) -} - -/// Returns the next etherscan api key for given chain. -pub fn next_etherscan_api_key(chain: NamedChain) -> String { - let keys = match chain { - Optimism => ÐERSCAN_OPTIMISM_KEYS, - _ => ÐERSCAN_MAINNET_KEYS, - }; - let key = next(keys).to_string(); - eprintln!("--- next_etherscan_api_key(chain={chain:?}) = {key} ---"); +/// Returns the next etherscan api key. +pub fn next_etherscan_api_key() -> String { + let key = next(ÐERSCAN_KEYS).to_string(); + eprintln!("--- next_etherscan_api_key() = {key} ---"); key } @@ -205,6 +186,7 @@ fn next_url(is_ws: bool, chain: NamedChain) -> String { mod tests { use super::*; use alloy_primitives::address; + use foundry_block_explorers::EtherscanApiVersion; use foundry_config::Chain; #[tokio::test] @@ -213,7 +195,7 @@ mod tests { let address = address!("0xdAC17F958D2ee523a2206206994597C13D831ec7"); let mut first_abi = None; let mut failed = Vec::new(); - for (i, &key) in ETHERSCAN_MAINNET_KEYS.iter().enumerate() { + for (i, &key) in ETHERSCAN_KEYS.iter().enumerate() { println!("trying key {i} ({key})"); let client = foundry_block_explorers::Client::builder() @@ -248,4 +230,32 @@ mod tests { panic!("failed keys: {failed:#?}"); } } + + #[tokio::test] + #[ignore = "run manually"] + async fn test_etherscan_keys_compatibility() { + let address = address!("0x111111125421cA6dc452d289314280a0f8842A65"); + let ehterscan_key = "JQNGFHINKS1W7Y5FRXU4SPBYF43J3NYK46"; + let client = foundry_block_explorers::Client::builder() + .with_api_key(ehterscan_key) + .chain(Chain::optimism_mainnet()) + .unwrap() + .build() + .unwrap(); + if client.contract_abi(address).await.is_ok() { + panic!("v1 Optimism key should not work with v2 version") + } + + let client = foundry_block_explorers::Client::builder() + .with_api_key(ehterscan_key) + .with_api_version(EtherscanApiVersion::V1) + .chain(Chain::optimism_mainnet()) + .unwrap() + .build() + .unwrap(); + match client.contract_abi(address).await { + Ok(_) => {} + Err(_) => panic!("v1 Optimism key should work with v1 version"), + }; + } } diff --git a/crates/verify/src/bytecode.rs b/crates/verify/src/bytecode.rs index 66e95c7e790b3..5c84dbc64d6a0 100644 --- a/crates/verify/src/bytecode.rs +++ b/crates/verify/src/bytecode.rs @@ -105,6 +105,10 @@ impl figment::Provider for VerifyBytecodeArgs { dict.insert("etherscan_api_key".into(), api_key.as_str().into()); } + if let Some(api_version) = &self.verifier.verifier_api_version { + dict.insert("etherscan_api_version".into(), api_version.to_string().into()); + } + if let Some(block) = &self.block { dict.insert("block".into(), figment::value::Value::serialize(block)?); } @@ -136,13 +140,8 @@ impl VerifyBytecodeArgs { self.etherscan.key = config.get_etherscan_config_with_chain(Some(chain))?.map(|c| c.key); // Etherscan client - let etherscan = EtherscanVerificationProvider.client( - self.etherscan.chain.unwrap_or_default(), - &self.verifier.verifier, - self.verifier.verifier_url.as_deref(), - self.etherscan.key().as_deref(), - &config, - )?; + let etherscan = + EtherscanVerificationProvider.client(&self.etherscan, &self.verifier, &config)?; // Get the bytecode at the address, bailing if it doesn't exist. let code = provider.get_code_at(self.address).await?; diff --git a/crates/verify/src/etherscan/mod.rs b/crates/verify/src/etherscan/mod.rs index aad51093886d7..fd0e08e355a14 100644 --- a/crates/verify/src/etherscan/mod.rs +++ b/crates/verify/src/etherscan/mod.rs @@ -1,7 +1,8 @@ use crate::{ - provider::{VerificationContext, VerificationProvider, VerificationProviderType}, + provider::{VerificationContext, VerificationProvider}, retry::RETRY_CHECK_ON_VERIFY, verify::{VerifyArgs, VerifyCheckArgs}, + VerifierArgs, }; use alloy_json_abi::Function; use alloy_primitives::hex; @@ -12,12 +13,15 @@ use foundry_block_explorers::{ errors::EtherscanError, utils::lookup_compiler_version, verify::{CodeFormat, VerifyContract}, - Client, + Client, EtherscanApiVersion, +}; +use foundry_cli::{ + opts::EtherscanOpts, + utils::{get_provider, read_constructor_args_file, LoadConfig}, }; -use foundry_cli::utils::{get_provider, read_constructor_args_file, LoadConfig}; use foundry_common::{abi::encode_function_args, retry::RetryError}; use foundry_compilers::{artifacts::BytecodeObject, Artifact}; -use foundry_config::{Chain, Config}; +use foundry_config::Config; use foundry_evm::constants::DEFAULT_CREATE2_DEPLOYER; use regex::Regex; use semver::{BuildMetadata, Version}; @@ -150,13 +154,7 @@ impl VerificationProvider for EtherscanVerificationProvider { /// Executes the command to check verification status on Etherscan async fn check(&self, args: VerifyCheckArgs) -> Result<()> { let config = args.load_config()?; - let etherscan = self.client( - args.etherscan.chain.unwrap_or_default(), - &args.verifier.verifier, - args.verifier.verifier_url.as_deref(), - args.etherscan.key().as_deref(), - &config, - )?; + let etherscan = self.client(&args.etherscan, &args.verifier, &config)?; args.retry .into_retry() .run_async_until_break(|| async { @@ -219,13 +217,7 @@ impl EtherscanVerificationProvider { context: &VerificationContext, ) -> Result<(Client, VerifyContract)> { let config = args.load_config()?; - let etherscan = self.client( - args.etherscan.chain.unwrap_or_default(), - &args.verifier.verifier, - args.verifier.verifier_url.as_deref(), - args.etherscan.key().as_deref(), - &config, - )?; + let etherscan = self.client(&args.etherscan, &args.verifier, &config)?; let verify_args = self.create_verify_request(args, context).await?; Ok((etherscan, verify_args)) @@ -252,16 +244,37 @@ impl EtherscanVerificationProvider { /// Create an Etherscan client. pub(crate) fn client( &self, - chain: Chain, - verifier_type: &VerificationProviderType, - verifier_url: Option<&str>, - etherscan_key: Option<&str>, + etherscan_opts: &EtherscanOpts, + verifier_args: &VerifierArgs, config: &Config, ) -> Result { + let chain = etherscan_opts.chain.unwrap_or_default(); + let etherscan_key = etherscan_opts.key(); + let verifier_type = &verifier_args.verifier; + let verifier_url = verifier_args.verifier_url.as_deref(); + + // Verifier is etherscan if explicitly set or if no verifier set (default sourcify) but + // API key passed. + let is_etherscan = verifier_type.is_etherscan() || + (verifier_type.is_sourcify() && etherscan_key.is_some()); let etherscan_config = config.get_etherscan_config_with_chain(Some(chain))?; + let api_version = verifier_args.verifier_api_version.unwrap_or_else(|| { + if is_etherscan { + etherscan_config.as_ref().map(|c| c.api_version).unwrap_or_default() + } else { + EtherscanApiVersion::V1 + } + }); + let etherscan_api_url = verifier_url - .or_else(|| etherscan_config.as_ref().map(|c| c.api_url.as_str())) + .or_else(|| { + if api_version == EtherscanApiVersion::V2 { + None + } else { + etherscan_config.as_ref().map(|c| c.api_url.as_str()) + } + }) .map(str::to_owned); let api_url = etherscan_api_url.as_deref(); @@ -269,20 +282,14 @@ impl EtherscanVerificationProvider { .as_ref() .and_then(|c| c.browser_url.as_deref()) .or_else(|| chain.etherscan_urls().map(|(_, url)| url)); - let etherscan_key = - etherscan_key.or_else(|| etherscan_config.as_ref().map(|c| c.key.as_str())); + etherscan_key.or_else(|| etherscan_config.as_ref().map(|c| c.key.clone())); - let mut builder = Client::builder(); + let mut builder = Client::builder().with_api_version(api_version); builder = if let Some(api_url) = api_url { // we don't want any trailing slashes because this can cause cloudflare issues: let api_url = api_url.trim_end_matches('/'); - - // Verifier is etherscan if explicitly set or if no verifier set (default sourcify) but - // API key passed. - let is_etherscan = verifier_type.is_etherscan() || - (verifier_type.is_sourcify() && etherscan_key.is_some()); let base_url = if !is_etherscan { // If verifier is not Etherscan then set base url as api url without /api suffix. api_url.strip_prefix("/api").unwrap_or(api_url) @@ -392,13 +399,7 @@ impl EtherscanVerificationProvider { context: &VerificationContext, ) -> Result { let provider = get_provider(&context.config)?; - let client = self.client( - args.etherscan.chain.unwrap_or_default(), - &args.verifier.verifier, - args.verifier.verifier_url.as_deref(), - args.etherscan.key.as_deref(), - &context.config, - )?; + let client = self.client(&args.etherscan, &args.verifier, &context.config)?; let creation_data = client.contract_creation_data(args.address).await?; let transaction = provider @@ -465,6 +466,7 @@ async fn ensure_solc_build_metadata(version: Version) -> Result { #[cfg(test)] mod tests { use super::*; + use crate::provider::VerificationProviderType; use clap::Parser; use foundry_common::fs; use foundry_test_utils::{forgetest_async, str}; @@ -498,15 +500,7 @@ mod tests { let config = args.load_config().unwrap(); let etherscan = EtherscanVerificationProvider::default(); - let client = etherscan - .client( - args.etherscan.chain.unwrap_or_default(), - &args.verifier.verifier, - args.verifier.verifier_url.as_deref(), - args.etherscan.key().as_deref(), - &config, - ) - .unwrap(); + let client = etherscan.client(&args.etherscan, &args.verifier, &config).unwrap(); assert_eq!(client.etherscan_api_url().as_str(), "https://api-testnet.polygonscan.com/"); assert!(format!("{client:?}").contains("dummykey")); @@ -526,16 +520,69 @@ mod tests { let config = args.load_config().unwrap(); let etherscan = EtherscanVerificationProvider::default(); - let client = etherscan - .client( - args.etherscan.chain.unwrap_or_default(), - &args.verifier.verifier, - args.verifier.verifier_url.as_deref(), - args.etherscan.key().as_deref(), - &config, - ) - .unwrap(); + let client = etherscan.client(&args.etherscan, &args.verifier, &config).unwrap(); + assert_eq!(client.etherscan_api_url().as_str(), "https://verifier-url.com/"); + assert!(format!("{client:?}").contains("dummykey")); + } + + #[test] + fn can_extract_etherscan_v2_verify_config() { + let temp = tempdir().unwrap(); + let root = temp.path(); + + let config = r#" + [profile.default] + + [etherscan] + mumbai = { key = "dummykey", chain = 80001, url = "https://api-testnet.polygonscan.com/" } + "#; + + let toml_file = root.join(Config::FILE_NAME); + fs::write(toml_file, config).unwrap(); + + let args: VerifyArgs = VerifyArgs::parse_from([ + "foundry-cli", + "0xd8509bee9c9bf012282ad33aba0d87241baf5064", + "src/Counter.sol:Counter", + "--verifier", + "etherscan", + "--chain", + "mumbai", + "--root", + root.as_os_str().to_str().unwrap(), + ]); + + let config = args.load_config().unwrap(); + + let etherscan = EtherscanVerificationProvider::default(); + + let client = etherscan.client(&args.etherscan, &args.verifier, &config).unwrap(); + + assert_eq!(client.etherscan_api_url().as_str(), "https://api.etherscan.io/v2/api"); + assert!(format!("{client:?}").contains("dummykey")); + + let args: VerifyArgs = VerifyArgs::parse_from([ + "foundry-cli", + "0xd8509bee9c9bf012282ad33aba0d87241baf5064", + "src/Counter.sol:Counter", + "--verifier", + "etherscan", + "--chain", + "mumbai", + "--verifier-url", + "https://verifier-url.com/", + "--root", + root.as_os_str().to_str().unwrap(), + ]); + + let config = args.load_config().unwrap(); + + assert_eq!(args.verifier.verifier, VerificationProviderType::Etherscan); + + let etherscan = EtherscanVerificationProvider::default(); + let client = etherscan.client(&args.etherscan, &args.verifier, &config).unwrap(); assert_eq!(client.etherscan_api_url().as_str(), "https://verifier-url.com/"); + assert_eq!(*client.etherscan_api_version(), EtherscanApiVersion::V2); assert!(format!("{client:?}").contains("dummykey")); } diff --git a/crates/verify/src/verify.rs b/crates/verify/src/verify.rs index 71bfc60cc1673..8fd9c98236a5d 100644 --- a/crates/verify/src/verify.rs +++ b/crates/verify/src/verify.rs @@ -2,7 +2,7 @@ use crate::{ etherscan::EtherscanVerificationProvider, - provider::{VerificationProvider, VerificationProviderType}, + provider::{VerificationContext, VerificationProvider, VerificationProviderType}, utils::is_host_only, RetryArgs, }; @@ -10,6 +10,7 @@ use alloy_primitives::Address; use alloy_provider::Provider; use clap::{Parser, ValueHint}; use eyre::Result; +use foundry_block_explorers::EtherscanApiVersion; use foundry_cli::{ opts::{EtherscanOpts, RpcOpts}, utils::{self, LoadConfig}, @@ -23,8 +24,6 @@ use revm_primitives::HashSet; use semver::BuildMetadata; use std::path::PathBuf; -use crate::provider::VerificationContext; - /// Verification provider arguments #[derive(Clone, Debug, Parser)] pub struct VerifierArgs { @@ -39,6 +38,10 @@ pub struct VerifierArgs { /// The verifier URL, if using a custom provider. #[arg(long, help_heading = "Verifier options", env = "VERIFIER_URL")] pub verifier_url: Option, + + /// The verifier API version, if using a custom provider. + #[arg(long, help_heading = "Verifier options", env = "VERIFIER_API_VERSION")] + pub verifier_api_version: Option, } impl Default for VerifierArgs { @@ -47,6 +50,7 @@ impl Default for VerifierArgs { verifier: VerificationProviderType::Sourcify, verifier_api_key: None, verifier_url: None, + verifier_api_version: None, } } } @@ -180,6 +184,10 @@ impl figment::Provider for VerifyArgs { dict.insert("etherscan_api_key".into(), api_key.as_str().into()); } + if let Some(api_version) = &self.verifier.verifier_api_version { + dict.insert("etherscan_api_version".into(), api_version.to_string().into()); + } + Ok(figment::value::Map::from([(Config::selected_profile(), dict)])) } } @@ -444,7 +452,16 @@ impl figment::Provider for VerifyCheckArgs { fn data( &self, ) -> Result, figment::Error> { - self.etherscan.data() + let mut dict = self.etherscan.dict(); + if let Some(api_key) = &self.etherscan.key { + dict.insert("etherscan_api_key".into(), api_key.as_str().into()); + } + + if let Some(api_version) = &self.etherscan.api_version { + dict.insert("etherscan_api_version".into(), api_version.to_string().into()); + } + + Ok(figment::value::Map::from([(Config::selected_profile(), dict)])) } } From 62e880aa8ead919aa47ba3313ced324b92d14e55 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Thu, 8 May 2025 09:54:06 +0200 Subject: [PATCH 062/244] feat: solc 0.8.30 (#10459) --- Cargo.lock | 26 +++++--------------------- crates/forge/tests/cli/svm.rs | 2 +- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c52b0803a0009..f7c9a5740b582 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1846,7 +1846,7 @@ dependencies = [ "bitflags 2.9.0", "cexpr", "clang-sys", - "itertools 0.12.1", + "itertools 0.10.5", "lazy_static", "lazycell", "log", @@ -1986,12 +1986,6 @@ dependencies = [ "serde", ] -[[package]] -name = "build_const" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" - [[package]] name = "bumpalo" version = "3.17.0" @@ -5377,15 +5371,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -8655,9 +8640,9 @@ dependencies = [ [[package]] name = "svm-rs" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039f8b5327f4c4c94384ad8596cc62fb23f58ef5e5d940945757b627fa56d0c2" +checksum = "62d304f1b54e9c83ec8f0537c9dd40d46344bd9142cc528d5242c4b6fe11ced0" dependencies = [ "const-hex", "dirs", @@ -8675,11 +8660,10 @@ dependencies = [ [[package]] name = "svm-rs-builds" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05723cae9acea48e97af3357b25cf0079277bf2ab54405fd3dd62258caae1a48" +checksum = "5ed5035d2abae3cd98c201b116ff22a82861589c060f3e4b687ce951cf381a6e" dependencies = [ - "build_const", "const-hex", "semver 1.0.26", "serde_json", diff --git a/crates/forge/tests/cli/svm.rs b/crates/forge/tests/cli/svm.rs index d585529da8e40..5fe82f5670cc2 100644 --- a/crates/forge/tests/cli/svm.rs +++ b/crates/forge/tests/cli/svm.rs @@ -11,7 +11,7 @@ use svm::Platform; /// 3. svm bumped in foundry-compilers /// 4. foundry-compilers update with any breaking changes /// 5. upgrade the `LATEST_SOLC` -const LATEST_SOLC: Version = Version::new(0, 8, 29); +const LATEST_SOLC: Version = Version::new(0, 8, 30); macro_rules! ensure_svm_releases { ($($test:ident => $platform:ident),* $(,)?) => {$( From 292d248db6f7a1fd0279e9892e566ef2674332ae Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Thu, 8 May 2025 13:27:26 +0530 Subject: [PATCH 063/244] chore: add OpRetro to funding.json (#10462) --- FUNDING.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/FUNDING.json b/FUNDING.json index 52baedf3bfc3c..8f127f0f4e008 100644 --- a/FUNDING.json +++ b/FUNDING.json @@ -3,5 +3,8 @@ "ethereum": { "ownedBy": "0x86308c59a6005d012C51Eef104bBc21786aC5D2E" } + }, + "opRetro": { + "projectId": "0x4562c0630907577f433cad78c7e2cc03349d918b6c14ef982f11a2678f5999ad" } -} +} \ No newline at end of file From 81b4679369f5014b481e06d33ffc772f83adcec6 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 8 May 2025 17:04:42 +0200 Subject: [PATCH 064/244] fix: add check for conflicting create (#10467) --- crates/cast/src/cmd/send.rs | 13 ++++++++++++- crates/cast/tests/cli/main.rs | 11 +++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/crates/cast/src/cmd/send.rs b/crates/cast/src/cmd/send.rs index 7e175d8a7ae5d..7686e70a38a91 100644 --- a/crates/cast/src/cmd/send.rs +++ b/crates/cast/src/cmd/send.rs @@ -8,7 +8,7 @@ use alloy_rpc_types::TransactionRequest; use alloy_serde::WithOtherFields; use alloy_signer::Signer; use clap::Parser; -use eyre::Result; +use eyre::{eyre, Result}; use foundry_cli::{ opts::{EthereumOpts, TransactionOpts}, utils, @@ -109,6 +109,17 @@ impl SendTxArgs { args: constructor_args, }) = command { + // ensure we don't violate settings for transactions that can't be CREATE: 7702 and 4844 + // which require mandatory target + if to.is_none() && tx.auth.is_some() { + return Err(eyre!("EIP-7702 transactions can't be CREATE transactions and require a destination address")); + } + // ensure we don't violate settings for transactions that can't be CREATE: 7702 and 4844 + // which require mandatory target + if to.is_none() && blob_data.is_some() { + return Err(eyre!("EIP-4844 transactions can't be CREATE transactions and require a destination address")); + } + sig = constructor_sig; args = constructor_args; Some(code) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index a661c432df1c5..2d2dd5db9e4f3 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -1318,6 +1318,17 @@ Error: Must specify a recipient address or contract code to deploy "#]]); }); +// +casttest!(send_7702_conflicts_with_create, |_prj, cmd| { + cmd.args([ + "send", "--private-key", "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" ,"--auth", "0xf85c827a6994f39fd6e51aad88f6f4ce6ab8827279cfffb922668001a03e1a66234e71242afcc7bc46c8950c3b2997b102db257774865f1232d2e7bf48a045e252dad189b27b2306792047745eba86bff0dd18aca813dbf3fba8c4e94576", "--create", "0x60806040523373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff1614610072576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610069906100e5565b60405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff16ff5b5f82825260208201905092915050565b7f74782e6f726967696e203d3d206d73672e73656e6465720000000000000000005f82015250565b5f6100cf60178361008b565b91506100da8261009b565b602082019050919050565b5f6020820190508181035f8301526100fc816100c3565b905091905056fe" + ]); + cmd.assert_failure().stderr_eq(str![[r#" +Error: EIP-7702 transactions can't be CREATE transactions and require a destination address + +"#]]); +}); + casttest!(storage, |_prj, cmd| { let rpc = next_http_archive_rpc_url(); cmd.args(["storage", "vitalik.eth", "1", "--rpc-url", &rpc]).assert_success().stdout_eq(str![ From 15d3970b1dbc96aac347eae4720c0941bca7f14f Mon Sep 17 00:00:00 2001 From: Torprius Date: Thu, 8 May 2025 22:46:07 +0200 Subject: [PATCH 065/244] test(`cast`): add and enable negative octal formatting test (#10468) Update base.rs --- crates/cast/src/base.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/cast/src/base.rs b/crates/cast/src/base.rs index 63ae59c1cbffb..1b71d65131b0f 100644 --- a/crates/cast/src/base.rs +++ b/crates/cast/src/base.rs @@ -676,13 +676,20 @@ mod tests { } } - // TODO: test for octal #[test] fn test_format_neg() { // underlying is 256 bits so we have to pad left manually let expected_2: Vec<_> = NEG_NUM.iter().map(|n| format!("{n:1>256b}")).collect(); - // let expected_8: Vec<_> = NEG_NUM.iter().map(|n| format!("1{:7>85o}", n)).collect(); + let expected_8: Vec<_> = NEG_NUM + .iter() + .map(|n| { + let i = I256::try_from(*n).unwrap(); + let mut u = NumberWithBase::from(i); + u.set_base(Octal); + u.format() + }) + .collect(); // Sign not included, see NumberWithBase::format let expected_10: Vec<_> = NEG_NUM.iter().map(|n| format!("{n:}").trim_matches('-').to_string()).collect(); @@ -693,7 +700,7 @@ mod tests { let mut num: NumberWithBase = I256::try_from(n).unwrap().into(); assert_eq!(num.set_base(Binary).format(), expected_2[i]); - // assert_eq!(num.set_base(Octal).format(), expected_8[i]); + assert_eq!(num.set_base(Octal).format(), expected_8[i]); assert_eq!(num.set_base(Decimal).format(), expected_10[i]); assert_eq!(num.set_base(Hexadecimal).format(), expected_l16[i]); assert_eq!(num.set_base(Hexadecimal).format().to_uppercase(), expected_u16[i]); From 9e5f4b97ea48e7743c20b5c8a0cd4e68f7f3197d Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 8 May 2025 23:05:35 +0200 Subject: [PATCH 066/244] perf: spawn mining on blocking (#10471) * perf: spawn mining on blocking * fmt --- crates/anvil/src/eth/api.rs | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 406024c270672..8a7e17e3e630c 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -1738,15 +1738,18 @@ impl EthApi { return Ok(()); } - // mine all the blocks - for _ in 0..blocks.to::() { - // If we have an interval, jump forwards in time to the "next" timestamp - if let Some(interval) = interval { - self.backend.time().increase_time(interval); + self.on_blocking_task(|this| async move { + // mine all the blocks + for _ in 0..blocks.to::() { + // If we have an interval, jump forwards in time to the "next" timestamp + if let Some(interval) = interval { + this.backend.time().increase_time(interval); + } + this.mine_one().await; } - - self.mine_one().await; - } + Ok(()) + }) + .await?; Ok(()) } @@ -2630,10 +2633,16 @@ impl EthApi { } } - // mine all the blocks - for _ in 0..blocks_to_mine { - self.mine_one().await; - } + // this can be blocking for a bit, especially in forking mode + // + self.on_blocking_task(|this| async move { + // mine all the blocks + for _ in 0..blocks_to_mine { + this.mine_one().await; + } + Ok(()) + }) + .await?; Ok(blocks_to_mine) } From 11f937f8beb734bee95b703bc2b3c2d2e631bfec Mon Sep 17 00:00:00 2001 From: Ishika Choudhury <117741714+Rimeeeeee@users.noreply.github.com> Date: Fri, 9 May 2025 16:22:32 +0530 Subject: [PATCH 067/244] chore: replaced trie with alloy-trie (#10478) * chore: replaced trie with alloy-trie * fixes --- crates/anvil/core/src/eth/block.rs | 13 ++++------ crates/anvil/core/src/eth/mod.rs | 1 - crates/anvil/core/src/eth/proof.rs | 5 ++-- crates/anvil/core/src/eth/trie.rs | 30 ------------------------ crates/anvil/src/eth/backend/executor.rs | 10 ++++---- 5 files changed, 13 insertions(+), 46 deletions(-) delete mode 100644 crates/anvil/core/src/eth/trie.rs diff --git a/crates/anvil/core/src/eth/block.rs b/crates/anvil/core/src/eth/block.rs index 8ac74bceb7c3f..fa68530e0f26b 100644 --- a/crates/anvil/core/src/eth/block.rs +++ b/crates/anvil/core/src/eth/block.rs @@ -1,9 +1,5 @@ -use super::{ - transaction::{TransactionInfo, TypedReceipt}, - trie, -}; -use alloy_consensus::{Header, EMPTY_OMMER_ROOT_HASH}; -use alloy_eips::eip2718::Encodable2718; +use super::transaction::{TransactionInfo, TypedReceipt}; +use alloy_consensus::{proofs::calculate_transaction_root, Header, EMPTY_OMMER_ROOT_HASH}; use alloy_primitives::{Address, Bloom, Bytes, B256, B64, U256}; use alloy_rlp::{RlpDecodable, RlpEncodable}; @@ -36,8 +32,9 @@ impl Block { T: Into, { let transactions: Vec<_> = transactions.into_iter().map(Into::into).collect(); - let transactions_root = - trie::ordered_trie_root(transactions.iter().map(|r| r.encoded_2718())); + let transactions1: Vec = + transactions.clone().into_iter().map(Into::into).collect(); + let transactions_root = calculate_transaction_root(&transactions1); Self { header: Header { diff --git a/crates/anvil/core/src/eth/mod.rs b/crates/anvil/core/src/eth/mod.rs index d380c3cc47e22..17807c12a3ba1 100644 --- a/crates/anvil/core/src/eth/mod.rs +++ b/crates/anvil/core/src/eth/mod.rs @@ -21,7 +21,6 @@ pub mod block; pub mod proof; pub mod subscription; pub mod transaction; -pub mod trie; pub mod wallet; pub mod serde_helpers; diff --git a/crates/anvil/core/src/eth/proof.rs b/crates/anvil/core/src/eth/proof.rs index 450e53e471410..9cbd5645c464e 100644 --- a/crates/anvil/core/src/eth/proof.rs +++ b/crates/anvil/core/src/eth/proof.rs @@ -1,7 +1,8 @@ //! Return types for `eth_getProof` -use crate::eth::trie::KECCAK_NULL_RLP; +//use crate::eth::trie::KECCAK_NULL_RLP; use alloy_primitives::{B256, U256}; +use alloy_trie::EMPTY_ROOT_HASH; use revm::primitives::KECCAK_EMPTY; #[derive(Clone, Debug, PartialEq, Eq, alloy_rlp::RlpEncodable, alloy_rlp::RlpDecodable)] @@ -18,7 +19,7 @@ impl Default for BasicAccount { balance: U256::ZERO, nonce: U256::ZERO, code_hash: KECCAK_EMPTY, - storage_root: KECCAK_NULL_RLP, + storage_root: EMPTY_ROOT_HASH, } } } diff --git a/crates/anvil/core/src/eth/trie.rs b/crates/anvil/core/src/eth/trie.rs deleted file mode 100644 index 59c5cd910a33e..0000000000000 --- a/crates/anvil/core/src/eth/trie.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! Utility functions for Ethereum adapted from - -use alloy_primitives::{fixed_bytes, B256}; -use alloy_trie::{HashBuilder, Nibbles}; -use std::collections::BTreeMap; - -/// The KECCAK of the RLP encoding of empty data. -pub const KECCAK_NULL_RLP: B256 = - fixed_bytes!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); - -/// Generates a trie root hash for a vector of values -pub fn ordered_trie_root(input: I) -> B256 -where - I: IntoIterator, - V: AsRef<[u8]>, -{ - let mut builder = HashBuilder::default(); - - let input = input - .into_iter() - .enumerate() - .map(|(i, v)| (alloy_rlp::encode(i), v)) - .collect::>(); - - for (key, value) in input { - builder.add_leaf(Nibbles::unpack(key), value.as_ref()); - } - - builder.root() -} diff --git a/crates/anvil/src/eth/backend/executor.rs b/crates/anvil/src/eth/backend/executor.rs index 0b2e118020628..29b03756c17c8 100644 --- a/crates/anvil/src/eth/backend/executor.rs +++ b/crates/anvil/src/eth/backend/executor.rs @@ -8,15 +8,16 @@ use crate::{ mem::inspector::Inspector, PrecompileFactory, }; -use alloy_consensus::{constants::EMPTY_WITHDRAWALS, Receipt, ReceiptWithBloom}; -use alloy_eips::{eip2718::Encodable2718, eip7685::EMPTY_REQUESTS_HASH}; +use alloy_consensus::{ + constants::EMPTY_WITHDRAWALS, proofs::calculate_receipt_root, Receipt, ReceiptWithBloom, +}; +use alloy_eips::eip7685::EMPTY_REQUESTS_HASH; use alloy_primitives::{Bloom, BloomInput, Log, B256}; use anvil_core::eth::{ block::{Block, BlockInfo, PartialHeader}, transaction::{ DepositReceipt, PendingTransaction, TransactionInfo, TypedReceipt, TypedTransaction, }, - trie, }; use foundry_evm::{ backend::DatabaseError, @@ -211,8 +212,7 @@ impl TransactionExecutor<'_, DB, V> { transactions.push(transaction.pending_transaction.transaction.clone()); } - let receipts_root = - trie::ordered_trie_root(receipts.iter().map(Encodable2718::encoded_2718)); + let receipts_root = calculate_receipt_root(&receipts); let partial_header = PartialHeader { parent_hash, From 90a8746d2938320ad50226d3f978318557ae5575 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Fri, 9 May 2025 17:15:40 +0300 Subject: [PATCH 068/244] fix(forge): Set empty code if the 7702 delegation address is 0x (#10481) fix(forge): Set empty code if the 7702 delegation address of authority is 0x --- crates/cheatcodes/src/script.rs | 11 ++++-- crates/forge/tests/it/repros.rs | 3 ++ testdata/default/repros/Issue10477.t.sol | 49 ++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 testdata/default/repros/Issue10477.t.sol diff --git a/crates/cheatcodes/src/script.rs b/crates/cheatcodes/src/script.rs index dc80b7021ab04..86f3e1db805d0 100644 --- a/crates/cheatcodes/src/script.rs +++ b/crates/cheatcodes/src/script.rs @@ -9,7 +9,7 @@ use alloy_signer_local::PrivateKeySigner; use alloy_sol_types::SolValue; use foundry_wallets::{multi_wallet::MultiWallet, WalletSigner}; use parking_lot::Mutex; -use revm::primitives::{Bytecode, SignedAuthorization, SpecId}; +use revm::primitives::{Bytecode, SignedAuthorization, SpecId, KECCAK_EMPTY}; use std::sync::Arc; impl Cheatcode for broadcast_0Call { @@ -129,8 +129,13 @@ fn write_delegation(ccx: &mut CheatsCtxt, auth: SignedAuthorization) -> Result<( return Err("invalid nonce".into()); } authority_acc.data.info.nonce += 1; - let bytecode = Bytecode::new_eip7702(*auth.address()); - ccx.ecx.journaled_state.set_code(authority, bytecode); + if auth.address.is_zero() { + // Set empty code if the delegation address of authority is 0x. + ccx.ecx.journaled_state.set_code_with_hash(authority, Bytecode::default(), KECCAK_EMPTY); + } else { + let bytecode = Bytecode::new_eip7702(*auth.address()); + ccx.ecx.journaled_state.set_code(authority, bytecode); + } Ok(()) } diff --git a/crates/forge/tests/it/repros.rs b/crates/forge/tests/it/repros.rs index 550111f92d763..d65fa295e103f 100644 --- a/crates/forge/tests/it/repros.rs +++ b/crates/forge/tests/it/repros.rs @@ -401,3 +401,6 @@ test_repro!(7238); // https://github.com/foundry-rs/foundry/issues/10302 test_repro!(10302); + +// https://github.com/foundry-rs/foundry/issues/10477 +test_repro!(10477); diff --git a/testdata/default/repros/Issue10477.t.sol b/testdata/default/repros/Issue10477.t.sol new file mode 100644 index 0000000000000..86d36fc741ef4 --- /dev/null +++ b/testdata/default/repros/Issue10477.t.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity ^0.8.18; + +import "ds-test/test.sol"; +import "cheats/Vm.sol"; + +contract SimpleDelegate { + function call(address target, bytes memory data) external returns (bool callResult, bytes memory callData) { + (callResult, callData) = target.call(data); + } +} + +contract Counter { + uint256 public value = 0; + + function increment() external { + value++; + } +} + +contract Issue10477Test is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + address payable ALICE_ADDRESS = payable(0x70997970C51812dc3A010C7d01b50e0d17dc79C8); + uint256 constant ALICE_PK = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d; + + function test_reset_delegate_indicator() public { + SimpleDelegate delegate = new SimpleDelegate(); + Counter counter = new Counter(); + + vm.startBroadcast(ALICE_PK); + vm.signAndAttachDelegation(address(delegate), ALICE_PK); + assertTrue(ALICE_ADDRESS.code.length > 0); + + (bool callResult, bytes memory callData) = + SimpleDelegate(ALICE_ADDRESS).call(address(counter), abi.encodeCall(Counter.increment, ())); + + assertTrue(callResult); + assertTrue(callData.length == 0); + + vm.signAndAttachDelegation(address(0), ALICE_PK); + + // Expected to succeed here + assertTrue(ALICE_ADDRESS.code.length == 0); + assertTrue(ALICE_ADDRESS.codehash == 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470); + + vm.stopBroadcast(); + } +} From 19ecdde491f19f79aed630623d56c567b34dd3c0 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 9 May 2025 19:34:22 +0200 Subject: [PATCH 069/244] chore: rm work type (#10474) --- crates/anvil/core/src/types.rs | 28 ++-------------------------- crates/anvil/src/eth/api.rs | 4 ++-- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/crates/anvil/core/src/types.rs b/crates/anvil/core/src/types.rs index e9d9c682e12dc..e0cf8762ad9af 100644 --- a/crates/anvil/core/src/types.rs +++ b/crates/anvil/core/src/types.rs @@ -1,30 +1,6 @@ -use alloy_primitives::{Bytes, B256, U256}; +use alloy_primitives::Bytes; use alloy_rpc_types::TransactionRequest; -use serde::{Deserialize, Serialize, Serializer}; - -/// Represents the result of `eth_getWork`. -/// -/// This may or may not include the block number. -#[derive(Debug, Default, PartialEq, Eq)] -pub struct Work { - pub pow_hash: B256, - pub seed_hash: B256, - pub target: B256, - pub number: Option, -} - -impl Serialize for Work { - fn serialize(&self, s: S) -> Result - where - S: Serializer, - { - if let Some(num) = self.number { - (&self.pow_hash, &self.seed_hash, &self.target, U256::from(num)).serialize(s) - } else { - (&self.pow_hash, &self.seed_hash, &self.target).serialize(s) - } - } -} +use serde::Deserialize; /// Represents the options used in `anvil_reorg` #[derive(Debug, Clone, Deserialize)] diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 8a7e17e3e630c..7b0fc9fe8d6dc 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -62,7 +62,7 @@ use alloy_rpc_types::{ }, txpool::{TxpoolContent, TxpoolInspect, TxpoolInspectSummary, TxpoolStatus}, AccessList, AccessListResult, BlockId, BlockNumberOrTag as BlockNumber, BlockTransactions, - EIP1186AccountProofResponse, FeeHistory, Filter, FilteredParams, Index, Log, + EIP1186AccountProofResponse, FeeHistory, Filter, FilteredParams, Index, Log, Work, }; use alloy_serde::WithOtherFields; use alloy_transport::TransportErrorKind; @@ -76,7 +76,7 @@ use anvil_core::{ wallet::{WalletCapabilities, WalletError}, EthRequest, }, - types::{ReorgOptions, TransactionData, Work}, + types::{ReorgOptions, TransactionData}, }; use anvil_rpc::{error::RpcError, response::ResponseResult}; use foundry_common::provider::ProviderBuilder; From cc50b162d7995a784a3338545ad9660cd7a62d4c Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 9 May 2025 19:50:58 +0200 Subject: [PATCH 070/244] chore: rm unused account type (#10472) * chore: rm unused account type * rm unused crate --- Cargo.lock | 1 - crates/anvil/core/Cargo.toml | 1 - crates/anvil/core/src/eth/mod.rs | 1 - crates/anvil/core/src/eth/proof.rs | 25 ------------------------- 4 files changed, 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f7c9a5740b582..6408030f5fc6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1012,7 +1012,6 @@ dependencies = [ "alloy-rlp", "alloy-rpc-types", "alloy-serde", - "alloy-trie", "bytes", "foundry-common", "foundry-evm", diff --git a/crates/anvil/core/Cargo.toml b/crates/anvil/core/Cargo.toml index b1cf977d0a468..f7428d356bf53 100644 --- a/crates/anvil/core/Cargo.toml +++ b/crates/anvil/core/Cargo.toml @@ -29,7 +29,6 @@ alloy-rlp.workspace = true 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, features = ["serde"] } alloy-network.workspace = true serde.workspace = true diff --git a/crates/anvil/core/src/eth/mod.rs b/crates/anvil/core/src/eth/mod.rs index 17807c12a3ba1..c1c6ab89a1420 100644 --- a/crates/anvil/core/src/eth/mod.rs +++ b/crates/anvil/core/src/eth/mod.rs @@ -18,7 +18,6 @@ use foundry_common::serde_helpers::{ }; pub mod block; -pub mod proof; pub mod subscription; pub mod transaction; pub mod wallet; diff --git a/crates/anvil/core/src/eth/proof.rs b/crates/anvil/core/src/eth/proof.rs index 9cbd5645c464e..e69de29bb2d1d 100644 --- a/crates/anvil/core/src/eth/proof.rs +++ b/crates/anvil/core/src/eth/proof.rs @@ -1,25 +0,0 @@ -//! Return types for `eth_getProof` - -//use crate::eth::trie::KECCAK_NULL_RLP; -use alloy_primitives::{B256, U256}; -use alloy_trie::EMPTY_ROOT_HASH; -use revm::primitives::KECCAK_EMPTY; - -#[derive(Clone, Debug, PartialEq, Eq, alloy_rlp::RlpEncodable, alloy_rlp::RlpDecodable)] -pub struct BasicAccount { - pub nonce: U256, - pub balance: U256, - pub storage_root: B256, - pub code_hash: B256, -} - -impl Default for BasicAccount { - fn default() -> Self { - Self { - balance: U256::ZERO, - nonce: U256::ZERO, - code_hash: KECCAK_EMPTY, - storage_root: EMPTY_ROOT_HASH, - } - } -} From 026b3513795e5638ccebdae7b51036480fe32e6e Mon Sep 17 00:00:00 2001 From: Ishika Choudhury <117741714+Rimeeeeee@users.noreply.github.com> Date: Sat, 10 May 2025 11:52:01 +0530 Subject: [PATCH 071/244] replaced default with calculate (#10236) * replaced default with calculate * fmt * fmt fixes * fixes * fmt * touchups --------- Co-authored-by: Matthias Seitz --- crates/anvil/src/eth/backend/mem/mod.rs | 30 ++++++++++++++++++------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 2f5aa321080bc..097e66ee92459 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -36,7 +36,9 @@ use crate::{ }; use alloy_chains::NamedChain; use alloy_consensus::{ - transaction::Recovered, Account, BlockHeader, Header, Receipt, ReceiptWithBloom, Signed, + proofs::{calculate_receipt_root, calculate_transaction_root}, + transaction::Recovered, + Account, BlockHeader, Header, Receipt, ReceiptWithBloom, Signed, Transaction as TransactionTrait, TxEnvelope, }; use alloy_eips::{eip1559::BaseFeeParams, eip4844::MAX_BLOBS_PER_BLOCK}; @@ -45,7 +47,8 @@ use alloy_network::{ EthereumWallet, UnknownTxEnvelope, UnknownTypedTransaction, }; use alloy_primitives::{ - address, hex, keccak256, utils::Unit, Address, Bytes, TxHash, TxKind, B256, U256, U64, + address, hex, keccak256, logs_bloom, utils::Unit, Address, Bytes, TxHash, TxKind, B256, U256, + U64, }; use alloy_rpc_types::{ anvil::Forking, @@ -1512,6 +1515,8 @@ impl Backend { let mut log_index = 0; let mut gas_used = 0; let mut transactions = Vec::with_capacity(calls.len()); + let mut receipts = Vec::new(); + let mut logs= Vec::new(); // apply state overrides before executing the transactions if let Some(state_overrides) = state_overrides { state::apply_cached_db_state_override(state_overrides, &mut cache_db)?; @@ -1617,7 +1622,7 @@ impl Backend { message: "execution failed".to_string(), } }), - logs: result + logs: result.clone() .into_logs() .into_iter() .enumerate() @@ -1634,15 +1639,24 @@ impl Backend { }) .collect(), }; - + let receipt = Receipt { + status: result.is_success().into(), + cumulative_gas_used: result.gas_used(), + logs:sim_res.logs.clone() + }; + receipts.push(receipt.with_bloom()); + logs.extend(sim_res.logs.clone().iter().map(|log| log.inner.clone())); log_index += sim_res.logs.len(); call_res.push(sim_res); } - + let transactions_envelopes: Vec = transactions + .iter() + .map(|tx| AnyTxEnvelope::from(tx.clone())) + .collect(); let header = Header { - logs_bloom: Default::default(), - transactions_root: Default::default(), - receipts_root: Default::default(), + logs_bloom:logs_bloom(logs.iter()), + transactions_root: calculate_transaction_root(&transactions_envelopes), + receipts_root: calculate_receipt_root(&transactions_envelopes), parent_hash: Default::default(), ommers_hash: Default::default(), beneficiary: block_env.coinbase, From 48533bbc06da4206299ae806469440013347ee8c Mon Sep 17 00:00:00 2001 From: just-mitch <68168980+just-mitch@users.noreply.github.com> Date: Sat, 10 May 2025 02:27:31 -0400 Subject: [PATCH 072/244] feat: add devcontainer (#10429) Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> --- .devcontainer/Dockerfile.dev | 84 +++++++++++++++++++++++++++++++++ .devcontainer/devcontainer.json | 49 +++++++++++++++++++ .github/workflows/nextest.yml | 1 + 3 files changed, 134 insertions(+) create mode 100644 .devcontainer/Dockerfile.dev create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/Dockerfile.dev b/.devcontainer/Dockerfile.dev new file mode 100644 index 0000000000000..9017115744e89 --- /dev/null +++ b/.devcontainer/Dockerfile.dev @@ -0,0 +1,84 @@ +FROM ubuntu:22.04 + +ARG USERNAME=foundry +ARG USER_UID=1000 +ARG USER_GID=$USER_UID +ARG PYTHON_VERSION=3.11 +ARG NODE_MAJOR=20 +ARG VYPER_VERSION=0.4.0 + +ENV DEBIAN_FRONTEND=noninteractive +ENV CARGO_TERM_COLOR=always \ + RUST_BACKTRACE=full + +WORKDIR /workspace + +RUN apt-get update && apt-get install -y --no-install-recommends \ + # Build tools + build-essential \ + clang \ + lld \ + pkg-config \ + # Network/SSL + curl \ + ca-certificates \ + gnupg \ + libssl-dev \ + # Version control & utils + git \ + sudo \ + unzip \ + # Python + python${PYTHON_VERSION} \ + python3-pip \ + python${PYTHON_VERSION}-venv \ + # Add Node.js repo + && mkdir -p /etc/apt/keyrings \ + && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \ + && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \ + # Update again after adding repo and install Node.js + && apt-get update && apt-get install -y --no-install-recommends \ + nodejs \ + # Clean up apt cache + && apt-get clean && rm -rf /var/lib/apt/lists/* + +# Ensure python points to the installed python version +RUN ln -sf /usr/bin/python${PYTHON_VERSION} /usr/bin/python && \ + ln -sf /usr/bin/python${PYTHON_VERSION} /usr/bin/python3 + +# Create non-root user with sudo privileges +RUN groupadd --gid $USER_GID $USERNAME \ + && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME -s /bin/bash \ + # Setup sudo without password prompt + && echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/$USERNAME \ + && chmod 0440 /etc/sudoers.d/$USERNAME \ + # Add user to the sudo group (standard practice) + && usermod -aG sudo $USERNAME + +# Switch to the non-root user +USER $USERNAME +WORKDIR /home/$USERNAME + +# --- User-specific installations --- + +# Install Bun +ENV BUN_INSTALL="/home/$USERNAME/.bun" +ENV PATH="$BUN_INSTALL/bin:$PATH" +RUN curl -fsSL https://bun.sh/install | bash + +# Install Rust & cargo-nextest +ENV CARGO_HOME="/home/$USERNAME/.cargo" +ENV RUSTUP_HOME="/home/$USERNAME/.rustup" +ENV PATH="$CARGO_HOME/bin:$PATH" +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \ + && cargo install cargo-nextest --locked + +# Install Vyper using pip +# Ensure pip user install directory is in PATH +ENV PYTHONUSERBASE="/home/$USERNAME/.local" +ENV PATH="$PYTHONUSERBASE/bin:$PATH" +RUN pip3 install --user vyper==${VYPER_VERSION} + +# Switch back to the main workspace directory +WORKDIR /workspace + diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000000..1c2eb26f5a9f6 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,49 @@ +// For format details, see https://aka.ms/devcontainer.json. +{ + "name": "Foundry Development", + "build": { + "context": "..", + "dockerfile": "Dockerfile.dev" + }, + + "features": { + "ghcr.io/devcontainers/features/common-utils:2": { + "installZsh": true, + "configureZshAsDefaultShell": true, + "installOhMyZsh": true, + "upgradePackages": true + } + }, + + "forwardPorts": [], + + "postCreateCommand": "rustup default stable && rustup update", + + "customizations": { + "vscode": { + "extensions": [ + "rust-lang.rust-analyzer", + "serayuzgur.crates", + "tamasfe.even-better-toml", + "ms-python.python", + "dbaeumer.vscode-eslint", + "oven.bun-vscode" + ], + "settings": { + "rust-analyzer.checkOnSave": true, + "rust-analyzer.cargo.features": "all" + } + } + }, + + "remoteUser": "foundry", + + "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached", + + "workspaceFolder": "/workspace", + + "mounts": [ + "source=${localEnv:HOME}/.cargo/registry,target=/home/foundry/.cargo/registry,type=bind,consistency=cached", + "source=${localEnv:HOME}/.cargo/git,target=/home/foundry/.cargo/git,type=bind,consistency=cached" + ] +} diff --git a/.github/workflows/nextest.yml b/.github/workflows/nextest.yml index d50953871eaf5..855e5933c1b6d 100644 --- a/.github/workflows/nextest.yml +++ b/.github/workflows/nextest.yml @@ -72,6 +72,7 @@ jobs: with: python-version: 3.11 - name: Install Vyper + # Also update vyper version in .devcontainer/Dockerfile.dev run: pip --version && pip install vyper==0.4.0 - name: Forge RPC cache From 59030b8bf7d9d76824e471f62699682440a2a2c4 Mon Sep 17 00:00:00 2001 From: Soubhik Singha Mahapatra <160333583+Soubhik-10@users.noreply.github.com> Date: Sat, 10 May 2025 13:44:32 +0530 Subject: [PATCH 073/244] feat: added TransactionStream to subscribe to pending transactions (#10482) * added new method to subscribe to pending tx * wip * clippy -.- * clippy -.- * unbounded channel * wip * wip test * touchup * check --------- Co-authored-by: Matthias Seitz --- crates/anvil/src/eth/api.rs | 26 +++++++++++++++++- crates/anvil/src/pubsub.rs | 10 +++++++ crates/anvil/src/server/handler.rs | 41 +++++++++++++++++++--------- crates/anvil/tests/it/transaction.rs | 30 +++++++++++++++++++- 4 files changed, 92 insertions(+), 15 deletions(-) diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 7b0fc9fe8d6dc..6bbb0f30ed48e 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -89,10 +89,14 @@ use foundry_evm::{ primitives::BlockEnv, }, }; -use futures::channel::{mpsc::Receiver, oneshot}; +use futures::{ + channel::{mpsc::Receiver, oneshot}, + StreamExt, +}; use parking_lot::RwLock; use revm::primitives::Bytecode; use std::{future::Future, sync::Arc, time::Duration}; +use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver}; /// The client version: `anvil/v{major}.{minor}.{patch}` pub const CLIENT_VERSION: &str = concat!("anvil/v", env!("CARGO_PKG_VERSION")); @@ -2863,6 +2867,26 @@ impl EthApi { self.pool.add_ready_listener() } + /// Returns a listener for pending transactions, yielding full transactions + pub fn full_pending_transactions(&self) -> UnboundedReceiver { + let (tx, rx) = unbounded_channel(); + let mut hashes = self.new_ready_transactions(); + + let this = self.clone(); + + tokio::spawn(async move { + while let Some(hash) = hashes.next().await { + if let Ok(Some(txn)) = this.transaction_by_hash(hash).await { + if tx.send(txn).is_err() { + break; + } + } + } + }); + + rx + } + /// Returns a new accessor for certain storage elements pub fn storage_info(&self) -> StorageInfo { StorageInfo::new(Arc::clone(&self.backend)) diff --git a/crates/anvil/src/pubsub.rs b/crates/anvil/src/pubsub.rs index b28cdba8ae84c..69f7896c72f78 100644 --- a/crates/anvil/src/pubsub.rs +++ b/crates/anvil/src/pubsub.rs @@ -2,6 +2,7 @@ use crate::{ eth::{backend::notifications::NewBlockNotifications, error::to_rpc_result}, StorageInfo, }; +use alloy_network::AnyRpcTransaction; use alloy_primitives::{TxHash, B256}; use alloy_rpc_types::{pubsub::SubscriptionResult, FilteredParams, Log, Transaction}; use anvil_core::eth::{block::Block, subscription::SubscriptionId, transaction::TypedReceipt}; @@ -13,6 +14,7 @@ use std::{ pin::Pin, task::{Context, Poll}, }; +use tokio::sync::mpsc::UnboundedReceiver; /// Listens for new blocks and matching logs emitted in that block #[derive(Debug)] @@ -86,6 +88,7 @@ pub enum EthSubscription { Logs(Box), Header(NewBlockNotifications, StorageInfo, SubscriptionId), PendingTransactions(Receiver, SubscriptionId), + FullPendingTransactions(UnboundedReceiver, SubscriptionId), } impl EthSubscription { @@ -120,6 +123,13 @@ impl EthSubscription { }); Poll::Ready(res) } + Self::FullPendingTransactions(tx, id) => { + let res = ready!(tx.poll_recv(cx)).map(to_rpc_result).map(|result| { + let params = EthSubscriptionParams { subscription: id.clone(), result }; + EthSubscriptionResponse::new(params) + }); + Poll::Ready(res) + } } } } diff --git a/crates/anvil/src/server/handler.rs b/crates/anvil/src/server/handler.rs index 79adb87df7bcb..3c474e9ee4b23 100644 --- a/crates/anvil/src/server/handler.rs +++ b/crates/anvil/src/server/handler.rs @@ -58,20 +58,22 @@ impl PubSubEthRpcHandler { let canceled = cx.remove_subscription(&id).is_some(); ResponseResult::Success(canceled.into()) } - EthPubSub::EthSubscribe(kind, params) => { - let filter = match *params { + EthPubSub::EthSubscribe(kind, raw_params) => { + let filter = match &*raw_params { Params::None => None, - Params::Logs(filter) => Some(*filter), - Params::Bool(_) => { - return ResponseResult::Error(RpcError::invalid_params( - "Expected params for logs subscription", - )) - } + Params::Logs(filter) => Some(filter.clone()), + Params::Bool(_) => None, }; - let params = FilteredParams::new(filter); + let params = FilteredParams::new(filter.map(|b| *b)); let subscription = match kind { SubscriptionKind::Logs => { + if raw_params.is_bool() { + return ResponseResult::Error(RpcError::invalid_params( + "Expected params for logs subscription", + )) + } + trace!(target: "rpc::ws", "received logs subscription {:?}", params); let blocks = self.api.new_block_notifications(); let storage = self.api.storage_info(); @@ -91,10 +93,23 @@ impl PubSubEthRpcHandler { } SubscriptionKind::NewPendingTransactions => { trace!(target: "rpc::ws", "received pending transactions subscription"); - EthSubscription::PendingTransactions( - self.api.new_ready_transactions(), - id.clone(), - ) + match *raw_params { + Params::Bool(true) => EthSubscription::FullPendingTransactions( + self.api.full_pending_transactions(), + id.clone(), + ), + Params::Bool(false) | Params::None => { + EthSubscription::PendingTransactions( + self.api.new_ready_transactions(), + id.clone(), + ) + } + _ => { + return ResponseResult::Error(RpcError::invalid_params( + "Expected boolean parameter for newPendingTransactions", + )) + } + } } SubscriptionKind::Syncing => { return RpcError::internal_error_with("Not implemented").into() diff --git a/crates/anvil/tests/it/transaction.rs b/crates/anvil/tests/it/transaction.rs index fc049614e3bdd..4c58170454601 100644 --- a/crates/anvil/tests/it/transaction.rs +++ b/crates/anvil/tests/it/transaction.rs @@ -4,7 +4,7 @@ use crate::{ }; use alloy_network::{EthereumWallet, TransactionBuilder, TransactionResponse}; use alloy_primitives::{address, hex, map::B256HashSet, Address, Bytes, FixedBytes, U256}; -use alloy_provider::Provider; +use alloy_provider::{Provider, WsConnect}; use alloy_rpc_types::{ state::{AccountOverride, StateOverride}, AccessList, AccessListItem, BlockId, BlockNumberOrTag, BlockTransactions, TransactionRequest, @@ -715,6 +715,34 @@ async fn can_get_pending_transaction() { assert_eq!(mined.tx_hash(), pending.unwrap().unwrap().tx_hash()); } +#[tokio::test(flavor = "multi_thread")] +async fn can_listen_full_pending_transaction() { + let (api, handle) = spawn(NodeConfig::test()).await; + + // Disable auto-mining so transactions remain pending + api.anvil_set_auto_mine(false).await.unwrap(); + + let provider = alloy_provider::ProviderBuilder::new() + .on_ws(WsConnect::new(handle.ws_endpoint())) + .await + .unwrap(); + + // Subscribe to full pending transactions + let sub = provider.subscribe_full_pending_transactions().await; + tokio::time::sleep(Duration::from_millis(1000)).await; + let mut stream = sub.expect("Failed to subscribe to pending tx").into_stream().take(5); + + let from = handle.dev_wallets().next().unwrap().address(); + let tx = TransactionRequest::default().from(from).value(U256::from(1337)).to(Address::random()); + + let tx = provider.send_transaction(tx).await.unwrap(); + + // Wait for the subscription to yield a transaction + let received = stream.next().await.expect("Failed to receive pending tx"); + + assert_eq!(received.tx_hash(), *tx.tx_hash()); +} + #[tokio::test(flavor = "multi_thread")] async fn can_get_raw_transaction() { let (api, handle) = spawn(NodeConfig::test()).await; From 5775ce1a703717ccdb309673f2567cdce5742ba4 Mon Sep 17 00:00:00 2001 From: Gengar Date: Sat, 10 May 2025 14:58:21 +0300 Subject: [PATCH 074/244] refactor(common): improve URL path handling in runtime transport (#10493) Update runtime_transport.rs --- crates/common/src/provider/runtime_transport.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/common/src/provider/runtime_transport.rs b/crates/common/src/provider/runtime_transport.rs index 9a59f6ed20423..d5e98afa57766 100644 --- a/crates/common/src/provider/runtime_transport.rs +++ b/crates/common/src/provider/runtime_transport.rs @@ -313,9 +313,8 @@ fn url_to_file_path(url: &Url) -> Result { let url_str = url.as_str(); - if url_str.starts_with(PREFIX) { - let pipe_name = &url_str[PREFIX.len()..]; - let pipe_path = format!(r"\\.\pipe\{}", pipe_name); + if let Some(pipe_name) = url_str.strip_prefix(PREFIX) { + let pipe_path = format!(r"\\.\pipe\{pipe_name}"); return Ok(PathBuf::from(pipe_path)); } From 755cee06c510d426f3da4ec834a2eaa1d1b02179 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Mon, 12 May 2025 00:58:47 +0300 Subject: [PATCH 075/244] fix(forge): fix nonce for tx with 7702 auth (#10464) * fix(forge): fix nonce for tx with 7702 auth * simplify, only set_code with incremented nonce --- crates/cheatcodes/src/inspector.rs | 3 + crates/cheatcodes/src/script.rs | 8 +- crates/forge/tests/cli/script.rs | 139 +++++++++++++++++- crates/forge/tests/cli/test_cmd.rs | 4 +- .../default/cheats/AttachDelegation.t.sol | 3 - 5 files changed, 148 insertions(+), 9 deletions(-) diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index 517b1ffbe72d7..aa07c74ad9003 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -1152,6 +1152,9 @@ where { (Some(auth_list), None) => { tx_req.authorization_list = Some(vec![auth_list]); tx_req.sidecar = None; + + // Increment nonce to reflect the signed authorization. + account.info.nonce += 1; } (None, Some(blob_sidecar)) => { tx_req.set_blob_sidecar(blob_sidecar); diff --git a/crates/cheatcodes/src/script.rs b/crates/cheatcodes/src/script.rs index 86f3e1db805d0..b3383992c19d8 100644 --- a/crates/cheatcodes/src/script.rs +++ b/crates/cheatcodes/src/script.rs @@ -98,7 +98,8 @@ fn sign_delegation( } else { let authority_acc = ccx.ecx.journaled_state.load_account(signer.address(), &mut ccx.ecx.db)?; - authority_acc.data.info.nonce + // If we don't have a nonce then use next auth account nonce. + authority_acc.data.info.nonce + 1 }; let auth = Authorization { address: implementation, @@ -125,10 +126,11 @@ fn sign_delegation( fn write_delegation(ccx: &mut CheatsCtxt, auth: SignedAuthorization) -> Result<()> { let authority = auth.recover_authority().map_err(|e| format!("{e}"))?; let authority_acc = ccx.ecx.journaled_state.load_account(authority, &mut ccx.ecx.db)?; - if authority_acc.data.info.nonce != auth.nonce { + + if authority_acc.data.info.nonce + 1 != auth.nonce { return Err("invalid nonce".into()); } - authority_acc.data.info.nonce += 1; + if auth.address.is_zero() { // Set empty code if the delegation address of authority is 0x. ccx.ecx.journaled_state.set_code_with_hash(authority, Bytecode::default(), KECCAK_EMPTY); diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index 1b1180e793015..8f12921685858 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -2,7 +2,7 @@ use crate::constants::TEMPLATE_CONTRACT; use alloy_primitives::{address, hex, Address, Bytes}; -use anvil::{spawn, NodeConfig}; +use anvil::{spawn, EthereumHardfork, NodeConfig}; use forge_script_sequence::ScriptSequence; use foundry_test_utils::{ rpc::{self, next_http_archive_rpc_url}, @@ -2720,3 +2720,140 @@ Warning: No transactions to broadcast. "# ]); }); + +// Tests EIP-7702 broadcast +forgetest_async!(can_broadcast_txes_with_signed_auth, |prj, cmd| { + foundry_test_utils::util::initialize(prj.root()); + prj.add_script( + "EIP7702Script.s.sol", + r#" +import "forge-std/Script.sol"; +import {Vm} from "forge-std/Vm.sol"; +import {Counter} from "../src/Counter.sol"; +contract EIP7702Script is Script { + uint256 constant PRIVATE_KEY = uint256(bytes32(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80)); + address constant SENDER = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; + function setUp() public {} + function run() public { + vm.startBroadcast(PRIVATE_KEY); + Counter counter = new Counter(); + Counter counter1 = new Counter(); + Counter counter2 = new Counter(); + vm.signAndAttachDelegation(address(counter), PRIVATE_KEY); + Counter(SENDER).increment(); + Counter(SENDER).increment(); + vm.signAndAttachDelegation(address(counter1), PRIVATE_KEY); + Counter(SENDER).setNumber(0); + vm.signAndAttachDelegation(address(counter2), PRIVATE_KEY); + Counter(SENDER).setNumber(0); + vm.stopBroadcast(); + } +} + "#, + ) + .unwrap(); + + let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::PragueEOF.into())); + let (_api, handle) = spawn(node_config).await; + + cmd.args([ + "script", + "script/EIP7702Script.s.sol", + "--rpc-url", + &handle.http_endpoint(), + "-vvvvv", + "--non-interactive", + "--slow", + "--broadcast", + "--evm-version", + "prague", + ]) + .assert_success() + .stdout_eq(str![[r#" +[COMPILING_FILES] with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! +Traces: + [..] EIP7702Script::setUp() + └─ ← [Stop] + + [..] EIP7702Script::run() + ├─ [0] VM::startBroadcast() + │ └─ ← [Return] + ├─ [..] → new Counter@0x5FbDB2315678afecb367f032d93F642f64180aa3 + │ └─ ← [Return] 481 bytes of code + ├─ [..] → new Counter@0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 + │ └─ ← [Return] 481 bytes of code + ├─ [..] → new Counter@0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0 + │ └─ ← [Return] 481 bytes of code + ├─ [0] VM::signAndAttachDelegation(0x5FbDB2315678afecb367f032d93F642f64180aa3, "") + │ └─ ← [Return] (0, 0xd4301eb9f82f747137a5f2c3dc3a5c2d253917cf99ecdc0d49f7bb85313c3159, 0x786d354f0bbd456f44116ddd3aa50475e989d72d8396005e5b3a12cede83fb68, 4, 0x5FbDB2315678afecb367f032d93F642f64180aa3) + ├─ [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::increment() + │ └─ ← [Stop] + ├─ [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::increment() + │ └─ ← [Stop] + ├─ [0] VM::signAndAttachDelegation(0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512, "") + │ └─ ← [Return] (0, 0xaba9128338f7ff036a0d2ecb96d4f4376389005cd565f87aba33b312570af962, 0x69acbe0831fb8ca95338bc4b908dcfebaf7b81b0f770a12c073ceb07b89fbdf3, 7, 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512) + ├─ [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::setNumber(0) + │ └─ ← [Stop] + ├─ [0] VM::signAndAttachDelegation(0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0, "") + │ └─ ← [Return] (1, 0x3a3427b66e589338ce7ea06135650708f9152e93e257b4a5ec6eb86a3e09a2ce, 0x444651c354c89fd3312aafb05948e12c0a16220827a5e467705253ab4d8aa8d3, 9, 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0) + ├─ [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::setNumber(0) + │ └─ ← [Stop] + ├─ [0] VM::stopBroadcast() + │ └─ ← [Return] + └─ ← [Stop] + + +Script ran successfully. + +## Setting up 1 EVM. +========================== +Simulated On-chain Traces: + + [..] → new Counter@0x5FbDB2315678afecb367f032d93F642f64180aa3 + └─ ← [Return] 481 bytes of code + + [..] → new Counter@0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 + └─ ← [Return] 481 bytes of code + + [..] → new Counter@0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0 + └─ ← [Return] 481 bytes of code + + [0] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::increment() + └─ ← [Stop] + + [0] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::increment() + └─ ← [Stop] + + [0] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::setNumber(0) + └─ ← [Stop] + + [0] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::setNumber(0) + └─ ← [Stop] + + +========================== + +Chain 31337 + +[ESTIMATED_GAS_PRICE] + +[ESTIMATED_TOTAL_GAS_USED] + +[ESTIMATED_AMOUNT_REQUIRED] + +========================== + + +========================== + +ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. + +[SAVED_TRANSACTIONS] + +[SAVED_SENSITIVE_VALUES] + + +"#]]); +}); diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index fb2e990f28984..e7735202d6dff 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -3308,9 +3308,9 @@ Traces: ├─ [0] VM::label(alice: [0x328809Bc894f92807417D2dAD6b7C998c1aFdac6], "alice") │ └─ ← [Return] ├─ [0] VM::signDelegation(0x0000000000000000000000000000000000000000, "") - │ └─ ← [Return] (0, 0x3d6ad67cc3dc94101a049f85f96937513a05485ae0f8b27545d25c4f71b12cf9, 0x3c0f2d62834f59d6ef0209e8a935f80a891a236eb18ac0e3700dd8f7ac8ae279, 0, 0x0000000000000000000000000000000000000000) + │ └─ ← [Return] (0, 0x38db2a0ada75402af7cd5bdb8248a1a5b4fec65fdafea4f935084f00dc2ff3c5, 0x29ce7b1c82f9ceaec21f12d690ba8fe6ecba65869caf6ab2d85d79890dc42df2, 1, 0x0000000000000000000000000000000000000000) ├─ [0] VM::signAndAttachDelegation(0x0000000000000000000000000000000000000000, "") - │ └─ ← [Return] (0, 0x3d6ad67cc3dc94101a049f85f96937513a05485ae0f8b27545d25c4f71b12cf9, 0x3c0f2d62834f59d6ef0209e8a935f80a891a236eb18ac0e3700dd8f7ac8ae279, 0, 0x0000000000000000000000000000000000000000) + │ └─ ← [Return] (0, 0x38db2a0ada75402af7cd5bdb8248a1a5b4fec65fdafea4f935084f00dc2ff3c5, 0x29ce7b1c82f9ceaec21f12d690ba8fe6ecba65869caf6ab2d85d79890dc42df2, 1, 0x0000000000000000000000000000000000000000) └─ ← [Stop] ... diff --git a/testdata/default/cheats/AttachDelegation.t.sol b/testdata/default/cheats/AttachDelegation.t.sol index 7b43ce95e4213..026558bdf39c0 100644 --- a/testdata/default/cheats/AttachDelegation.t.sol +++ b/testdata/default/cheats/AttachDelegation.t.sol @@ -46,8 +46,6 @@ contract AttachDelegationTest is DSTest { vm._expectCheatcodeRevert("vm.attachDelegation: invalid nonce"); vm.attachDelegation(signedDelegation); - signedDelegation = vm.signDelegation(address(implementation), alice_pk, 0); - vm.attachDelegation(signedDelegation); signedDelegation = vm.signDelegation(address(implementation), alice_pk, 1); vm.attachDelegation(signedDelegation); } @@ -145,7 +143,6 @@ contract AttachDelegationTest is DSTest { vm._expectCheatcodeRevert("vm.signAndAttachDelegation: invalid nonce"); vm.signAndAttachDelegation(address(implementation), alice_pk, 11); - vm.signAndAttachDelegation(address(implementation), alice_pk, 0); vm.signAndAttachDelegation(address(implementation), alice_pk, 1); } } From 00cbbab6bb5629cf5d9b3cf9f420fce2466da0b0 Mon Sep 17 00:00:00 2001 From: Ishika Choudhury <117741714+Rimeeeeee@users.noreply.github.com> Date: Mon, 12 May 2025 13:38:28 +0530 Subject: [PATCH 076/244] added eth_getAccountInfo to anvil (#10496) * added eth_getAccountInfo to anvil * fixes * fixes --- crates/anvil/core/src/eth/mod.rs | 3 +++ crates/anvil/src/eth/api.rs | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/crates/anvil/core/src/eth/mod.rs b/crates/anvil/core/src/eth/mod.rs index c1c6ab89a1420..ccc866d090c8e 100644 --- a/crates/anvil/core/src/eth/mod.rs +++ b/crates/anvil/core/src/eth/mod.rs @@ -73,6 +73,9 @@ pub enum EthRequest { #[serde(rename = "eth_getAccount")] EthGetAccount(Address, Option), + #[serde(rename = "eth_getAccountInfo")] + EthGetAccountInfo(Address, Option), + #[serde(rename = "eth_getStorageAt")] EthGetStorageAt(Address, U256, Option), diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 6bbb0f30ed48e..58f98785c4d05 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -175,6 +175,9 @@ impl EthApi { EthRequest::EthGetAccount(addr, block) => { self.get_account(addr, block).await.to_rpc_result() } + EthRequest::EthGetAccountInfo(addr, block) => { + self.get_account_info(addr, block).await.to_rpc_result() + } EthRequest::EthGetBalance(addr, block) => { self.balance(addr, block).await.to_rpc_result() } @@ -727,6 +730,25 @@ impl EthApi { self.backend.get_account_at_block(address, Some(block_request)).await } + /// Returns the account information including balance, nonce, code and storage + pub async fn get_account_info( + &self, + address: Address, + block_number: Option, + ) -> Result { + node_info!("eth_getAccountInfo"); + let account = self + .backend + .get_account_at_block(address, Some(self.block_request(block_number).await?)) + .await?; + let code = + self.backend.get_code(address, Some(self.block_request(block_number).await?)).await?; + Ok(serde_json::json!({ + "balance": account.balance, + "nonce": account.nonce, + "code": code + })) + } /// Returns content of the storage at given address. /// /// Handler for ETH RPC call: `eth_getStorageAt` From a31d9be30bb5a2f07c5ceac22affe1b4c6622993 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 12 May 2025 17:39:46 +0100 Subject: [PATCH 077/244] fix: Replay raw txs without tweaks in anvil_reorg (#10442) fix: Replay raw txs without txs in anvil_reorg Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> --- crates/anvil/core/src/eth/transaction/mod.rs | 31 ------- crates/anvil/src/eth/api.rs | 85 ++++++++++---------- 2 files changed, 44 insertions(+), 72 deletions(-) diff --git a/crates/anvil/core/src/eth/transaction/mod.rs b/crates/anvil/core/src/eth/transaction/mod.rs index a5975fa41d2c6..b33dbf2798d85 100644 --- a/crates/anvil/core/src/eth/transaction/mod.rs +++ b/crates/anvil/core/src/eth/transaction/mod.rs @@ -577,37 +577,6 @@ pub enum TypedTransaction { Deposit(DepositTransaction), } -/// This is a function that demotes TypedTransaction to TransactionRequest for greater flexibility -/// over the type. -/// -/// This function is purely for convenience and specific use cases, e.g. RLP encoded transactions -/// decode to TypedTransactions where the API over TypedTransctions is quite strict. -impl TryFrom for TransactionRequest { - type Error = ConversionError; - - fn try_from(value: TypedTransaction) -> Result { - let from = - value.recover().map_err(|_| ConversionError::Custom("InvalidSignature".to_string()))?; - let essentials = value.essentials(); - let tx_type = value.r#type(); - Ok(Self { - from: Some(from), - to: Some(value.kind()), - gas_price: essentials.gas_price, - max_fee_per_gas: essentials.max_fee_per_gas, - max_priority_fee_per_gas: essentials.max_priority_fee_per_gas, - max_fee_per_blob_gas: essentials.max_fee_per_blob_gas, - gas: Some(essentials.gas_limit), - value: Some(essentials.value), - input: essentials.input.into(), - nonce: Some(essentials.nonce), - chain_id: essentials.chain_id, - transaction_type: tx_type, - ..Default::default() - }) - } -} - impl TryFrom for TypedTransaction { type Error = ConversionError; diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 58f98785c4d05..428e54c80d9f9 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -2080,55 +2080,58 @@ impl EthApi { for pair in pairs { let (tx_data, block_index) = pair; - let mut tx_req = match tx_data { - TransactionData::JSON(req) => WithOtherFields::new(req), + let pending = match tx_data { TransactionData::Raw(bytes) => { let mut data = bytes.as_ref(); let decoded = TypedTransaction::decode_2718(&mut data) .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?; - let request = - TransactionRequest::try_from(decoded.clone()).map_err(|_| { - BlockchainError::RpcError(RpcError::invalid_params( - "Failed to convert raw transaction", - )) - })?; - WithOtherFields::new(request) + PendingTransaction::new(decoded)? } - }; - - let from = tx_req.from.map(Ok).unwrap_or_else(|| { - self.accounts()?.first().cloned().ok_or(BlockchainError::NoSignerAvailable) - })?; - // Get the nonce at the common block - let curr_nonce = nonces.entry(from).or_insert( - self.get_transaction_count(from, Some(common_block.header.number.into())) - .await?, - ); + TransactionData::JSON(req) => { + let mut tx_req = WithOtherFields::new(req); + let from = tx_req.from.map(Ok).unwrap_or_else(|| { + self.accounts()? + .first() + .cloned() + .ok_or(BlockchainError::NoSignerAvailable) + })?; + + // Get the nonce at the common block + let curr_nonce = nonces.entry(from).or_insert( + self.get_transaction_count( + from, + Some(common_block.header.number.into()), + ) + .await?, + ); + + // Estimate gas + if tx_req.gas.is_none() { + if let Ok(gas) = self.estimate_gas(tx_req.clone(), None, None).await { + tx_req.gas = Some(gas.to()); + } + } - // Estimate gas - if tx_req.gas.is_none() { - if let Ok(gas) = self.estimate_gas(tx_req.clone(), None, None).await { - tx_req.gas = Some(gas.to()); + // Build typed transaction request + let typed = self.build_typed_tx_request(tx_req, *curr_nonce)?; + + // Increment nonce + *curr_nonce += 1; + + // Handle signer and convert to pending transaction + if self.is_impersonated(from) { + let bypass_signature = self.impersonated_signature(&typed); + let transaction = + sign::build_typed_transaction(typed, bypass_signature)?; + self.ensure_typed_transaction_supported(&transaction)?; + PendingTransaction::with_impersonated(transaction, from) + } else { + let transaction = self.sign_request(&from, typed)?; + self.ensure_typed_transaction_supported(&transaction)?; + PendingTransaction::new(transaction)? + } } - } - - // Build typed transaction request - let typed = self.build_typed_tx_request(tx_req, *curr_nonce)?; - - // Increment nonce - *curr_nonce += 1; - - // Handle signer and convert to pending transaction - let pending = if self.is_impersonated(from) { - let bypass_signature = self.impersonated_signature(&typed); - let transaction = sign::build_typed_transaction(typed, bypass_signature)?; - self.ensure_typed_transaction_supported(&transaction)?; - PendingTransaction::with_impersonated(transaction, from) - } else { - let transaction = self.sign_request(&from, typed)?; - self.ensure_typed_transaction_supported(&transaction)?; - PendingTransaction::new(transaction)? }; let pooled = PoolTransaction::new(pending); From f240a34ac6824d7a5b3d7b25cb9dfe78aee2f4d4 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 13 May 2025 11:10:05 +0300 Subject: [PATCH 078/244] fix(anvil): use saturating_to when check for req funds (#10503) --- crates/anvil/src/eth/backend/mem/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 097e66ee92459..f986fc73d8868 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -3116,7 +3116,7 @@ impl TransactionValidator for Backend { } _ => { // check sufficient funds: `gas * price + value` - let req_funds = max_cost.checked_add(value.to()).ok_or_else(|| { + let req_funds = max_cost.checked_add(value.saturating_to()).ok_or_else(|| { warn!(target: "backend", "[{:?}] cost too high", tx.hash()); InvalidTransactionError::InsufficientFunds })?; From 155220ebe6776c1038f837e8aba1fd019730544f Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 13 May 2025 11:33:14 +0300 Subject: [PATCH 079/244] chore: prepare v1.2 release (#10502) --- .github/workflows/release.yml | 2 +- Cargo.lock | 60 +++++++++++++++++------------------ Cargo.toml | 2 +- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8d96287ebb22c..4bf0543fb7482 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ env: CARGO_TERM_COLOR: always IS_NIGHTLY: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} PROFILE: maxperf - STABLE_VERSION: "v1.0.0" + STABLE_VERSION: "v1.1.0" jobs: prepare: diff --git a/Cargo.lock b/Cargo.lock index 6408030f5fc6c..682063965edaf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -942,7 +942,7 @@ dependencies = [ [[package]] name = "anvil" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-chains", "alloy-consensus", @@ -1002,7 +1002,7 @@ dependencies = [ [[package]] name = "anvil-core" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "anvil-rpc" -version = "1.1.0" +version = "1.2.0" dependencies = [ "serde", "serde_json", @@ -1033,7 +1033,7 @@ dependencies = [ [[package]] name = "anvil-server" -version = "1.1.0" +version = "1.2.0" dependencies = [ "anvil-rpc", "async-trait", @@ -2070,7 +2070,7 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "cast" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-chains", "alloy-consensus", @@ -2166,7 +2166,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chisel" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -3447,7 +3447,7 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "forge" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-chains", "alloy-dyn-abi", @@ -3528,7 +3528,7 @@ dependencies = [ [[package]] name = "forge-doc" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-primitives", "derive_more 2.0.1", @@ -3551,7 +3551,7 @@ dependencies = [ [[package]] name = "forge-fmt" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-primitives", "ariadne", @@ -3567,7 +3567,7 @@ dependencies = [ [[package]] name = "forge-script" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-chains", "alloy-consensus", @@ -3612,7 +3612,7 @@ dependencies = [ [[package]] name = "forge-script-sequence" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-network", "alloy-primitives", @@ -3628,7 +3628,7 @@ dependencies = [ [[package]] name = "forge-sol-macro-gen" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -3643,7 +3643,7 @@ dependencies = [ [[package]] name = "forge-verify" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -3703,7 +3703,7 @@ dependencies = [ [[package]] name = "foundry-cheatcodes" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-chains", "alloy-consensus", @@ -3751,7 +3751,7 @@ dependencies = [ [[package]] name = "foundry-cheatcodes-spec" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-sol-types", "foundry-macros", @@ -3762,7 +3762,7 @@ dependencies = [ [[package]] name = "foundry-cli" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-chains", "alloy-dyn-abi", @@ -3803,7 +3803,7 @@ dependencies = [ [[package]] name = "foundry-common" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-consensus", "alloy-contract", @@ -3860,7 +3860,7 @@ dependencies = [ [[package]] name = "foundry-common-fmt" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -3988,7 +3988,7 @@ dependencies = [ [[package]] name = "foundry-config" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-chains", "alloy-primitives", @@ -4025,7 +4025,7 @@ dependencies = [ [[package]] name = "foundry-debugger" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-primitives", "crossterm", @@ -4043,7 +4043,7 @@ dependencies = [ [[package]] name = "foundry-evm" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4070,7 +4070,7 @@ dependencies = [ [[package]] name = "foundry-evm-abi" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -4082,7 +4082,7 @@ dependencies = [ [[package]] name = "foundry-evm-core" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -4116,7 +4116,7 @@ dependencies = [ [[package]] name = "foundry-evm-coverage" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-primitives", "eyre", @@ -4131,7 +4131,7 @@ dependencies = [ [[package]] name = "foundry-evm-fuzz" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4155,7 +4155,7 @@ dependencies = [ [[package]] name = "foundry-evm-traces" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4205,7 +4205,7 @@ dependencies = [ [[package]] name = "foundry-linking" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-primitives", "foundry-compilers", @@ -4215,7 +4215,7 @@ dependencies = [ [[package]] name = "foundry-macros" -version = "1.1.0" +version = "1.2.0" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -4225,7 +4225,7 @@ dependencies = [ [[package]] name = "foundry-test-utils" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-primitives", "alloy-provider", @@ -4249,7 +4249,7 @@ dependencies = [ [[package]] name = "foundry-wallets" -version = "1.1.0" +version = "1.2.0" dependencies = [ "alloy-consensus", "alloy-dyn-abi", diff --git a/Cargo.toml b/Cargo.toml index e76ac670d7cf7..976d34bd265ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ members = [ resolver = "2" [workspace.package] -version = "1.1.0" +version = "1.2.0" edition = "2021" # Remember to update clippy.toml as well rust-version = "1.83" From e0ad278c4433bc48f1c6ec902f72bf4d980957e0 Mon Sep 17 00:00:00 2001 From: Miguel Palhas Date: Tue, 13 May 2025 09:49:17 +0100 Subject: [PATCH 080/244] fix(anvil): recomputing next-base-fee after reloading state (#10488) * recomputing next-base-fee after reloading state * unit test --------- Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> --- crates/anvil/src/eth/backend/mem/mod.rs | 20 ++++++++++++++++ crates/anvil/tests/it/state.rs | 32 +++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index f986fc73d8868..c21dec7022fd8 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -1006,6 +1006,26 @@ impl Backend { } } + if let Some(block) = state.blocks.last() { + let header = &block.header; + let next_block_base_fee = self.fees.get_next_block_base_fee_per_gas( + header.gas_used as u128, + header.gas_limit as u128, + header.base_fee_per_gas.unwrap_or_default(), + ); + let next_block_excess_blob_gas = self.fees.get_next_block_blob_excess_gas( + header.excess_blob_gas.map(|g| g as u128).unwrap_or_default(), + header.blob_gas_used.map(|g| g as u128).unwrap_or_default(), + ); + + // update next base fee + self.fees.set_base_fee(next_block_base_fee); + self.fees.set_blob_excess_gas_and_price(BlobExcessGasAndPrice::new( + next_block_excess_blob_gas, + false, + )); + } + if !self.db.write().await.load_state(state.clone())? { return Err(RpcError::invalid_params( "Loading state not supported with the current configuration", diff --git a/crates/anvil/tests/it/state.rs b/crates/anvil/tests/it/state.rs index 81235f18eebec..7b262e09baf9b 100644 --- a/crates/anvil/tests/it/state.rs +++ b/crates/anvil/tests/it/state.rs @@ -276,3 +276,35 @@ async fn test_fork_load_state_with_greater_state_block() { assert_eq!(new_block_number, block_number); } + +// +#[tokio::test(flavor = "multi_thread")] +async fn computes_next_base_fee_after_loading_state() { + let tmp = tempfile::tempdir().unwrap(); + let state_file = tmp.path().join("state.json"); + + let (api, handle) = spawn(NodeConfig::test()).await; + + let bob = address!("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); + let alice = address!("0x9276449EaC5b4f7Bc17cFC6700f7BeeB86F9bCd0"); + + let provider = handle.http_provider(); + + let value = Unit::ETHER.wei().saturating_mul(U256::from(1)); // 1 ether + let tx = TransactionRequest::default().with_to(alice).with_value(value).with_from(bob); + let tx = WithOtherFields::new(tx); + + let base_fee_empty_chain = api.backend.fees().base_fee(); + provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap(); + + let base_fee_after_one_tx = api.backend.fees().base_fee(); + // the test is meaningless if this does not hold + assert!(base_fee_empty_chain != base_fee_after_one_tx); + + let ser_state = api.serialized_state(true).await.unwrap(); + foundry_common::fs::write_json_file(&state_file, &ser_state).unwrap(); + + let (api, _handle) = spawn(NodeConfig::test().with_init_state_path(state_file)).await; + let base_fee_after_reload = api.backend.fees().base_fee(); + assert_eq!(base_fee_after_reload, base_fee_after_one_tx); +} From 12b2ed44f8d0667b3c10ce58493466484a66c245 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 13 May 2025 12:09:51 +0300 Subject: [PATCH 081/244] fix(forge): support preproc with try contract creation (#10498) * fix(forge): support preproc with try contract creation * visit nested vars and statements of try stmt --- crates/common/src/preprocessor/deps.rs | 136 ++++++++++++----- crates/forge/tests/cli/test_optimizer.rs | 177 +++++++++++++++++++++++ 2 files changed, 273 insertions(+), 40 deletions(-) diff --git a/crates/common/src/preprocessor/deps.rs b/crates/common/src/preprocessor/deps.rs index e15e21798e9af..5fd3fd6ee64b6 100644 --- a/crates/common/src/preprocessor/deps.rs +++ b/crates/common/src/preprocessor/deps.rs @@ -6,7 +6,7 @@ use foundry_compilers::Updates; use itertools::Itertools; use solar_parse::interface::Session; use solar_sema::{ - hir::{ContractId, Expr, ExprKind, Hir, NamedArg, TypeKind, Visit}, + hir::{CallArgs, ContractId, Expr, ExprKind, Hir, NamedArg, Stmt, StmtKind, TypeKind, Visit}, interface::{data_structures::Never, source_map::FileName, SourceMap}, }; use std::{ @@ -105,6 +105,8 @@ enum BytecodeDependencyKind { value: Option, /// `salt` (if any) used when creating contract. salt: Option, + /// Whether it's a try contract creation statement. + try_stmt: bool, }, } @@ -182,42 +184,17 @@ impl<'hir> Visit<'hir> for BytecodeDependencyCollector<'hir> { fn visit_expr(&mut self, expr: &'hir Expr<'hir>) -> ControlFlow { match &expr.kind { - ExprKind::Call(ty, call_args, named_args) => { - if let ExprKind::New(ty_new) = &ty.kind { - if let TypeKind::Custom(item_id) = ty_new.kind { - if let Some(contract_id) = item_id.as_contract() { - let name_loc = span_to_range(self.source_map, ty_new.span); - let name = &self.src[name_loc]; - - // Calculate offset to remove named args, e.g. for an expression like - // `new Counter {value: 333} ( address(this))` - // the offset will be used to replace `{value: 333} ( ` with `(` - let call_args_offset = if named_args.is_some() && !call_args.is_empty() - { - (call_args.span().lo() - ty_new.span.hi()).to_usize() - } else { - 0 - }; - - let args_len = expr.span.hi() - ty_new.span.hi(); - self.collect_dependency(BytecodeDependency { - kind: BytecodeDependencyKind::New { - name: name.to_string(), - args_length: args_len.to_usize(), - call_args_offset, - value: named_arg( - self.src, - named_args, - "value", - self.source_map, - ), - salt: named_arg(self.src, named_args, "salt", self.source_map), - }, - loc: span_to_range(self.source_map, ty.span), - referenced_contract: contract_id, - }); - } - } + ExprKind::Call(call_expr, call_args, named_args) => { + if let Some(dependency) = handle_call_expr( + self.src, + self.source_map, + expr, + call_expr, + call_args, + named_args, + false, + ) { + self.collect_dependency(dependency); } } ExprKind::Member(member_expr, ident) => { @@ -239,6 +216,78 @@ impl<'hir> Visit<'hir> for BytecodeDependencyCollector<'hir> { } self.walk_expr(expr) } + + fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) -> ControlFlow { + if let StmtKind::Try(stmt_try) = stmt.kind { + if let ExprKind::Call(call_expr, call_args, named_args) = stmt_try.expr.kind { + if let Some(dependency) = handle_call_expr( + self.src, + self.source_map, + &stmt_try.expr, + call_expr, + &call_args, + &named_args, + true, + ) { + self.collect_dependency(dependency); + for clause in stmt_try.clauses { + for &var in clause.args { + self.visit_nested_var(var)?; + } + for stmt in clause.block { + self.visit_stmt(stmt)?; + } + } + return ControlFlow::Continue(()); + } + } + } + self.walk_stmt(stmt) + } +} + +/// Helper function to analyze and extract bytecode dependency from a given call expression. +fn handle_call_expr( + src: &str, + source_map: &SourceMap, + parent_expr: &Expr<'_>, + call_expr: &Expr<'_>, + call_args: &CallArgs<'_>, + named_args: &Option<&[NamedArg<'_>]>, + try_stmt: bool, +) -> Option { + if let ExprKind::New(ty_new) = &call_expr.kind { + if let TypeKind::Custom(item_id) = ty_new.kind { + if let Some(contract_id) = item_id.as_contract() { + let name_loc = span_to_range(source_map, ty_new.span); + let name = &src[name_loc]; + + // Calculate offset to remove named args, e.g. for an expression like + // `new Counter {value: 333} ( address(this))` + // the offset will be used to replace `{value: 333} ( ` with `(` + let call_args_offset = if named_args.is_some() && !call_args.is_empty() { + (call_args.span().lo() - ty_new.span.hi()).to_usize() + } else { + 0 + }; + + let args_len = parent_expr.span.hi() - ty_new.span.hi(); + return Some(BytecodeDependency { + kind: BytecodeDependencyKind::New { + name: name.to_string(), + args_length: args_len.to_usize(), + call_args_offset, + value: named_arg(src, named_args, "value", source_map), + salt: named_arg(src, named_args, "salt", source_map), + try_stmt, + }, + loc: span_to_range(source_map, call_expr.span), + referenced_contract: contract_id, + }) + } + } + } + None } /// Helper function to extract value of a given named arg. @@ -300,8 +349,14 @@ pub(crate) fn remove_bytecode_dependencies( call_args_offset, value, salt, + try_stmt, } => { - let mut update = format!("{name}(payable({vm}.deployCode({{"); + let (mut update, closing_seq) = if *try_stmt { + (String::new(), "})") + } else { + (format!("{name}(payable("), "})))") + }; + update.push_str(&format!("{vm}.deployCode({{")); update.push_str(&format!("_artifact: \"{artifact}\"")); if let Some(value) = value { @@ -327,13 +382,14 @@ pub(crate) fn remove_bytecode_dependencies( update.push('('); } updates.insert((dep.loc.start, dep.loc.end + call_args_offset, update)); + updates.insert(( dep.loc.end + args_length, dep.loc.end + args_length, - ")})))".to_string(), + format!("){closing_seq}"), )); } else { - update.push_str("})))"); + update.push_str(closing_seq); updates.insert((dep.loc.start, dep.loc.end + args_length, update)); } } diff --git a/crates/forge/tests/cli/test_optimizer.rs b/crates/forge/tests/cli/test_optimizer.rs index 8b522e5c95862..6c286c52793ec 100644 --- a/crates/forge/tests/cli/test_optimizer.rs +++ b/crates/forge/tests/cli/test_optimizer.rs @@ -1412,3 +1412,180 @@ Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) "#]]); }); + +// +// Preprocess test contracts with try constructor statements. +forgetest_init!(preprocess_contract_with_try_ctor_stmt, |prj, cmd| { + prj.wipe_contracts(); + prj.update_config(|config| { + config.dynamic_test_linking = true; + }); + + prj.add_source( + "CounterA.sol", + r#" +contract CounterA { + uint256 number; +} + "#, + ) + .unwrap(); + prj.add_source( + "CounterB.sol", + r#" +contract CounterB { + uint256 number; + constructor(uint256 a) payable { + require(a > 0, "ctor failure"); + number = a; + } +} + "#, + ) + .unwrap(); + prj.add_source( + "CounterC.sol", + r#" +contract CounterC { + uint256 number; + constructor(uint256 a) { + require(a > 0, "ctor failure"); + number = a; + } +} + "#, + ) + .unwrap(); + + prj.add_test( + "Counter.t.sol", + r#" +import {Test} from "forge-std/Test.sol"; +import {CounterA} from "../src/CounterA.sol"; +import {CounterB} from "../src/CounterB.sol"; +import {CounterC} from "../src/CounterC.sol"; + +contract CounterTest is Test { + function test_try_counterA_creation() public { + try new CounterA() {} catch { + revert(); + } + } + + function test_try_counterB_creation() public { + try new CounterB(1) {} catch { + revert(); + } + } + + function test_try_counterB_creation_with_salt() public { + try new CounterB{value: 111, salt: bytes32("preprocess_counter_with_salt")}(1) {} catch { + revert(); + } + } + + function test_try_counterC_creation() public { + try new CounterC(2) { + new CounterC(1); + } catch { + revert(); + } + } +} + "#, + ) + .unwrap(); + // All 23 files should properly compile, tests pass. + cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" +... +Compiling 23 files with [..] +... +[PASS] test_try_counterA_creation() (gas: [..]) +[PASS] test_try_counterB_creation() (gas: [..]) +[PASS] test_try_counterB_creation_with_salt() (gas: [..]) +[PASS] test_try_counterC_creation() (gas: [..]) +... + +"#]]); + + // Change CounterB to fail test. + prj.add_source( + "CounterB.sol", + r#" +contract CounterB { + uint256 number; + constructor(uint256 a) payable { + require(a > 11, "ctor failure"); + number = a; + } +} + "#, + ) + .unwrap(); + // Only CounterB should compile. + cmd.assert_failure().stdout_eq(str![[r#" +... +Compiling 1 files with [..] +... +[PASS] test_try_counterA_creation() (gas: [..]) +[FAIL: EvmError: Revert] test_try_counterB_creation() (gas: [..]) +[FAIL: EvmError: Revert] test_try_counterB_creation_with_salt() (gas: [..]) +[PASS] test_try_counterC_creation() (gas: [..]) +... + +"#]]); + + // Change CounterC to fail test in try statement. + prj.add_source( + "CounterC.sol", + r#" +contract CounterC { + uint256 number; + constructor(uint256 a) { + require(a > 1, "ctor failure"); + number = a; + } +} + "#, + ) + .unwrap(); + // Only CounterC should compile. + cmd.assert_failure().stdout_eq(str![[r#" +... +Compiling 1 files with [..] +... +[PASS] test_try_counterA_creation() (gas: [..]) +[FAIL: EvmError: Revert] test_try_counterB_creation() (gas: [..]) +[FAIL: EvmError: Revert] test_try_counterB_creation_with_salt() (gas: [..]) +[FAIL: ctor failure] test_try_counterC_creation() (gas: [..]) +... + +"#]]); + + // Change CounterC to fail test in try statement. + prj.add_source( + "CounterC.sol", + r#" +contract CounterC { + uint256 number; + constructor(uint256 a) { + require(a > 2, "ctor failure"); + number = a; + } +} + "#, + ) + .unwrap(); + // Only CounterC should compile and revert. + cmd.assert_failure().stdout_eq(str![[r#" +... +Compiling 1 files with [..] +... +[PASS] test_try_counterA_creation() (gas: [..]) +[FAIL: EvmError: Revert] test_try_counterB_creation() (gas: [..]) +[FAIL: EvmError: Revert] test_try_counterB_creation_with_salt() (gas: [..]) +[FAIL: EvmError: Revert] test_try_counterC_creation() (gas: [..]) +... + +"#]]); +}); From eef4acdbcb4dd8bfe0894052750b051fe5a31754 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 13 May 2025 13:46:40 +0200 Subject: [PATCH 082/244] feat: add 7702 support to eth-sendtransaction (#10504) --- crates/anvil/core/src/eth/transaction/mod.rs | 21 +++++- crates/anvil/src/eth/api.rs | 11 +++ crates/anvil/src/eth/sign.rs | 4 + crates/anvil/tests/it/eip7702.rs | 78 +++++++++++++++++++- 4 files changed, 112 insertions(+), 2 deletions(-) diff --git a/crates/anvil/core/src/eth/transaction/mod.rs b/crates/anvil/core/src/eth/transaction/mod.rs index b33dbf2798d85..e04a3afb09c36 100644 --- a/crates/anvil/core/src/eth/transaction/mod.rs +++ b/crates/anvil/core/src/eth/transaction/mod.rs @@ -54,7 +54,8 @@ pub fn transaction_request_to_typed( access_list, sidecar, transaction_type, - .. + authorization_list, + chain_id: _, }, other, } = tx; @@ -75,6 +76,23 @@ pub fn transaction_request_to_typed( })); } + // EIP7702 + if transaction_type == Some(4) || authorization_list.is_some() { + return Some(TypedTransactionRequest::EIP7702(TxEip7702 { + nonce: nonce.unwrap_or_default(), + max_fee_per_gas: max_fee_per_gas.unwrap_or_default(), + max_priority_fee_per_gas: max_priority_fee_per_gas.unwrap_or_default(), + gas_limit: gas.unwrap_or_default(), + value: value.unwrap_or(U256::ZERO), + input: input.into_input().unwrap_or_default(), + // requires to + to: to?.into_to()?, + chain_id: 0, + access_list: access_list.unwrap_or_default(), + authorization_list: authorization_list.unwrap(), + })); + } + match ( transaction_type, gas_price, @@ -173,6 +191,7 @@ pub enum TypedTransactionRequest { Legacy(TxLegacy), EIP2930(TxEip2930), EIP1559(TxEip1559), + EIP7702(TxEip7702), EIP4844(TxEip4844Variant), Deposit(TxDeposit), } diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 428e54c80d9f9..6bfc59ec2d4b3 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -3008,6 +3008,15 @@ impl EthApi { } TypedTransactionRequest::EIP1559(m) } + Some(TypedTransactionRequest::EIP7702(mut m)) => { + m.nonce = nonce; + m.chain_id = chain_id; + m.gas_limit = gas_limit; + if max_fee_per_gas.is_none() { + m.max_fee_per_gas = self.gas_price(); + } + TypedTransactionRequest::EIP7702(m) + } Some(TypedTransactionRequest::EIP4844(m)) => { TypedTransactionRequest::EIP4844(match m { // We only accept the TxEip4844 variant which has the sidecar. @@ -3075,6 +3084,7 @@ impl EthApi { ), TypedTransactionRequest::EIP2930(_) | TypedTransactionRequest::EIP1559(_) | + TypedTransactionRequest::EIP7702(_) | TypedTransactionRequest::EIP4844(_) | TypedTransactionRequest::Deposit(_) => Signature::from_scalars_and_parity( B256::with_last_byte(1), @@ -3198,6 +3208,7 @@ fn determine_base_gas_by_kind(request: &WithOtherFields) -> TxKind::Call(_) => MIN_TRANSACTION_GAS, TxKind::Create => MIN_CREATE_GAS, }, + TypedTransactionRequest::EIP7702(_) => MIN_TRANSACTION_GAS, TypedTransactionRequest::EIP2930(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 e2ea036a0cafb..af13baa0d2b4e 100644 --- a/crates/anvil/src/eth/sign.rs +++ b/crates/anvil/src/eth/sign.rs @@ -104,6 +104,7 @@ impl Signer for DevSigner { TypedTransactionRequest::Legacy(mut tx) => Ok(signer.sign_transaction_sync(&mut tx)?), TypedTransactionRequest::EIP2930(mut tx) => Ok(signer.sign_transaction_sync(&mut tx)?), TypedTransactionRequest::EIP1559(mut tx) => Ok(signer.sign_transaction_sync(&mut tx)?), + TypedTransactionRequest::EIP7702(mut tx) => Ok(signer.sign_transaction_sync(&mut tx)?), TypedTransactionRequest::EIP4844(mut tx) => Ok(signer.sign_transaction_sync(&mut tx)?), TypedTransactionRequest::Deposit(_) => { unreachable!("op deposit txs should not be signed") @@ -129,6 +130,9 @@ pub fn build_typed_transaction( TypedTransactionRequest::EIP1559(tx) => { TypedTransaction::EIP1559(tx.into_signed(signature)) } + TypedTransactionRequest::EIP7702(tx) => { + TypedTransaction::EIP7702(tx.into_signed(signature)) + } TypedTransactionRequest::EIP4844(tx) => { TypedTransaction::EIP4844(tx.into_signed(signature)) } diff --git a/crates/anvil/tests/it/eip7702.rs b/crates/anvil/tests/it/eip7702.rs index 85d45eb1c66b3..c09412c85e306 100644 --- a/crates/anvil/tests/it/eip7702.rs +++ b/crates/anvil/tests/it/eip7702.rs @@ -2,7 +2,7 @@ use crate::utils::http_provider; use alloy_consensus::{transaction::TxEip7702, SignableTransaction}; use alloy_network::{ReceiptResponse, TransactionBuilder, TxSignerSync}; use alloy_primitives::{bytes, U256}; -use alloy_provider::Provider; +use alloy_provider::{PendingTransactionConfig, Provider}; use alloy_rpc_types::{Authorization, TransactionRequest}; use alloy_serde::WithOtherFields; use alloy_signer::SignerSync; @@ -76,3 +76,79 @@ async fn can_send_eip7702_tx() { assert_eq!(log.topics().len(), 0); assert_eq!(log.data().data, log_data); } + +#[tokio::test(flavor = "multi_thread")] +async fn can_send_eip7702_request() { + let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into())); + let (api, handle) = spawn(node_config).await; + let provider = http_provider(&handle.http_endpoint()); + + let wallets = handle.dev_wallets().collect::>(); + + // deploy simple contract forwarding calldata to LOG0 + // PUSH7(CALLDATASIZE PUSH0 PUSH0 CALLDATACOPY CALLDATASIZE PUSH0 LOG0) PUSH0 MSTORE PUSH1(7) + // PUSH1(25) RETURN + let logger_bytecode = bytes!("66365f5f37365fa05f5260076019f3"); + + let eip1559_est = provider.estimate_eip1559_fees().await.unwrap(); + + let from = wallets[0].address(); + let tx = TransactionRequest::default() + .with_from(from) + .into_create() + .with_nonce(0) + .with_max_fee_per_gas(eip1559_est.max_fee_per_gas) + .with_max_priority_fee_per_gas(eip1559_est.max_priority_fee_per_gas) + .with_input(logger_bytecode); + + let receipt = provider + .send_transaction(WithOtherFields::new(tx)) + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + assert!(receipt.status()); + + let contract = receipt.contract_address.unwrap(); + let authorization = Authorization { + chain_id: U256::from(31337u64), + address: contract, + nonce: provider.get_transaction_count(from).await.unwrap(), + }; + let signature = wallets[0].sign_hash_sync(&authorization.signature_hash()).unwrap(); + let authorization = authorization.into_signed(signature); + + let log_data = bytes!("11112222"); + let tx = TxEip7702 { + max_fee_per_gas: eip1559_est.max_fee_per_gas, + max_priority_fee_per_gas: eip1559_est.max_priority_fee_per_gas, + gas_limit: 100000, + chain_id: 31337, + to: from, + input: bytes!("11112222"), + authorization_list: vec![authorization], + ..Default::default() + }; + + let sender = wallets[1].address(); + let request = TransactionRequest::from_transaction(tx).with_from(sender); + + api.anvil_impersonate_account(sender).await.unwrap(); + let txhash = api.send_transaction(WithOtherFields::new(request)).await.unwrap(); + + let txhash = provider + .watch_pending_transaction(PendingTransactionConfig::new(txhash)) + .await + .unwrap() + .await + .unwrap(); + + let receipt = provider.get_transaction_receipt(txhash).await.unwrap().unwrap(); + let log = &receipt.inner.inner.logs()[0]; + // assert that log was from EOA which signed authorization + assert_eq!(log.address(), from); + assert_eq!(log.topics().len(), 0); + assert_eq!(log.data().data, log_data); +} From ba15ec34c0f3f8c78eb3d28071b1a533874874d2 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Tue, 13 May 2025 16:38:50 +0400 Subject: [PATCH 083/244] chore: remove `Eof::decode` usage (#10499) * chore: remove Eof::decode * fmt --- crates/cast/src/args.rs | 4 --- crates/cast/src/lib.rs | 19 ------------ crates/cast/src/opts.rs | 4 --- crates/common/fmt/src/eof.rs | 1 - crates/common/fmt/src/lib.rs | 3 -- crates/forge/src/cmd/inspect.rs | 53 ++++----------------------------- crates/forge/tests/cli/eof.rs | 41 ------------------------- 7 files changed, 5 insertions(+), 120 deletions(-) diff --git a/crates/cast/src/args.rs b/crates/cast/src/args.rs index fc6df76364a82..89b19eef406d8 100644 --- a/crates/cast/src/args.rs +++ b/crates/cast/src/args.rs @@ -715,10 +715,6 @@ pub async fn run_command(args: CastArgs) -> Result<()> { sh_println!("{}", serde_json::to_string_pretty(&tx)?)?; } } - CastSubcommand::DecodeEof { eof } => { - let eof = stdin::unwrap_line(eof)?; - sh_println!("{}", SimpleCast::decode_eof(&eof)?)? - } CastSubcommand::TxPool { command } => command.run().await?, }; diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 66a0abc75f78f..c0ae8b4f3e96b 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -36,7 +36,6 @@ use foundry_compilers::flatten::Flattener; use foundry_config::Chain; use futures::{future::Either, FutureExt, StreamExt}; use rayon::prelude::*; -use revm::primitives::Eof; use std::{ borrow::Cow, fmt::Write, @@ -2216,24 +2215,6 @@ impl SimpleCast { let tx = TxEnvelope::decode_2718(&mut tx_hex.as_slice())?; Ok(tx) } - - /// Decodes EOF container bytes - /// Pretty prints the decoded EOF container contents - /// - /// # Example - /// - /// ``` - /// use cast::SimpleCast as Cast; - /// - /// let eof = "0xef0001010004020001005604002000008000046080806040526004361015e100035f80fd5f3560e01c63773d45e01415e1ffee6040600319360112e10028600435906024358201809211e100066020918152f3634e487b7160e01b5f52601160045260245ffd5f80fd0000000000000000000000000124189fc71496f8660db5189f296055ed757632"; - /// let decoded = Cast::decode_eof(&eof)?; - /// println!("{}", decoded); - /// # Ok::<(), eyre::Report>(()) - pub fn decode_eof(eof: &str) -> Result { - let eof_hex = hex::decode(eof)?; - let eof = Eof::decode(eof_hex.into())?; - Ok(pretty_eof(&eof)?) - } } fn strip_0x(s: &str) -> &str { diff --git a/crates/cast/src/opts.rs b/crates/cast/src/opts.rs index 7594d0fe23fc5..90c39900f12c6 100644 --- a/crates/cast/src/opts.rs +++ b/crates/cast/src/opts.rs @@ -1061,10 +1061,6 @@ pub enum CastSubcommand { resolve: bool, }, - /// Decodes EOF container bytes - #[command()] - DecodeEof { eof: Option }, - /// Inspect the TxPool of a node. #[command(visible_alias = "tp")] TxPool { diff --git a/crates/common/fmt/src/eof.rs b/crates/common/fmt/src/eof.rs index 1ae9de70b6b3a..1527d42bb77bc 100644 --- a/crates/common/fmt/src/eof.rs +++ b/crates/common/fmt/src/eof.rs @@ -1,6 +1,5 @@ use comfy_table::{modifiers::UTF8_ROUND_CORNERS, ContentArrangement, Table}; use revm_primitives::{ - eof::{EofBody, EofHeader}, Eof, }; use std::fmt::{self, Write}; diff --git a/crates/common/fmt/src/lib.rs b/crates/common/fmt/src/lib.rs index b76016cd45d25..fa1c4543d6463 100644 --- a/crates/common/fmt/src/lib.rs +++ b/crates/common/fmt/src/lib.rs @@ -11,6 +11,3 @@ pub use exp::{format_int_exp, format_uint_exp, to_exp_notation}; mod ui; pub use ui::{get_pretty_block_attr, get_pretty_tx_attr, EthValue, UIfmt}; - -mod eof; -pub use eof::pretty_eof; diff --git a/crates/forge/src/cmd/inspect.rs b/crates/forge/src/cmd/inspect.rs index 32daac06f6172..77f3e4df34ed1 100644 --- a/crates/forge/src/cmd/inspect.rs +++ b/crates/forge/src/cmd/inspect.rs @@ -1,22 +1,19 @@ -use crate::revm::primitives::Eof; use alloy_json_abi::{EventParam, InternalType, JsonAbi, Param}; -use alloy_primitives::{hex, keccak256, Address}; +use alloy_primitives::{hex, keccak256}; use clap::Parser; use comfy_table::{modifiers::UTF8_ROUND_CORNERS, Cell, Table}; -use eyre::{Context, Result}; +use eyre::Result; use foundry_cli::opts::{BuildOpts, CompilerOpts}; use foundry_common::{ compile::{PathOrContractInfo, ProjectCompiler}, - find_matching_contract_artifact, find_target_path, - fmt::pretty_eof, - shell, + find_matching_contract_artifact, find_target_path, shell, }; use foundry_compilers::artifacts::{ output_selection::{ BytecodeOutputSelection, ContractOutputSelection, DeployedBytecodeOutputSelection, EvmOutputSelection, EwasmOutputSelection, }, - CompactBytecode, StorageLayout, + StorageLayout, }; use regex::Regex; use serde_json::{Map, Value}; @@ -132,12 +129,6 @@ impl InspectArgs { let out = artifact.abi.as_ref().map_or(Map::new(), parse_events); print_errors_events(&out, false)?; } - ContractArtifactField::Eof => { - print_eof(artifact.deployed_bytecode.and_then(|b| b.bytecode))?; - } - ContractArtifactField::EofInit => { - print_eof(artifact.bytecode)?; - } }; Ok(()) @@ -362,8 +353,6 @@ pub enum ContractArtifactField { Ewasm, Errors, Events, - Eof, - EofInit, } macro_rules! impl_value_enum { @@ -451,8 +440,6 @@ impl_value_enum! { Ewasm => "ewasm" | "e-wasm", Errors => "errors" | "er", Events => "events" | "ev", - Eof => "eof" | "eof-container" | "eof-deployed", - EofInit => "eof-init" | "eof-initcode" | "eof-initcontainer", } } @@ -478,10 +465,6 @@ impl From for ContractOutputSelection { Caf::Ewasm => Self::Ewasm(EwasmOutputSelection::All), Caf::Errors => Self::Abi, Caf::Events => Self::Abi, - Caf::Eof => Self::Evm(EvmOutputSelection::DeployedByteCode( - DeployedBytecodeOutputSelection::All, - )), - Caf::EofInit => Self::Evm(EvmOutputSelection::ByteCode(BytecodeOutputSelection::All)), } } } @@ -506,9 +489,7 @@ impl PartialEq for ContractArtifactField { (Self::IrOptimized, Cos::IrOptimized) | (Self::Metadata, Cos::Metadata) | (Self::UserDoc, Cos::UserDoc) | - (Self::Ewasm, Cos::Ewasm(_)) | - (Self::Eof, Cos::Evm(Eos::DeployedByteCode(_))) | - (Self::EofInit, Cos::Evm(Eos::ByteCode(_))) + (Self::Ewasm, Cos::Ewasm(_)) ) } } @@ -568,30 +549,6 @@ fn get_json_str(obj: &impl serde::Serialize, key: Option<&str>) -> Result) -> Result<()> { - let Some(mut bytecode) = bytecode else { eyre::bail!("No bytecode") }; - - // Replace link references with zero address. - if bytecode.object.is_unlinked() { - for (file, references) in bytecode.link_references.clone() { - for (name, _) in references { - bytecode.link(&file, &name, Address::ZERO); - } - } - } - - let Some(bytecode) = bytecode.object.into_bytes() else { - eyre::bail!("Failed to link bytecode"); - }; - - let eof = Eof::decode(bytecode).wrap_err("Failed to decode EOF")?; - - sh_println!("{}", pretty_eof(&eof)?)?; - - Ok(()) -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/forge/tests/cli/eof.rs b/crates/forge/tests/cli/eof.rs index 445980304547d..0c422e5bf8e98 100644 --- a/crates/forge/tests/cli/eof.rs +++ b/crates/forge/tests/cli/eof.rs @@ -1,5 +1,3 @@ -use foundry_compilers::artifacts::ConfigurableContractArtifact; - // Ensure we can build and decode EOF bytecode. forgetest_init!(test_build_with_eof, |prj, cmd| { cmd.forge_fuse() @@ -10,45 +8,6 @@ forgetest_init!(test_build_with_eof, |prj, cmd| { [SOLC_VERSION] [ELAPSED] Compiler run successful! -"#]]); - - // get artifact bytecode - let artifact_path = prj.paths().artifacts.join("Counter.sol/Counter.json"); - let artifact: ConfigurableContractArtifact = - foundry_compilers::utils::read_json_file(&artifact_path).unwrap(); - assert!(artifact.metadata.is_some()); - let bytecode = format!("{}", artifact.bytecode.unwrap().object.into_bytes().unwrap()); - - cmd.cast_fuse() - .args(["decode-eof", bytecode.as_str()]) - .assert_success().stdout_eq(str![[r#" -Header: -╭------------------------+-------╮ -| type_size | 4 | -|------------------------+-------| -| num_code_sections | 1 | -|------------------------+-------| -| code_sizes | [17] | -|------------------------+-------| -| num_container_sections | 1 | -|------------------------+-------| -| container_sizes | [257] | -|------------------------+-------| -| data_size | 0 | -╰------------------------+-------╯ - -Code sections: -╭---+--------+---------+------------------+--------------------------------------╮ -| | Inputs | Outputs | Max stack height | Code | -+================================================================================+ -| 0 | 0 | 128 | 2 | 0x608060405234e100055f6080ee005f80fd | -╰---+--------+---------+------------------+--------------------------------------╯ - -Container sections: -╭---+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------╮ -| 0 | 0xef000101000402000100ab04004300008000056080806040526004361015e100035f80fd5f3560e01c9081633fb5c1cb14e1006d81638381f58a14e100475063d09de08a14e100045fe0ffd534e100325f600319360112e100255f545f198114e10009600190015f555f80f3634e487b7160e01b5f52601160045260245ffd5f80fd5f80fd34e100155f600319360112e100086020905f548152f35f80fd5f80fd34e100166020600319360112e100086004355f555f80f35f80fd5f80fda364697066735822122030195051c5939201983e86f52c88296e7ba03945a054b4e413a7b16cafb76bd96c6578706572696d656e74616cf564736f6c634300081d0041 | -╰---+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------╯ - "#]]); }); From 0a7b3f02b559fcb884f9886274f04a89dec15f9c Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 13 May 2025 14:41:48 +0200 Subject: [PATCH 084/244] fix: sort blocks by number (#10505) --- crates/anvil/src/eth/backend/mem/storage.rs | 8 +++++++- crates/anvil/tests/it/state.rs | 7 ++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/crates/anvil/src/eth/backend/mem/storage.rs b/crates/anvil/src/eth/backend/mem/storage.rs index e024d97505467..f6191d090c77e 100644 --- a/crates/anvil/src/eth/backend/mem/storage.rs +++ b/crates/anvil/src/eth/backend/mem/storage.rs @@ -409,7 +409,13 @@ impl BlockchainStorage { } pub fn serialized_blocks(&self) -> Vec { - self.blocks.values().map(|block| block.clone().into()).collect() + let mut blocks = self + .blocks + .values() + .map(|block| block.clone().into()) + .collect::>(); + blocks.sort_by_key(|block| block.header.number); + blocks } pub fn serialized_transactions(&self) -> Vec { diff --git a/crates/anvil/tests/it/state.rs b/crates/anvil/tests/it/state.rs index 7b262e09baf9b..d642582269e68 100644 --- a/crates/anvil/tests/it/state.rs +++ b/crates/anvil/tests/it/state.rs @@ -290,16 +290,17 @@ async fn computes_next_base_fee_after_loading_state() { let provider = handle.http_provider(); + let base_fee_empty_chain = api.backend.fees().base_fee(); + let value = Unit::ETHER.wei().saturating_mul(U256::from(1)); // 1 ether let tx = TransactionRequest::default().with_to(alice).with_value(value).with_from(bob); let tx = WithOtherFields::new(tx); - let base_fee_empty_chain = api.backend.fees().base_fee(); - provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap(); + let _receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap(); let base_fee_after_one_tx = api.backend.fees().base_fee(); // the test is meaningless if this does not hold - assert!(base_fee_empty_chain != base_fee_after_one_tx); + assert_ne!(base_fee_empty_chain, base_fee_after_one_tx); let ser_state = api.serialized_state(true).await.unwrap(); foundry_common::fs::write_json_file(&state_file, &ser_state).unwrap(); From 58297d3457569989bc5cfbcf88ac43766fa8f4b3 Mon Sep 17 00:00:00 2001 From: Miguel Palhas Date: Tue, 13 May 2025 17:42:48 +0100 Subject: [PATCH 085/244] perf: find latest block for next-base-fee. replaces #10505 (#10511) * perf: find latest block for next-base-fee. replaces #10505 * wip --- crates/anvil/src/eth/backend/mem/mod.rs | 4 ++-- crates/anvil/src/eth/backend/mem/storage.rs | 8 +------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index c21dec7022fd8..0cb4ad0ab65f9 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -1006,8 +1006,8 @@ impl Backend { } } - if let Some(block) = state.blocks.last() { - let header = &block.header; + if let Some(latest) = state.blocks.iter().max_by_key(|b| b.header.number) { + let header = &latest.header; let next_block_base_fee = self.fees.get_next_block_base_fee_per_gas( header.gas_used as u128, header.gas_limit as u128, diff --git a/crates/anvil/src/eth/backend/mem/storage.rs b/crates/anvil/src/eth/backend/mem/storage.rs index f6191d090c77e..e024d97505467 100644 --- a/crates/anvil/src/eth/backend/mem/storage.rs +++ b/crates/anvil/src/eth/backend/mem/storage.rs @@ -409,13 +409,7 @@ impl BlockchainStorage { } pub fn serialized_blocks(&self) -> Vec { - let mut blocks = self - .blocks - .values() - .map(|block| block.clone().into()) - .collect::>(); - blocks.sort_by_key(|block| block.header.number); - blocks + self.blocks.values().map(|block| block.clone().into()).collect() } pub fn serialized_transactions(&self) -> Vec { From 776897b169e17117be345bf4a226e093ca768c17 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Wed, 14 May 2025 10:20:31 +0200 Subject: [PATCH 086/244] chore: account for auths in 7702 min estimated gas (#10512) --- crates/anvil/src/eth/api.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 6bfc59ec2d4b3..dc6e78bb6fedb 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -94,7 +94,7 @@ use futures::{ StreamExt, }; use parking_lot::RwLock; -use revm::primitives::Bytecode; +use revm::primitives::{eip7702::PER_EMPTY_ACCOUNT_COST, Bytecode}; use std::{future::Future, sync::Arc, time::Duration}; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver}; @@ -3208,7 +3208,10 @@ fn determine_base_gas_by_kind(request: &WithOtherFields) -> TxKind::Call(_) => MIN_TRANSACTION_GAS, TxKind::Create => MIN_CREATE_GAS, }, - TypedTransactionRequest::EIP7702(_) => MIN_TRANSACTION_GAS, + TypedTransactionRequest::EIP7702(req) => { + MIN_TRANSACTION_GAS + + req.authorization_list.len() as u128 * PER_EMPTY_ACCOUNT_COST as u128 + } TypedTransactionRequest::EIP2930(req) => match req.to { TxKind::Call(_) => MIN_TRANSACTION_GAS, TxKind::Create => MIN_CREATE_GAS, From 38536c965bde2d155666fdc2d54302b750edee02 Mon Sep 17 00:00:00 2001 From: Yu Zeng Date: Thu, 15 May 2025 17:37:03 +0800 Subject: [PATCH 087/244] fix: fix formating crash caused by non-breaking space in comment. (#10522) fix: fix formating crash caused by non-breaking space in comment --- crates/fmt/src/buffer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fmt/src/buffer.rs b/crates/fmt/src/buffer.rs index 031cccd6169f8..18db4fea0459b 100644 --- a/crates/fmt/src/buffer.rs +++ b/crates/fmt/src/buffer.rs @@ -181,7 +181,7 @@ impl FormatBuffer { .take(self.base_indent_len) .take_while(|(_, _, ch)| ch.is_whitespace()) .last() - .map(|(state, idx, _)| (state, idx + 1)) + .map(|(state, idx, ch)| (state, idx + ch.len_utf8())) .unwrap_or((comment_state, 0)); comment_state = new_comment_state; let trimmed_line = &line[line_start..]; From 73fec683a281be0d2215ab735fac43222e1fd358 Mon Sep 17 00:00:00 2001 From: Philippe Dumonet Date: Thu, 15 May 2025 11:56:08 +0200 Subject: [PATCH 088/244] fix(cast): disassembler PC & end of code push padding (#10520) * fix da * fix da test * fix fmt --- crates/cast/src/lib.rs | 13 +++++++++---- crates/evm/core/src/ic.rs | 24 ++++++++++++++++-------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index c0ae8b4f3e96b..38dc123dde465 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -2387,16 +2387,21 @@ mod tests { #[test] fn disassemble_incomplete_sequence() { let incomplete = &hex!("60"); // PUSH1 - let disassembled = Cast::disassemble(incomplete); - assert!(disassembled.is_err()); + let disassembled = Cast::disassemble(incomplete).unwrap(); + assert_eq!(disassembled, "00000000: PUSH1 0x00\n"); let complete = &hex!("6000"); // PUSH1 0x00 let disassembled = Cast::disassemble(complete); assert!(disassembled.is_ok()); let incomplete = &hex!("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // PUSH32 with 31 bytes - let disassembled = Cast::disassemble(incomplete); - assert!(disassembled.is_err()); + + let disassembled = Cast::disassemble(incomplete).unwrap(); + + assert_eq!( + disassembled, + "00000000: PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00\n" + ); let complete = &hex!("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // PUSH32 with 32 bytes let disassembled = Cast::disassemble(complete); diff --git a/crates/evm/core/src/ic.rs b/crates/evm/core/src/ic.rs index 80fef528c9ac5..d58193dbefd03 100644 --- a/crates/evm/core/src/ic.rs +++ b/crates/evm/core/src/ic.rs @@ -98,17 +98,17 @@ fn make_map(code: &[u8]) -> FxHashMap { } /// Represents a single instruction consisting of the opcode and its immediate data. -pub struct Instruction<'a> { +pub struct Instruction { /// OpCode, if it could be decoded. pub op: Option, /// Immediate data following the opcode. - pub immediate: &'a [u8], + pub immediate: Box<[u8]>, /// Program counter of the opcode. pub pc: u32, } /// Decodes raw opcode bytes into [`Instruction`]s. -pub fn decode_instructions(code: &[u8]) -> Result>> { +pub fn decode_instructions(code: &[u8]) -> Result> { assert!(code.len() <= u32::MAX as usize, "bytecode is too big"); let mut pc = 0usize; @@ -116,16 +116,24 @@ pub fn decode_instructions(code: &[u8]) -> Result>> { while pc < code.len() { let op = OpCode::new(code[pc]); - pc += 1; - let immediate_size = op.map(|op| immediate_size(op, &code[pc..])).unwrap_or(0) as usize; + let next_pc = pc + 1; + let immediate_size = + op.map(|op| immediate_size(op, &code[next_pc..])).unwrap_or(0) as usize; + let is_normal_push = op.map(|op| op.is_push()).unwrap_or(false); - if pc + immediate_size > code.len() { + if !is_normal_push && next_pc + immediate_size > code.len() { eyre::bail!("incomplete sequence of bytecode"); } - steps.push(Instruction { op, pc: pc as u32, immediate: &code[pc..pc + immediate_size] }); + // Ensure immediate is padded if needed. + let immediate_end = (next_pc + immediate_size).min(code.len()); + let mut immediate = vec![0u8; immediate_size]; + let immediate_part = &code[next_pc..immediate_end]; + immediate[..immediate_part.len()].copy_from_slice(immediate_part); + + steps.push(Instruction { op, pc: pc as u32, immediate: immediate.into_boxed_slice() }); - pc += immediate_size; + pc = next_pc + immediate_size; } Ok(steps) From b47cf78425f6d28bae5c90870eacbeea93c1a0e0 Mon Sep 17 00:00:00 2001 From: Mablr <59505383+mablr@users.noreply.github.com> Date: Thu, 15 May 2025 13:04:14 +0200 Subject: [PATCH 089/244] fix(`Makefile`): update `lint-foundry` target to explicitly use nightly (#10526) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 24431a88458a7..3af5189576414 100644 --- a/Makefile +++ b/Makefile @@ -86,7 +86,7 @@ fmt: ## Run all formatters. ./.github/scripts/format.sh --check lint-foundry: - RUSTFLAGS="-Dwarnings" cargo clippy --workspace --all-targets --all-features + RUSTFLAGS="-Dwarnings" cargo +nightly clippy --workspace --all-targets --all-features lint-codespell: ensure-codespell codespell --skip "*.json" From 297d4e25e1da36a0f1a8e3d0f2e6850375bad3a9 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Thu, 15 May 2025 18:19:37 +0300 Subject: [PATCH 090/244] feat(forge): cheatcodes to crosschain sign and attach delegation (#10518) * feat(forge): cheatcodes to crosschain sign and attach delegation * Update crates/cheatcodes/spec/src/vm.rs Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> * Update crates/cheatcodes/spec/src/vm.rs Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> * Update crates/cheatcodes/spec/src/vm.rs Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> * Nits --------- Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- crates/cheatcodes/assets/cheatcodes.json | 62 ++++++++++++++- crates/cheatcodes/spec/src/vm.rs | 12 +++ crates/cheatcodes/src/script.rs | 79 +++++++++++++------ testdata/cheats/Vm.sol | 3 + .../default/cheats/AttachDelegation.t.sol | 49 ++++++++++++ 5 files changed, 179 insertions(+), 26 deletions(-) diff --git a/crates/cheatcodes/assets/cheatcodes.json b/crates/cheatcodes/assets/cheatcodes.json index 5d46978a4fdb9..eb541e269a888 100644 --- a/crates/cheatcodes/assets/cheatcodes.json +++ b/crates/cheatcodes/assets/cheatcodes.json @@ -3252,7 +3252,7 @@ }, { "func": { - "id": "attachDelegation", + "id": "attachDelegation_0", "description": "Designate the next call as an EIP-7702 transaction", "declaration": "function attachDelegation(SignedDelegation calldata signedDelegation) external;", "visibility": "external", @@ -3270,6 +3270,26 @@ "status": "stable", "safety": "safe" }, + { + "func": { + "id": "attachDelegation_1", + "description": "Designate the next call as an EIP-7702 transaction, with optional cross-chain validity.", + "declaration": "function attachDelegation(SignedDelegation calldata signedDelegation, bool crossChain) external;", + "visibility": "external", + "mutability": "", + "signature": "attachDelegation((uint8,bytes32,bytes32,uint64,address),bool)", + "selector": "0xf4460d34", + "selectorBytes": [ + 244, + 70, + 13, + 52 + ] + }, + "group": "scripting", + "status": "stable", + "safety": "safe" + }, { "func": { "id": "blobBaseFee", @@ -9620,6 +9640,26 @@ "status": "stable", "safety": "safe" }, + { + "func": { + "id": "signAndAttachDelegation_2", + "description": "Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction, with optional cross-chain validity.", + "declaration": "function signAndAttachDelegation(address implementation, uint256 privateKey, bool crossChain) external returns (SignedDelegation memory signedDelegation);", + "visibility": "external", + "mutability": "", + "signature": "signAndAttachDelegation(address,uint256,bool)", + "selector": "0xd936e146", + "selectorBytes": [ + 217, + 54, + 225, + 70 + ] + }, + "group": "scripting", + "status": "stable", + "safety": "safe" + }, { "func": { "id": "signCompact_0", @@ -9740,6 +9780,26 @@ "status": "stable", "safety": "safe" }, + { + "func": { + "id": "signDelegation_2", + "description": "Sign an EIP-7702 authorization for delegation, with optional cross-chain validity.", + "declaration": "function signDelegation(address implementation, uint256 privateKey, bool crossChain) external returns (SignedDelegation memory signedDelegation);", + "visibility": "external", + "mutability": "", + "signature": "signDelegation(address,uint256,bool)", + "selector": "0xcdd7563d", + "selectorBytes": [ + 205, + 215, + 86, + 61 + ] + }, + "group": "scripting", + "status": "stable", + "safety": "safe" + }, { "func": { "id": "signP256", diff --git a/crates/cheatcodes/spec/src/vm.rs b/crates/cheatcodes/spec/src/vm.rs index afb687894f863..a75217eaa4742 100644 --- a/crates/cheatcodes/spec/src/vm.rs +++ b/crates/cheatcodes/spec/src/vm.rs @@ -2229,10 +2229,18 @@ interface Vm { #[cheatcode(group = Scripting)] function signDelegation(address implementation, uint256 privateKey, uint64 nonce) external returns (SignedDelegation memory signedDelegation); + /// Sign an EIP-7702 authorization for delegation, with optional cross-chain validity. + #[cheatcode(group = Scripting)] + function signDelegation(address implementation, uint256 privateKey, bool crossChain) external returns (SignedDelegation memory signedDelegation); + /// Designate the next call as an EIP-7702 transaction #[cheatcode(group = Scripting)] function attachDelegation(SignedDelegation calldata signedDelegation) external; + /// Designate the next call as an EIP-7702 transaction, with optional cross-chain validity. + #[cheatcode(group = Scripting)] + function attachDelegation(SignedDelegation calldata signedDelegation, bool crossChain) external; + /// Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction #[cheatcode(group = Scripting)] function signAndAttachDelegation(address implementation, uint256 privateKey) external returns (SignedDelegation memory signedDelegation); @@ -2241,6 +2249,10 @@ interface Vm { #[cheatcode(group = Scripting)] function signAndAttachDelegation(address implementation, uint256 privateKey, uint64 nonce) external returns (SignedDelegation memory signedDelegation); + /// Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction, with optional cross-chain validity. + #[cheatcode(group = Scripting)] + function signAndAttachDelegation(address implementation, uint256 privateKey, bool crossChain) external returns (SignedDelegation memory signedDelegation); + /// Attach an EIP-4844 blob to the next call #[cheatcode(group = Scripting)] function attachBlob(bytes calldata blob) external; diff --git a/crates/cheatcodes/src/script.rs b/crates/cheatcodes/src/script.rs index b3383992c19d8..2b3d6fc8efc24 100644 --- a/crates/cheatcodes/src/script.rs +++ b/crates/cheatcodes/src/script.rs @@ -33,56 +33,85 @@ impl Cheatcode for broadcast_2Call { } } -impl Cheatcode for attachDelegationCall { +impl Cheatcode for attachDelegation_0Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { signedDelegation } = self; - let SignedDelegation { v, r, s, nonce, implementation } = signedDelegation; + attach_delegation(ccx, signedDelegation, false) + } +} - let auth = Authorization { - address: *implementation, - nonce: *nonce, - chain_id: U256::from(ccx.ecx.env.cfg.chain_id), - }; - let signed_auth = SignedAuthorization::new_unchecked( - auth, - *v, - U256::from_be_bytes(r.0), - U256::from_be_bytes(s.0), - ); - write_delegation(ccx, signed_auth.clone())?; - ccx.state.active_delegation = Some(signed_auth); - Ok(Default::default()) +impl Cheatcode for attachDelegation_1Call { + fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { + let Self { signedDelegation, crossChain } = self; + attach_delegation(ccx, signedDelegation, *crossChain) } } impl Cheatcode for signDelegation_0Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { implementation, privateKey } = *self; - sign_delegation(ccx, privateKey, implementation, None, false) + sign_delegation(ccx, privateKey, implementation, None, false, false) } } impl Cheatcode for signDelegation_1Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { implementation, privateKey, nonce } = *self; - sign_delegation(ccx, privateKey, implementation, Some(nonce), false) + sign_delegation(ccx, privateKey, implementation, Some(nonce), false, false) + } +} + +impl Cheatcode for signDelegation_2Call { + fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { + let Self { implementation, privateKey, crossChain } = *self; + sign_delegation(ccx, privateKey, implementation, None, crossChain, false) } } impl Cheatcode for signAndAttachDelegation_0Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { implementation, privateKey } = *self; - sign_delegation(ccx, privateKey, implementation, None, true) + sign_delegation(ccx, privateKey, implementation, None, false, true) } } impl Cheatcode for signAndAttachDelegation_1Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { implementation, privateKey, nonce } = *self; - sign_delegation(ccx, privateKey, implementation, Some(nonce), true) + sign_delegation(ccx, privateKey, implementation, Some(nonce), false, true) } } +impl Cheatcode for signAndAttachDelegation_2Call { + fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { + let Self { implementation, privateKey, crossChain } = *self; + sign_delegation(ccx, privateKey, implementation, None, crossChain, true) + } +} + +/// Helper function to attach an EIP-7702 delegation. +fn attach_delegation( + ccx: &mut CheatsCtxt, + delegation: &SignedDelegation, + cross_chain: bool, +) -> Result { + let SignedDelegation { v, r, s, nonce, implementation } = delegation; + // Set chain id to 0 if universal deployment is preferred. + // See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7702.md#protection-from-malleability-cross-chain + let chain_id = if cross_chain { U256::from(0) } else { U256::from(ccx.ecx.env.cfg.chain_id) }; + + let auth = Authorization { address: *implementation, nonce: *nonce, chain_id }; + let signed_auth = SignedAuthorization::new_unchecked( + auth, + *v, + U256::from_be_bytes(r.0), + U256::from_be_bytes(s.0), + ); + write_delegation(ccx, signed_auth.clone())?; + ccx.state.active_delegation = Some(signed_auth); + Ok(Default::default()) +} + /// Helper function to sign and attach (if needed) an EIP-7702 delegation. /// Uses the provided nonce, otherwise retrieves and increments the nonce of the EOA. fn sign_delegation( @@ -90,6 +119,7 @@ fn sign_delegation( private_key: Uint<256, 4>, implementation: Address, nonce: Option, + cross_chain: bool, attach: bool, ) -> Result> { let signer = PrivateKeySigner::from_bytes(&B256::from(private_key))?; @@ -101,11 +131,9 @@ fn sign_delegation( // If we don't have a nonce then use next auth account nonce. authority_acc.data.info.nonce + 1 }; - let auth = Authorization { - address: implementation, - nonce, - chain_id: U256::from(ccx.ecx.env.cfg.chain_id), - }; + let chain_id = if cross_chain { U256::from(0) } else { U256::from(ccx.ecx.env.cfg.chain_id) }; + + let auth = Authorization { address: implementation, nonce, chain_id }; let sig = signer.sign_hash_sync(&auth.signature_hash())?; // Attach delegation. if attach { @@ -133,6 +161,7 @@ fn write_delegation(ccx: &mut CheatsCtxt, auth: SignedAuthorization) -> Result<( if auth.address.is_zero() { // Set empty code if the delegation address of authority is 0x. + // See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7702.md#behavior. ccx.ecx.journaled_state.set_code_with_hash(authority, Bytecode::default(), KECCAK_EMPTY); } else { let bytecode = Bytecode::new_eip7702(*auth.address()); diff --git a/testdata/cheats/Vm.sol b/testdata/cheats/Vm.sol index c043d29489763..6d054abbfc6ec 100644 --- a/testdata/cheats/Vm.sol +++ b/testdata/cheats/Vm.sol @@ -157,6 +157,7 @@ interface Vm { function assumeNoRevert(PotentialRevert[] calldata potentialReverts) external pure; function attachBlob(bytes calldata blob) external; function attachDelegation(SignedDelegation calldata signedDelegation) external; + function attachDelegation(SignedDelegation calldata signedDelegation, bool crossChain) external; function blobBaseFee(uint256 newBlobBaseFee) external; function blobhashes(bytes32[] calldata hashes) external; function breakpoint(string calldata char) external pure; @@ -474,12 +475,14 @@ interface Vm { function shuffle(uint256[] calldata array) external returns (uint256[] memory); function signAndAttachDelegation(address implementation, uint256 privateKey) external returns (SignedDelegation memory signedDelegation); function signAndAttachDelegation(address implementation, uint256 privateKey, uint64 nonce) external returns (SignedDelegation memory signedDelegation); + function signAndAttachDelegation(address implementation, uint256 privateKey, bool crossChain) external returns (SignedDelegation memory signedDelegation); function signCompact(Wallet calldata wallet, bytes32 digest) external returns (bytes32 r, bytes32 vs); function signCompact(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 vs); function signCompact(bytes32 digest) external pure returns (bytes32 r, bytes32 vs); function signCompact(address signer, bytes32 digest) external pure returns (bytes32 r, bytes32 vs); function signDelegation(address implementation, uint256 privateKey) external returns (SignedDelegation memory signedDelegation); function signDelegation(address implementation, uint256 privateKey, uint64 nonce) external returns (SignedDelegation memory signedDelegation); + function signDelegation(address implementation, uint256 privateKey, bool crossChain) external returns (SignedDelegation memory signedDelegation); function signP256(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 s); function sign(Wallet calldata wallet, bytes32 digest) external returns (uint8 v, bytes32 r, bytes32 s); function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); diff --git a/testdata/default/cheats/AttachDelegation.t.sol b/testdata/default/cheats/AttachDelegation.t.sol index 026558bdf39c0..91535b85718f0 100644 --- a/testdata/default/cheats/AttachDelegation.t.sol +++ b/testdata/default/cheats/AttachDelegation.t.sol @@ -39,6 +39,22 @@ contract AttachDelegationTest is DSTest { assertEq(token.balanceOf(bob), 100); } + function testCallSingleAttachCrossChainDelegation() public { + Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(implementation), alice_pk, true); + SimpleDelegateContract.Call[] memory calls = new SimpleDelegateContract.Call[](1); + bytes memory data = abi.encodeCall(ERC20.mint, (100, bob)); + calls[0] = SimpleDelegateContract.Call({to: address(token), data: data, value: 0}); + // executing as bob to make clear that we don't need to execute the tx as alice + vm.broadcast(bob_pk); + vm.attachDelegation(signedDelegation, true); + + bytes memory code = address(alice).code; + require(code.length > 0, "no code written to alice"); + SimpleDelegateContract(alice).execute(calls); + + assertEq(token.balanceOf(bob), 100); + } + /// forge-config: default.allow_internal_expect_revert = true function testCallSingleAttachDelegationWithNonce() public { Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(implementation), alice_pk, 11); @@ -70,6 +86,26 @@ contract AttachDelegationTest is DSTest { assertEq(token.balanceOf(address(this)), 50); } + function testMultiCallAttachCrossChainDelegation() public { + Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(implementation), alice_pk, true); + vm.broadcast(bob_pk); + vm.attachDelegation(signedDelegation, true); + + SimpleDelegateContract.Call[] memory calls = new SimpleDelegateContract.Call[](2); + calls[0] = + SimpleDelegateContract.Call({to: address(token), data: abi.encodeCall(ERC20.mint, (50, bob)), value: 0}); + calls[1] = SimpleDelegateContract.Call({ + to: address(token), + data: abi.encodeCall(ERC20.mint, (50, address(this))), + value: 0 + }); + + SimpleDelegateContract(alice).execute(calls); + + assertEq(token.balanceOf(bob), 50); + assertEq(token.balanceOf(address(this)), 50); + } + function testSwitchAttachDelegation() public { Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(implementation), alice_pk); @@ -138,6 +174,19 @@ contract AttachDelegationTest is DSTest { assertEq(token.balanceOf(bob), 100); } + function testCallSingleSignAndAttachCrossChainDelegation() public { + SimpleDelegateContract.Call[] memory calls = new SimpleDelegateContract.Call[](1); + bytes memory data = abi.encodeCall(ERC20.mint, (100, bob)); + calls[0] = SimpleDelegateContract.Call({to: address(token), data: data, value: 0}); + vm.signAndAttachDelegation(address(implementation), alice_pk, true); + bytes memory code = address(alice).code; + require(code.length > 0, "no code written to alice"); + vm.broadcast(bob_pk); + SimpleDelegateContract(alice).execute(calls); + + assertEq(token.balanceOf(bob), 100); + } + /// forge-config: default.allow_internal_expect_revert = true function testCallSingleSignAndAttachDelegationWithNonce() public { vm._expectCheatcodeRevert("vm.signAndAttachDelegation: invalid nonce"); From f37b4f0fd6f844f82738824902107943d57af876 Mon Sep 17 00:00:00 2001 From: Mablr <59505383+mablr@users.noreply.github.com> Date: Thu, 15 May 2025 22:44:57 +0200 Subject: [PATCH 091/244] Refactor: abstract global allocator in `foundry-cli` to be used across crates (#10523) Refactor: abstract global allocator in `foundry-cli` to be used cross crates - Conditional allocator type selection with cfg-if macro - Explicit use of `std::alloc::System` if feature "jemalloc" is not enabled - Linking "jemalloc" feature in all crates to "foundry-cli/jemalloc" --- Cargo.lock | 6 ++---- crates/anvil/Cargo.toml | 5 +---- crates/anvil/bin/main.rs | 3 +-- crates/cast/Cargo.toml | 5 +---- crates/cast/bin/main.rs | 3 +-- crates/chisel/Cargo.toml | 5 +---- crates/chisel/bin/main.rs | 3 +-- crates/cli/Cargo.toml | 5 +++++ crates/cli/src/utils/allocator.rs | 18 ++++++++++++++++++ crates/cli/src/utils/mod.rs | 3 +++ crates/forge/Cargo.toml | 5 +---- crates/forge/bin/main.rs | 3 +-- 12 files changed, 36 insertions(+), 28 deletions(-) create mode 100644 crates/cli/src/utils/allocator.rs diff --git a/Cargo.lock b/Cargo.lock index 682063965edaf..e80a5ad52f97b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -993,7 +993,6 @@ dependencies = [ "serde_json", "tempfile", "thiserror 2.0.12", - "tikv-jemallocator", "tokio", "tracing", "tracing-subscriber", @@ -2117,7 +2116,6 @@ dependencies = [ "serde", "serde_json", "tempfile", - "tikv-jemallocator", "tokio", "tracing", "yansi", @@ -2190,7 +2188,6 @@ dependencies = [ "solang-parser", "solar-parse", "strum 0.27.1", - "tikv-jemallocator", "time", "tokio", "tracing", @@ -3514,7 +3511,6 @@ dependencies = [ "svm-rs", "tempfile", "thiserror 2.0.12", - "tikv-jemallocator", "tokio", "toml 0.8.22", "toml_edit", @@ -3771,6 +3767,7 @@ dependencies = [ "alloy-primitives", "alloy-provider", "alloy-rlp", + "cfg-if", "clap", "color-eyre", "dotenvy", @@ -3794,6 +3791,7 @@ dependencies = [ "strsim", "strum 0.27.1", "tempfile", + "tikv-jemallocator", "tokio", "tracing", "tracing-subscriber", diff --git a/crates/anvil/Cargo.toml b/crates/anvil/Cargo.toml index ffbfd9d6e3348..777026f038c0e 100644 --- a/crates/anvil/Cargo.toml +++ b/crates/anvil/Cargo.toml @@ -98,9 +98,6 @@ ctrlc = { version = "3", optional = true } fdlimit = { version = "0.3", optional = true } clap_complete_fig = "4" -[target.'cfg(unix)'.dependencies] -tikv-jemallocator = { workspace = true, optional = true } - [dev-dependencies] alloy-provider = { workspace = true, features = ["txpool-api"] } alloy-pubsub.workspace = true @@ -112,7 +109,7 @@ op-alloy-rpc-types.workspace = true [features] default = ["cli", "jemalloc"] asm-keccak = ["alloy-primitives/asm-keccak"] -jemalloc = ["dep:tikv-jemallocator"] +jemalloc = ["foundry-cli/jemalloc"] cli = ["tokio/full", "cmd"] cmd = [ "clap", diff --git a/crates/anvil/bin/main.rs b/crates/anvil/bin/main.rs index e8ee4306265e1..327264335842a 100644 --- a/crates/anvil/bin/main.rs +++ b/crates/anvil/bin/main.rs @@ -2,9 +2,8 @@ use anvil::args::run; -#[cfg(all(feature = "jemalloc", unix))] #[global_allocator] -static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; +static ALLOC: foundry_cli::utils::Allocator = foundry_cli::utils::new_allocator(); fn main() { if let Err(err) = run() { diff --git a/crates/cast/Cargo.toml b/crates/cast/Cargo.toml index 0f23a854f653b..fc6e4368a8d8f 100644 --- a/crates/cast/Cargo.toml +++ b/crates/cast/Cargo.toml @@ -84,9 +84,6 @@ tracing.workspace = true yansi.workspace = true evmole.workspace = true -[target.'cfg(unix)'.dependencies] -tikv-jemallocator = { workspace = true, optional = true } - [dev-dependencies] anvil.workspace = true foundry-test-utils.workspace = true @@ -94,7 +91,7 @@ foundry-test-utils.workspace = true [features] default = ["jemalloc"] asm-keccak = ["alloy-primitives/asm-keccak"] -jemalloc = ["dep:tikv-jemallocator"] +jemalloc = ["foundry-cli/jemalloc"] aws-kms = ["foundry-wallets/aws-kms", "dep:aws-sdk-kms"] gcp-kms = ["foundry-wallets/gcp-kms", "dep:gcloud-sdk"] isolate-by-default = ["foundry-config/isolate-by-default"] diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index 5cf14dfe8e576..a554d01d7be44 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -3,9 +3,8 @@ use cast::args::run; -#[cfg(all(feature = "jemalloc", unix))] #[global_allocator] -static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; +static ALLOC: foundry_cli::utils::Allocator = foundry_cli::utils::new_allocator(); fn main() { if let Err(err) = run() { diff --git a/crates/chisel/Cargo.toml b/crates/chisel/Cargo.toml index 2e40c92e9f99d..a0154b867817f 100644 --- a/crates/chisel/Cargo.toml +++ b/crates/chisel/Cargo.toml @@ -57,13 +57,10 @@ yansi.workspace = true tracing.workspace = true walkdir.workspace = true -[target.'cfg(unix)'.dependencies] -tikv-jemallocator = { workspace = true, optional = true } - [dev-dependencies] tracing-subscriber.workspace = true [features] default = ["jemalloc"] asm-keccak = ["alloy-primitives/asm-keccak"] -jemalloc = ["dep:tikv-jemallocator"] +jemalloc = ["foundry-cli/jemalloc"] diff --git a/crates/chisel/bin/main.rs b/crates/chisel/bin/main.rs index fcb26f62b1b8c..13f82d136941c 100644 --- a/crates/chisel/bin/main.rs +++ b/crates/chisel/bin/main.rs @@ -2,9 +2,8 @@ use chisel::args::run; -#[cfg(all(feature = "jemalloc", unix))] #[global_allocator] -static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; +static ALLOC: foundry_cli::utils::Allocator = foundry_cli::utils::new_allocator(); fn main() { if let Err(err) = run() { diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index b9dfd5f83d67f..120a114c82a0f 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -31,6 +31,7 @@ alloy-provider.workspace = true alloy-rlp.workspace = true alloy-chains.workspace = true +cfg-if = "1.0" clap = { version = "4", features = ["derive", "env", "unicode", "wrap_help"] } color-eyre.workspace = true dotenvy = "0.15" @@ -55,5 +56,9 @@ tracing-tracy = { version = "0.11", optional = true } [dev-dependencies] tempfile.workspace = true +[target.'cfg(unix)'.dependencies] +tikv-jemallocator = { workspace = true, optional = true } + [features] tracy = ["dep:tracing-tracy"] +jemalloc = ["dep:tikv-jemallocator"] diff --git a/crates/cli/src/utils/allocator.rs b/crates/cli/src/utils/allocator.rs new file mode 100644 index 0000000000000..2d2cb4a69bd91 --- /dev/null +++ b/crates/cli/src/utils/allocator.rs @@ -0,0 +1,18 @@ +//! Abstract global allocator implementation. + +// If jemalloc feature is enabled on Unix systems, use jemalloc as the global allocator. +// Otherwise, explicitly use the system allocator. +cfg_if::cfg_if! { + if #[cfg(all(feature = "jemalloc", unix))] { + type AllocatorInner = tikv_jemallocator::Jemalloc; + } else { + type AllocatorInner = std::alloc::System; + } +} + +pub type Allocator = AllocatorInner; + +/// Creates a new [allocator][Allocator]. +pub const fn new_allocator() -> Allocator { + AllocatorInner {} +} diff --git a/crates/cli/src/utils/mod.rs b/crates/cli/src/utils/mod.rs index 68cb49a6891fd..391d519d05621 100644 --- a/crates/cli/src/utils/mod.rs +++ b/crates/cli/src/utils/mod.rs @@ -26,6 +26,9 @@ pub use suggestions::*; mod abi; pub use abi::*; +mod allocator; +pub use allocator::*; + // reexport all `foundry_config::utils` #[doc(hidden)] pub use foundry_config::utils::*; diff --git a/crates/forge/Cargo.toml b/crates/forge/Cargo.toml index 4f8a20e86c9ad..c03a708a1f38f 100644 --- a/crates/forge/Cargo.toml +++ b/crates/forge/Cargo.toml @@ -93,9 +93,6 @@ opener = "0.7" soldeer-commands.workspace = true quick-junit = "0.5.0" -[target.'cfg(unix)'.dependencies] -tikv-jemallocator = { workspace = true, optional = true } - [dev-dependencies] anvil.workspace = true foundry-test-utils.workspace = true @@ -115,7 +112,7 @@ alloy-signer-local.workspace = true [features] default = ["jemalloc"] asm-keccak = ["alloy-primitives/asm-keccak"] -jemalloc = ["dep:tikv-jemallocator"] +jemalloc = ["foundry-cli/jemalloc"] aws-kms = ["foundry-wallets/aws-kms"] gcp-kms = ["foundry-wallets/gcp-kms"] isolate-by-default = ["foundry-config/isolate-by-default"] diff --git a/crates/forge/bin/main.rs b/crates/forge/bin/main.rs index e198d9a4afc1b..bce1bd085f1fa 100644 --- a/crates/forge/bin/main.rs +++ b/crates/forge/bin/main.rs @@ -3,9 +3,8 @@ use forge::args::run; -#[cfg(all(feature = "jemalloc", unix))] #[global_allocator] -static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; +static ALLOC: foundry_cli::utils::Allocator = foundry_cli::utils::new_allocator(); fn main() { if let Err(err) = run() { From fb9904b17c070ea74f4fc4525c00bc6c403c0acb Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Fri, 16 May 2025 10:56:05 +0300 Subject: [PATCH 092/244] fix(forge): mark prank applied on contract creation too (#10532) --- crates/cheatcodes/src/inspector.rs | 11 +++++++++++ testdata/default/cheats/Prank.t.sol | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index aa07c74ad9003..af38531f42bfe 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -696,14 +696,25 @@ impl Cheatcodes { // Apply our prank if let Some(prank) = &self.get_prank(curr_depth) { if curr_depth >= prank.depth && input.caller() == prank.prank_caller { + let mut prank_applied = false; + // At the target depth we set `msg.sender` if ecx.journaled_state.depth() == prank.depth { input.set_caller(prank.new_caller); + prank_applied = true; } // At the target depth, or deeper, we set `tx.origin` if let Some(new_origin) = prank.new_origin { ecx.env.tx.caller = new_origin; + prank_applied = true; + } + + // If prank applied for first time, then update + if prank_applied { + if let Some(applied_prank) = prank.first_time_applied() { + self.pranks.insert(curr_depth, applied_prank); + } } } } diff --git a/testdata/default/cheats/Prank.t.sol b/testdata/default/cheats/Prank.t.sol index 41c8453528e88..151f0d8306776 100644 --- a/testdata/default/cheats/Prank.t.sol +++ b/testdata/default/cheats/Prank.t.sol @@ -591,3 +591,23 @@ contract C { require(0x769A6A5f81bD725e4302751162A7cb30482A222d == address(this), "wrong address(this) in C"); } } + +contract Counter { + uint256 number; + + function increment() external { + number++; + } +} + +contract Issue10528 is DSTest { + Vm constant vm = Vm(address(bytes20(uint160(uint256(keccak256("hevm cheat code")))))); + + function testStartPrankOnContractCreation() external { + vm.startPrank(address(0x22222)); + Counter counter = new Counter(); + + vm.startPrank(address(0x11111)); + counter.increment(); + } +} From 447ef284e6fc1210028ce6bcffad1c87c9fb7df4 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Fri, 16 May 2025 12:09:09 +0300 Subject: [PATCH 093/244] fix(forge): do not revert if event with count 0 not emitted (#10534) --- crates/cheatcodes/src/inspector.rs | 5 +-- crates/forge/tests/it/repros.rs | 3 ++ testdata/default/repros/Issue10527.t.sol | 42 ++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 testdata/default/repros/Issue10527.t.sol diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index af38531f42bfe..4664f4da15d7c 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -1656,8 +1656,9 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { }) .collect::>(); - // Not all emits were matched. - if self.expected_emits.iter().any(|(expected, _)| !expected.found) { + // Revert if not all emits expected were matched. + if self.expected_emits.iter().any(|(expected, _)| !expected.found && expected.count > 0) + { outcome.result.result = InstructionResult::Revert; outcome.result.output = "log != expected log".abi_encode().into(); return outcome; diff --git a/crates/forge/tests/it/repros.rs b/crates/forge/tests/it/repros.rs index d65fa295e103f..dbbb8783ee163 100644 --- a/crates/forge/tests/it/repros.rs +++ b/crates/forge/tests/it/repros.rs @@ -404,3 +404,6 @@ test_repro!(10302); // https://github.com/foundry-rs/foundry/issues/10477 test_repro!(10477); + +// https://github.com/foundry-rs/foundry/issues/10527 +test_repro!(10527); diff --git a/testdata/default/repros/Issue10527.t.sol b/testdata/default/repros/Issue10527.t.sol new file mode 100644 index 0000000000000..f9149267dbde3 --- /dev/null +++ b/testdata/default/repros/Issue10527.t.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity ^0.8.18; + +import "ds-test/test.sol"; +import "cheats/Vm.sol"; + +contract A { + event Event1(); + event Event2(); + + function foo() public { + emit Event1(); + } + + function bar() public { + emit Event2(); + } +} + +contract Issue10527Test is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + A a; + + function setUp() public { + a = new A(); + } + + function test_foo_Event1() public { + vm.expectEmit(address(a)); + emit A.Event1(); + + a.foo(); + } + + function test_foo_Event2() public { + vm.expectEmit({emitter: address(a), count: 0}); + emit A.Event2(); + + a.foo(); + } +} From 093b0cb61c7c5fb9641a035537f414ab62a17474 Mon Sep 17 00:00:00 2001 From: Philippe Dumonet Date: Fri, 16 May 2025 12:34:44 +0200 Subject: [PATCH 094/244] chore(meta): delete CHANGELOG.md (#10535) --- CHANGELOG.md | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 2d9a4e1a92665..0000000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,37 +0,0 @@ -# Changelog - -## Pre 1.0 - -### Important note for users - -Multiple breaking changes will occur so Semver can be followed as soon as Foundry 1.0 is released. They will be listed here, along with the updates needed for your projects. - -If you need a stable Foundry version, we recommend using the latest pinned nightly of May 2nd, locally and on your CI. - -To use the latest pinned nightly locally, use the following command: - -``` -foundryup --version nightly-e15e33a07c0920189fc336391f538c3dad53da73 -```` - -To use the latest pinned nightly on your CI, modify your Foundry installation step to use an specific version: - -``` -- name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: nightly-e15e33a07c0920189fc336391f538c3dad53da73 -``` - -### Breaking changes - -- [expectEmit](https://github.com/foundry-rs/foundry/pull/4920) will now only work for the next call. -- expectCall will now only work if the call(s) are made exactly after the cheatcode is invoked. -- [expectRevert will now work if the next call does revert](https://github.com/foundry-rs/foundry/pull/4945), instead of expecting a revert during the whole test. - - This will very likely break your tests. Please make sure that all the calls you expect to revert are external, and if not, abstract them into a separate contract so that they can be called externally and the cheatcode can be used. -- `-m`, the deprecated alias for `--mt` or `--match-test`, has now been removed. -- [startPrank will now override the existing prank instead of erroring](https://github.com/foundry-rs/foundry/pull/4826). -- [precompiles will not be compatible with all cheatcodes](https://github.com/foundry-rs/foundry/pull/4905). -- The difficulty and prevrandao cheatcodes now [fail if not used with the correct EVM version](https://github.com/foundry-rs/foundry/pull/4904). -- The default EVM version will be Shanghai. If you're using an EVM chain which is not compatible with [EIP-3855](https://eips.ethereum.org/EIPS/eip-3855) you need to change your EVM version. See [Matt Solomon's thread](https://twitter.com/msolomon44/status/1656411871635972096) for more information. -- Non-existent JSON keys are now processed correctly, and `parseJson` returns non-decodable empty bytes if they do not exist. https://github.com/foundry-rs/foundry/pull/5511 From 9e53778208a2cdb335d5ef794cb13122b8288364 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 16 May 2025 14:11:33 +0200 Subject: [PATCH 095/244] fix(`cast`): respect `full` arg in `cast block` (#10536) fix: respect full arg --- crates/cast/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 38dc123dde465..70447311c719e 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -367,7 +367,7 @@ impl> Cast

{ let block = self .provider .get_block(block) - .full() + .kind(full.into()) .await? .ok_or_else(|| eyre::eyre!("block {:?} not found", block))?; From 71f9b8e645abc24da099912ce4d4ce481d26ffad Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Fri, 16 May 2025 14:04:49 -0400 Subject: [PATCH 096/244] fix(`common`): find target by path if present (#10538) * fix(`common`): prefer to find by path if present * test --- crates/common/src/contracts.rs | 23 ++++++++++++++++++++++ crates/forge/tests/cli/cmd.rs | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/crates/common/src/contracts.rs b/crates/common/src/contracts.rs index ecfb67d67f1cd..f0b30724edf2e 100644 --- a/crates/common/src/contracts.rs +++ b/crates/common/src/contracts.rs @@ -454,6 +454,29 @@ pub fn find_target_path(project: &Project, identifier: &PathOrContractInfo) -> R match identifier { PathOrContractInfo::Path(path) => Ok(canonicalized(project.root().join(path))), PathOrContractInfo::ContractInfo(info) => { + if let Some(path) = info.path.as_ref() { + let path = canonicalized(project.root().join(path)); + let sources = project.sources()?; + let contract_path = sources + .iter() + .find_map(|(src_path, _)| { + if **src_path == path { + return Some(src_path.clone()); + } + None + }) + .ok_or_else(|| { + eyre::eyre!( + "Could not find source file for contract `{}` at {}", + info.name, + path.strip_prefix(project.root()).unwrap().display() + ) + })?; + return Ok(contract_path) + } + // If ContractInfo.path hasn't been provided we try to find the contract using the name. + // This will fail if projects have multiple contracts with the same name. In that case, + // path must be specified. let path = project.find_contract_path(&info.name)?; Ok(path) } diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index cd34f4d646237..15b7a8d3f3436 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -3569,6 +3569,42 @@ forgetest!(test_inspect_contract_with_same_name, |prj, cmd| { ╰-------------------------------+----------╯ +"#]]); +}); + +// +forgetest!(inspect_multiple_contracts_with_different_paths, |prj, cmd| { + prj.add_source( + "Source.sol", + r#" + contract Source { + function foo() public {} + } + "#, + ) + .unwrap(); + + prj.add_source( + "another/Source.sol", + r#" + contract Source { + function bar() public {} + } + "#, + ) + .unwrap(); + + cmd.args(["inspect", "src/another/Source.sol:Source", "methodIdentifiers"]) + .assert_success() + .stdout_eq(str![[r#" + +╭--------+------------╮ +| Method | Identifier | ++=====================+ +| bar() | febb0f7e | +╰--------+------------╯ + + "#]]); }); From 0f8a1ff67a0a417acccc0869290b28a5c3cef3ce Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Sat, 17 May 2025 03:12:57 -0500 Subject: [PATCH 097/244] fix: adds zksync, abstract to diff gas calc (#10539) --- crates/cli/src/utils/cmd.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/cli/src/utils/cmd.rs b/crates/cli/src/utils/cmd.rs index a28b0780e450b..5f6d5b1074a92 100644 --- a/crates/cli/src/utils/cmd.rs +++ b/crates/cli/src/utils/cmd.rs @@ -179,7 +179,10 @@ pub fn has_different_gas_calc(chain_id: u64) -> bool { NamedChain::Moonbeam | NamedChain::MoonbeamDev | NamedChain::Moonriver | - NamedChain::Metis + NamedChain::Metis | + NamedChain::Abstract | + NamedChain::ZkSync | + NamedChain::ZkSyncTestnet ); } false From e7751408f6b2168ad41952699a194225b57fd729 Mon Sep 17 00:00:00 2001 From: Brage <5640782+2xic@users.noreply.github.com> Date: Sat, 17 May 2025 10:19:09 +0200 Subject: [PATCH 098/244] Add standard-json as inspect output field (#10537) * Add standard-json as inspect output field option * Address PR feedback --- crates/forge/src/cmd/inspect.rs | 111 +++++++++++++++++++++----------- crates/forge/tests/cli/cmd.rs | 47 ++++++++++++++ 2 files changed, 120 insertions(+), 38 deletions(-) diff --git a/crates/forge/src/cmd/inspect.rs b/crates/forge/src/cmd/inspect.rs index 77f3e4df34ed1..af0b10a66b5f0 100644 --- a/crates/forge/src/cmd/inspect.rs +++ b/crates/forge/src/cmd/inspect.rs @@ -2,18 +2,21 @@ use alloy_json_abi::{EventParam, InternalType, JsonAbi, Param}; use alloy_primitives::{hex, keccak256}; use clap::Parser; use comfy_table::{modifiers::UTF8_ROUND_CORNERS, Cell, Table}; -use eyre::Result; +use eyre::{eyre, Result}; use foundry_cli::opts::{BuildOpts, CompilerOpts}; use foundry_common::{ compile::{PathOrContractInfo, ProjectCompiler}, find_matching_contract_artifact, find_target_path, shell, }; -use foundry_compilers::artifacts::{ - output_selection::{ - BytecodeOutputSelection, ContractOutputSelection, DeployedBytecodeOutputSelection, - EvmOutputSelection, EwasmOutputSelection, +use foundry_compilers::{ + artifacts::{ + output_selection::{ + BytecodeOutputSelection, ContractOutputSelection, DeployedBytecodeOutputSelection, + EvmOutputSelection, EwasmOutputSelection, + }, + StorageLayout, }, - StorageLayout, + solc::SolcLanguage, }; use regex::Regex; use serde_json::{Map, Value}; @@ -47,8 +50,8 @@ impl InspectArgs { // Map field to ContractOutputSelection let mut cos = build.compiler.extra_output; - if !field.is_default() && !cos.iter().any(|selected| field == *selected) { - cos.push(field.into()); + if !field.can_skip_field() && !cos.iter().any(|selected| field == *selected) { + cos.push(field.try_into()?); } // Run Optimized? @@ -58,6 +61,9 @@ impl InspectArgs { build.compiler.optimize }; + // Get the solc version if specified + let solc_version = build.use_solc.clone(); + // Build modified Args let modified_build_args = BuildOpts { compiler: CompilerOpts { extra_output: cos, optimize: optimized, ..build.compiler }, @@ -129,6 +135,18 @@ impl InspectArgs { let out = artifact.abi.as_ref().map_or(Map::new(), parse_events); print_errors_events(&out, false)?; } + ContractArtifactField::StandardJson => { + let standard_json = if let Some(version) = solc_version { + let version = version.parse()?; + let mut standard_json = + project.standard_json_input(&target_path)?.normalize_evm_version(&version); + standard_json.settings.sanitize(&version, SolcLanguage::Solidity); + standard_json + } else { + project.standard_json_input(&target_path)? + }; + print_json(&standard_json)?; + } }; Ok(()) @@ -353,6 +371,7 @@ pub enum ContractArtifactField { Ewasm, Errors, Events, + StandardJson, } macro_rules! impl_value_enum { @@ -440,31 +459,39 @@ impl_value_enum! { Ewasm => "ewasm" | "e-wasm", Errors => "errors" | "er", Events => "events" | "ev", + StandardJson => "standardJson" | "standard-json" | "standard_json", } } -impl From for ContractOutputSelection { - fn from(field: ContractArtifactField) -> Self { +impl TryFrom for ContractOutputSelection { + type Error = eyre::Error; + + fn try_from(field: ContractArtifactField) -> Result { type Caf = ContractArtifactField; match field { - Caf::Abi => Self::Abi, - Caf::Bytecode => Self::Evm(EvmOutputSelection::ByteCode(BytecodeOutputSelection::All)), - Caf::DeployedBytecode => Self::Evm(EvmOutputSelection::DeployedByteCode( + Caf::Abi => Ok(Self::Abi), + Caf::Bytecode => { + Ok(Self::Evm(EvmOutputSelection::ByteCode(BytecodeOutputSelection::All))) + } + Caf::DeployedBytecode => Ok(Self::Evm(EvmOutputSelection::DeployedByteCode( DeployedBytecodeOutputSelection::All, - )), - Caf::Assembly | Caf::AssemblyOptimized => Self::Evm(EvmOutputSelection::Assembly), - Caf::LegacyAssembly => Self::Evm(EvmOutputSelection::LegacyAssembly), - Caf::MethodIdentifiers => Self::Evm(EvmOutputSelection::MethodIdentifiers), - Caf::GasEstimates => Self::Evm(EvmOutputSelection::GasEstimates), - Caf::StorageLayout => Self::StorageLayout, - Caf::DevDoc => Self::DevDoc, - Caf::Ir => Self::Ir, - Caf::IrOptimized => Self::IrOptimized, - Caf::Metadata => Self::Metadata, - Caf::UserDoc => Self::UserDoc, - Caf::Ewasm => Self::Ewasm(EwasmOutputSelection::All), - Caf::Errors => Self::Abi, - Caf::Events => Self::Abi, + ))), + Caf::Assembly | Caf::AssemblyOptimized => Ok(Self::Evm(EvmOutputSelection::Assembly)), + Caf::LegacyAssembly => Ok(Self::Evm(EvmOutputSelection::LegacyAssembly)), + Caf::MethodIdentifiers => Ok(Self::Evm(EvmOutputSelection::MethodIdentifiers)), + Caf::GasEstimates => Ok(Self::Evm(EvmOutputSelection::GasEstimates)), + Caf::StorageLayout => Ok(Self::StorageLayout), + Caf::DevDoc => Ok(Self::DevDoc), + Caf::Ir => Ok(Self::Ir), + Caf::IrOptimized => Ok(Self::IrOptimized), + Caf::Metadata => Ok(Self::Metadata), + Caf::UserDoc => Ok(Self::UserDoc), + Caf::Ewasm => Ok(Self::Ewasm(EwasmOutputSelection::All)), + Caf::Errors => Ok(Self::Abi), + Caf::Events => Ok(Self::Abi), + Caf::StandardJson => { + Err(eyre!("StandardJson is not supported for ContractOutputSelection")) + } } } } @@ -501,9 +528,9 @@ impl fmt::Display for ContractArtifactField { } impl ContractArtifactField { - /// Returns true if this field is generated by default. - pub const fn is_default(&self) -> bool { - matches!(self, Self::Bytecode | Self::DeployedBytecode) + /// Returns true if this field does not need to be passed to the compiler. + pub const fn can_skip_field(&self) -> bool { + matches!(self, Self::Bytecode | Self::DeployedBytecode | Self::StandardJson) } } @@ -556,14 +583,22 @@ mod tests { #[test] fn contract_output_selection() { for &field in ContractArtifactField::ALL { - let selection: ContractOutputSelection = field.into(); - assert_eq!(field, selection); - - let s = field.as_str(); - assert_eq!(s, field.to_string()); - assert_eq!(s.parse::().unwrap(), field); - for alias in field.aliases() { - assert_eq!(alias.parse::().unwrap(), field); + if field == ContractArtifactField::StandardJson { + let selection: Result = field.try_into(); + assert!(selection + .unwrap_err() + .to_string() + .eq("StandardJson is not supported for ContractOutputSelection")); + } else { + let selection: ContractOutputSelection = field.try_into().unwrap(); + assert_eq!(field, selection); + + let s = field.as_str(); + assert_eq!(s, field.to_string()); + assert_eq!(s.parse::().unwrap(), field); + for alias in field.aliases() { + assert_eq!(alias.parse::().unwrap(), field); + } } } } diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 15b7a8d3f3436..611fc39056351 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -3632,6 +3632,53 @@ forgetest!(inspect_custom_counter_method_identifiers, |prj, cmd| { ╰----------------------------+------------╯ +"#]]); +}); + +forgetest_init!(can_inspect_standard_json, |prj, cmd| { + cmd.args(["inspect", "src/Counter.sol:Counter", "standard-json"]).assert_success().stdout_eq(str![[r#" +{ + "language": "Solidity", + "sources": { + "src/Counter.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED/npragma solidity ^0.8.13;/n/ncontract Counter {/n uint256 public number;/n/n function setNumber(uint256 newNumber) public {/n number = newNumber;/n }/n/n function increment() public {/n number++;/n }/n}/n" + } + }, + "settings": { + "remappings": [ + "forge-std/=lib/forge-std/src/" + ], + "optimizer": { + "enabled": false, + "runs": 200 + }, + "metadata": { + "useLiteralContent": false, + "bytecodeHash": "ipfs", + "appendCBOR": true + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode.object", + "evm.bytecode.sourceMap", + "evm.bytecode.linkReferences", + "evm.deployedBytecode.object", + "evm.deployedBytecode.sourceMap", + "evm.deployedBytecode.linkReferences", + "evm.deployedBytecode.immutableReferences", + "evm.methodIdentifiers", + "metadata" + ] + } + }, + "evmVersion": "cancun", + "viaIR": false, + "libraries": {} + } +} + "#]]); }); From dc6a2160ef1cecf21531eaf6722af9f7f64ca3c7 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sun, 18 May 2025 12:15:08 +0200 Subject: [PATCH 099/244] fix: patch solang-parser (#10509) * fix: patch solang-parser * layout at test * bump * chore: update * update * format layout * fix pragma * chore: update * chore: update * fix: pragma 2 * feat: re-implement pragma --- Cargo.lock | 164 +++++------------- Cargo.toml | 4 +- crates/fmt/src/formatter.rs | 53 ++++-- crates/fmt/src/solang_ext/ast_eq.rs | 29 +++- crates/fmt/src/solang_ext/loc.rs | 12 ++ crates/fmt/src/solang_ext/mod.rs | 11 +- crates/fmt/src/visit.rs | 15 +- .../fmt/testdata/VariableDefinition/fmt.sol | 4 +- .../testdata/VariableDefinition/original.sol | 4 +- .../override-spacing.fmt.sol | 4 +- crates/fmt/tests/formatter.rs | 10 +- crates/forge/src/cmd/fmt.rs | 3 +- 12 files changed, 148 insertions(+), 165 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e80a5ad52f97b..37ddf3367eded 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1211,9 +1211,9 @@ dependencies = [ [[package]] name = "ascii-canvas" -version = "3.0.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +checksum = "ef1e3e699d84ab1b0911a1010c5c106aa34ae89aeac103be5ce0c3859db1e891" dependencies = [ "term", ] @@ -1844,7 +1844,7 @@ dependencies = [ "bitflags 2.9.0", "cexpr", "clang-sys", - "itertools 0.10.5", + "itertools 0.11.0", "lazy_static", "lazycell", "log", @@ -1858,30 +1858,15 @@ dependencies = [ "which 4.4.2", ] -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec 0.6.3", -] - [[package]] name = "bit-set" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "bit-vec 0.8.0", + "bit-vec", ] -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - [[package]] name = "bit-vec" version = "0.8.0" @@ -2178,6 +2163,7 @@ dependencies = [ "foundry-compilers", "foundry-config", "foundry-evm", + "foundry-solang-parser", "regex", "reqwest", "revm", @@ -2185,7 +2171,6 @@ dependencies = [ "semver 1.0.26", "serde", "serde_json", - "solang-parser", "solar-parse", "strum 0.27.1", "time", @@ -2991,16 +2976,6 @@ dependencies = [ "dirs-sys", ] -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - [[package]] name = "dirs-sys" version = "0.5.0" @@ -3009,21 +2984,10 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", - "redox_users 0.5.0", + "redox_users", "windows-sys 0.59.0", ] -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users 0.4.6", - "winapi", -] - [[package]] name = "doctest-file" version = "1.0.0" @@ -3416,9 +3380,9 @@ dependencies = [ [[package]] name = "fixedbitset" -version = "0.4.2" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" @@ -3482,6 +3446,7 @@ dependencies = [ "foundry-debugger", "foundry-evm", "foundry-linking", + "foundry-solang-parser", "foundry-test-utils", "foundry-wallets", "futures", @@ -3504,7 +3469,6 @@ dependencies = [ "serde_json", "similar", "similar-asserts", - "solang-parser", "solar-parse", "soldeer-commands", "strum 0.27.1", @@ -3533,13 +3497,13 @@ dependencies = [ "foundry-common", "foundry-compilers", "foundry-config", + "foundry-solang-parser", "itertools 0.14.0", "mdbook", "rayon", "regex", "serde", "serde_json", - "solang-parser", "thiserror 2.0.12", "toml 0.8.22", "tracing", @@ -3552,9 +3516,9 @@ dependencies = [ "alloy-primitives", "ariadne", "foundry-config", + "foundry-solang-parser", "itertools 0.14.0", "similar-asserts", - "solang-parser", "thiserror 2.0.12", "toml 0.8.22", "tracing", @@ -4221,6 +4185,20 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "foundry-solang-parser" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "113b7633ca67d24a96ad90715d15be108ed8ddd35e7632884126838dfc60c7c9" +dependencies = [ + "itertools 0.14.0", + "lalrpop", + "lalrpop-util", + "phf", + "thiserror 2.0.12", + "unicode-xid", +] + [[package]] name = "foundry-test-utils" version = "1.2.0" @@ -5090,7 +5068,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.61.0", + "windows-core 0.59.0", ] [[package]] @@ -5535,32 +5513,33 @@ dependencies = [ [[package]] name = "lalrpop" -version = "0.20.2" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" +checksum = "7047a26de42016abf8f181b46b398aef0b77ad46711df41847f6ed869a2a1d5b" dependencies = [ "ascii-canvas", - "bit-set 0.5.3", + "bit-set", "ena", - "itertools 0.11.0", + "itertools 0.14.0", "lalrpop-util", "petgraph", "regex", "regex-syntax 0.8.5", + "sha3", "string_cache", "term", - "tiny-keccak", "unicode-xid", "walkdir", ] [[package]] name = "lalrpop-util" -version = "0.20.2" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" +checksum = "e8d05b3fe34b8bd562c338db725dfa9beb9451a48f65f129ccb9538b48d2c93b" dependencies = [ "regex-automata 0.4.9", + "rustversion", ] [[package]] @@ -6503,9 +6482,9 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.6.5" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ "fixedbitset", "indexmap 2.9.0", @@ -6827,8 +6806,8 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ - "bit-set 0.8.0", - "bit-vec 0.8.0", + "bit-set", + "bit-vec", "bitflags 2.9.0", "lazy_static", "num-traits", @@ -7171,17 +7150,6 @@ dependencies = [ "bitflags 2.9.0", ] -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom 0.2.16", - "libredox", - "thiserror 1.0.69", -] - [[package]] name = "redox_users" version = "0.5.0" @@ -8222,20 +8190,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "solang-parser" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" -dependencies = [ - "itertools 0.11.0", - "lalrpop", - "lalrpop-util", - "phf", - "thiserror 1.0.69", - "unicode-xid", -] - [[package]] name = "solar-ast" version = "0.1.2" @@ -8763,13 +8717,12 @@ dependencies = [ [[package]] name = "term" -version = "0.7.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +checksum = "8a984c8d058c627faaf5e8e2ed493fa3c51771889196de1016cf9c1c6e90d750" dependencies = [ - "dirs-next", - "rustversion", - "winapi", + "home", + "windows-sys 0.59.0", ] [[package]] @@ -10030,19 +9983,6 @@ dependencies = [ "windows-targets 0.53.0", ] -[[package]] -name = "windows-core" -version = "0.61.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" -dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", - "windows-link", - "windows-result 0.3.2", - "windows-strings 0.4.0", -] - [[package]] name = "windows-implement" version = "0.58.0" @@ -10065,17 +10005,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "windows-interface" version = "0.58.0" @@ -10152,15 +10081,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-strings" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-sys" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index 976d34bd265ed..96ff120cb30c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -99,7 +99,7 @@ foundry-compilers.opt-level = 3 serde_json.opt-level = 3 serde.opt-level = 3 -solang-parser.opt-level = 3 +foundry-solang-parser.opt-level = 3 lalrpop-util.opt-level = 3 solar-ast.opt-level = 3 @@ -191,7 +191,7 @@ foundry-linking = { path = "crates/linking" } foundry-block-explorers = { version = "0.13.3", default-features = false } foundry-compilers = { version = "0.14.0", default-features = false } foundry-fork-db = "0.12" -solang-parser = "=0.3.3" +solang-parser = { version = "=0.3.7", package = "foundry-solang-parser" } solar-parse = { version = "=0.1.2", default-features = false } solar-sema = { version = "=0.1.2", default-features = false } diff --git a/crates/fmt/src/formatter.rs b/crates/fmt/src/formatter.rs index 98a2adcef86c5..641be5943012a 100644 --- a/crates/fmt/src/formatter.rs +++ b/crates/fmt/src/formatter.rs @@ -2005,6 +2005,12 @@ impl Visitor for Formatter<'_, W> { ); } + if let Some(layout) = &mut contract.layout { + write_chunk!(fmt, "layout at ")?; + fmt.visit_expr(layout.loc(), layout)?; + write_chunk!(fmt, " ")?; + } + write_chunk!(fmt, "{{")?; fmt.indented(1, |fmt| { @@ -2083,28 +2089,37 @@ impl Visitor for Formatter<'_, W> { Ok(()) } - #[instrument(name = "pragma", skip_all)] fn visit_pragma( &mut self, - loc: Loc, - ident: &mut Option, - string: &mut Option, - ) -> Result<()> { - let (ident, string) = (ident.safe_unwrap(), string.safe_unwrap()); + pragma: &mut PragmaDirective, + ) -> std::result::Result<(), Self::Error> { + let loc = pragma.loc(); return_source_if_disabled!(self, loc, ';'); - let pragma_descriptor = if ident.name == "solidity" { - // There are some issues with parsing Solidity's versions with crates like `semver`: - // 1. Ranges like `>=0.4.21<0.6.0` or `>=0.4.21 <0.6.0` are not parseable at all. - // 2. Versions like `0.8.10` got transformed into `^0.8.10` which is not the same. - // TODO: semver-solidity crate :D - &string.string - } else { - &string.string - }; - - write_chunk!(self, string.loc.end(), "pragma {} {};", &ident.name, pragma_descriptor)?; - + match pragma { + PragmaDirective::Identifier(loc, id1, id2) => { + write_chunk!( + self, + loc.start(), + loc.end(), + "pragma {}{}{};", + id1.as_ref().map(|id| id.name.to_string()).unwrap_or_default(), + if id1.is_some() && id2.is_some() { " " } else { "" }, + id2.as_ref().map(|id| id.name.to_string()).unwrap_or_default(), + )?; + } + PragmaDirective::StringLiteral(_loc, id, lit) => { + write_chunk!(self, "pragma {} ", id.name)?; + let StringLiteral { loc, string, .. } = lit; + write_chunk!(self, loc.start(), loc.end(), "\"{string}\";")?; + } + PragmaDirective::Version(loc, id, version) => { + write_chunk!(self, loc.start(), id.loc().end(), "pragma {}", id.name)?; + let version_loc = loc.with_start(version[0].loc().start()); + self.visit_source(version_loc)?; + self.write_semicolon()?; + } + } Ok(()) } @@ -3306,6 +3321,7 @@ impl Visitor for Formatter<'_, W> { VariableAttribute::Visibility(visibility) => Some(visibility.to_string()), VariableAttribute::Constant(_) => Some("constant".to_string()), VariableAttribute::Immutable(_) => Some("immutable".to_string()), + VariableAttribute::StorageType(_) => None, // Unsupported VariableAttribute::Override(loc, idents) => { write_chunk!(self, loc.start(), "override")?; if !idents.is_empty() && self.config.override_spacing { @@ -3314,6 +3330,7 @@ impl Visitor for Formatter<'_, W> { self.visit_list("", idents, Some(loc.start()), Some(loc.end()), false)?; None } + VariableAttribute::StorageLocation(storage) => Some(storage.to_string()), }; if let Some(token) = token { let loc = attribute.loc(); diff --git a/crates/fmt/src/solang_ext/ast_eq.rs b/crates/fmt/src/solang_ext/ast_eq.rs index 3c796a0d00128..1ba1748d84644 100644 --- a/crates/fmt/src/solang_ext/ast_eq.rs +++ b/crates/fmt/src/solang_ext/ast_eq.rs @@ -387,6 +387,8 @@ derive_ast_eq! { (0 A, 1 B) } derive_ast_eq! { (0 A, 1 B, 2 C) } derive_ast_eq! { (0 A, 1 B, 2 C, 3 D) } derive_ast_eq! { (0 A, 1 B, 2 C, 3 D, 4 E) } +derive_ast_eq! { (0 A, 1 B, 2 C, 3 D, 4 E, 5 F) } +derive_ast_eq! { (0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G) } derive_ast_eq! { bool } derive_ast_eq! { u8 } derive_ast_eq! { u16 } @@ -413,7 +415,7 @@ derive_ast_eq! { struct VariableDeclaration { loc, ty, storage, name } } derive_ast_eq! { struct Using { loc, list, ty, global } } derive_ast_eq! { struct UsingFunction { loc, path, oper } } derive_ast_eq! { struct TypeDefinition { loc, name, ty } } -derive_ast_eq! { struct ContractDefinition { loc, ty, name, base, parts } } +derive_ast_eq! { struct ContractDefinition { loc, ty, name, base, layout, parts } } derive_ast_eq! { struct EventParameter { loc, ty, indexed, name } } derive_ast_eq! { struct ErrorParameter { loc, ty, name } } derive_ast_eq! { struct EventDefinition { loc, name, fields, anonymous } } @@ -421,6 +423,13 @@ derive_ast_eq! { struct ErrorDefinition { loc, keyword, name, fields } } derive_ast_eq! { struct StructDefinition { loc, name, fields } } derive_ast_eq! { struct EnumDefinition { loc, name, values } } derive_ast_eq! { struct Annotation { loc, id, value } } +derive_ast_eq! { enum PragmaDirective { + _ + Identifier(loc, id1, id2), + StringLiteral(loc, id, lit), + Version(loc, id, version), + _ +}} derive_ast_eq! { enum UsingList { Error, _ @@ -480,6 +489,7 @@ derive_ast_eq! { enum StorageLocation { Memory(loc), Storage(loc), Calldata(loc), + Transient(loc), _ }} derive_ast_eq! { enum Type { @@ -615,7 +625,7 @@ derive_ast_eq! { enum YulSwitchOptions { derive_ast_eq! { enum SourceUnitPart { _ ContractDefinition(def), - PragmaDirective(loc, ident, string), + PragmaDirective(pragma), ImportDirective(import), EnumDefinition(def), StructDefinition(def), @@ -679,5 +689,20 @@ derive_ast_eq! { enum VariableAttribute { Constant(loc), Immutable(loc), Override(loc, idents), + StorageType(st), + StorageLocation(st), _ }} + +// Who cares +impl AstEq for StorageType { + fn ast_eq(&self, _other: &Self) -> bool { + true + } +} + +impl AstEq for VersionComparator { + fn ast_eq(&self, _other: &Self) -> bool { + true + } +} diff --git a/crates/fmt/src/solang_ext/loc.rs b/crates/fmt/src/solang_ext/loc.rs index 54bf771c6df90..6261e08c637ee 100644 --- a/crates/fmt/src/solang_ext/loc.rs +++ b/crates/fmt/src/solang_ext/loc.rs @@ -90,6 +90,17 @@ impl CodeLocationExt for pt::ImportPath { } } +impl CodeLocationExt for pt::VersionComparator { + fn loc(&self) -> pt::Loc { + match self { + Self::Plain { loc, .. } | + Self::Operator { loc, .. } | + Self::Or { loc, .. } | + Self::Range { loc, .. } => *loc, + } + } +} + macro_rules! impl_delegate { ($($t:ty),+ $(,)?) => {$( impl CodeLocationExt for $t { @@ -111,6 +122,7 @@ impl_delegate! { pt::ErrorParameter, pt::EventDefinition, pt::EventParameter, + pt::PragmaDirective, // pt::FunctionDefinition, pt::HexLiteral, pt::Identifier, diff --git a/crates/fmt/src/solang_ext/mod.rs b/crates/fmt/src/solang_ext/mod.rs index aa4fe734ee64f..3aa7c526c5ba1 100644 --- a/crates/fmt/src/solang_ext/mod.rs +++ b/crates/fmt/src/solang_ext/mod.rs @@ -11,11 +11,12 @@ pub mod pt { EnumDefinition, ErrorDefinition, ErrorParameter, EventDefinition, EventParameter, Expression, FunctionAttribute, FunctionDefinition, FunctionTy, HexLiteral, Identifier, IdentifierPath, Import, ImportPath, Loc, Mutability, NamedArgument, OptionalCodeLocation, - Parameter, ParameterList, SourceUnit, SourceUnitPart, Statement, StorageLocation, - StringLiteral, StructDefinition, Type, TypeDefinition, UserDefinedOperator, Using, - UsingFunction, UsingList, VariableAttribute, VariableDeclaration, VariableDefinition, - Visibility, YulBlock, YulExpression, YulFor, YulFunctionCall, YulFunctionDefinition, - YulStatement, YulSwitch, YulSwitchOptions, YulTypedIdentifier, + Parameter, ParameterList, PragmaDirective, SourceUnit, SourceUnitPart, Statement, + StorageLocation, StringLiteral, StructDefinition, Type, TypeDefinition, + UserDefinedOperator, Using, UsingFunction, UsingList, VariableAttribute, + VariableDeclaration, VariableDefinition, Visibility, YulBlock, YulExpression, YulFor, + YulFunctionCall, YulFunctionDefinition, YulStatement, YulSwitch, YulSwitchOptions, + YulTypedIdentifier, }; } diff --git a/crates/fmt/src/visit.rs b/crates/fmt/src/visit.rs index db6287b72209d..b0d93ce0e84c6 100644 --- a/crates/fmt/src/visit.rs +++ b/crates/fmt/src/visit.rs @@ -1,6 +1,6 @@ //! Visitor helpers to traverse the [solang Solidity Parse Tree](solang_parser::pt). -use crate::solang_ext::pt::*; +use crate::solang_ext::{pt::*, CodeLocationExt}; /// A trait that is invoked while traversing the Solidity Parse Tree. /// Each method of the [Visitor] trait is a hook that can be potentially overridden. @@ -25,13 +25,8 @@ pub trait Visitor { self.visit_source(annotation.loc) } - fn visit_pragma( - &mut self, - loc: Loc, - _ident: &mut Option, - _str: &mut Option, - ) -> Result<(), Self::Error> { - self.visit_source(loc) + fn visit_pragma(&mut self, pragma: &mut PragmaDirective) -> Result<(), Self::Error> { + self.visit_source(pragma.loc()) } fn visit_import_plain( @@ -331,7 +326,7 @@ pub trait Visitor { _expr: &mut Option<&mut YulExpression>, ) -> Result<(), Self::Error> where - T: Visitable + CodeLocation, + T: Visitable + CodeLocationExt, { self.visit_source(loc) } @@ -459,7 +454,7 @@ impl Visitable for SourceUnitPart { { match self { Self::ContractDefinition(contract) => v.visit_contract(contract), - Self::PragmaDirective(loc, ident, str) => v.visit_pragma(*loc, ident, str), + Self::PragmaDirective(pragma) => v.visit_pragma(pragma), Self::ImportDirective(import) => import.visit(v), Self::EnumDefinition(enumeration) => v.visit_enum(enumeration), Self::StructDefinition(structure) => v.visit_struct(structure), diff --git a/crates/fmt/testdata/VariableDefinition/fmt.sol b/crates/fmt/testdata/VariableDefinition/fmt.sol index 9ff53c8d55237..85a88e5326de8 100644 --- a/crates/fmt/testdata/VariableDefinition/fmt.sol +++ b/crates/fmt/testdata/VariableDefinition/fmt.sol @@ -1,5 +1,7 @@ // config: line_length = 40 -contract Contract { +contract Contract layout at 69 { + bytes32 transient a; + bytes32 private constant BYTES; bytes32 private diff --git a/crates/fmt/testdata/VariableDefinition/original.sol b/crates/fmt/testdata/VariableDefinition/original.sol index bd15a6384601b..279c62e55b30c 100644 --- a/crates/fmt/testdata/VariableDefinition/original.sol +++ b/crates/fmt/testdata/VariableDefinition/original.sol @@ -1,4 +1,6 @@ -contract Contract { +contract Contract layout at 69 { + bytes32 transient a; + bytes32 constant private BYTES; bytes32 private constant override (Base1) BYTES; bytes32 private constant override (Base1, Base2) BYTES; diff --git a/crates/fmt/testdata/VariableDefinition/override-spacing.fmt.sol b/crates/fmt/testdata/VariableDefinition/override-spacing.fmt.sol index 5fde30038126e..41ef397f65156 100644 --- a/crates/fmt/testdata/VariableDefinition/override-spacing.fmt.sol +++ b/crates/fmt/testdata/VariableDefinition/override-spacing.fmt.sol @@ -1,6 +1,8 @@ // config: line_length = 40 // config: override_spacing = true -contract Contract { +contract Contract layout at 69 { + bytes32 transient a; + bytes32 private constant BYTES; bytes32 private diff --git a/crates/fmt/tests/formatter.rs b/crates/fmt/tests/formatter.rs index 4aac7e05256bd..06a714ea32cb0 100644 --- a/crates/fmt/tests/formatter.rs +++ b/crates/fmt/tests/formatter.rs @@ -107,8 +107,14 @@ fn test_formatter( assert_eof(expected_source); - let source_parsed = parse(source).unwrap(); - let expected_parsed = parse(expected_source).unwrap(); + let source_parsed = match parse(source) { + Ok(p) => p, + Err(e) => panic!("{e}"), + }; + let expected_parsed = match parse(expected_source) { + Ok(p) => p, + Err(e) => panic!("{e}"), + }; if !test_config.skip_compare_ast_eq && !source_parsed.pt.ast_eq(&expected_parsed.pt) { similar_asserts::assert_eq!( diff --git a/crates/forge/src/cmd/fmt.rs b/crates/forge/src/cmd/fmt.rs index 26f601d7bbac1..104c3224829c5 100644 --- a/crates/forge/src/cmd/fmt.rs +++ b/crates/forge/src/cmd/fmt.rs @@ -123,7 +123,8 @@ impl FmtArgs { solang_parser::parse(&output, 0).map_err(|diags| { eyre::eyre!( "Failed to construct valid Solidity code for {name}. Leaving source unchanged.\n\ - Debug info: {diags:?}" + Debug info: {diags:?}\n\ + Formatted output:\n\n{output}" ) })?; From d381a8aab3196ca53366e2584bcdb4210febfc5c Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Mon, 19 May 2025 10:10:38 +0300 Subject: [PATCH 100/244] fix(forge): vm.cool mark cold instead storage cleaning (#10546) --- crates/cheatcodes/src/evm.rs | 2 +- crates/forge/tests/cli/test_cmd.rs | 44 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/crates/cheatcodes/src/evm.rs b/crates/cheatcodes/src/evm.rs index 8b7d714d3dd8f..543b6189784e9 100644 --- a/crates/cheatcodes/src/evm.rs +++ b/crates/cheatcodes/src/evm.rs @@ -588,7 +588,7 @@ impl Cheatcode for coolCall { let Self { target } = self; if let Some(account) = ccx.ecx.journaled_state.state.get_mut(target) { account.unmark_touch(); - account.storage.clear(); + account.storage.values_mut().for_each(|slot| slot.mark_cold()); } Ok(Default::default()) } diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index e7735202d6dff..4035cf2a8ae11 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -3600,3 +3600,47 @@ Ran 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests) "#]]); }); + +// +forgetest_init!(should_not_panic_on_cool, |prj, cmd| { + prj.add_test( + "Counter.t.sol", + r#" +import "forge-std/Test.sol"; +import {Counter} from "../src/Counter.sol"; + +contract CounterTest is Test { + Counter counter = new Counter(); + + function testCoolPanic() public { + address alice = makeAddr("alice"); + vm.deal(alice, 10000 ether); + counter.setNumber(1); + vm.cool(address(counter)); + vm.prank(alice); + payable(address(counter)).transfer(1 ether); + } +} + "#, + ) + .unwrap(); + + cmd.args(["test", "--mc", "CounterTest"]).assert_failure().stdout_eq(str![[r#" +[COMPILING_FILES] with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 1 test for test/Counter.t.sol:CounterTest +[FAIL: EvmError: Revert] testCoolPanic() ([GAS]) +Suite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests) + +Failing tests: +Encountered 1 failing test in test/Counter.t.sol:CounterTest +[FAIL: EvmError: Revert] testCoolPanic() ([GAS]) + +Encountered a total of 1 failing tests, 0 tests succeeded + +"#]]); +}); From 477876a87fea0cd8e2c398f23f836189f2aad58c Mon Sep 17 00:00:00 2001 From: Gregory Markou <16929357+GregTheGreek@users.noreply.github.com> Date: Mon, 19 May 2025 10:07:17 +0200 Subject: [PATCH 101/244] feat(cast): Verbose signing output (#10529) * add verbose logging * respect pipe as default * add verbose signing to signAuth --- crates/cast/src/cmd/wallet/mod.rs | 50 +++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/crates/cast/src/cmd/wallet/mod.rs b/crates/cast/src/cmd/wallet/mod.rs index 52d24c01b6941..71cdcabac2825 100644 --- a/crates/cast/src/cmd/wallet/mod.rs +++ b/crates/cast/src/cmd/wallet/mod.rs @@ -454,7 +454,29 @@ impl WalletSubcommands { } else { wallet.sign_message(&Self::hex_str_to_bytes(&message)?).await? }; - sh_println!("0x{}", hex::encode(sig.as_bytes()))?; + + if shell::verbosity() > 0 { + if shell::is_json() { + sh_println!( + "{}", + serde_json::to_string_pretty(&json!({ + "message": message, + "address": wallet.address(), + "signature": hex::encode(sig.as_bytes()), + }))? + )?; + } else { + sh_println!( + "Successfully signed!\n Message: {}\n Address: {}\n Signature: 0x{}", + message, + wallet.address(), + hex::encode(sig.as_bytes()), + )?; + } + } else { + // Pipe friendly output + sh_println!("0x{}", hex::encode(sig.as_bytes()))?; + } } Self::SignAuth { rpc, nonce, chain, wallet, address } => { let wallet = wallet.signer().await?; @@ -472,7 +494,31 @@ impl WalletSubcommands { let auth = Authorization { chain_id: U256::from(chain_id), address, nonce }; let signature = wallet.sign_hash(&auth.signature_hash()).await?; let auth = auth.into_signed(signature); - sh_println!("{}", hex::encode_prefixed(alloy_rlp::encode(&auth)))?; + + if shell::verbosity() > 0 { + if shell::is_json() { + sh_println!( + "{}", + serde_json::to_string_pretty(&json!({ + "nonce": nonce, + "chain_id": chain_id, + "address": wallet.address(), + "signature": hex::encode_prefixed(alloy_rlp::encode(&auth)), + }))? + )?; + } else { + sh_println!( + "Successfully signed!\n Nonce: {}\n Chain ID: {}\n Address: {}\n Signature: 0x{}", + nonce, + chain_id, + wallet.address(), + hex::encode_prefixed(alloy_rlp::encode(&auth)), + )?; + } + } else { + // Pipe friendly output + sh_println!("{}", hex::encode_prefixed(alloy_rlp::encode(&auth)))?; + } } Self::Verify { message, signature, address } => { let recovered_address = Self::recover_address_from_message(&message, &signature)?; From 39f524d6f01f1edddcfccddac4b14611a8300326 Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Mon, 19 May 2025 14:51:44 +0200 Subject: [PATCH 102/244] ci: fix flaky fork test using `StdChains`, add temporary workaround for `eth.llamarpc.com` being down (#10549) add temporary workaround for eth.llamarpc.com being down --- crates/forge/tests/cli/test_cmd.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index 4035cf2a8ae11..bec547b078394 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -3551,6 +3551,13 @@ contract CounterTest is Test { mapping(uint256 => SomeStruct) internal data; function setUp() public { + // Temporary workaround for `https://eth.llamarpc.com/` being down + setChain("mainnet", ChainData({ + name: "mainnet", + rpcUrl: "https://reth-ethereum.ithaca.xyz/rpc", + chainId: 1 + })); + StdChains.Chain memory chain1 = getChain("mainnet"); StdChains.Chain memory chain2 = getChain("base"); Domain memory domain1 = Domain(chain1, vm.createFork(chain1.rpcUrl, 22253716)); From 066e0ce084ddb23b170558061cc40ea32fdd6fe2 Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Mon, 19 May 2025 15:03:25 +0200 Subject: [PATCH 103/244] bump(`revm`: step 1): bump `revm` to `21.0.0` release (#10183) * start fixing imports * continue fixing imports * continue fixing imports * continue fixing imports * add alloy-evm * fix known good changes * more known good fixes * more known good fixes * more known good fixes * more known good fixes, unclear how OptimismFields should be ported * start introducing crate::Env * continue introducing crate::Env * fix cow types * fix type * add journaledstate types, fix env types * fix JournaledState = JournalInner * fix types * fix merge type * add odyssey precompile * continue fixing type issues, handler abstraction * start working on create2 handler * revert to type instead of struct, investigating handlers * comment out accesslistinspector for now, needs to be addressed * fix imports, minor fixes * imports, minor fixes, there is no equivalent of AuthorizationList - requires slight refactor * more interpreter type fixes * continue type fixes * fix inspectorext * start porting inspectors * start adding custom evm * continue adding custom FoundryEvm * impl traits for FoundryEvm * restructure, move out of utils into evm, precompiles and future handlers * clean up * clean up * improve docs * scaffold handler * evaluate how to add handles * prefer EnvRef over EnvMut * address feedback of owned env * revert get_or_insert_map workaround * avoid changing types, leave mut where previously, avoid unnecessary mut * start layout out handler registry connected to evm * get create2 from frame inputs * start adding create2 handler * continue create2handler * wrap up create2 handler * clean up * continue fixing types * generalize precompiles * clean up * tag inline * fix imports * start fixing cheatcode types * use `env` on handler * clean up * temp revert * odyssey precompile was deprecated * refix cheatcode types * clean up * still facing issues with borrow-checker, double mut * open questions around passing around env * minor fix * for now work around mutability limitations by limited cloning, unclear performance impact or whether it will work with cheatcode macros * continue fixing types, still issues around cheatcodes, inspector * bump revm * bump deps * minor type fixes * bump foundry-fork-db to handle c-kzg build issue * bump rust version * utilize Host, ContextTr, JournalTr to avoid double mutable borrows * temp revert * temp revert * restore handler, improve types * refactor types * restore types * restore, clean up * continue fixing types * clean up * continue fixing types * revert journal env cloning, still issues around double borrows * fix core types per conversation, use EnvMut<'_> * fix types * more progress for foundry-evm * mutate outcome in place * temp revert exec_create * some progress with porting with_evm core loop * remove redundant types * context -> test_context in Cheatcodes config * construct new handler, wrapping evm context, imports Handler trait * temporarily comment out exec_create section to unblock * add replacement of EnvWithHandlerCfg * minor fixes * continue fixing types * continue fixing types * continue fixing types * continue fixing types * continue types * fix cached_env * remove possibly incorrect handling of CreateOutcome on methods like do_eofcreate_end as outcome is now mutated in place * add custom_printer from revm19, porting for compatibility * cast: fix types * verify: fix types * forge + script: fix types * anvil: start fixing types * anvil: continue porting types * anvil: continue porting types * anvil: continue porting types * anvil: continue porting types, small fix in foundry-evm * use AnvilEvm * stash optimism hardfork specifics for now * temp mute anvil use in forge * apply apparant fixes, test still failing * clean up * revert to replay * apply possible nonce 0/1 fixes, committed to proceed * disable nonce check in local_evm_env * undo is_odyssey remove * always spawn evm with handler * replay() -> inspect_replay() * modify macro, comment out anvil related cast tests for the time being * reapply state depth = 1 * something like this? * introduce outer block for early return * print debugging * clean up * fix merge * migrate: anvil to revm 21 (#10361) * downgrade op-revm to 2.0.0 to resolve dep conflict * op-revm 3.0 uses revm 22 * add `as_mut_dyn` to trait `MaybeFullDatabase` as we now require mut db_ref access ( * Revert "add `as_mut_dyn` to trait `MaybeFullDatabase` as we now require mut db_ref access (" This reverts commit 84d11f1742df768d773253de216a223a7d4683e6. * fix: Inspector should be generic over CTX not DB * fixes helpers: new_evm_with_inspector_* to use CTX generic * fix: pass TxEnv to evm.transact * fix: inspector inference in TransactionExecutor and build_access_list_with_state * workaround: dup LogCollector to use with AnvilEvmContext * coz FoundryEvmContext is not generic over DB, instead hardoded to dyn DatabaseExt * fix tests * fix traces test * fix: use default kzg settings in blob validation * reintroduce OptimismHardfork * fix: disable nonce check if nonce is None * fix!: load state tests by addressing breaking changes in state files * BlockEnv Breaking change: - most fields now use `u64` instead of `U64` / `U256` - coinbase renamed to beneficiary - best_block_number is `u64`, prev `U64` * fix: access_list test by using evm.inspect_with_tx * fix: replace evm.transact with evm.inspect_with_tx * fix: make impl Inspector for AnvilInspector generic over CTX * fix: clone inspector in TransactionExecutor to enable evm.inspect_commit * fix: remove cloned inspector from TransactionExecutor * feat(`anvil`): op support revm 21 (#10407) * enable OpHardforks in NodeConfig * feat: add is_optimism flag to foundry_evm::Env * feat(`anvil`): set is_optimism in Backend * feat(`anvil`): introducing EvmContext enum holding Eth and Op variants. * adds OpEnv to foundry_evm_core * feat: EitherEvm * impl Evm for EitherEvm * integrate EitherEvm into RPC and executor *Map OpHaltReason and OpTransactionError * rm old evm helpers * feat(`foundry_evm`): add deposit tx parts field to Env * fix(`anvil`): set deposit tx parts in tx executor and backend.inspect_tx * nit * docs EitherEvm * nit * refac: return TxEnv and Deposit parts separately * nits * nit * make anvil result aliases more generic * nit * intermediary(`revm bump`): re-enable Anvil tests, remove duplicate `LogCollector`, entire codebase builds (#10412) * temp refactor, still facing issue * clean up * clean up * temp cleanup, can later be refd * clean up, refactor stack.rs to apply ecx restore from cache to outside lamba * fix * clean up * clean up * avoid borrowing mutably for clarity * use EthEvmContext directly * FoundryEvmContext -> EthEvmContext * continue * fix tests * fix inspectors * codebase now builds entirely * fix clippy lints * remove duplicate LogCollector in Anvil * fmt * fix clippy * fix doctests * disable nonce checks on forks, enforce setting of tx.nonce on set_nonce * fix: use `transact` from alloy-evm (#10417) * Patch revm to fix interpreter panic * bump revm * fix eof test * fix bytecode hash * fix fixture * fix fixture * fix fixture * chore: mv EitherEvm to foundry_evm (#10445) mv EitherEvm to foundry_evm_core * remove unused JournalTr * restore formatting, avoid diff * remove leftover comment re: optimism support * fix displays_chained_error test * fix doc test * remove optimism todo leftover * avoid direct field assignment, prefer *current. * create2 handler register * fix patch * fix test_broadcast_raw_create2_deployer * fix gas meter test * correctly reset env.tx to cached env, cfg and block, ref https://github.com/foundry-rs/foundry/blob/a34f4c989b94f572497631ff5c85909d674c23a6/crates/evm/evm/src/inspectors/stack.rs#L640-L649 * exec_create * revert test_GasMeter, assert exact gas used * fix arbitrum test * doc test fixes * fix clippy warnings * remove leftover comment * fix assert_can_detect_unlinked_target_with_libraries, ref: https://github.com/bluealloy/revm/commit/fc54dd087ba9a96291b1130bc8be73ade5d01ea5 * fix gas metering tests * restore unintended .wrap_err changes, ref: https://github.com/search?q=repo%3Afoundry-rs%2Ffoundry%20wrap_err(%22EVM%20error%22)&type=code * fix test_cheats_local_default * add CC0-1.0 license exception, has been previously approved in Reth: https://github.com/paradigmxyz/reth/blob/adb8bdc70758558d6122e87d78d73cc0f12d4dbb/deny.toml#L48 * usize depth * repin foundry-fork-db, this aligns the revm and alloy version back * fix clippy, after usize depth change * allow foundry-fork-db as git exception * fix: EitherEvm should work over OpTransaction * fix fmt * Env::from_with_spec_id -> Env::new_with_spec_id * bump clippy msrv to align with foundry.toml * chore: avoid leaking Anvil specific optimism fields into evm/core (#10466) * start sketching * maybe ? * some kind of conversion still required * continue porting * clean up types * pass op transaction in directly * fixes * restore setting of enveloped_tx * refactor anvil Env and reduce changes in tx processing * fix: correctly set txtype when setting up TxEnv * update last commits from master to be u64 compatible * fix clippy lint * revert clippy changes, make sure lint-foundry uses nightly clippy version * apply tx_type if set, upgrading from legacy to eip2930 if access_list is present and tx type is legacy * restore #[ret] macro that was removed unintendedly * replace redundant Env::new_with_spec_id(..) with default * allow passing is_optimism into Env constructor specific to Anvil * extract environment configuration into init.rs to make configuring the environment less error prone * remove redundant debug derive --------- Co-authored-by: Arsenii Kulikov Co-authored-by: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Co-authored-by: grandizzy --- Cargo.lock | 909 ++++++++++++++---- Cargo.toml | 75 +- clippy.toml | 2 +- crates/anvil/Cargo.toml | 22 +- crates/anvil/core/Cargo.toml | 1 + crates/anvil/core/src/eth/transaction/mod.rs | 115 ++- crates/anvil/src/cmd.rs | 8 +- crates/anvil/src/config.rs | 110 ++- crates/anvil/src/eth/api.rs | 34 +- crates/anvil/src/eth/backend/db.rs | 52 +- crates/anvil/src/eth/backend/env.rs | 30 + crates/anvil/src/eth/backend/executor.rs | 176 ++-- crates/anvil/src/eth/backend/fork.rs | 2 +- crates/anvil/src/eth/backend/genesis.rs | 6 +- crates/anvil/src/eth/backend/mem/fork_db.rs | 25 +- .../anvil/src/eth/backend/mem/in_memory_db.rs | 25 +- crates/anvil/src/eth/backend/mem/inspector.rs | 92 +- crates/anvil/src/eth/backend/mem/mod.rs | 567 ++++++----- crates/anvil/src/eth/backend/mem/state.rs | 13 +- crates/anvil/src/eth/backend/mem/storage.rs | 59 +- crates/anvil/src/eth/backend/mod.rs | 1 + crates/anvil/src/eth/backend/validate.rs | 11 +- crates/anvil/src/eth/error.rs | 74 +- crates/anvil/src/eth/fees.rs | 44 +- crates/anvil/src/eth/pool/mod.rs | 4 +- crates/anvil/src/eth/pool/transactions.rs | 5 + crates/anvil/src/eth/util.rs | 4 +- crates/anvil/src/evm.rs | 133 +-- crates/anvil/src/hardfork.rs | 22 +- crates/anvil/src/lib.rs | 7 +- .../test-data/state-dump-legacy-stress.json | 2 +- crates/anvil/test-data/state-dump-legacy.json | 2 +- crates/anvil/test-data/state-dump.json | 2 +- crates/anvil/tests/it/anvil_api.rs | 2 +- crates/anvil/tests/it/fork.rs | 3 +- crates/anvil/tests/it/gas.rs | 2 +- crates/anvil/tests/it/state.rs | 4 +- crates/anvil/tests/it/traces.rs | 14 +- crates/anvil/tests/it/transaction.rs | 2 +- crates/cast/Cargo.toml | 2 + crates/cast/src/cmd/call.rs | 16 +- crates/cast/src/cmd/run.rs | 42 +- crates/cast/src/cmd/wallet/mod.rs | 2 +- crates/cast/src/lib.rs | 2 +- crates/cheatcodes/Cargo.toml | 1 + crates/cheatcodes/src/error.rs | 2 +- crates/cheatcodes/src/evm.rs | 145 +-- crates/cheatcodes/src/evm/fork.rs | 105 +- crates/cheatcodes/src/evm/mapping.rs | 19 +- crates/cheatcodes/src/evm/mock.rs | 28 +- crates/cheatcodes/src/evm/prank.rs | 14 +- .../cheatcodes/src/evm/record_debug_step.rs | 2 +- crates/cheatcodes/src/fs.rs | 17 +- crates/cheatcodes/src/inspector.rs | 482 +++++----- crates/cheatcodes/src/inspector/utils.rs | 8 +- crates/cheatcodes/src/lib.rs | 12 +- crates/cheatcodes/src/script.rs | 25 +- crates/cheatcodes/src/test.rs | 2 +- crates/cheatcodes/src/test/assert.rs | 7 +- crates/cheatcodes/src/test/assume.rs | 10 +- crates/cheatcodes/src/test/expect.rs | 41 +- crates/cheatcodes/src/utils.rs | 5 +- crates/common/fmt/Cargo.toml | 2 +- crates/common/fmt/src/eof.rs | 12 +- crates/common/fmt/src/ui.rs | 2 +- crates/config/Cargo.toml | 3 +- crates/config/src/lib.rs | 4 +- crates/config/src/utils.rs | 2 +- crates/debugger/src/dump.rs | 2 +- crates/debugger/src/op.rs | 2 +- crates/debugger/src/tui/context.rs | 2 +- crates/evm/core/Cargo.toml | 5 +- crates/evm/core/src/backend/cow.rs | 73 +- crates/evm/core/src/backend/error.rs | 3 +- crates/evm/core/src/backend/in_memory_db.rs | 6 +- crates/evm/core/src/backend/mod.rs | 164 ++-- crates/evm/core/src/backend/snapshot.rs | 10 +- crates/evm/core/src/buffer.rs | 2 +- crates/evm/core/src/either_evm.rs | 239 +++++ crates/evm/core/src/env.rs | 103 ++ crates/evm/core/src/evm.rs | 371 +++++++ crates/evm/core/src/fork/database.rs | 22 +- crates/evm/core/src/fork/init.rs | 61 +- crates/evm/core/src/fork/mod.rs | 4 +- crates/evm/core/src/fork/multi.rs | 18 +- crates/evm/core/src/ic.rs | 57 +- crates/evm/core/src/lib.rs | 16 +- crates/evm/core/src/opcodes.rs | 2 +- crates/evm/core/src/opts.rs | 63 +- crates/evm/core/src/utils.rs | 240 +---- crates/evm/coverage/src/anchors.rs | 4 +- crates/evm/coverage/src/inspector.rs | 39 +- crates/evm/evm/Cargo.toml | 1 + crates/evm/evm/src/executors/builder.rs | 17 +- crates/evm/evm/src/executors/invariant/mod.rs | 6 +- .../evm/evm/src/executors/invariant/replay.rs | 3 +- crates/evm/evm/src/executors/mod.rs | 119 ++- crates/evm/evm/src/executors/trace.rs | 9 +- crates/evm/evm/src/inspectors/chisel_state.rs | 24 +- .../evm/evm/src/inspectors/custom_printer.rs | 114 +++ crates/evm/evm/src/inspectors/logs.rs | 28 +- crates/evm/evm/src/inspectors/mod.rs | 3 + crates/evm/evm/src/inspectors/script.rs | 28 +- crates/evm/evm/src/inspectors/stack.rs | 268 +++--- crates/evm/evm/src/lib.rs | 4 +- crates/evm/fuzz/src/inspector.rs | 26 +- crates/evm/fuzz/src/strategies/param.rs | 2 +- crates/evm/fuzz/src/strategies/state.rs | 8 +- crates/evm/traces/src/debug/mod.rs | 2 +- crates/evm/traces/src/debug/sources.rs | 2 +- crates/evm/traces/src/lib.rs | 2 +- crates/forge/Cargo.toml | 3 + crates/forge/src/cmd/coverage.rs | 2 +- crates/forge/src/multi_runner.rs | 10 +- crates/forge/tests/cli/test_cmd.rs | 2 +- crates/forge/tests/it/config.rs | 2 +- crates/forge/tests/it/spec.rs | 2 +- crates/forge/tests/it/test_helpers.rs | 3 +- crates/script/src/simulate.rs | 4 +- crates/test-utils/src/util.rs | 2 + crates/verify/Cargo.toml | 3 +- crates/verify/src/bytecode.rs | 19 +- crates/verify/src/utils.rs | 31 +- crates/verify/src/verify.rs | 3 +- deny.toml | 18 +- testdata/default/cheats/Fee.t.sol | 2 +- .../default/cheats/GetBlockTimestamp.t.sol | 2 +- testdata/default/cheats/Roll.t.sol | 2 +- testdata/default/cheats/Warp.t.sol | 2 +- testdata/default/cheats/getBlockNumber.t.sol | 2 +- 130 files changed, 3762 insertions(+), 2201 deletions(-) create mode 100644 crates/anvil/src/eth/backend/env.rs create mode 100644 crates/evm/core/src/either_evm.rs create mode 100644 crates/evm/core/src/env.rs create mode 100644 crates/evm/core/src/evm.rs create mode 100644 crates/evm/evm/src/inspectors/custom_printer.rs diff --git a/Cargo.lock b/Cargo.lock index 37ddf3367eded..d5d411c5c5da6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,9 +70,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fbf458101ed6c389e9bb70a34ebc56039868ad10472540614816cdedc8f5265" +checksum = "27d301f5bcfd37e3aac727c360d8b50c33ddff9169ce0370198dedda36a9927d" dependencies = [ "alloy-eips", "alloy-primitives", @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "alloy-consensus-any" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc982af629e511292310fe85b433427fd38cb3105147632b574abc997db44c91" +checksum = "9f4f97a85a45965e0e4f9f5b94bbafaa3e4ee6868bdbcf2e4a9acb4b358038fe" dependencies = [ "alloy-consensus", "alloy-eips", @@ -107,9 +107,9 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0a0c1ddee20ecc14308aae21c2438c994df7b39010c26d70f86e1d8fdb8db0" +checksum = "f39e8b96c9e25dde7222372332489075f7e750e4fd3e81c11eec0939b78b71b8" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -145,7 +145,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "winnow 0.7.9", + "winnow 0.7.10", ] [[package]] @@ -169,8 +169,6 @@ checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" dependencies = [ "alloy-primitives", "alloy-rlp", - "arbitrary", - "rand 0.8.5", "serde", ] @@ -182,18 +180,16 @@ checksum = "9b15b13d38b366d01e818fe8e710d4d702ef7499eacd44926a06171dd9585d0c" dependencies = [ "alloy-primitives", "alloy-rlp", - "arbitrary", "k256", - "rand 0.8.5", "serde", "thiserror 2.0.12", ] [[package]] name = "alloy-eips" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e86967eb559920e4b9102e4cb825fe30f2e9467988353ce4809f0d3f2c90cd4" +checksum = "10b11c382ca8075128d1ae6822b60921cf484c911d9a5831797a01218f98125f" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -205,16 +201,34 @@ dependencies = [ "c-kzg", "derive_more 2.0.1", "either", - "once_cell", "serde", - "sha2", + "sha2 0.10.9", +] + +[[package]] +name = "alloy-evm" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71b0b181c956dca015b4c08b36668736013787c9dc9e743fd39a23b8b130c14" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-hardforks", + "alloy-primitives", + "alloy-sol-types", + "auto_impl", + "derive_more 2.0.1", + "op-alloy-consensus", + "op-revm", + "revm", + "thiserror 2.0.12", ] [[package]] name = "alloy-genesis" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a40de6f5b53ecf5fd7756072942f41335426d9a3704cd961f77d854739933bcf" +checksum = "7bd9e75c5dd40319ebbe807ebe9dfb10c24e4a70d9c7d638e62921d8dd093c8b" dependencies = [ "alloy-eips", "alloy-primitives", @@ -223,6 +237,19 @@ dependencies = [ "serde", ] +[[package]] +name = "alloy-hardforks" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "473ee2ab7f5262b36e8fbc1b5327d5c9d488ab247e31ac739b929dbe2444ae79" +dependencies = [ + "alloy-chains", + "alloy-eip2124", + "alloy-primitives", + "auto_impl", + "dyn-clone", +] + [[package]] name = "alloy-json-abi" version = "0.8.25" @@ -237,9 +264,9 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27434beae2514d4a2aa90f53832cbdf6f23e4b5e2656d95eaf15f9276e2418b6" +checksum = "bbcf26d02a72e23d5bc245425ea403c93ba17d254f20f9c23556a249c6c7e143" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -251,9 +278,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a33a38c7486b1945f8d093ff027add2f3a8f83c7300dbad6165cc49150085e" +checksum = "b44dd4429e190f727358571175ebf323db360a303bf4e1731213f510ced1c2e6" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -277,9 +304,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db973a7a23cbe96f2958e5687c51ce2d304b5c6d0dc5ccb3de8667ad8476f50b" +checksum = "86f736e1d1eb1b770dbd32919bdf46d4dcd4617f2eed07947dfb32649962baba" dependencies = [ "alloy-consensus", "alloy-eips", @@ -288,6 +315,33 @@ dependencies = [ "serde", ] +[[package]] +name = "alloy-op-evm" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "324cf0b3b08b4c3354460dee8208384a59245da8b0eaefe9e962d3942d919d58" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-evm", + "alloy-op-hardforks", + "alloy-primitives", + "auto_impl", + "op-alloy-consensus", + "op-revm", + "revm", +] + +[[package]] +name = "alloy-op-hardforks" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217a4efe17c43df77c1f261825350be0be1d907f56eb38a4b258936e33cfd1d8" +dependencies = [ + "alloy-hardforks", + "auto_impl", +] + [[package]] name = "alloy-primitives" version = "0.8.25" @@ -321,9 +375,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b03bde77ad73feae14aa593bcabb932c8098c0f0750ead973331cfc0003a4e1" +checksum = "a557f9e3ec89437b06db3bfc97d20782b1f7cc55b5b602b6a82bf3f64d7efb0e" dependencies = [ "alloy-chains", "alloy-consensus", @@ -338,6 +392,7 @@ dependencies = [ "alloy-rpc-types-eth", "alloy-rpc-types-trace", "alloy-rpc-types-txpool", + "alloy-signer", "alloy-sol-types", "alloy-transport", "alloy-transport-http", @@ -347,6 +402,7 @@ dependencies = [ "async-trait", "auto_impl", "dashmap", + "either", "futures", "futures-utils-wasm", "lru 0.13.0", @@ -364,15 +420,16 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721aca709a9231815ad5903a2d284042cc77e7d9d382696451b30c9ee0950001" +checksum = "f0a261caff6c2ec6fe1d6eb77ba41159024c8387d05e4138804a387d403def55" dependencies = [ "alloy-json-rpc", "alloy-primitives", "alloy-transport", "bimap", "futures", + "parking_lot", "serde", "serde_json", "tokio", @@ -405,9 +462,9 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445a3298c14fae7afb5b9f2f735dead989f3dd83020c2ab8e48ed95d7b6d1acb" +checksum = "cec6dc89c4c3ef166f9fa436d1831f8142c16cf2e637647c936a6aaaabd8d898" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -433,9 +490,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157deaec6ba2ad7854f16146e4cd60280e76593eed79fdcb06e0fa8b6c60f77" +checksum = "3849f8131a18cc5d7f95f301d68a6af5aa2db28ad8522fb9db1f27b3794e8b68" dependencies = [ "alloy-primitives", "alloy-rpc-types-anvil", @@ -449,9 +506,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a80ee83ef97e7ffd667a81ebdb6154558dfd5e8f20d8249a10a12a1671a04b3" +checksum = "19051fd5e8de7e1f95ec228c9303debd776dcc7caf8d1ece3191f711f5c06541" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -461,9 +518,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604dea1f00fd646debe8033abe8e767c732868bf8a5ae9df6321909ccbc99c56" +checksum = "ecd6d480e4e6e456f30eeeb3aef1512aaecb68df2a35d1f78865dbc4d20dc0fd" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -472,9 +529,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-debug" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08b113a0087d226291b9768ed331818fa0b0744cc1207ae7c150687cf3fde1bd" +checksum = "805eb9fa07f92f1225253e842b5454b4b3e258813445c1a1c9d8dd0fd90817c1" dependencies = [ "alloy-primitives", "serde", @@ -482,9 +539,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874ac9d1249ece0453e262d9ba72da9dbb3b7a2866220ded5940c2e47f1aa04d" +checksum = "689521777149dabe210ef122605fb00050e038f2e85b8c9897534739f1a904f8" dependencies = [ "alloy-consensus", "alloy-eips", @@ -500,9 +557,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e13d71eac04513a71af4b3df580f52f2b4dcbff9d971cc9a52519acf55514cb" +checksum = "9a8b6d55bdaa0c4a08650d4b32f174494cbade56adf6f2fcfa2a4f3490cb5511" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -520,9 +577,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4747763aee39c1b0f5face79bde9be8932be05b2db7d8bdcebb93490f32c889c" +checksum = "6019cd6a89230d765a621a7b1bc8af46a6a9cde2d2e540e6f9ce930e0fb7c6db" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -534,9 +591,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70132ebdbea1eaa68c4d6f7a62c2fadf0bdce83b904f895ab90ca4ec96f63468" +checksum = "ee36e5404642696af511f09991f9f54a11b90e86e55efad868f8f56350eff5b0" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -546,9 +603,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1cd73fc054de6353c7f22ff9b846b0f0f145cd0112da07d4119e41e9959207" +checksum = "1824791912f468a481dedc1db50feef3e85a078f6d743a62db2ee9c2ca674882" dependencies = [ "alloy-primitives", "serde", @@ -557,9 +614,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96fbde54bee943cd94ebacc8a62c50b38c7dfd2552dcd79ff61aea778b1bfcc" +checksum = "3d087fe5aea96a93fbe71be8aaed5c57c3caac303c09e674bc5b1647990d648b" dependencies = [ "alloy-dyn-abi", "alloy-primitives", @@ -574,9 +631,9 @@ dependencies = [ [[package]] name = "alloy-signer-aws" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e73835ed6689740b76cab0f59afbdce374a03d3f856ea33ba1fc054630a1b28" +checksum = "6623e424e692388d0c42071ed997513d7a19d8b83e83732466c0c93aedd486bd" dependencies = [ "alloy-consensus", "alloy-network", @@ -592,9 +649,9 @@ dependencies = [ [[package]] name = "alloy-signer-gcp" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a16b468ae86bb876d9c7a3b49b1e8d614a581a1a9673e4e0d2393b411080fe64" +checksum = "53755624ad8fbd12be2dc2e9df31cbab38e4067fa3d4ba02814145535a221f98" dependencies = [ "alloy-consensus", "alloy-network", @@ -610,9 +667,9 @@ dependencies = [ [[package]] name = "alloy-signer-ledger" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cf8a7f45edcc43566218e44b70ed3c278b7556926158cfeb63c8d41fefef70" +checksum = "d4224cd9c7b8107b1f7973361e81cf75e20a99835bcdc6ba7ac8ea50a6256e47" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -630,9 +687,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6e72002cc1801d8b41e9892165e3a6551b7bd382bd9d0414b21e90c0c62551" +checksum = "2940353d2425bb75965cd5101075334e6271051e35610f903bf8099a52b0b1a9" dependencies = [ "alloy-consensus", "alloy-network", @@ -649,9 +706,9 @@ dependencies = [ [[package]] name = "alloy-signer-trezor" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d4fd403c53cf7924c3e16c61955742cfc3813188f0975622f4fa6f8a01760aa" +checksum = "3bafd519704c7d9f2c449686e895a7681e5e7172bfef3f2d3ad8d0b4476d6f9d" dependencies = [ "alloy-consensus", "alloy-network", @@ -722,7 +779,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d162f8524adfdfb0e4bd0505c734c985f3e2474eb022af32eef0d52a4f3935c" dependencies = [ "serde", - "winnow 0.7.9", + "winnow 0.7.10", ] [[package]] @@ -740,9 +797,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec325c2af8562ef355c02aeb527c755a07e9d8cf6a1e65dda8d0bf23e29b2c" +checksum = "6818b4c82a474cc01ac9e88ccfcd9f9b7bc893b2f8aea7e890a28dcd55c0a7aa" dependencies = [ "alloy-json-rpc", "base64 0.22.1", @@ -762,9 +819,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a082c9473c6642cce8b02405a979496126a03b096997888e86229afad05db06c" +checksum = "4cc3079a33483afa1b1365a3add3ea3e21c75b10f704870198ba7846627d10f2" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -777,9 +834,9 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a78cfda2cac16fa83f6b5dd8b4643caec6161433b25b67e484ce05d2194513" +checksum = "66c6f8e20aa6b748357bed157c14e561a176d0f6cffed7f99ee37758a7d16202" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -797,9 +854,9 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae865917bdabaae21f418010fe7e8837c6daa6611fde25f8d78a1778d6ecb523" +checksum = "5ef7a4301e8967c1998f193755fd9429e0ca81730e2e134e30c288c43dbf96f0" dependencies = [ "alloy-pubsub", "alloy-transport", @@ -949,8 +1006,10 @@ dependencies = [ "alloy-contract", "alloy-dyn-abi", "alloy-eips", + "alloy-evm", "alloy-genesis", "alloy-network", + "alloy-op-evm", "alloy-primitives", "alloy-provider", "alloy-pubsub", @@ -979,12 +1038,14 @@ dependencies = [ "foundry-common", "foundry-config", "foundry-evm", + "foundry-evm-core", "foundry-test-utils", "futures", "hyper", "itertools 0.14.0", "op-alloy-consensus", "op-alloy-rpc-types", + "op-revm", "parking_lot", "rand 0.8.5", "revm", @@ -995,7 +1056,7 @@ dependencies = [ "thiserror 2.0.12", "tokio", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", "yansi", ] @@ -1015,6 +1076,7 @@ dependencies = [ "foundry-common", "foundry-evm", "op-alloy-consensus", + "op-revm", "rand 0.8.5", "revm", "serde", @@ -1076,6 +1138,51 @@ dependencies = [ "yansi", ] +[[package]] +name = "ark-bls12-381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-r1cs-std", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-poly", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.3", + "itertools 0.13.0", + "num-bigint", + "num-integer", + "num-traits", + "zeroize", +] + [[package]] name = "ark-ff" version = "0.3.0" @@ -1114,6 +1221,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "zeroize", +] + [[package]] name = "ark-ff-asm" version = "0.3.0" @@ -1134,6 +1261,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.101", +] + [[package]] name = "ark-ff-macros" version = "0.3.0" @@ -1159,6 +1296,63 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.3", +] + +[[package]] +name = "ark-r1cs-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941551ef1df4c7a401de7068758db6503598e6f01850bdb2cfdb614a1f9dbea1" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-relations", + "ark-std 0.5.0", + "educe", + "num-bigint", + "num-integer", + "num-traits", + "tracing", +] + +[[package]] +name = "ark-relations" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384" +dependencies = [ + "ark-ff 0.5.0", + "ark-std 0.5.0", + "tracing", + "tracing-subscriber 0.2.25", +] + [[package]] name = "ark-serialize" version = "0.3.0" @@ -1180,6 +1374,30 @@ dependencies = [ "num-bigint", ] +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "ark-std" version = "0.3.0" @@ -1200,6 +1418,22 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + [[package]] name = "arrayvec" version = "0.7.6" @@ -1434,9 +1668,9 @@ dependencies = [ [[package]] name = "aws-sdk-kms" -version = "1.66.0" +version = "1.67.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655097cd83ab1f15575890943135192560f77097413c6dd1733fdbdc453e81ac" +checksum = "2b650cf9e1e153ab13acd3aa1f73b271dac14e019353ec0b0c176f24a21bad03" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1457,9 +1691,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.65.0" +version = "1.66.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8efec445fb78df585327094fcef4cad895b154b58711e504db7a93c41aa27151" +checksum = "858007b14d0f1ade2e0124473c2126b24d334dc9486ad12eb7c0ed14757be464" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1480,9 +1714,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.66.0" +version = "1.67.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e49cca619c10e7b002dc8e66928ceed66ab7f56c1a3be86c5437bf2d8d89bba" +checksum = "b83abf3ae8bd10a014933cc2383964a12ca5a3ebbe1948ad26b1b808e7d0d1f2" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1503,9 +1737,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.66.0" +version = "1.67.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7420479eac0a53f776cc8f0d493841ffe58ad9d9783f3947be7265784471b47a" +checksum = "74e8e9ac4a837859c8f1d747054172e1e55933f02ed34728b0b34dea0591ec84" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1542,7 +1776,7 @@ dependencies = [ "http 0.2.12", "http 1.3.1", "percent-encoding", - "sha2", + "sha2 0.10.9", "time", "tracing", ] @@ -1776,9 +2010,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", @@ -1873,6 +2107,22 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +[[package]] +name = "bitcoin-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -1885,7 +2135,6 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" dependencies = [ - "arbitrary", "serde", ] @@ -1902,6 +2151,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -1954,7 +2212,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ - "sha2", + "sha2 0.10.9", "tinyvec", ] @@ -2033,10 +2291,11 @@ dependencies = [ [[package]] name = "c-kzg" -version = "1.0.3" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0307f72feab3300336fb803a57134159f6e20139af1357f36c54cb90d8e8928" +checksum = "4e7e3c397401eb76228c89561cf22f85f41c95aa799ee9d860de3ea1cbc728fc" dependencies = [ + "arbitrary", "blst", "cc", "glob", @@ -2088,6 +2347,7 @@ dependencies = [ "foundry-compilers", "foundry-config", "foundry-evm", + "foundry-evm-core", "foundry-test-utils", "foundry-wallets", "futures", @@ -2096,6 +2356,7 @@ dependencies = [ "rand 0.8.5", "rayon", "regex", + "revm", "rpassword", "semver 1.0.26", "serde", @@ -2176,7 +2437,7 @@ dependencies = [ "time", "tokio", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", "walkdir", "yansi", ] @@ -2279,9 +2540,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.48" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8c97f3a6f02b9e24cadc12aaba75201d18754b53ea0a9d99642f806ccdb4c9" +checksum = "c91d3baa3bcd889d60e6ef28874126a0b384fd225ab83aa6d8a801c519194ce1" dependencies = [ "clap", ] @@ -2371,7 +2632,7 @@ dependencies = [ "hmac", "k256", "serde", - "sha2", + "sha2 0.10.9", "thiserror 1.0.69", ] @@ -2387,7 +2648,7 @@ dependencies = [ "once_cell", "pbkdf2 0.12.2", "rand 0.8.5", - "sha2", + "sha2 0.10.9", "thiserror 1.0.69", ] @@ -2405,7 +2666,7 @@ dependencies = [ "generic-array", "ripemd", "serde", - "sha2", + "sha2 0.10.9", "sha3", "thiserror 1.0.69", ] @@ -2848,6 +3109,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive-where" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e73f2692d4bd3cac41dca28934a39894200c9fabf49586d77d0e5954af1d7902" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "derive_arbitrary" version = "1.4.1" @@ -2961,7 +3233,7 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "const-oid", "crypto-common", "subtle", @@ -3048,6 +3320,18 @@ dependencies = [ "spki", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "either" version = "1.15.0" @@ -3133,6 +3417,26 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "enumn" version = "0.1.14" @@ -3221,7 +3525,7 @@ dependencies = [ "scrypt", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "sha3", "thiserror 1.0.69", "uuid 0.8.2", @@ -3445,6 +3749,7 @@ dependencies = [ "foundry-config", "foundry-debugger", "foundry-evm", + "foundry-evm-core", "foundry-linking", "foundry-solang-parser", "foundry-test-utils", @@ -3464,6 +3769,7 @@ dependencies = [ "rayon", "regex", "reqwest", + "revm", "semver 1.0.26", "serde", "serde_json", @@ -3522,7 +3828,7 @@ dependencies = [ "thiserror 2.0.12", "toml 0.8.22", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -3619,12 +3925,13 @@ dependencies = [ "foundry-compilers", "foundry-config", "foundry-evm", + "foundry-evm-core", "foundry-test-utils", "futures", "itertools 0.14.0", "regex", "reqwest", - "revm-primitives", + "revm", "semver 1.0.26", "serde", "serde_json", @@ -3668,6 +3975,7 @@ dependencies = [ "alloy-chains", "alloy-consensus", "alloy-dyn-abi", + "alloy-evm", "alloy-genesis", "alloy-json-abi", "alloy-network", @@ -3758,7 +4066,7 @@ dependencies = [ "tikv-jemallocator", "tokio", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", "tracing-tracy", "yansi", ] @@ -3833,7 +4141,7 @@ dependencies = [ "chrono", "comfy-table", "foundry-macros", - "revm-primitives", + "revm", "serde", "serde_json", "similar-asserts", @@ -3864,7 +4172,7 @@ dependencies = [ "semver 1.0.26", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "solar-parse", "solar-sema", "svm-rs", @@ -3873,7 +4181,7 @@ dependencies = [ "thiserror 2.0.12", "tokio", "tracing", - "winnow 0.7.9", + "winnow 0.7.10", "yansi", ] @@ -3969,7 +4277,7 @@ dependencies = [ "path-slash", "regex", "reqwest", - "revm-primitives", + "revm", "semver 1.0.26", "serde", "serde_json", @@ -4008,6 +4316,7 @@ name = "foundry-evm" version = "1.2.0" dependencies = [ "alloy-dyn-abi", + "alloy-evm", "alloy-json-abi", "alloy-primitives", "alloy-sol-types", @@ -4048,9 +4357,11 @@ version = "1.2.0" dependencies = [ "alloy-consensus", "alloy-dyn-abi", + "alloy-evm", "alloy-genesis", "alloy-json-abi", "alloy-network", + "alloy-op-evm", "alloy-primitives", "alloy-provider", "alloy-rpc-types", @@ -4065,6 +4376,7 @@ dependencies = [ "foundry-test-utils", "futures", "itertools 0.14.0", + "op-revm", "parking_lot", "revm", "revm-inspectors", @@ -4146,8 +4458,7 @@ dependencies = [ [[package]] name = "foundry-fork-db" version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba7beb856e73f59015823eb221a98b7c22b58bc4e7066c9c86774ebe74e61dd6" +source = "git+https://github.com/foundry-rs/foundry-fork-db?rev=811a61a#811a61a1312d6510447d5511f0e8714024813322" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -4220,7 +4531,7 @@ dependencies = [ "tempfile", "tokio", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -4760,9 +5071,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" dependencies = [ "atomic-waker", "bytes", @@ -4845,9 +5156,9 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hermit-abi" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" +checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" [[package]] name = "hex" @@ -4858,6 +5169,15 @@ dependencies = [ "serde", ] +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + [[package]] name = "hidapi-rusb" version = "1.3.3" @@ -5020,7 +5340,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots", + "webpki-roots 0.26.11", ] [[package]] @@ -5317,7 +5637,7 @@ version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi 0.5.0", + "hermit-abi 0.5.1", "libc", "windows-sys 0.59.0", ] @@ -5372,9 +5692,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd" +checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -5387,9 +5707,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300" +checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48" dependencies = [ "proc-macro2", "quote", @@ -5468,7 +5788,7 @@ dependencies = [ "elliptic-curve", "once_cell", "serdect", - "sha2", + "sha2 0.10.9", "signature", ] @@ -5493,9 +5813,9 @@ dependencies = [ [[package]] name = "kqueue" -version = "1.0.8" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" dependencies = [ "kqueue-sys", "libc", @@ -5557,9 +5877,6 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] [[package]] name = "lazycell" @@ -5595,9 +5912,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" @@ -5610,6 +5927,52 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "libsecp256k1" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79019718125edc905a079a70cfa5f3820bc76139fc91d6f9abc27ea2a887139" +dependencies = [ + "arrayref", + "base64 0.22.1", + "digest 0.9.0", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.5", + "serde", + "sha2 0.9.9", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + [[package]] name = "libusb1-sys" version = "0.7.0" @@ -5663,7 +6026,7 @@ dependencies = [ "generator", "scoped-tls", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -5752,9 +6115,9 @@ checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "mdbook" -version = "0.4.48" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6fbb4ac2d9fd7aa987c3510309ea3c80004a968d063c42f0d34fea070817c1" +checksum = "d1daacee059634081dee4250d2814763a365b92dfe14bfdef964bc27835209d4" dependencies = [ "ammonia", "anyhow", @@ -5773,7 +6136,7 @@ dependencies = [ "regex", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "shlex", "tempfile", "toml 0.5.11", @@ -6213,9 +6576,9 @@ dependencies = [ [[package]] name = "op-alloy-consensus" -version = "0.11.4" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "889facbf449b2d9c8de591cd467a6c7217936f3c1c07a281759c01c49d08d66d" +checksum = "917f7a65b83e8f9cf06d5209161babf39f5e5768e226a08ad42c033386248a66" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6229,9 +6592,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types" -version = "0.11.4" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba7bfcc5d0b08c7a8bbdfaffa81e47edbb00185f0bf08e9f008216057700e50" +checksum = "57c087949da266a53e4c24d841a68590126ecfd3631b2fe74dbcd6da45702983" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6245,6 +6608,23 @@ dependencies = [ "serde_json", ] +[[package]] +name = "op-revm" +version = "2.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +dependencies = [ + "auto_impl", + "once_cell", + "revm", + "serde", +] + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "opener" version = "0.7.2" @@ -6296,7 +6676,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -6477,7 +6857,7 @@ checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" dependencies = [ "once_cell", "pest", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -6508,6 +6888,7 @@ checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ "phf_macros", "phf_shared", + "serde", ] [[package]] @@ -7260,31 +7641,131 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots", + "webpki-roots 0.26.11", "windows-registry", ] [[package]] name = "revm" -version = "19.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c175ecec83bba464aa8406502fe5bf670491c2ace81a153264891d43bc7fa332" +version = "21.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +dependencies = [ + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database", + "revm-database-interface", + "revm-handler", + "revm-inspector", + "revm-interpreter", + "revm-precompile", + "revm-primitives", + "revm-state", +] + +[[package]] +name = "revm-bytecode" +version = "2.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +dependencies = [ + "bitvec", + "phf", + "revm-primitives", + "serde", +] + +[[package]] +name = "revm-context" +version = "2.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" dependencies = [ - "auto_impl", "cfg-if", - "dyn-clone", - "once_cell", + "derive-where", + "revm-bytecode", + "revm-context-interface", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-context-interface" +version = "2.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +dependencies = [ + "alloy-eip2930", + "alloy-eip7702", + "auto_impl", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-database" +version = "2.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +dependencies = [ + "alloy-eips", + "auto_impl", + "revm-bytecode", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-database-interface" +version = "2.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +dependencies = [ + "auto_impl", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-handler" +version = "2.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +dependencies = [ + "auto_impl", + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database-interface", "revm-interpreter", "revm-precompile", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-inspector" +version = "2.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +dependencies = [ + "auto_impl", + "revm-context", + "revm-database-interface", + "revm-handler", + "revm-interpreter", + "revm-primitives", + "revm-state", "serde", "serde_json", ] [[package]] name = "revm-inspectors" -version = "0.16.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a43423d81f4bef634469bfb2d9ebe36a9ea9167f20ab3a7d1ff1e05fa63099" +checksum = "8a32ec21c38a85f83773e6b3cdb7060aae8ac9edb291118fbfd4da7f2a50e620" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -7300,51 +7781,57 @@ dependencies = [ [[package]] name = "revm-interpreter" -version = "15.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dcab7ef2064057acfc84731205f4bc77f4ec1b35630800b26ff6a185731c5ab" +version = "17.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" dependencies = [ + "revm-bytecode", + "revm-context-interface", "revm-primitives", "serde", ] [[package]] name = "revm-precompile" -version = "16.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99743c3a2cac341084cc15ac74286c4bf34a0941ebf60aa420cfdb9f81f72f9f" -dependencies = [ +version = "18.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +dependencies = [ + "ark-bls12-381", + "ark-bn254", + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", "aurora-engine-modexp", "blst", "c-kzg", "cfg-if", "k256", + "libsecp256k1", "once_cell", "p256", "revm-primitives", "ripemd", "secp256k1", - "sha2", - "substrate-bn", + "sha2 0.10.9", ] [[package]] name = "revm-primitives" -version = "15.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f987564210317706def498421dfba2ae1af64a8edce82c6102758b48133fcb" +version = "17.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" dependencies = [ - "alloy-eip2930", - "alloy-eip7702", "alloy-primitives", - "auto_impl", - "bitflags 2.9.0", - "bitvec", - "c-kzg", - "cfg-if", - "dyn-clone", "enumn", - "hex", + "serde", +] + +[[package]] +name = "revm-state" +version = "2.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +dependencies = [ + "bitflags 2.9.0", + "revm-bytecode", + "revm-primitives", "serde", ] @@ -7538,9 +8025,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.26" +version = "0.23.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ "aws-lc-rs", "log", @@ -7575,18 +8062,19 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ "web-time", + "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.1" +version = "0.103.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +checksum = "7149975849f1abb3832b246010ef62ccc80d3a76169517ada7188252b9cfb437" dependencies = [ "aws-lc-rs", "ring", @@ -7730,7 +8218,7 @@ dependencies = [ "hmac", "pbkdf2 0.11.0", "salsa20", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -7756,10 +8244,11 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.29.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ + "bitcoin_hashes", "rand 0.8.5", "secp256k1-sys", ] @@ -7994,6 +8483,19 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + [[package]] name = "sha2" version = "0.10.9" @@ -8365,7 +8867,7 @@ dependencies = [ "semver 1.0.26", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "thiserror 2.0.12", "tokio", "toml_edit", @@ -8374,12 +8876,6 @@ dependencies = [ "zip-extract", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - [[package]] name = "spki" version = "0.7.3" @@ -8492,19 +8988,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "substrate-bn" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" -dependencies = [ - "byteorder", - "crunchy", - "lazy_static", - "rand 0.8.5", - "rustc-hex", -] - [[package]] name = "subtle" version = "2.6.1" @@ -8602,7 +9085,7 @@ dependencies = [ "semver 1.0.26", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "tempfile", "thiserror 2.0.12", "url", @@ -8902,9 +9385,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.44.2" +version = "1.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" dependencies = [ "backtrace", "bytes", @@ -8988,7 +9471,7 @@ dependencies = [ "tokio", "tokio-rustls", "tungstenite 0.26.2", - "webpki-roots", + "webpki-roots 0.26.11", ] [[package]] @@ -9046,7 +9529,7 @@ dependencies = [ "serde_spanned", "toml_datetime", "toml_write", - "winnow 0.7.9", + "winnow 0.7.10", ] [[package]] @@ -9219,7 +9702,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" dependencies = [ "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -9245,6 +9728,15 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.19" @@ -9270,7 +9762,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eaa1852afa96e0fe9e44caa53dc0bd2d9d05e0f2611ce09f97f8677af56e4ba" dependencies = [ "tracing-core", - "tracing-subscriber", + "tracing-subscriber 0.3.19", "tracy-client", ] @@ -9857,9 +10349,9 @@ dependencies = [ [[package]] name = "web_atoms" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bcbdcad8fb2e316072ba6bbe09419afdb550285668ac2534f4230a6f2da0ee" +checksum = "0b9c5f0bc545ea3b20b423e33b9b457764de0b3730cd957f6c6aa6c301785f6e" dependencies = [ "phf", "phf_codegen", @@ -9869,9 +10361,18 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.10" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.0", +] + +[[package]] +name = "webpki-roots" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37493cadf42a2a939ed404698ded7fb378bf301b5011f973361779a3a74f8c93" +checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" dependencies = [ "rustls-pki-types", ] @@ -10238,9 +10739,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] @@ -10387,9 +10888,9 @@ dependencies = [ [[package]] name = "zip-extract" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3938d2b7d7ffd0fb7d4a86baeade9189535487d05d175401daf92306c531c0" +checksum = "db6d94e397dd6d0273e6747e46e7aa0289bfd9736ba8772f2fe948bc4adc3f73" dependencies = [ "log", "thiserror 2.0.12", diff --git a/Cargo.toml b/Cargo.toml index 96ff120cb30c8..fcf9b8e7c9a45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ resolver = "2" version = "1.2.0" edition = "2021" # Remember to update clippy.toml as well -rust-version = "1.83" +rust-version = "1.85" authors = ["Foundry Contributors"] license = "MIT OR Apache-2.0" homepage = "https://github.com/foundry-rs/foundry" @@ -116,10 +116,17 @@ alloy-sol-types.opt-level = 3 hashbrown.opt-level = 3 foldhash.opt-level = 3 keccak.opt-level = 3 +revm.opt-level = 3 +revm-primitives.opt-level = 3 revm-interpreter.opt-level = 3 revm-precompile.opt-level = 3 -revm-primitives.opt-level = 3 -revm.opt-level = 3 +revm-database-interface.opt-level = 3 +revm-database.opt-level = 3 +revm-bytecode.opt-level = 3 +revm-state.opt-level = 3 +revm-context-interface.opt-level = 3 +revm-context.opt-level = 3 +revm-inspector.opt-level = 3 ruint.opt-level = 3 sha2.opt-level = 3 sha3.opt-level = 3 @@ -196,32 +203,32 @@ solar-parse = { version = "=0.1.2", default-features = false } solar-sema = { version = "=0.1.2", default-features = false } ## revm -revm = { version = "19.4.0", default-features = false } -revm-primitives = { version = "15.1.0", default-features = false } -revm-inspectors = { version = "0.16.0", features = ["serde"] } +revm = { version = "21.0.0", default-features = false } +revm-inspectors = { version = "0.18.1", features = ["serde"] } +op-revm = { version = "2.0.0", default-features = false } ## alloy -alloy-consensus = { version = "0.12.1", default-features = false } -alloy-contract = { version = "0.12.1", default-features = false } -alloy-eips = { version = "0.12.1", default-features = false } -alloy-genesis = { version = "0.12.1", default-features = false } -alloy-json-rpc = { version = "0.12.1", default-features = false } -alloy-network = { version = "0.12.1", default-features = false } -alloy-provider = { version = "0.12.1", default-features = false } -alloy-pubsub = { version = "0.12.1", default-features = false } -alloy-rpc-client = { version = "0.12.1", default-features = false } -alloy-rpc-types = { version = "0.12.1", default-features = true } -alloy-serde = { version = "0.12.1", default-features = false } -alloy-signer = { version = "0.12.1", default-features = false } -alloy-signer-aws = { version = "0.12.1", default-features = false } -alloy-signer-gcp = { version = "0.12.1", default-features = false } -alloy-signer-ledger = { version = "0.12.1", default-features = false } -alloy-signer-local = { version = "0.12.1", default-features = false } -alloy-signer-trezor = { version = "0.12.1", default-features = false } -alloy-transport = { version = "0.12.1", default-features = false } -alloy-transport-http = { version = "0.12.1", default-features = false } -alloy-transport-ipc = { version = "0.12.1", default-features = false } -alloy-transport-ws = { version = "0.12.1", default-features = false } +alloy-consensus = { version = "0.13.0", default-features = false } +alloy-contract = { version = "0.13.0", default-features = false } +alloy-eips = { version = "0.13.0", default-features = false } +alloy-genesis = { version = "0.13.0", default-features = false } +alloy-json-rpc = { version = "0.13.0", default-features = false } +alloy-network = { version = "0.13.0", default-features = false } +alloy-provider = { version = "0.13.0", default-features = false } +alloy-pubsub = { version = "0.13.0", default-features = false } +alloy-rpc-client = { version = "0.13.0", default-features = false } +alloy-rpc-types = { version = "0.13.0", default-features = true } +alloy-serde = { version = "0.13.0", default-features = false } +alloy-signer = { version = "0.13.0", default-features = false } +alloy-signer-aws = { version = "0.13.0", default-features = false } +alloy-signer-gcp = { version = "0.13.0", default-features = false } +alloy-signer-ledger = { version = "0.13.0", default-features = false } +alloy-signer-local = { version = "0.13.0", default-features = false } +alloy-signer-trezor = { version = "0.13.0", default-features = false } +alloy-transport = { version = "0.13.0", default-features = false } +alloy-transport-http = { version = "0.13.0", default-features = false } +alloy-transport-ipc = { version = "0.13.0", default-features = false } +alloy-transport-ws = { version = "0.13.0", default-features = false } ## alloy-core alloy-dyn-abi = "0.8.22" @@ -237,12 +244,14 @@ alloy-sol-macro-input = "0.8.22" alloy-sol-types = "0.8.22" alloy-chains = "0.1" +alloy-evm = "0.3.2" +alloy-op-evm = "0.3.2" alloy-rlp = "0.3" alloy-trie = "0.7.0" ## op-alloy -op-alloy-consensus = "0.11.0" -op-alloy-rpc-types = "0.11.0" +op-alloy-consensus = "0.12.0" +op-alloy-rpc-types = "0.12.0" ## cli anstream = "0.6" @@ -359,3 +368,11 @@ idna_adapter = "=1.1.0" # alloy-transport-http = { git = "https://github.com/alloy-rs/alloy", rev = "7fab7ee" } # alloy-transport-ipc = { git = "https://github.com/alloy-rs/alloy", rev = "7fab7ee" } # alloy-transport-ws = { git = "https://github.com/alloy-rs/alloy", rev = "7fab7ee" } + +## revm +revm = { git = "https://github.com/bluealloy/revm.git", rev = "2401c2c3" } +op-revm = { git = "https://github.com/bluealloy/revm.git", rev = "2401c2c3" } +# revm-inspectors = { git = "https://github.com/paradigmxyz/revm-inspectors.git", rev = "a625c04" } + +## foundry +foundry-fork-db = { git = "https://github.com/foundry-rs/foundry-fork-db", rev = "811a61a" } diff --git a/clippy.toml b/clippy.toml index 69dfa469ce10b..86b7412b14a56 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,4 +1,4 @@ -msrv = "1.83" +msrv = "1.85" # `bytes::Bytes` is included by default and `alloy_primitives::Bytes` is a wrapper around it, # so it is safe to ignore it as well. diff --git a/crates/anvil/Cargo.toml b/crates/anvil/Cargo.toml index 777026f038c0e..c70d1eb82c592 100644 --- a/crates/anvil/Cargo.toml +++ b/crates/anvil/Cargo.toml @@ -27,15 +27,11 @@ foundry-cli.workspace = true foundry-common.workspace = true foundry-config.workspace = true foundry-evm.workspace = true +foundry-evm-core.workspace = true -# evm support -revm = { workspace = true, features = [ - "std", - "serde", - "memory_limit", - "c-kzg", -] } -revm-inspectors.workspace = true +# alloy +alloy-evm.workspace = true +alloy-op-evm.workspace = true alloy-primitives = { workspace = true, features = ["serde"] } alloy-consensus = { workspace = true, features = ["k256", "kzg"] } alloy-contract = { workspace = true, features = ["pubsub"] } @@ -61,6 +57,16 @@ alloy-genesis.workspace = true alloy-trie.workspace = true op-alloy-consensus = { workspace = true, features = ["serde"] } +# revm +revm = { workspace = true, features = [ + "std", + "serde", + "memory_limit", + "c-kzg", +] } +revm-inspectors.workspace = true +op-revm.workspace = true + # axum related axum.workspace = true hyper.workspace = true diff --git a/crates/anvil/core/Cargo.toml b/crates/anvil/core/Cargo.toml index f7428d356bf53..0b64c630bda9b 100644 --- a/crates/anvil/core/Cargo.toml +++ b/crates/anvil/core/Cargo.toml @@ -21,6 +21,7 @@ revm = { workspace = true, default-features = false, features = [ "memory_limit", "c-kzg", ] } +op-revm.workspace = true alloy-primitives = { workspace = true, features = ["serde", "rlp"] } alloy-rpc-types = { workspace = true, features = ["anvil", "trace"] } diff --git a/crates/anvil/core/src/eth/transaction/mod.rs b/crates/anvil/core/src/eth/transaction/mod.rs index e04a3afb09c36..85bba5504d9a0 100644 --- a/crates/anvil/core/src/eth/transaction/mod.rs +++ b/crates/anvil/core/src/eth/transaction/mod.rs @@ -23,10 +23,8 @@ use alloy_serde::{OtherFields, WithOtherFields}; use bytes::BufMut; use foundry_evm::traces::CallTraceNode; use op_alloy_consensus::{TxDeposit, DEPOSIT_TX_TYPE_ID}; -use revm::{ - interpreter::InstructionResult, - primitives::{OptimismFields, TxEnv}, -}; +use op_revm::{transaction::deposit::DepositTransactionParts, OpTransaction}; +use revm::{context::TxEnv, interpreter::InstructionResult}; use serde::{Deserialize, Serialize}; use std::ops::{Deref, Mul}; @@ -180,7 +178,7 @@ pub fn transaction_request_to_typed( } } -fn has_optimism_fields(other: &OtherFields) -> bool { +pub fn has_optimism_fields(other: &OtherFields) -> bool { other.contains_key("sourceHash") && other.contains_key("mint") && other.contains_key("isSystemTx") @@ -403,7 +401,9 @@ impl PendingTransaction { /// Converts the [PendingTransaction] into the [TxEnv] context that [`revm`](foundry_evm) /// expects. - pub fn to_revm_tx_env(&self) -> TxEnv { + /// + /// Base [`TxEnv`] is encapsulated in the [`op_revm::OpTransaction`] + pub fn to_revm_tx_env(&self) -> OpTransaction { fn transact_to(kind: &TxKind) -> TxKind { match kind { TxKind::Call(c) => TxKind::Call(*c), @@ -416,19 +416,20 @@ impl PendingTransaction { TypedTransaction::Legacy(tx) => { let chain_id = tx.tx().chain_id; let TxLegacy { nonce, gas_price, gas_limit, value, to, input, .. } = tx.tx(); - TxEnv { + OpTransaction::new(TxEnv { caller, - transact_to: transact_to(to), + kind: transact_to(to), data: input.clone(), chain_id, - nonce: Some(*nonce), + nonce: *nonce, value: (*value), - gas_price: U256::from(*gas_price), + gas_price: *gas_price, gas_priority_fee: None, gas_limit: *gas_limit, - access_list: vec![], + access_list: vec![].into(), + tx_type: 0, ..Default::default() - } + }) } TypedTransaction::EIP2930(tx) => { let TxEip2930 { @@ -442,19 +443,20 @@ impl PendingTransaction { access_list, .. } = tx.tx(); - TxEnv { + OpTransaction::new(TxEnv { caller, - transact_to: transact_to(to), + kind: transact_to(to), data: input.clone(), chain_id: Some(*chain_id), - nonce: Some(*nonce), + nonce: *nonce, value: *value, - gas_price: U256::from(*gas_price), + gas_price: *gas_price, gas_priority_fee: None, gas_limit: *gas_limit, - access_list: access_list.clone().into(), + access_list: access_list.clone(), + tx_type: 1, ..Default::default() - } + }) } TypedTransaction::EIP1559(tx) => { let TxEip1559 { @@ -469,19 +471,20 @@ impl PendingTransaction { access_list, .. } = tx.tx(); - TxEnv { + OpTransaction::new(TxEnv { caller, - transact_to: transact_to(to), + kind: transact_to(to), data: input.clone(), chain_id: Some(*chain_id), - nonce: Some(*nonce), + nonce: *nonce, value: *value, - gas_price: U256::from(*max_fee_per_gas), - gas_priority_fee: Some(U256::from(*max_priority_fee_per_gas)), + gas_price: *max_fee_per_gas, + gas_priority_fee: Some(*max_priority_fee_per_gas), gas_limit: *gas_limit, - access_list: access_list.clone().into(), + access_list: access_list.clone(), + tx_type: 2, ..Default::default() - } + }) } TypedTransaction::EIP4844(tx) => { let TxEip4844 { @@ -498,21 +501,22 @@ impl PendingTransaction { blob_versioned_hashes, .. } = tx.tx().tx(); - TxEnv { + OpTransaction::new(TxEnv { caller, - transact_to: TxKind::Call(*to), + kind: TxKind::Call(*to), data: input.clone(), chain_id: Some(*chain_id), - nonce: Some(*nonce), + nonce: *nonce, value: *value, - gas_price: U256::from(*max_fee_per_gas), - gas_priority_fee: Some(U256::from(*max_priority_fee_per_gas)), - max_fee_per_blob_gas: Some(U256::from(*max_fee_per_blob_gas)), + gas_price: *max_fee_per_gas, + gas_priority_fee: Some(*max_priority_fee_per_gas), + max_fee_per_blob_gas: *max_fee_per_blob_gas, blob_hashes: blob_versioned_hashes.clone(), gas_limit: *gas_limit, - access_list: access_list.clone().into(), + access_list: access_list.clone(), + tx_type: 3, ..Default::default() - } + }) } TypedTransaction::EIP7702(tx) => { let TxEip7702 { @@ -527,20 +531,21 @@ impl PendingTransaction { authorization_list, input, } = tx.tx(); - TxEnv { + OpTransaction::new(TxEnv { caller, - transact_to: TxKind::Call(*to), + kind: TxKind::Call(*to), data: input.clone(), chain_id: Some(*chain_id), - nonce: Some(*nonce), + nonce: *nonce, value: *value, - gas_price: U256::from(*max_fee_per_gas), - gas_priority_fee: Some(U256::from(*max_priority_fee_per_gas)), + gas_price: *max_fee_per_gas, + gas_priority_fee: Some(*max_priority_fee_per_gas), gas_limit: *gas_limit, - access_list: access_list.clone().into(), - authorization_list: Some(authorization_list.clone().into()), + access_list: access_list.clone(), + authorization_list: authorization_list.clone(), + tx_type: 4, ..Default::default() - } + }) } TypedTransaction::Deposit(tx) => { let chain_id = tx.chain_id(); @@ -555,25 +560,29 @@ impl PendingTransaction { is_system_tx, .. } = tx; - TxEnv { + + let base = TxEnv { caller, - transact_to: transact_to(kind), + kind: transact_to(kind), data: input.clone(), chain_id, - nonce: Some(*nonce), + nonce: *nonce, value: *value, - gas_price: U256::ZERO, + gas_price: 0, gas_priority_fee: None, gas_limit: { *gas_limit }, - access_list: vec![], - optimism: OptimismFields { - source_hash: Some(*source_hash), - mint: Some(mint.to::()), - is_system_transaction: Some(*is_system_tx), - enveloped_tx: None, - }, + access_list: vec![].into(), + tx_type: DEPOSIT_TX_TYPE_ID, ..Default::default() - } + }; + + let deposit = DepositTransactionParts { + source_hash: *source_hash, + mint: Some(mint.to::()), + is_system_transaction: *is_system_tx, + }; + + OpTransaction { base, deposit, enveloped_tx: None } } } } diff --git a/crates/anvil/src/cmd.rs b/crates/anvil/src/cmd.rs index 4b89f0a6dfb89..2968b12739786 100644 --- a/crates/anvil/src/cmd.rs +++ b/crates/anvil/src/cmd.rs @@ -1,8 +1,7 @@ use crate::{ config::{ForkChoice, DEFAULT_MNEMONIC}, eth::{backend::db::SerializableState, pool::transactions::TransactionOrder, EthApi}, - hardfork::OptimismHardfork, - AccountGenerator, EthereumHardfork, NodeConfig, CHAIN_ID, + AccountGenerator, EthereumHardfork, NodeConfig, OptimismHardfork, CHAIN_ID, }; use alloy_genesis::Genesis; use alloy_primitives::{utils::Unit, B256, U256}; @@ -521,7 +520,7 @@ pub struct AnvilEvmArgs { /// The block gas limit. #[arg(long, alias = "block-gas-limit", help_heading = "Environment config")] - pub gas_limit: Option, + pub gas_limit: Option, /// Disable the `call.gas_limit <= block.gas_limit` constraint. #[arg( @@ -792,9 +791,8 @@ fn duration_from_secs_f64(s: &str) -> Result { #[cfg(test)] mod tests { - use crate::EthereumHardfork; - use super::*; + use crate::{EthereumHardfork, OptimismHardfork}; use std::{env, net::Ipv4Addr}; #[test] diff --git a/crates/anvil/src/config.rs b/crates/anvil/src/config.rs index f9606eeeb08fd..097618ecf8afa 100644 --- a/crates/anvil/src/config.rs +++ b/crates/anvil/src/config.rs @@ -2,6 +2,7 @@ use crate::{ eth::{ backend::{ db::{Db, SerializableState}, + env::Env, fork::{ClientFork, ClientForkConfig}, genesis::GenesisConfig, mem::fork_db::ForkedDatabase, @@ -10,9 +11,9 @@ use crate::{ fees::{INITIAL_BASE_FEE, INITIAL_GAS_PRICE}, pool::transactions::{PoolTransaction, TransactionOrder}, }, - hardfork::{ChainHardfork, OptimismHardfork}, + hardfork::ChainHardfork, mem::{self, in_memory_db::MemDb}, - EthereumHardfork, FeeManager, PrecompileFactory, + EthereumHardfork, FeeManager, OptimismHardfork, PrecompileFactory, }; use alloy_consensus::BlockHeader; use alloy_genesis::Genesis; @@ -36,13 +37,18 @@ use foundry_config::Config; use foundry_evm::{ backend::{BlockchainDb, BlockchainDbMeta, SharedBackend}, constants::DEFAULT_CREATE2_DEPLOYER, - revm::primitives::{BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, SpecId, TxEnv}, utils::apply_chain_and_block_specific_env_changes, }; +use foundry_evm_core::AsEnvMut; use itertools::Itertools; +use op_revm::OpTransaction; use parking_lot::RwLock; use rand::thread_rng; -use revm::primitives::BlobExcessGasAndPrice; +use revm::{ + context::{BlockEnv, CfgEnv, TxEnv}, + context_interface::block::BlobExcessGasAndPrice, + primitives::hardfork::SpecId, +}; use serde_json::{json, Value}; use std::{ fmt::Write as FmtWrite, @@ -63,7 +69,7 @@ pub const NODE_PORT: u16 = 8545; /// Default chain id of the node pub const CHAIN_ID: u64 = 31337; /// The default gas limit for all transactions -pub const DEFAULT_GAS_LIMIT: u128 = 30_000_000; +pub const DEFAULT_GAS_LIMIT: u64 = 30_000_000; /// Default mnemonic for dev accounts pub const DEFAULT_MNEMONIC: &str = "test test test test test test test test test test test junk"; @@ -86,7 +92,7 @@ pub struct NodeConfig { /// Chain ID of the EVM chain pub chain_id: Option, /// Default gas limit for all txs - pub gas_limit: Option, + pub gas_limit: Option, /// If set to `true`, disables the block gas limit pub disable_block_gas_limit: bool, /// Default gas price for all txs @@ -505,7 +511,7 @@ impl NodeConfig { pub fn get_blob_excess_gas_and_price(&self) -> BlobExcessGasAndPrice { if let Some(blob_excess_gas_and_price) = &self.blob_excess_gas_and_price { - blob_excess_gas_and_price.clone() + *blob_excess_gas_and_price } else if let Some(excess_blob_gas) = self.genesis.as_ref().and_then(|g| g.excess_blob_gas) { BlobExcessGasAndPrice::new(excess_blob_gas, false) @@ -587,7 +593,7 @@ impl NodeConfig { /// Sets the gas limit #[must_use] - pub fn with_gas_limit(mut self, gas_limit: Option) -> Self { + pub fn with_gas_limit(mut self, gas_limit: Option) -> Self { self.gas_limit = gas_limit; self } @@ -1018,8 +1024,9 @@ impl NodeConfig { pub(crate) async fn setup(&mut self) -> Result { // configure the revm environment - let mut cfg = - CfgEnvWithHandlerCfg::new_with_spec_id(CfgEnv::default(), self.get_hardfork().into()); + let mut cfg = CfgEnv::default(); + cfg.spec = self.get_hardfork().into(); + cfg.chain_id = self.get_chain_id(); cfg.limit_contract_code_size = self.code_size_limit; // EIP-3607 rejects transactions from senders with deployed code. @@ -1027,25 +1034,28 @@ impl NodeConfig { // caller is a contract. So we disable the check by default. cfg.disable_eip3607 = true; cfg.disable_block_gas_limit = self.disable_block_gas_limit; - cfg.handler_cfg.is_optimism = self.enable_optimism; if let Some(value) = self.memory_limit { cfg.memory_limit = value; } - let env = revm::primitives::Env { - cfg: cfg.cfg_env, - block: BlockEnv { - gas_limit: U256::from(self.gas_limit()), - basefee: U256::from(self.get_base_fee()), + let spec_id = cfg.spec; + let mut env = Env::new( + cfg, + BlockEnv { + gas_limit: self.gas_limit(), + basefee: self.get_base_fee(), ..Default::default() }, - tx: TxEnv { chain_id: self.get_chain_id().into(), ..Default::default() }, - }; - let mut env = EnvWithHandlerCfg::new(Box::new(env), cfg.handler_cfg); + OpTransaction { + base: TxEnv { chain_id: Some(self.get_chain_id()), ..Default::default() }, + ..Default::default() + }, + self.enable_optimism, + ); let fees = FeeManager::new( - cfg.handler_cfg.spec_id, + spec_id, self.get_base_fee(), !self.disable_min_priority_fee, self.get_gas_price(), @@ -1064,16 +1074,16 @@ impl NodeConfig { // --chain-id flag gets precedence over the genesis.json chain id // if self.chain_id.is_none() { - env.cfg.chain_id = genesis.config.chain_id; + env.evm_env.cfg_env.chain_id = genesis.config.chain_id; } - env.block.timestamp = U256::from(genesis.timestamp); + env.evm_env.block_env.timestamp = genesis.timestamp; if let Some(base_fee) = genesis.base_fee_per_gas { - env.block.basefee = U256::from(base_fee); + env.evm_env.block_env.basefee = base_fee.try_into()?; } if let Some(number) = genesis.number { - env.block.number = U256::from(number); + env.evm_env.block_env.number = number; } - env.block.coinbase = genesis.coinbase; + env.evm_env.block_env.beneficiary = genesis.coinbase; } let genesis = GenesisConfig { @@ -1129,7 +1139,7 @@ impl NodeConfig { pub async fn setup_fork_db( &mut self, eth_rpc_url: String, - env: &mut EnvWithHandlerCfg, + env: &mut Env, fees: &FeeManager, ) -> Result<(Arc>>, Option)> { let (db, config) = self.setup_fork_db_config(eth_rpc_url, env, fees).await?; @@ -1146,7 +1156,7 @@ impl NodeConfig { pub async fn setup_fork_db_config( &mut self, eth_rpc_url: String, - env: &mut EnvWithHandlerCfg, + env: &mut Env, fees: &FeeManager, ) -> Result<(ForkedDatabase, ClientForkConfig)> { debug!(target: "node", ?eth_rpc_url, "setting up fork db"); @@ -1177,7 +1187,7 @@ impl NodeConfig { provider.get_chain_id().await.wrap_err("failed to fetch network chain ID")?; if alloy_chains::NamedChain::Mainnet == chain_id { let hardfork: EthereumHardfork = fork_block_number.into(); - env.handler_cfg.spec_id = hardfork.into(); + env.evm_env.cfg_env.spec = hardfork.into(); self.hardfork = Some(ChainHardfork::Ethereum(hardfork)); } Some(U256::from(chain_id)) @@ -1221,16 +1231,16 @@ latest block number: {latest_block}" let gas_limit = self.fork_gas_limit(&block); self.gas_limit = Some(gas_limit); - env.block = BlockEnv { - number: U256::from(fork_block_number), - timestamp: U256::from(block.header.timestamp), + env.evm_env.block_env = BlockEnv { + number: fork_block_number, + timestamp: block.header.timestamp, difficulty: block.header.difficulty, // ensures prevrandao is set prevrandao: Some(block.header.mix_hash.unwrap_or_default()), - gas_limit: U256::from(gas_limit), + gas_limit, // Keep previous `coinbase` and `basefee` value - coinbase: env.block.coinbase, - basefee: env.block.basefee, + beneficiary: env.evm_env.block_env.beneficiary, + basefee: env.evm_env.block_env.basefee, ..Default::default() }; @@ -1238,11 +1248,11 @@ latest block number: {latest_block}" if self.base_fee.is_none() { if let Some(base_fee) = block.header.base_fee_per_gas { self.base_fee = Some(base_fee); - env.block.basefee = U256::from(base_fee); + env.evm_env.block_env.basefee = base_fee; // this is the base fee of the current block, but we need the base fee of // the next block let next_block_base_fee = fees.get_next_block_base_fee_per_gas( - block.header.gas_used as u128, + block.header.gas_used, gas_limit, block.header.base_fee_per_gas.unwrap_or_default(), ); @@ -1253,10 +1263,10 @@ latest block number: {latest_block}" if let (Some(blob_excess_gas), Some(blob_gas_used)) = (block.header.excess_blob_gas, block.header.blob_gas_used) { - env.block.blob_excess_gas_and_price = + env.evm_env.block_env.blob_excess_gas_and_price = Some(BlobExcessGasAndPrice::new(blob_excess_gas, false)); - let next_block_blob_excess_gas = fees - .get_next_block_blob_excess_gas(blob_excess_gas as u128, blob_gas_used as u128); + let next_block_blob_excess_gas = + fees.get_next_block_blob_excess_gas(blob_excess_gas, blob_gas_used); fees.set_blob_excess_gas_and_price(BlobExcessGasAndPrice::new( next_block_blob_excess_gas, false, @@ -1285,15 +1295,15 @@ latest block number: {latest_block}" // need to update the dev signers and env with the chain id self.set_chain_id(Some(chain_id)); - env.cfg.chain_id = chain_id; - env.tx.chain_id = chain_id.into(); + env.evm_env.cfg_env.chain_id = chain_id; + env.tx.base.chain_id = chain_id.into(); chain_id }; let override_chain_id = self.chain_id; // apply changes such as difficulty -> prevrandao and chain specifics for current chain id - apply_chain_and_block_specific_env_changes::(env, &block); + apply_chain_and_block_specific_env_changes::(env.as_env_mut(), &block); - let meta = BlockchainDbMeta::new(*env.env.clone(), eth_rpc_url.clone()); + let meta = BlockchainDbMeta::new(env.evm_env.block_env.clone(), eth_rpc_url.clone()); let block_chain_db = if self.fork_chain_id.is_some() { BlockchainDb::new_skip_check(meta, self.block_cache_path(fork_block_number)) } else { @@ -1324,7 +1334,7 @@ latest block number: {latest_block}" compute_units_per_second: self.compute_units_per_second, total_difficulty: block.header.total_difficulty.unwrap_or_default(), blob_gas_used: block.header.blob_gas_used.map(|g| g as u128), - blob_excess_gas_and_price: env.block.blob_excess_gas_and_price.clone(), + blob_excess_gas_and_price: env.evm_env.block_env.blob_excess_gas_and_price, force_transactions, }; @@ -1344,24 +1354,24 @@ latest block number: {latest_block}" pub(crate) fn fork_gas_limit( &self, block: &Block, - ) -> u128 { + ) -> u64 { if !self.disable_block_gas_limit { if let Some(gas_limit) = self.gas_limit { return gas_limit; } else if block.header.gas_limit() > 0 { - return block.header.gas_limit() as u128; + return block.header.gas_limit(); } } - u64::MAX as u128 + u64::MAX } /// Returns the gas limit for a non forked anvil instance /// /// Checks the config for the `disable_block_gas_limit` flag - pub(crate) fn gas_limit(&self) -> u128 { + pub(crate) fn gas_limit(&self) -> u64 { if self.disable_block_gas_limit { - return u64::MAX as u128; + return u64::MAX; } self.gas_limit.unwrap_or(DEFAULT_GAS_LIMIT) @@ -1380,7 +1390,7 @@ async fn derive_block_and_transactions( ForkChoice::Block(block_number) => { let block_number = *block_number; if block_number >= 0 { - return Ok((block_number as u64, None)) + return Ok((block_number as u64, None)); } // subtract from latest block number let latest = provider.get_block_number().await?; diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index dc6e78bb6fedb..670ef2d091c08 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -27,7 +27,6 @@ use crate::{ }, filter::{EthFilter, Filters, LogsFilter}, mem::transaction_build, - revm::primitives::{BlobExcessGasAndPrice, Output}, ClientFork, LoggingManager, Miner, MiningMode, StorageInfo, }; use alloy_consensus::{ @@ -80,21 +79,20 @@ use anvil_core::{ }; use anvil_rpc::{error::RpcError, response::ResponseResult}; use foundry_common::provider::ProviderBuilder; -use foundry_evm::{ - backend::DatabaseError, - decode::RevertDecoder, - revm::{ - db::DatabaseRef, - interpreter::{return_ok, return_revert, InstructionResult}, - primitives::BlockEnv, - }, -}; +use foundry_evm::{backend::DatabaseError, decode::RevertDecoder}; use futures::{ channel::{mpsc::Receiver, oneshot}, StreamExt, }; use parking_lot::RwLock; -use revm::primitives::{eip7702::PER_EMPTY_ACCOUNT_COST, Bytecode}; +use revm::{ + bytecode::Bytecode, + context::BlockEnv, + context_interface::{block::BlobExcessGasAndPrice, result::Output}, + database::DatabaseRef, + interpreter::{return_ok, return_revert, InstructionResult}, + primitives::eip7702::PER_EMPTY_ACCOUNT_COST, +}; use std::{future::Future, sync::Arc, time::Duration}; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver}; @@ -1965,11 +1963,11 @@ impl EthApi { let env = self.backend.env().read(); let fork_config = self.backend.get_fork(); let tx_order = self.transaction_order.read(); - let hard_fork: &str = env.handler_cfg.spec_id.into(); + let hard_fork: &str = env.evm_env.cfg_env.spec.into(); Ok(NodeInfo { current_block_number: self.backend.best_number(), - current_block_timestamp: env.block.timestamp.try_into().unwrap_or(u64::MAX), + current_block_timestamp: env.evm_env.block_env.timestamp, current_block_hash: self.backend.best_hash(), hard_fork: hard_fork.to_string(), transaction_order: match *tx_order { @@ -2327,7 +2325,7 @@ impl EthApi { /// Sets the reported block number /// /// Handler for ETH RPC call: `anvil_setBlock` - pub fn anvil_set_block(&self, block_number: U256) -> Result<()> { + pub fn anvil_set_block(&self, block_number: u64) -> Result<()> { node_info!("anvil_setBlock"); self.backend.set_block_number(block_number); Ok(()) @@ -2753,8 +2751,7 @@ impl EthApi { // get the highest possible gas limit, either the request's set value or the currently // configured gas limit - let mut highest_gas_limit = - request.gas.map_or(block_env.gas_limit.to::(), |g| g as u128); + let mut highest_gas_limit = request.gas.map_or(block_env.gas_limit.into(), |g| g as u128); let gas_price = fees.gas_price.unwrap_or_default(); // If we have non-zero gas price, cap gas limit by sender balance @@ -3256,7 +3253,8 @@ impl TryFrom, u128, State)>> for GasEs InstructionResult::MemoryOOG | InstructionResult::MemoryLimitOOG | InstructionResult::PrecompileOOG | - InstructionResult::InvalidOperandOOG => Ok(Self::OutOfGas), + InstructionResult::InvalidOperandOOG | + InstructionResult::ReentrancySentryOOG => Ok(Self::OutOfGas), InstructionResult::OpcodeNotFound | InstructionResult::CallNotAllowedInsideStatic | @@ -3283,7 +3281,7 @@ impl TryFrom, u128, State)>> for GasEs // Handle Revm EOF InstructionResults: Not supported yet InstructionResult::ReturnContractInNotInitEOF | InstructionResult::EOFOpcodeDisabledInLegacy | - InstructionResult::EOFFunctionStackOverflow | + InstructionResult::SubRoutineStackOverflow | InstructionResult::CreateInitCodeStartingEF00 | InstructionResult::InvalidEOFInitCode | InstructionResult::EofAuxDataOverflow | diff --git a/crates/anvil/src/eth/backend/db.rs b/crates/anvil/src/eth/backend/db.rs index ecf1759e63a52..e39baee9193df 100644 --- a/crates/anvil/src/eth/backend/db.rs +++ b/crates/anvil/src/eth/backend/db.rs @@ -1,24 +1,24 @@ //! Helper types for working with [revm](foundry_evm::revm) -use crate::{mem::storage::MinedTransaction, revm::primitives::AccountInfo}; +use crate::mem::storage::MinedTransaction; use alloy_consensus::Header; -use alloy_primitives::{keccak256, Address, Bytes, B256, U256, U64}; +use alloy_primitives::{keccak256, map::HashMap, Address, Bytes, B256, U256}; use alloy_rpc_types::BlockId; use anvil_core::eth::{ block::Block, transaction::{MaybeImpersonatedTransaction, TransactionInfo, TypedReceipt, TypedTransaction}, }; use foundry_common::errors::FsPathError; -use foundry_evm::{ - backend::{ - BlockchainDb, DatabaseError, DatabaseResult, MemDb, RevertStateSnapshotAction, - StateSnapshot, - }, - revm::{ - db::{CacheDB, DatabaseRef, DbAccount}, - primitives::{BlockEnv, Bytecode, HashMap, KECCAK_EMPTY}, - Database, DatabaseCommit, - }, +use foundry_evm::backend::{ + BlockchainDb, DatabaseError, DatabaseResult, MemDb, RevertStateSnapshotAction, StateSnapshot, +}; +use revm::{ + bytecode::Bytecode, + context::BlockEnv, + database::{CacheDB, DatabaseRef, DbAccount}, + primitives::KECCAK_EMPTY, + state::AccountInfo, + Database, DatabaseCommit, }; use serde::{ de::{MapAccess, Visitor}, @@ -139,7 +139,7 @@ pub trait Db: fn dump_state( &self, at: BlockEnv, - best_number: U64, + best_number: u64, blocks: Vec, transactions: Vec, historical_states: Option, @@ -215,13 +215,13 @@ impl + Send + Sync + Clone + fmt::Debug> D } fn insert_block_hash(&mut self, number: U256, hash: B256) { - self.block_hashes.insert(number, hash); + self.cache.block_hashes.insert(number, hash); } fn dump_state( &self, _at: BlockEnv, - _best_number: U64, + _best_number: u64, _blocks: Vec, _transaction: Vec, _historical_states: Option, @@ -248,37 +248,37 @@ impl> MaybeFullDatabase for CacheDB { } fn maybe_as_full_db(&self) -> Option<&HashMap> { - Some(&self.accounts) + Some(&self.cache.accounts) } fn clear_into_state_snapshot(&mut self) -> StateSnapshot { - let db_accounts = std::mem::take(&mut self.accounts); + let db_accounts = std::mem::take(&mut self.cache.accounts); let mut accounts = HashMap::default(); let mut account_storage = HashMap::default(); for (addr, mut acc) in db_accounts { account_storage.insert(addr, std::mem::take(&mut acc.storage)); let mut info = acc.info; - info.code = self.contracts.remove(&info.code_hash); + info.code = self.cache.contracts.remove(&info.code_hash); accounts.insert(addr, info); } - let block_hashes = std::mem::take(&mut self.block_hashes); + let block_hashes = std::mem::take(&mut self.cache.block_hashes); StateSnapshot { accounts, storage: account_storage, block_hashes } } fn read_as_state_snapshot(&self) -> StateSnapshot { - let db_accounts = self.accounts.clone(); + let db_accounts = self.cache.accounts.clone(); let mut accounts = HashMap::default(); let mut account_storage = HashMap::default(); for (addr, acc) in db_accounts { account_storage.insert(addr, acc.storage.clone()); let mut info = acc.info; - info.code = self.contracts.get(&info.code_hash).cloned(); + info.code = self.cache.contracts.get(&info.code_hash).cloned(); accounts.insert(addr, info); } - let block_hashes = self.block_hashes.clone(); + let block_hashes = self.cache.block_hashes.clone(); StateSnapshot { accounts, storage: account_storage, block_hashes } } @@ -291,9 +291,9 @@ impl> MaybeFullDatabase for CacheDB { for (addr, mut acc) in accounts { if let Some(code) = acc.code.take() { - self.contracts.insert(acc.code_hash, code); + self.cache.contracts.insert(acc.code_hash, code); } - self.accounts.insert( + self.cache.accounts.insert( addr, DbAccount { info: acc, @@ -302,7 +302,7 @@ impl> MaybeFullDatabase for CacheDB { }, ); } - self.block_hashes = block_hashes; + self.cache.block_hashes = block_hashes; } } @@ -388,7 +388,7 @@ pub struct SerializableState { pub block: Option, pub accounts: BTreeMap, /// The best block number of the state, can be different from block number (Arbitrum chain). - pub best_block_number: Option, + pub best_block_number: Option, #[serde(default)] pub blocks: Vec, #[serde(default)] diff --git a/crates/anvil/src/eth/backend/env.rs b/crates/anvil/src/eth/backend/env.rs new file mode 100644 index 0000000000000..d4b8de797023d --- /dev/null +++ b/crates/anvil/src/eth/backend/env.rs @@ -0,0 +1,30 @@ +use alloy_evm::EvmEnv; +use foundry_evm::EnvMut; +use foundry_evm_core::AsEnvMut; +use op_revm::OpTransaction; +use revm::context::{BlockEnv, CfgEnv, TxEnv}; + +/// Helper container type for [`EvmEnv`] and [`OpTransaction`]. +#[derive(Clone, Debug, Default)] +pub struct Env { + pub evm_env: EvmEnv, + pub tx: OpTransaction, + pub is_optimism: bool, +} + +/// Helper container type for [`EvmEnv`] and [`OpTransaction`]. +impl Env { + pub fn new(cfg: CfgEnv, block: BlockEnv, tx: OpTransaction, is_optimism: bool) -> Self { + Self { evm_env: EvmEnv { cfg_env: cfg, block_env: block }, tx, is_optimism } + } +} + +impl AsEnvMut for Env { + fn as_env_mut(&mut self) -> EnvMut<'_> { + EnvMut { + block: &mut self.evm_env.block_env, + cfg: &mut self.evm_env.cfg_env, + tx: &mut self.tx.base, + } + } +} diff --git a/crates/anvil/src/eth/backend/executor.rs b/crates/anvil/src/eth/backend/executor.rs index 29b03756c17c8..2a036489fb2ce 100644 --- a/crates/anvil/src/eth/backend/executor.rs +++ b/crates/anvil/src/eth/backend/executor.rs @@ -1,17 +1,22 @@ use crate::{ eth::{ - backend::{db::Db, validate::TransactionValidator}, + backend::{ + db::Db, env::Env, mem::op_haltreason_to_instruction_result, + validate::TransactionValidator, + }, error::InvalidTransactionError, pool::transactions::PoolTransaction, }, - inject_precompiles, - mem::inspector::Inspector, + // inject_precompiles, + mem::inspector::AnvilInspector, PrecompileFactory, }; use alloy_consensus::{ constants::EMPTY_WITHDRAWALS, proofs::calculate_receipt_root, Receipt, ReceiptWithBloom, }; use alloy_eips::eip7685::EMPTY_REQUESTS_HASH; +use alloy_evm::{eth::EthEvmContext, EthEvm, Evm}; +use alloy_op_evm::OpEvm; use alloy_primitives::{Bloom, BloomInput, Log, B256}; use anvil_core::eth::{ block::{Block, BlockInfo, PartialHeader}, @@ -19,19 +24,18 @@ use anvil_core::eth::{ DepositReceipt, PendingTransaction, TransactionInfo, TypedReceipt, TypedTransaction, }, }; -use foundry_evm::{ - backend::DatabaseError, - revm::{ - interpreter::InstructionResult, - primitives::{ - BlockEnv, CfgEnvWithHandlerCfg, EVMError, EnvWithHandlerCfg, ExecutionResult, Output, - SpecId, - }, - }, - traces::CallTraceNode, - utils::odyssey_handler_register, +use foundry_evm::{backend::DatabaseError, traces::CallTraceNode}; +use foundry_evm_core::{either_evm::EitherEvm, evm::FoundryPrecompiles}; +use op_revm::{L1BlockInfo, OpContext}; +use revm::{ + context::{Block as RevmBlock, BlockEnv, CfgEnv, Evm as RevmEvm, JournalTr}, + context_interface::result::{EVMError, ExecutionResult, Output}, + database::WrapDatabaseRef, + handler::instructions::EthInstructions, + interpreter::InstructionResult, + primitives::hardfork::SpecId, + Database, DatabaseRef, Inspector, Journal, }; -use revm::db::WrapDatabaseRef; use std::sync::Arc; /// Represents an executed transaction (transacted on the DB) @@ -100,7 +104,7 @@ pub struct TransactionExecutor<'a, Db: ?Sized, V: TransactionValidator> { pub pending: std::vec::IntoIter>, pub block_env: BlockEnv, /// The configuration environment and spec id - pub cfg_env: CfgEnvWithHandlerCfg, + pub cfg_env: CfgEnv, pub parent_hash: B256, /// Cumulative gas used by all executed transactions pub gas_used: u64, @@ -108,6 +112,7 @@ pub struct TransactionExecutor<'a, Db: ?Sized, V: TransactionValidator> { pub blob_gas_used: u64, pub enable_steps_tracing: bool, pub odyssey: bool, + pub optimism: bool, pub print_logs: bool, pub print_traces: bool, /// Precompiles to inject to the EVM. @@ -124,22 +129,22 @@ impl TransactionExecutor<'_, DB, V> { let mut cumulative_gas_used = 0u64; let mut invalid = Vec::new(); let mut included = Vec::new(); - let gas_limit = self.block_env.gas_limit.to::(); + let gas_limit = self.block_env.gas_limit; let parent_hash = self.parent_hash; - let block_number = self.block_env.number.to::(); + let block_number = self.block_env.number; let difficulty = self.block_env.difficulty; - let beneficiary = self.block_env.coinbase; - let timestamp = self.block_env.timestamp.to::(); - let base_fee = if self.cfg_env.handler_cfg.spec_id.is_enabled_in(SpecId::LONDON) { - Some(self.block_env.basefee.to::()) + let beneficiary = self.block_env.beneficiary; + let timestamp = self.block_env.timestamp; + let base_fee = if self.cfg_env.spec.is_enabled_in(SpecId::LONDON) { + Some(self.block_env.basefee) } else { None }; - let is_shanghai = self.cfg_env.handler_cfg.spec_id >= SpecId::SHANGHAI; - let is_cancun = self.cfg_env.handler_cfg.spec_id >= SpecId::CANCUN; - let is_prague = self.cfg_env.handler_cfg.spec_id >= SpecId::PRAGUE; - let excess_blob_gas = if is_cancun { self.block_env.get_blob_excess_gas() } else { None }; + let is_shanghai = self.cfg_env.spec >= SpecId::SHANGHAI; + let is_cancun = self.cfg_env.spec >= SpecId::CANCUN; + let is_prague = self.cfg_env.spec >= SpecId::PRAGUE; + let excess_blob_gas = if is_cancun { self.block_env.blob_excess_gas() } else { None }; let mut cumulative_blob_gas_used = if is_cancun { Some(0u64) } else { None }; for tx in self.into_iter() { @@ -241,14 +246,14 @@ impl TransactionExecutor<'_, DB, V> { ExecutedTransactions { block, included, invalid } } - fn env_for(&self, tx: &PendingTransaction) -> EnvWithHandlerCfg { + fn env_for(&self, tx: &PendingTransaction) -> Env { let mut tx_env = tx.to_revm_tx_env(); - if self.cfg_env.handler_cfg.is_optimism { - tx_env.optimism.enveloped_tx = - Some(alloy_rlp::encode(&tx.transaction.transaction).into()); + + if self.optimism { + tx_env.enveloped_tx = Some(alloy_rlp::encode(&tx.transaction.transaction).into()); } - EnvWithHandlerCfg::new_with_cfg_env(self.cfg_env.clone(), self.block_env.clone(), tx_env) + Env::new(self.cfg_env.clone(), self.block_env.clone(), tx_env, self.optimism) } } @@ -280,8 +285,9 @@ impl Iterator for &mut TransactionExec let env = self.env_for(&transaction.pending_transaction); // check that we comply with the block's gas limit, if not disabled - let max_gas = self.gas_used.saturating_add(env.tx.gas_limit); - if !env.cfg.disable_block_gas_limit && max_gas > env.block.gas_limit.to::() { + let max_gas = self.gas_used.saturating_add(env.tx.base.gas_limit); + if !env.evm_env.cfg_env.disable_block_gas_limit && max_gas > env.evm_env.block_env.gas_limit + { return Some(TransactionExecutionOutcome::Exhausted(transaction)) } @@ -300,13 +306,12 @@ impl Iterator for &mut TransactionExec &env, ) { warn!(target: "backend", "Skipping invalid tx execution [{:?}] {}", transaction.hash(), err); - return Some(TransactionExecutionOutcome::Invalid(transaction, err)) + return Some(TransactionExecutionOutcome::Invalid(transaction, err)); } let nonce = account.nonce; - // records all call and step traces - let mut inspector = Inspector::default().with_tracing(); + let mut inspector = AnvilInspector::default().with_tracing(); if self.enable_steps_tracing { inspector = inspector.with_steps_tracing(); } @@ -318,14 +323,14 @@ impl Iterator for &mut TransactionExec } let exec_result = { - let mut evm = new_evm_with_inspector(&mut *self.db, env, &mut inspector, self.odyssey); - if let Some(factory) = &self.precompile_factory { - inject_precompiles(&mut evm, factory.precompiles()); - } + let mut evm = new_evm_with_inspector(&mut *self.db, &env, &mut inspector); + // if let Some(factory) = &self.precompile_factory { + // inject_precompiles(&mut evm, factory.precompiles()); + // } trace!(target: "backend", "[{:?}] executing", transaction.hash()); // transact and commit the transaction - match evm.transact_commit() { + match evm.transact_commit(env.tx) { Ok(exec_result) => exec_result, Err(err) => { warn!(target: "backend", "[{:?}] failed to execute: {:?}", transaction.hash(), err); @@ -362,7 +367,9 @@ impl Iterator for &mut TransactionExec ExecutionResult::Revert { gas_used, output } => { (InstructionResult::Revert, gas_used, Some(Output::Call(output)), None) } - ExecutionResult::Halt { reason, gas_used } => (reason.into(), gas_used, None, None), + ExecutionResult::Halt { reason, gas_used } => { + (op_haltreason_to_instruction_result(reason), gas_used, None, None) + } }; if exit_reason == InstructionResult::OutOfGas { @@ -407,35 +414,78 @@ fn build_logs_bloom(logs: Vec, bloom: &mut Bloom) { } /// Creates a database with given database and inspector, optionally enabling odyssey features. -pub fn new_evm_with_inspector( +pub fn new_evm_with_inspector( db: DB, - env: EnvWithHandlerCfg, - inspector: &mut dyn revm::Inspector, - odyssey: bool, -) -> revm::Evm<'_, &mut dyn revm::Inspector, DB> { - let EnvWithHandlerCfg { env, handler_cfg } = env; + env: &Env, + inspector: I, +) -> EitherEvm +where + DB: Database, + I: Inspector> + Inspector>, +{ + if env.is_optimism { + let op_context = OpContext { + journaled_state: { + let mut journal = Journal::new(db); + // Converting SpecId into OpSpecId + journal.set_spec_id(env.evm_env.cfg_env.spec); + journal + }, + block: env.evm_env.block_env.clone(), + cfg: env.evm_env.cfg_env.clone().with_spec(op_revm::OpSpecId::BEDROCK), + tx: env.tx.clone(), + chain: L1BlockInfo::default(), + error: Ok(()), + }; - let mut handler = revm::Handler::new(handler_cfg); + let evm = op_revm::OpEvm(RevmEvm::new_with_inspector( + op_context, + inspector, + EthInstructions::default(), + FoundryPrecompiles::default(), + )); + + let op = OpEvm::new(evm, true); + + EitherEvm::Op(op) + } else { + let evm_context = EthEvmContext { + journaled_state: { + let mut journal = Journal::new(db); + journal.set_spec_id(env.evm_env.cfg_env.spec); + journal + }, + block: env.evm_env.block_env.clone(), + cfg: env.evm_env.cfg_env.clone(), + tx: env.tx.base.clone(), + chain: (), + error: Ok(()), + }; - handler.append_handler_register_plain(revm::inspector_handle_register); - if odyssey { - handler.append_handler_register_plain(odyssey_handler_register); - } + let evm = RevmEvm::new_with_inspector( + evm_context, + inspector, + EthInstructions::default(), + FoundryPrecompiles::new(), + ); - let context = revm::Context::new(revm::EvmContext::new_with_env(db, env), inspector); + let eth = EthEvm::new(evm, true); - revm::Evm::new(context, handler) + EitherEvm::Eth(eth) + } } /// Creates a new EVM with the given inspector and wraps the database in a `WrapDatabaseRef`. -pub fn new_evm_with_inspector_ref<'a, DB>( - db: DB, - env: EnvWithHandlerCfg, - inspector: &mut dyn revm::Inspector>, - odyssey: bool, -) -> revm::Evm<'a, &mut dyn revm::Inspector>, WrapDatabaseRef> +pub fn new_evm_with_inspector_ref<'db, DB, I>( + db: &'db DB, + env: &Env, + inspector: &'db mut I, +) -> EitherEvm, &'db mut I, FoundryPrecompiles> where - DB: revm::DatabaseRef, + DB: DatabaseRef + 'db + ?Sized, + I: Inspector>> + + Inspector>>, + WrapDatabaseRef<&'db DB>: Database, { - new_evm_with_inspector(WrapDatabaseRef(db), env, inspector, odyssey) + new_evm_with_inspector(WrapDatabaseRef(db), env, inspector) } diff --git a/crates/anvil/src/eth/backend/fork.rs b/crates/anvil/src/eth/backend/fork.rs index ea8a9894cdf55..841d740abc44f 100644 --- a/crates/anvil/src/eth/backend/fork.rs +++ b/crates/anvil/src/eth/backend/fork.rs @@ -30,7 +30,7 @@ use parking_lot::{ lock_api::{RwLockReadGuard, RwLockWriteGuard}, RawRwLock, RwLock, }; -use revm::primitives::BlobExcessGasAndPrice; +use revm::context_interface::block::BlobExcessGasAndPrice; use std::{sync::Arc, time::Duration}; use tokio::sync::RwLock as AsyncRwLock; diff --git a/crates/anvil/src/eth/backend/genesis.rs b/crates/anvil/src/eth/backend/genesis.rs index 649717bd1cdf8..597dd1ee2d179 100644 --- a/crates/anvil/src/eth/backend/genesis.rs +++ b/crates/anvil/src/eth/backend/genesis.rs @@ -3,10 +3,8 @@ use crate::eth::backend::db::Db; use alloy_genesis::{Genesis, GenesisAccount}; use alloy_primitives::{Address, U256}; -use foundry_evm::{ - backend::DatabaseResult, - revm::primitives::{AccountInfo, Bytecode, KECCAK_EMPTY}, -}; +use foundry_evm::backend::DatabaseResult; +use revm::{bytecode::Bytecode, primitives::KECCAK_EMPTY, state::AccountInfo}; use tokio::sync::RwLockWriteGuard; /// Genesis settings diff --git a/crates/anvil/src/eth/backend/mem/fork_db.rs b/crates/anvil/src/eth/backend/mem/fork_db.rs index be5c3bcd7b32e..56a4944ada5a8 100644 --- a/crates/anvil/src/eth/backend/mem/fork_db.rs +++ b/crates/anvil/src/eth/backend/mem/fork_db.rs @@ -1,20 +1,20 @@ -use crate::{ - eth::backend::db::{ - Db, MaybeForkedDatabase, MaybeFullDatabase, SerializableAccountRecord, SerializableBlock, - SerializableHistoricalStates, SerializableState, SerializableTransaction, StateDb, - }, - revm::primitives::AccountInfo, +use crate::eth::backend::db::{ + Db, MaybeForkedDatabase, MaybeFullDatabase, SerializableAccountRecord, SerializableBlock, + SerializableHistoricalStates, SerializableState, SerializableTransaction, StateDb, }; -use alloy_primitives::{map::HashMap, Address, B256, U256, U64}; +use alloy_primitives::{map::HashMap, Address, B256, U256}; use alloy_rpc_types::BlockId; use foundry_evm::{ backend::{ BlockchainDb, DatabaseError, DatabaseResult, RevertStateSnapshotAction, StateSnapshot, }, fork::database::ForkDbStateSnapshot, - revm::{primitives::BlockEnv, Database}, }; -use revm::{db::DbAccount, DatabaseRef}; +use revm::{ + context::BlockEnv, + database::{Database, DatabaseRef, DbAccount}, + state::AccountInfo, +}; pub use foundry_evm::fork::database::ForkedDatabase; @@ -36,7 +36,7 @@ impl Db for ForkedDatabase { fn dump_state( &self, at: BlockEnv, - best_number: U64, + best_number: u64, blocks: Vec, transactions: Vec, historical_states: Option, @@ -44,6 +44,7 @@ impl Db for ForkedDatabase { let mut db = self.database().clone(); let accounts = self .database() + .cache .accounts .clone() .into_iter() @@ -93,7 +94,7 @@ impl MaybeFullDatabase for ForkedDatabase { } fn maybe_as_full_db(&self) -> Option<&HashMap> { - Some(&self.database().accounts) + Some(&self.database().cache.accounts) } fn clear_into_state_snapshot(&mut self) -> StateSnapshot { @@ -132,7 +133,7 @@ impl MaybeFullDatabase for ForkDbStateSnapshot { } fn maybe_as_full_db(&self) -> Option<&HashMap> { - Some(&self.local.accounts) + Some(&self.local.cache.accounts) } fn clear_into_state_snapshot(&mut self) -> StateSnapshot { diff --git a/crates/anvil/src/eth/backend/mem/in_memory_db.rs b/crates/anvil/src/eth/backend/mem/in_memory_db.rs index adc9c6f1f44b7..08a78b43406c7 100644 --- a/crates/anvil/src/eth/backend/mem/in_memory_db.rs +++ b/crates/anvil/src/eth/backend/mem/in_memory_db.rs @@ -6,15 +6,19 @@ use crate::{ SerializableHistoricalStates, SerializableState, SerializableTransaction, StateDb, }, mem::state::state_root, - revm::{db::DbAccount, primitives::AccountInfo}, }; -use alloy_primitives::{map::HashMap, Address, B256, U256, U64}; +use alloy_primitives::{map::HashMap, Address, B256, U256}; use alloy_rpc_types::BlockId; use foundry_evm::backend::{BlockchainDb, DatabaseResult, StateSnapshot}; +use revm::{ + context::BlockEnv, + database::{DatabaseRef, DbAccount}, + state::AccountInfo, +}; // reexport for convenience -pub use foundry_evm::{backend::MemDb, revm::db::DatabaseRef}; -use foundry_evm::{backend::RevertStateSnapshotAction, revm::primitives::BlockEnv}; +pub use foundry_evm::backend::MemDb; +use foundry_evm::backend::RevertStateSnapshotAction; impl Db for MemDb { fn insert_account(&mut self, address: Address, account: AccountInfo) { @@ -26,19 +30,20 @@ impl Db for MemDb { } fn insert_block_hash(&mut self, number: U256, hash: B256) { - self.inner.block_hashes.insert(number, hash); + self.inner.cache.block_hashes.insert(number, hash); } fn dump_state( &self, at: BlockEnv, - best_number: U64, + best_number: u64, blocks: Vec, transactions: Vec, historical_states: Option, ) -> DatabaseResult> { let accounts = self .inner + .cache .accounts .clone() .into_iter() @@ -92,7 +97,7 @@ impl Db for MemDb { } fn maybe_state_root(&self) -> Option { - Some(state_root(&self.inner.accounts)) + Some(state_root(&self.inner.cache.accounts)) } fn current_state(&self) -> StateDb { @@ -106,7 +111,7 @@ impl MaybeFullDatabase for MemDb { } fn maybe_as_full_db(&self) -> Option<&HashMap> { - Some(&self.inner.accounts) + Some(&self.inner.cache.accounts) } fn clear_into_state_snapshot(&mut self) -> StateSnapshot { @@ -144,7 +149,7 @@ impl MaybeForkedDatabase for MemDb { mod tests { use super::*; use alloy_primitives::{address, Bytes}; - use foundry_evm::revm::primitives::{Bytecode, KECCAK_EMPTY}; + use revm::{bytecode::Bytecode, primitives::KECCAK_EMPTY}; use std::collections::BTreeMap; // verifies that all substantial aspects of a loaded account remain the same after an account @@ -171,7 +176,7 @@ mod tests { // blocks dumping/loading tested in storage.rs let state = dump_db - .dump_state(Default::default(), U64::ZERO, Vec::new(), Vec::new(), Default::default()) + .dump_state(Default::default(), 0, Vec::new(), Vec::new(), Default::default()) .unwrap() .unwrap(); diff --git a/crates/anvil/src/eth/backend/mem/inspector.rs b/crates/anvil/src/eth/backend/mem/inspector.rs index 9a68b70612461..b850af64300bf 100644 --- a/crates/anvil/src/eth/backend/mem/inspector.rs +++ b/crates/anvil/src/eth/backend/mem/inspector.rs @@ -1,33 +1,37 @@ //! Anvil specific [`revm::Inspector`] implementation -use crate::{eth::macros::node_info, revm::Database}; -use alloy_primitives::{Address, Log}; +use crate::eth::macros::node_info; +use alloy_evm::eth::EthEvmContext; +use alloy_primitives::{Address, Log, U256}; use foundry_evm::{ + backend::DatabaseError, call_inspectors, decode::decode_console_logs, inspectors::{LogCollector, TracingInspector}, - revm::{ - interpreter::{ - CallInputs, CallOutcome, CreateInputs, CreateOutcome, EOFCreateInputs, Interpreter, - }, - primitives::U256, - EvmContext, - }, traces::{ render_trace_arena_inner, CallTraceDecoder, SparsedTraceArena, TracingInspectorConfig, }, }; +use revm::{ + context::ContextTr, + inspector::JournalExt, + interpreter::{ + interpreter::EthInterpreter, CallInputs, CallOutcome, CreateInputs, CreateOutcome, + EOFCreateInputs, Interpreter, + }, + Database, Inspector, +}; /// The [`revm::Inspector`] used when transacting in the evm #[derive(Clone, Debug, Default)] -pub struct Inspector { +pub struct AnvilInspector { /// Collects all traces pub tracer: Option, /// Collects all `console.sol` logs pub log_collector: Option, } -impl Inspector { +impl AnvilInspector { /// Called after the inspecting the evm /// /// This will log all `console.sol` logs @@ -104,32 +108,38 @@ fn print_traces(tracer: TracingInspector) { node_info!("{}", render_trace_arena_inner(&traces, false, true)); } -impl revm::Inspector for Inspector { - fn initialize_interp(&mut self, interp: &mut Interpreter, ecx: &mut EvmContext) { +impl Inspector for AnvilInspector +where + D: Database, + CTX: ContextTr, + CTX::Journal: JournalExt, +{ + fn initialize_interp(&mut self, interp: &mut Interpreter, ecx: &mut CTX) { call_inspectors!([&mut self.tracer], |inspector| { inspector.initialize_interp(interp, ecx); }); } - fn step(&mut self, interp: &mut Interpreter, ecx: &mut EvmContext) { + fn step(&mut self, interp: &mut Interpreter, ecx: &mut CTX) { call_inspectors!([&mut self.tracer], |inspector| { inspector.step(interp, ecx); }); } - fn step_end(&mut self, interp: &mut Interpreter, ecx: &mut EvmContext) { + fn step_end(&mut self, interp: &mut Interpreter, ecx: &mut CTX) { call_inspectors!([&mut self.tracer], |inspector| { inspector.step_end(interp, ecx); }); } - fn log(&mut self, interp: &mut Interpreter, ecx: &mut EvmContext, log: &Log) { + fn log(&mut self, interp: &mut Interpreter, ecx: &mut CTX, log: Log) { call_inspectors!([&mut self.tracer, &mut self.log_collector], |inspector| { - inspector.log(interp, ecx, log); + // TODO: rm the log.clone + inspector.log(interp, ecx, log.clone()); }); } - fn call(&mut self, ecx: &mut EvmContext, inputs: &mut CallInputs) -> Option { + fn call(&mut self, ecx: &mut CTX, inputs: &mut CallInputs) -> Option { call_inspectors!( #[ret] [&mut self.tracer, &mut self.log_collector], @@ -138,24 +148,13 @@ impl revm::Inspector for Inspector { None } - fn call_end( - &mut self, - ecx: &mut EvmContext, - inputs: &CallInputs, - outcome: CallOutcome, - ) -> CallOutcome { + fn call_end(&mut self, ecx: &mut CTX, inputs: &CallInputs, outcome: &mut CallOutcome) { if let Some(tracer) = &mut self.tracer { - return tracer.call_end(ecx, inputs, outcome); + tracer.call_end(ecx, inputs, outcome); } - - outcome } - fn create( - &mut self, - ecx: &mut EvmContext, - inputs: &mut CreateInputs, - ) -> Option { + fn create(&mut self, ecx: &mut CTX, inputs: &mut CreateInputs) -> Option { if let Some(tracer) = &mut self.tracer { if let Some(out) = tracer.create(ecx, inputs) { return Some(out); @@ -164,25 +163,14 @@ impl revm::Inspector for Inspector { None } - fn create_end( - &mut self, - ecx: &mut EvmContext, - inputs: &CreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { + fn create_end(&mut self, ecx: &mut CTX, inputs: &CreateInputs, outcome: &mut CreateOutcome) { if let Some(tracer) = &mut self.tracer { - return tracer.create_end(ecx, inputs, outcome); + tracer.create_end(ecx, inputs, outcome); } - - outcome } #[inline] - fn eofcreate( - &mut self, - ecx: &mut EvmContext, - inputs: &mut EOFCreateInputs, - ) -> Option { + fn eofcreate(&mut self, ecx: &mut CTX, inputs: &mut EOFCreateInputs) -> Option { if let Some(tracer) = &mut self.tracer { if let Some(out) = tracer.eofcreate(ecx, inputs) { return Some(out); @@ -194,21 +182,19 @@ impl revm::Inspector for Inspector { #[inline] fn eofcreate_end( &mut self, - ecx: &mut EvmContext, + ecx: &mut CTX, inputs: &EOFCreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { + outcome: &mut CreateOutcome, + ) { if let Some(tracer) = &mut self.tracer { - return tracer.eofcreate_end(ecx, inputs, outcome); + tracer.eofcreate_end(ecx, inputs, outcome); } - - outcome } #[inline] fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { if let Some(tracer) = &mut self.tracer { - revm::Inspector::::selfdestruct(tracer, contract, target, value); + Inspector::>::selfdestruct(tracer, contract, target, value); } } } diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 0cb4ad0ab65f9..35cbe1b19d6d2 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -1,13 +1,13 @@ //! In-memory blockchain backend. use self::state::trie_storage; -use super::executor::new_evm_with_inspector_ref; use crate::{ config::PruneStateHistoryConfig, eth::{ backend::{ cheats::CheatsManager, db::{Db, MaybeFullDatabase, SerializableState}, + env::Env, executor::{ExecutedTransactions, TransactionExecutor}, fork::ClientFork, genesis::GenesisConfig, @@ -26,29 +26,38 @@ use crate::{ sign::build_typed_transaction, util::get_precompiles_for, }, - inject_precompiles, + // inject_precompiles, mem::{ - inspector::Inspector, + inspector::AnvilInspector, storage::{BlockchainStorage, InMemoryBlockStates, MinedBlockOutcome}, }, - revm::{db::DatabaseRef, primitives::AccountInfo}, - ForkChoice, NodeConfig, PrecompileFactory, + ForkChoice, + NodeConfig, + PrecompileFactory, }; use alloy_chains::NamedChain; use alloy_consensus::{ proofs::{calculate_receipt_root, calculate_transaction_root}, transaction::Recovered, - Account, BlockHeader, Header, Receipt, ReceiptWithBloom, Signed, + Account, BlockHeader, EnvKzgSettings, Header, Receipt, ReceiptWithBloom, Signed, Transaction as TransactionTrait, TxEnvelope, }; -use alloy_eips::{eip1559::BaseFeeParams, eip4844::MAX_BLOBS_PER_BLOCK}; +use alloy_eips::{ + eip1559::BaseFeeParams, + eip2718::{ + EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID, + LEGACY_TX_TYPE_ID, + }, + eip4844::MAX_BLOBS_PER_BLOCK, +}; +use alloy_evm::{eth::EthEvmContext, Database, Evm}; use alloy_network::{ AnyHeader, AnyRpcBlock, AnyRpcHeader, AnyRpcTransaction, AnyTxEnvelope, AnyTxType, EthereumWallet, UnknownTxEnvelope, UnknownTypedTransaction, }; use alloy_primitives::{ - address, hex, keccak256, logs_bloom, utils::Unit, Address, Bytes, TxHash, TxKind, B256, U256, - U64, + address, hex, keccak256, logs_bloom, map::HashMap, utils::Unit, Address, Bytes, TxHash, TxKind, + B256, U256, U64, }; use alloy_rpc_types::{ anvil::Forking, @@ -75,9 +84,9 @@ use alloy_trie::{proof::ProofRetainer, HashBuilder, Nibbles}; use anvil_core::eth::{ block::{Block, BlockInfo}, transaction::{ - optimism::DepositTransaction, transaction_request_to_typed, DepositReceipt, - MaybeImpersonatedTransaction, PendingTransaction, ReceiptResponse, TransactionInfo, - TypedReceipt, TypedTransaction, + has_optimism_fields, optimism::DepositTransaction, transaction_request_to_typed, + DepositReceipt, MaybeImpersonatedTransaction, PendingTransaction, ReceiptResponse, + TransactionInfo, TypedReceipt, TypedTransaction, }, wallet::{Capabilities, DelegationCapability, WalletCapabilities}, }; @@ -90,24 +99,26 @@ use foundry_evm::{ constants::DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE, decode::RevertDecoder, inspectors::AccessListInspector, - revm::{ - db::CacheDB, - interpreter::InstructionResult, - primitives::{ - BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ExecutionResult, Output, SpecId, - TxEnv, KECCAK_EMPTY, - }, - }, traces::TracingInspectorConfig, }; +use foundry_evm_core::{either_evm::EitherEvm, evm::FoundryPrecompiles}; use futures::channel::mpsc::{unbounded, UnboundedSender}; use op_alloy_consensus::{TxDeposit, DEPOSIT_TX_TYPE_ID}; +use op_revm::{ + transaction::deposit::DepositTransactionParts, OpContext, OpHaltReason, OpTransaction, +}; use parking_lot::{Mutex, RwLock}; use revm::{ - db::WrapDatabaseRef, - interpreter::Host, - primitives::{BlobExcessGasAndPrice, HashMap, OptimismFields, ResultAndState}, - DatabaseCommit, + context::{Block as RevmBlock, BlockEnv, TxEnv}, + context_interface::{ + block::BlobExcessGasAndPrice, + result::{ExecutionResult, Output, ResultAndState}, + }, + database::{CacheDB, DatabaseRef, WrapDatabaseRef}, + interpreter::InstructionResult, + primitives::{hardfork::SpecId, KECCAK_EMPTY}, + state::AccountInfo, + DatabaseCommit, Inspector, }; use revm_inspectors::transfer::TransferInspector; use std::{ @@ -121,6 +132,8 @@ use std::{ use storage::{Blockchain, MinedTransaction, DEFAULT_HISTORY_LIMIT}; use tokio::sync::RwLock as AsyncRwLock; +use super::executor::new_evm_with_inspector_ref; + pub mod cache; pub mod fork_db; pub mod in_memory_db; @@ -168,29 +181,30 @@ impl BlockRequest { pub struct Backend { /// Access to [`revm::Database`] abstraction. /// - /// This will be used in combination with [`revm::Evm`] and is responsible for feeding data to - /// the evm during its execution. + /// This will be used in combination with [`alloy_evm::Evm`] and is responsible for feeding + /// data to the evm during its execution. /// /// At time of writing, there are two different types of `Db`: /// - [`MemDb`](crate::mem::in_memory_db::MemDb): everything is stored in memory /// - [`ForkDb`](crate::mem::fork_db::ForkedDatabase): forks off a remote client, missing /// data is retrieved via RPC-calls /// - /// In order to commit changes to the [`revm::Database`], the [`revm::Evm`] requires mutable - /// access, which requires a write-lock from this `db`. In forking mode, the time during - /// which the write-lock is active depends on whether the `ForkDb` can provide all requested - /// data from memory or whether it has to retrieve it via RPC calls first. This means that it - /// potentially blocks for some time, even taking into account the rate limits of RPC - /// endpoints. Therefore the `Db` is guarded by a `tokio::sync::RwLock` here so calls that - /// need to read from it, while it's currently written to, don't block. E.g. a new block is - /// currently mined and a new [`Self::set_storage_at()`] request is being executed. + /// In order to commit changes to the [`revm::Database`], the [`alloy_evm::Evm`] requires + /// mutable access, which requires a write-lock from this `db`. In forking mode, the time + /// during which the write-lock is active depends on whether the `ForkDb` can provide all + /// requested data from memory or whether it has to retrieve it via RPC calls first. This + /// means that it potentially blocks for some time, even taking into account the rate + /// limits of RPC endpoints. Therefore the `Db` is guarded by a `tokio::sync::RwLock` here + /// so calls that need to read from it, while it's currently written to, don't block. E.g. + /// a new block is currently mined and a new [`Self::set_storage_at()`] request is being + /// executed. db: Arc>>, /// stores all block related data in memory. blockchain: Blockchain, /// Historic states of previous blocks. states: Arc>, /// Env data of the chain - env: Arc>, + env: Arc>, /// This is set if this is currently forked off another client. fork: Arc>>, /// Provides time related info, like timestamp. @@ -230,7 +244,7 @@ impl Backend { #[expect(clippy::too_many_arguments)] pub async fn with_genesis( db: Arc>>, - env: Arc>, + env: Arc>, genesis: GenesisConfig, fees: FeeManager, fork: Arc>>, @@ -253,7 +267,7 @@ impl Backend { let env = env.read(); Blockchain::new( &env, - env.handler_cfg.spec_id, + env.evm_env.cfg_env.spec, fees.is_eip1559().then(|| fees.base_fee()), genesis.timestamp, genesis.number, @@ -310,7 +324,7 @@ impl Backend { let mut capabilities = WalletCapabilities::default(); - let chain_id = env.read().cfg.chain_id; + let chain_id = env.read().evm_env.cfg_env.chain_id; capabilities.insert( chain_id, Capabilities { @@ -389,7 +403,7 @@ impl Backend { /// Adds an address to the [`DelegationCapability`] of the wallet. pub(crate) fn add_capability(&self, address: Address) { - let chain_id = self.env.read().cfg.chain_id; + let chain_id = self.env.read().evm_env.cfg_env.chain_id; let mut capabilities = self.capabilities.write(); let mut capability = capabilities.get(chain_id).cloned().unwrap_or_default(); capability.delegation.addresses.push(address); @@ -467,7 +481,7 @@ impl Backend { } // Ensure EIP-3607 is disabled let mut env = self.env.write(); - env.cfg.disable_eip3607 = true; + env.evm_env.cfg_env.disable_eip3607 = true; self.cheats.impersonate(addr) } @@ -504,7 +518,7 @@ impl Backend { } pub fn precompiles(&self) -> Vec

{ - get_precompiles_for(self.env.read().handler_cfg.spec_id) + get_precompiles_for(self.env.read().evm_env.cfg_env.spec) } /// Resets the fork to a fresh state @@ -564,23 +578,23 @@ impl Backend { let gas_limit = self.node_config.read().await.fork_gas_limit(&fork_block); let mut env = self.env.write(); - env.cfg.chain_id = fork.chain_id(); - env.block = BlockEnv { - number: U256::from(fork_block_number), - timestamp: U256::from(fork_block.header.timestamp), - gas_limit: U256::from(gas_limit), + env.evm_env.cfg_env.chain_id = fork.chain_id(); + env.evm_env.block_env = BlockEnv { + number: fork_block_number, + timestamp: fork_block.header.timestamp, + gas_limit, difficulty: fork_block.header.difficulty, prevrandao: Some(fork_block.header.mix_hash.unwrap_or_default()), - // Keep previous `coinbase` and `basefee` value - coinbase: env.block.coinbase, - basefee: env.block.basefee, - ..env.block.clone() + // Keep previous `beneficiary` and `basefee` value + beneficiary: env.evm_env.block_env.beneficiary, + basefee: env.evm_env.block_env.basefee, + ..env.evm_env.block_env.clone() }; // this is the base fee of the current block, but we need the base fee of // the next block let next_block_base_fee = self.fees.get_next_block_base_fee_per_gas( - fork_block.header.gas_used as u128, + fork_block.header.gas_used, gas_limit, fork_block.header.base_fee_per_gas.unwrap_or_default(), ); @@ -656,7 +670,7 @@ impl Backend { } /// The env data of the blockchain - pub fn env(&self) -> &Arc> { + pub fn env(&self) -> &Arc> { &self.env } @@ -667,27 +681,27 @@ impl Backend { /// Returns the current best number of the chain pub fn best_number(&self) -> u64 { - self.blockchain.storage.read().best_number.try_into().unwrap_or(u64::MAX) + self.blockchain.storage.read().best_number } /// Sets the block number - pub fn set_block_number(&self, number: U256) { + pub fn set_block_number(&self, number: u64) { let mut env = self.env.write(); - env.block.number = number; + env.evm_env.block_env.number = number; } /// Returns the client coinbase address. pub fn coinbase(&self) -> Address { - self.env.read().block.coinbase + self.env.read().evm_env.block_env.beneficiary } /// Returns the client coinbase address. pub fn chain_id(&self) -> U256 { - U256::from(self.env.read().cfg.chain_id) + U256::from(self.env.read().evm_env.cfg_env.chain_id) } pub fn set_chain_id(&self, chain_id: u64) { - self.env.write().cfg.chain_id = chain_id; + self.env.write().evm_env.cfg_env.chain_id = chain_id; } /// Returns balance of the given account. @@ -702,7 +716,7 @@ impl Backend { /// Sets the coinbase address pub fn set_coinbase(&self, address: Address) { - self.env.write().block.coinbase = address; + self.env.write().evm_env.block_env.beneficiary = address; } /// Sets the nonce of the given address @@ -732,7 +746,7 @@ impl Backend { /// Returns the configured specid pub fn spec_id(&self) -> SpecId { - self.env.read().handler_cfg.spec_id + self.env.read().evm_env.cfg_env.spec } /// Returns true for post London @@ -762,7 +776,7 @@ impl Backend { /// Returns true if op-stack deposits are active pub fn is_optimism(&self) -> bool { - self.env.read().handler_cfg.is_optimism + self.env.read().is_optimism } /// Returns an error if EIP1559 is not active (pre Berlin) @@ -805,12 +819,12 @@ impl Backend { /// Returns the block gas limit pub fn gas_limit(&self) -> u64 { - self.env.read().block.gas_limit.saturating_to() + self.env.read().evm_env.block_env.gas_limit } /// Sets the block gas limit pub fn set_gas_limit(&self, gas_limit: u64) { - self.env.write().block.gas_limit = U256::from(gas_limit); + self.env.write().evm_env.block_env.gas_limit = gas_limit; } /// Returns the current base fee @@ -872,7 +886,6 @@ impl Backend { for n in ((num + 1)..=current_height).rev() { trace!(target: "backend", "reverting block {}", n); - let n = U64::from(n); if let Some(hash) = storage.hashes.remove(&n) { if let Some(block) = storage.blocks.remove(&hash) { for tx in block.transactions { @@ -882,7 +895,7 @@ impl Backend { } } - storage.best_number = U64::from(num); + storage.best_number = num; storage.best_hash = hash; hash }; @@ -893,18 +906,18 @@ impl Backend { self.time.reset(reset_time); let mut env = self.env.write(); - env.block = BlockEnv { - number: U256::from(num), - timestamp: U256::from(block.header.timestamp), + env.evm_env.block_env = BlockEnv { + number: num, + timestamp: block.header.timestamp, difficulty: block.header.difficulty, // ensures prevrandao is set prevrandao: Some(block.header.mix_hash.unwrap_or_default()), - gas_limit: U256::from(block.header.gas_limit), - // Keep previous `coinbase` and `basefee` value - coinbase: env.block.coinbase, - basefee: env.block.basefee, + gas_limit: block.header.gas_limit, + // Keep previous `beneficiary` and `basefee` value + beneficiary: env.evm_env.block_env.beneficiary, + basefee: env.evm_env.block_env.basefee, ..Default::default() - }; + } } Ok(self.db.write().await.revert_state(id, RevertStateSnapshotAction::RevertRemove)) } @@ -918,7 +931,7 @@ impl Backend { &self, preserve_historical_states: bool, ) -> Result { - let at = self.env.read().block.clone(); + let at = self.env.read().evm_env.block_env.clone(); let best_number = self.blockchain.storage.read().best_number; let blocks = self.blockchain.storage.read().serialized_blocks(); let transactions = self.blockchain.storage.read().serialized_transactions(); @@ -961,19 +974,19 @@ impl Backend { self.blockchain.storage.write().load_transactions(state.transactions.clone()); // reset the block env if let Some(block) = state.block.clone() { - self.env.write().block = block.clone(); + self.env.write().evm_env.block_env = block.clone(); // Set the current best block number. // Defaults to block number for compatibility with existing state files. let fork_num_and_hash = self.get_fork().map(|f| (f.block_number(), f.block_hash())); if let Some((number, hash)) = fork_num_and_hash { - let best_number = state.best_block_number.unwrap_or(block.number.to::()); + let best_number = state.best_block_number.unwrap_or(block.number); trace!(target: "backend", state_block_number=?best_number, fork_block_number=?number); // If the state.block_number is greater than the fork block number, set best number // to the state block number. // Ref: https://github.com/foundry-rs/foundry/issues/9539 - if best_number.to::() > number { + if best_number > number { self.blockchain.storage.write().best_number = best_number; let best_hash = self.blockchain.storage.read().hash(best_number.into()).ok_or_else( @@ -987,11 +1000,11 @@ impl Backend { } else { // If loading state file on a fork, set best number to the fork block number. // Ref: https://github.com/foundry-rs/foundry/pull/9215#issue-2618681838 - self.blockchain.storage.write().best_number = U64::from(number); + self.blockchain.storage.write().best_number = number; self.blockchain.storage.write().best_hash = hash; } } else { - let best_number = state.best_block_number.unwrap_or(block.number.to::()); + let best_number = state.best_block_number.unwrap_or(block.number); self.blockchain.storage.write().best_number = best_number; // Set the current best block hash; @@ -1009,13 +1022,13 @@ impl Backend { if let Some(latest) = state.blocks.iter().max_by_key(|b| b.header.number) { let header = &latest.header; let next_block_base_fee = self.fees.get_next_block_base_fee_per_gas( - header.gas_used as u128, - header.gas_limit as u128, + header.gas_used, + header.gas_limit, header.base_fee_per_gas.unwrap_or_default(), ); let next_block_excess_blob_gas = self.fees.get_next_block_blob_excess_gas( - header.excess_blob_gas.map(|g| g as u128).unwrap_or_default(), - header.blob_gas_used.map(|g| g as u128).unwrap_or_default(), + header.excess_blob_gas.unwrap_or_default(), + header.blob_gas_used.unwrap_or_default(), ); // update next base fee @@ -1060,34 +1073,37 @@ impl Backend { } /// Returns the environment for the next block - fn next_env(&self) -> EnvWithHandlerCfg { + fn next_env(&self) -> Env { let mut env = self.env.read().clone(); // increase block number for this block - env.block.number = env.block.number.saturating_add(U256::from(1)); - env.block.basefee = U256::from(self.base_fee()); - env.block.timestamp = U256::from(self.time.current_call_timestamp()); + env.evm_env.block_env.number = env.evm_env.block_env.number.saturating_add(1); + env.evm_env.block_env.basefee = self.base_fee(); + env.evm_env.block_env.timestamp = self.time.current_call_timestamp(); env } /// Creates an EVM instance with optionally injected precompiles. - #[expect(clippy::type_complexity)] - fn new_evm_with_inspector_ref<'i, 'db>( + fn new_evm_with_inspector_ref<'db, I>( &self, db: &'db dyn DatabaseRef, - env: EnvWithHandlerCfg, - inspector: &'i mut dyn revm::Inspector< - WrapDatabaseRef<&'db dyn DatabaseRef>, - >, - ) -> revm::Evm< - '_, - &'i mut dyn revm::Inspector>>, + env: &Env, + inspector: &'db mut I, + ) -> EitherEvm< WrapDatabaseRef<&'db dyn DatabaseRef>, - > { - let mut evm = new_evm_with_inspector_ref(db, env, inspector, self.odyssey); - if let Some(factory) = &self.precompile_factory { - inject_precompiles(&mut evm, factory.precompiles()); - } - evm + &'db mut I, + FoundryPrecompiles, + > + where + I: Inspector>>> + + Inspector>>>, + WrapDatabaseRef<&'db dyn DatabaseRef>: + Database, + { + new_evm_with_inspector_ref(db, env, inspector) + // TODO(yash): inject precompiles + // if let Some(factory) = &self.precompile_factory { + // inject_precompiles(&mut evm, factory.precompiles()); + // } } /// executes the transactions without writing to the underlying database @@ -1101,15 +1117,15 @@ impl Backend { let mut env = self.next_env(); env.tx = tx.pending_transaction.to_revm_tx_env(); - if env.handler_cfg.is_optimism { - env.tx.optimism.enveloped_tx = + if env.is_optimism { + env.tx.enveloped_tx = Some(alloy_rlp::encode(&tx.pending_transaction.transaction.transaction).into()); } let db = self.db.read().await; let mut inspector = self.build_inspector(); - let mut evm = self.new_evm_with_inspector_ref(db.as_dyn(), env, &mut inspector); - let ResultAndState { result, state } = evm.transact()?; + let mut evm = self.new_evm_with_inspector_ref(db.as_dyn(), &env, &mut inspector); + let ResultAndState { result, state } = evm.transact(env.tx)?; let (exit_reason, gas_used, out, logs) = match result { ExecutionResult::Success { reason, gas_used, logs, output, .. } => { (reason.into(), gas_used, Some(output), Some(logs)) @@ -1117,7 +1133,10 @@ impl Backend { ExecutionResult::Revert { gas_used, output } => { (InstructionResult::Revert, gas_used, Some(Output::Call(output)), None) } - ExecutionResult::Halt { reason, gas_used } => (reason.into(), gas_used, None, None), + ExecutionResult::Halt { reason, gas_used } => { + let eth_reason = op_haltreason_to_instruction_result(reason); + (eth_reason, gas_used, None, None) + } }; drop(evm); @@ -1155,13 +1174,12 @@ impl Backend { let storage = self.blockchain.storage.read(); - let cfg_env = CfgEnvWithHandlerCfg::new(env.cfg.clone(), env.handler_cfg); let executor = TransactionExecutor { db: &mut cache_db, validator: self, pending: pool_transactions.into_iter(), - block_env: env.block.clone(), - cfg_env, + block_env: env.evm_env.block_env.clone(), + cfg_env: env.evm_env.cfg_env, parent_hash: storage.best_hash, gas_used: 0, blob_gas_used: 0, @@ -1170,6 +1188,7 @@ impl Backend { print_traces: self.print_traces, precompile_factory: self.precompile_factory.clone(), odyssey: self.odyssey, + optimism: self.is_optimism(), }; // create a new pending block @@ -1201,28 +1220,27 @@ impl Backend { let mut env = self.env.read().clone(); - if env.block.basefee.is_zero() { + if env.evm_env.block_env.basefee == 0 { // this is an edge case because the evm fails if `tx.effective_gas_price < base_fee` // 0 is only possible if it's manually set - env.cfg.disable_base_fee = true; + env.evm_env.cfg_env.disable_base_fee = true; } - let block_number = - self.blockchain.storage.read().best_number.saturating_add(U64::from(1)); + let block_number = self.blockchain.storage.read().best_number.saturating_add(1); // increase block number for this block - if is_arbitrum(env.cfg.chain_id) { + if is_arbitrum(env.evm_env.cfg_env.chain_id) { // Temporary set `env.block.number` to `block_number` for Arbitrum chains. - env.block.number = block_number.to(); + env.evm_env.block_env.number = block_number; } else { - env.block.number = env.block.number.saturating_add(U256::from(1)); + env.evm_env.block_env.number = env.evm_env.block_env.number.saturating_add(1); } - env.block.basefee = U256::from(current_base_fee); - env.block.blob_excess_gas_and_price = current_excess_blob_gas_and_price; + env.evm_env.block_env.basefee = current_base_fee; + env.evm_env.block_env.blob_excess_gas_and_price = current_excess_blob_gas_and_price; // pick a random value for prevrandao - env.block.prevrandao = Some(B256::random()); + env.evm_env.block_env.prevrandao = Some(B256::random()); let best_hash = self.blockchain.storage.read().best_hash; @@ -1238,14 +1256,14 @@ impl Backend { // finally set the next block timestamp, this is done just before execution, because // there can be concurrent requests that can delay acquiring the db lock and we want // to ensure the timestamp is as close as possible to the actual execution. - env.block.timestamp = U256::from(self.time.next_timestamp()); + env.evm_env.block_env.timestamp = self.time.next_timestamp(); let executor = TransactionExecutor { db: &mut **db, validator: self, pending: pool_transactions.into_iter(), - block_env: env.block.clone(), - cfg_env: CfgEnvWithHandlerCfg::new(env.cfg.clone(), env.handler_cfg), + block_env: env.evm_env.block_env.clone(), + cfg_env: env.evm_env.cfg_env.clone(), parent_hash: best_hash, gas_used: 0, blob_gas_used: 0, @@ -1254,6 +1272,7 @@ impl Backend { print_traces: self.print_traces, odyssey: self.odyssey, precompile_factory: self.precompile_factory.clone(), + optimism: self.is_optimism(), }; let executed_tx = executor.execute(); @@ -1309,12 +1328,7 @@ impl Backend { } node_info!(""); - let mined_tx = MinedTransaction { - info, - receipt, - block_hash, - block_number: block_number.to::(), - }; + let mined_tx = MinedTransaction { info, receipt, block_hash, block_number }; storage.transactions.insert(mined_tx.info.transaction_hash, mined_tx); } @@ -1322,14 +1336,13 @@ impl Backend { if let Some(transaction_block_keeper) = self.transaction_block_keeper { if storage.blocks.len() > transaction_block_keeper { let to_clear = block_number - .to::() .saturating_sub(transaction_block_keeper.try_into().unwrap_or(u64::MAX)); storage.remove_block_transactions_by_number(to_clear) } } // we intentionally set the difficulty to `0` for newer blocks - env.block.difficulty = U256::from(0); + env.evm_env.block_env.difficulty = U256::from(0); // update env with new values *self.env.write() = env; @@ -1350,13 +1363,13 @@ impl Backend { (outcome, header, block_hash) }; let next_block_base_fee = self.fees.get_next_block_base_fee_per_gas( - header.gas_used as u128, - header.gas_limit as u128, + header.gas_used, + header.gas_limit, header.base_fee_per_gas.unwrap_or_default(), ); let next_block_excess_blob_gas = self.fees.get_next_block_blob_excess_gas( - header.excess_blob_gas.map(|g| g as u128).unwrap_or_default(), - header.blob_gas_used.map(|g| g as u128).unwrap_or_default(), + header.excess_blob_gas.unwrap_or_default(), + header.blob_gas_used.unwrap_or_default(), ); // update next base fee @@ -1385,7 +1398,7 @@ impl Backend { overrides: Option, ) -> Result<(InstructionResult, Option, u128, State), BlockchainError> { self.with_database_at(block_request, |state, block| { - let block_number = block.number.to::(); + let block_number = block.number; let (exit, out, gas, state) = match overrides { None => self.call_with_state(state.as_dyn(), request, fee_details, block), Some(overrides) => { @@ -1404,13 +1417,13 @@ impl Backend { /// /// - `disable_eip3607` is set to `true` /// - `disable_base_fee` is set to `true` - /// - `nonce` is set to `None` + /// - `nonce` check is skipped if `request.nonce` is None fn build_call_env( &self, request: WithOtherFields, fee_details: FeeDetails, block_env: BlockEnv, - ) -> EnvWithHandlerCfg { + ) -> Env { let WithOtherFields:: { inner: TransactionRequest { @@ -1422,16 +1435,31 @@ impl Backend { access_list, blob_versioned_hashes, authorization_list, - // nonce is always ignored for calls - nonce: _, + nonce, sidecar: _, - chain_id: _, - transaction_type: _, + chain_id, + transaction_type, + max_fee_per_gas, + max_priority_fee_per_gas, .. // Rest of the gas fees related fields are taken from `fee_details` }, - .. + other, } = request; + let tx_type = transaction_type.unwrap_or_else(|| { + if authorization_list.is_some() { + EIP7702_TX_TYPE_ID + } else if blob_versioned_hashes.is_some() { + EIP4844_TX_TYPE_ID + } else if max_fee_per_gas.is_some() || max_priority_fee_per_gas.is_some() { + EIP1559_TX_TYPE_ID + } else if access_list.is_some() { + EIP2930_TX_TYPE_ID + } else { + LEGACY_TX_TYPE_ID + } + }); + let FeeDetails { gas_price, max_fee_per_gas, @@ -1439,19 +1467,19 @@ impl Backend { max_fee_per_blob_gas, } = fee_details; - let gas_limit = gas.unwrap_or(block_env.gas_limit.to()); + let gas_limit = gas.unwrap_or(block_env.gas_limit); let mut env = self.env.read().clone(); - env.block = block_env; + env.evm_env.block_env = block_env; // we want to disable this in eth_call, since this is common practice used by other node // impls and providers - env.cfg.disable_block_gas_limit = true; + env.evm_env.cfg_env.disable_block_gas_limit = true; // The basefee should be ignored for calls against state for // - eth_call // - eth_estimateGas // - eth_createAccessList // - tracing - env.cfg.disable_base_fee = true; + env.evm_env.cfg_env.disable_base_fee = true; let gas_price = gas_price.or(max_fee_per_gas).unwrap_or_else(|| { self.fees().raw_gas_price().saturating_add(MIN_SUGGESTED_PRIORITY_FEE) @@ -1459,48 +1487,75 @@ impl Backend { let caller = from.unwrap_or_default(); let to = to.as_ref().and_then(TxKind::to); let blob_hashes = blob_versioned_hashes.unwrap_or_default(); - env.tx = - TxEnv { + env.tx = OpTransaction { + base: TxEnv { caller, gas_limit, - gas_price: U256::from(gas_price), - gas_priority_fee: max_priority_fee_per_gas.map(U256::from), + gas_price, + gas_priority_fee: max_priority_fee_per_gas, max_fee_per_blob_gas: max_fee_per_blob_gas .or_else(|| { if !blob_hashes.is_empty() { - env.block.get_blob_gasprice() + env.evm_env.block_env.blob_gasprice() } else { - None + Some(0) } }) - .map(U256::from), - transact_to: match to { + .unwrap_or_default(), + kind: match to { Some(addr) => TxKind::Call(*addr), None => TxKind::Create, }, + tx_type, value: value.unwrap_or_default(), data: input.into_input().unwrap_or_default(), - chain_id: None, - // set nonce to None so that the correct nonce is chosen by the EVM - nonce: None, - access_list: access_list.unwrap_or_default().into(), + chain_id: Some(chain_id.unwrap_or(self.env.read().evm_env.cfg_env.chain_id)), + access_list: access_list.unwrap_or_default(), blob_hashes, - optimism: OptimismFields { enveloped_tx: Some(Bytes::new()), ..Default::default() }, - authorization_list: authorization_list.map(Into::into), - }; + authorization_list: authorization_list.unwrap_or_default(), + ..Default::default() + }, + ..Default::default() + }; - if env.block.basefee.is_zero() { + if let Some(nonce) = nonce { + env.tx.base.nonce = nonce; + } else { + // Disable nonce check in revm + env.evm_env.cfg_env.disable_nonce_check = true; + } + + if env.evm_env.block_env.basefee == 0 { // this is an edge case because the evm fails if `tx.effective_gas_price < base_fee` // 0 is only possible if it's manually set - env.cfg.disable_base_fee = true; + env.evm_env.cfg_env.disable_base_fee = true; + } + + // Deposit transaction? + if transaction_type == Some(DEPOSIT_TX_TYPE_ID) && has_optimism_fields(&other) { + let deposit = DepositTransactionParts { + source_hash: other + .get_deserialized::("sourceHash") + .map(|sh| sh.unwrap_or_default()) + .unwrap_or_default(), + mint: other + .get_deserialized::("mint") + .map(|m| m.unwrap_or_default()) + .or(None), + is_system_transaction: other + .get_deserialized::("isSystemTx") + .map(|st| st.unwrap_or_default()) + .unwrap_or_default(), + }; + env.tx.deposit = deposit; } env } /// Builds [`Inspector`] with the configured options. - fn build_inspector(&self) -> Inspector { - let mut inspector = Inspector::default(); + fn build_inspector(&self) -> AnvilInspector { + let mut inspector = AnvilInspector::default(); if self.print_logs { inspector = inspector.with_log_collector(); @@ -1551,13 +1606,13 @@ impl Backend { block_env.difficulty = difficulty; } if let Some(time) = overrides.time { - block_env.timestamp = U256::from(time); + block_env.timestamp = time; } if let Some(gas_limit) = overrides.gas_limit { - block_env.gas_limit = U256::from(gas_limit); + block_env.gas_limit = gas_limit; } if let Some(coinbase) = overrides.coinbase { - block_env.coinbase = coinbase; + block_env.beneficiary = coinbase; } if let Some(random) = overrides.random { block_env.prevrandao = Some(random); @@ -1584,11 +1639,11 @@ impl Backend { ); // Always disable EIP-3607 - env.cfg.disable_eip3607 = true; + env.evm_env.cfg_env.disable_eip3607 = true; if !validation { - env.cfg.disable_base_fee = !validation; - env.block.basefee = U256::from(0); + env.evm_env.cfg_env.disable_base_fee = !validation; + env.evm_env.block_env.basefee = 0; } // transact @@ -1596,16 +1651,23 @@ impl Backend { // prepare inspector to capture transfer inside the evm so they are // recorded and included in logs let mut inspector = TransferInspector::new(false).with_logs(true); - let mut evm = - self.new_evm_with_inspector_ref(cache_db.as_dyn(), env, &mut inspector); - trace!(target: "backend", env=?evm.context.env(), spec=?evm.spec_id(), "simulate evm env"); - evm.transact()? + let mut evm= self.new_evm_with_inspector_ref( + cache_db.as_dyn(), + &env, + &mut inspector, + ); + + trace!(target: "backend", env=?env.evm_env, spec=?env.evm_env.spec_id(),"simulate evm env"); + evm.transact(env.tx)? } else { let mut inspector = self.build_inspector(); - let mut evm = - self.new_evm_with_inspector_ref(cache_db.as_dyn(), env, &mut inspector); - trace!(target: "backend", env=?evm.context.env(),spec=?evm.spec_id(), "simulate evm env"); - evm.transact()? + let mut evm = self.new_evm_with_inspector_ref( + cache_db.as_dyn(), + &env, + &mut inspector, + ); + trace!(target: "backend", env=?env.evm_env, spec=?env.evm_env.spec_id(),"simulate evm env"); + evm.transact(env.tx)? }; trace!(target: "backend", ?result, ?request, "simulate call"); @@ -1627,7 +1689,7 @@ impl Backend { MaybeImpersonatedTransaction::impersonated(tx, from), None, None, - Some(block_env.basefee.to()), + Some(block_env.basefee), ); transactions.push(rpc_tx); @@ -1648,8 +1710,8 @@ impl Backend { .enumerate() .map(|(idx, log)| Log { inner: log, - block_number: Some(block_env.number.to()), - block_timestamp: Some(block_env.timestamp.to()), + block_number: Some(block_env.number), + block_timestamp: Some(block_env.timestamp), transaction_index: Some(req_idx as u64), log_index: Some((idx + log_index) as u64), removed: false, @@ -1679,17 +1741,17 @@ impl Backend { receipts_root: calculate_receipt_root(&transactions_envelopes), parent_hash: Default::default(), ommers_hash: Default::default(), - beneficiary: block_env.coinbase, + beneficiary: block_env.beneficiary, state_root: Default::default(), difficulty: Default::default(), - number: block_env.number.to(), - gas_limit: block_env.gas_limit.to(), + number: block_env.number, + gas_limit: block_env.gas_limit, gas_used, - timestamp: block_env.timestamp.to(), + timestamp: block_env.timestamp, extra_data: Default::default(), mix_hash: Default::default(), nonce: Default::default(), - base_fee_per_gas: Some(block_env.basefee.to()), + base_fee_per_gas: Some(block_env.basefee), withdrawals_root: None, blob_gas_used: None, excess_blob_gas: None, @@ -1718,15 +1780,13 @@ impl Backend { }; // update block env - block_env.number += U256::from(1); - block_env.timestamp += U256::from(12); - block_env.basefee = U256::from( - simulated_block - .inner - .header - .next_block_base_fee(BaseFeeParams::ethereum()) - .unwrap_or_default(), - ); + block_env.number += 1; + block_env.timestamp += 12; + block_env.basefee = simulated_block + .inner + .header + .next_block_base_fee(BaseFeeParams::ethereum()) + .unwrap_or_default(); block_res.push(simulated_block); } @@ -1746,8 +1806,8 @@ impl Backend { let mut inspector = self.build_inspector(); let env = self.build_call_env(request, fee_details, block_env); - let mut evm = self.new_evm_with_inspector_ref(state, env, &mut inspector); - let ResultAndState { result, state } = evm.transact()?; + let mut evm = self.new_evm_with_inspector_ref(state, &env, &mut inspector); + let ResultAndState { result, state } = evm.transact(env.tx)?; let (exit_reason, gas_used, out) = match result { ExecutionResult::Success { reason, gas_used, output, .. } => { (reason.into(), gas_used, Some(output)) @@ -1755,7 +1815,9 @@ impl Backend { ExecutionResult::Revert { gas_used, output } => { (InstructionResult::Revert, gas_used, Some(Output::Call(output))) } - ExecutionResult::Halt { reason, gas_used } => (reason.into(), gas_used, None), + ExecutionResult::Halt { reason, gas_used } => { + (op_haltreason_to_instruction_result(reason), gas_used, None) + } }; drop(evm); inspector.print_logs(); @@ -1803,10 +1865,10 @@ impl Backend { let env = self.build_call_env(request, fee_details, block); let mut evm = self.new_evm_with_inspector_ref( state.as_dyn(), - env, + &env, &mut inspector, ); - let ResultAndState { result, state: _ } = evm.transact()?; + let ResultAndState { result, state: _ } = evm.transact(env.tx)?; drop(evm); let tracing_inspector = inspector.tracer.expect("tracer disappeared"); @@ -1837,8 +1899,8 @@ impl Backend { .with_tracing_config(TracingInspectorConfig::from_geth_config(&config)); let env = self.build_call_env(request, fee_details, block); - let mut evm = self.new_evm_with_inspector_ref(state.as_dyn(), env, &mut inspector); - let ResultAndState { result, state: _ } = evm.transact()?; + let mut evm = self.new_evm_with_inspector_ref(state.as_dyn(), &env, &mut inspector); + let ResultAndState { result, state: _ } = evm.transact(env.tx)?; let (exit_reason, gas_used, out) = match result { ExecutionResult::Success { reason, gas_used, output, .. } => { @@ -1847,7 +1909,9 @@ impl Backend { ExecutionResult::Revert { gas_used, output } => { (InstructionResult::Revert, gas_used, Some(Output::Call(output))) } - ExecutionResult::Halt { reason, gas_used } => (reason.into(), gas_used, None), + ExecutionResult::Halt { reason, gas_used } => { + (op_haltreason_to_instruction_result(reason), gas_used, None) + } }; drop(evm); @@ -1877,8 +1941,8 @@ impl Backend { AccessListInspector::new(request.access_list.clone().unwrap_or_default()); let env = self.build_call_env(request, fee_details, block_env); - let mut evm = self.new_evm_with_inspector_ref(state, env, &mut inspector); - let ResultAndState { result, state: _ } = evm.transact()?; + let mut evm = self.new_evm_with_inspector_ref(state, &env, &mut inspector); + let ResultAndState { result, state: _ } = evm.transact(env.tx)?; let (exit_reason, gas_used, out) = match result { ExecutionResult::Success { reason, gas_used, output, .. } => { (reason.into(), gas_used, Some(output)) @@ -1886,7 +1950,9 @@ impl Backend { ExecutionResult::Revert { gas_used, output } => { (InstructionResult::Revert, gas_used, Some(Output::Call(output))) } - ExecutionResult::Halt { reason, gas_used } => (reason.into(), gas_used, None), + ExecutionResult::Halt { reason, gas_used } => { + (op_haltreason_to_instruction_result(reason), gas_used, None) + } }; drop(evm); let access_list = inspector.access_list(); @@ -2136,12 +2202,12 @@ impl Backend { BlockId::Hash(hash) => hash.block_hash, BlockId::Number(number) => { let storage = self.blockchain.storage.read(); - let slots_in_an_epoch = U64::from(self.slots_in_an_epoch); + let slots_in_an_epoch = self.slots_in_an_epoch; match number { BlockNumber::Latest => storage.best_hash, BlockNumber::Earliest => storage.genesis_hash, BlockNumber::Pending => return None, - BlockNumber::Number(num) => *storage.hashes.get(&U64::from(num))?, + BlockNumber::Number(num) => *storage.hashes.get(&num)?, BlockNumber::Safe => { if storage.best_number > (slots_in_an_epoch) { *storage.hashes.get(&(storage.best_number - (slots_in_an_epoch)))? @@ -2150,10 +2216,8 @@ impl Backend { } } BlockNumber::Finalized => { - if storage.best_number > (slots_in_an_epoch * U64::from(2)) { - *storage - .hashes - .get(&(storage.best_number - (slots_in_an_epoch * U64::from(2))))? + if storage.best_number > (slots_in_an_epoch * 2) { + *storage.hashes.get(&(storage.best_number - (slots_in_an_epoch * 2)))? } else { storage.genesis_hash } @@ -2210,7 +2274,7 @@ impl Backend { let mut block = WithOtherFields::new(block); // If Arbitrum, apply chain specifics to converted block. - if is_arbitrum(self.env.read().cfg.chain_id) { + if is_arbitrum(self.env.read().evm_env.cfg_env.chain_id) { // Set `l1BlockNumber` field. block.other.insert("l1BlockNumber".to_string(), number.into()); } @@ -2279,13 +2343,13 @@ impl Backend { .with_pending_block(pool_transactions, |state, block| { let block = block.block; let block = BlockEnv { - number: U256::from(block.header.number), - coinbase: block.header.beneficiary, - timestamp: U256::from(block.header.timestamp), + number: block.header.number, + beneficiary: block.header.beneficiary, + timestamp: block.header.timestamp, difficulty: block.header.difficulty, prevrandao: Some(block.header.mix_hash), - basefee: U256::from(block.header.base_fee_per_gas.unwrap_or_default()), - gas_limit: U256::from(block.header.gas_limit), + basefee: block.header.base_fee_per_gas.unwrap_or_default(), + gas_limit: block.header.gas_limit, ..Default::default() }; f(state, block) @@ -2296,23 +2360,23 @@ impl Backend { Some(BlockRequest::Number(bn)) => Some(BlockNumber::Number(bn)), None => None, }; - let block_number: U256 = U256::from(self.convert_block_number(block_number)); + let block_number = self.convert_block_number(block_number); - if block_number < self.env.read().block.number { + if block_number < self.env.read().evm_env.block_env.number { if let Some((block_hash, block)) = self - .block_by_number(BlockNumber::Number(block_number.to::())) + .block_by_number(BlockNumber::Number(block_number)) .await? .map(|block| (block.header.hash, block)) { if let Some(state) = self.states.write().get(&block_hash) { let block = BlockEnv { number: block_number, - coinbase: block.header.beneficiary, - timestamp: U256::from(block.header.timestamp), + beneficiary: block.header.beneficiary, + timestamp: block.header.timestamp, difficulty: block.header.difficulty, prevrandao: block.header.mix_hash, - basefee: U256::from(block.header.base_fee_per_gas.unwrap_or_default()), - gas_limit: U256::from(block.header.gas_limit), + basefee: block.header.base_fee_per_gas.unwrap_or_default(), + gas_limit: block.header.gas_limit, ..Default::default() }; return Ok(f(Box::new(state), block)); @@ -2321,13 +2385,13 @@ impl Backend { warn!(target: "backend", "Not historic state found for block={}", block_number); return Err(BlockchainError::BlockOutOfRange( - self.env.read().block.number.to::(), - block_number.to::(), + self.env.read().evm_env.block_env.number, + block_number, )); } let db = self.db.read().await; - let block = self.env.read().block.clone(); + let block = self.env.read().evm_env.block_env.clone(); Ok(f(Box::new(&**db), block)) } @@ -2976,13 +3040,13 @@ impl Backend { // Set environment back to common block let mut env = self.env.write(); - env.block.number = U256::from(common_block.header.number); - env.block.timestamp = U256::from(common_block.header.timestamp); - env.block.gas_limit = U256::from(common_block.header.gas_limit); - env.block.difficulty = common_block.header.difficulty; - env.block.prevrandao = Some(common_block.header.mix_hash); + env.evm_env.block_env.number = common_block.header.number; + env.evm_env.block_env.timestamp = common_block.header.timestamp; + env.evm_env.block_env.gas_limit = common_block.header.gas_limit; + env.evm_env.block_env.difficulty = common_block.header.difficulty; + env.evm_env.block_env.prevrandao = Some(common_block.header.mix_hash); - self.time.reset(env.block.timestamp.to::()); + self.time.reset(env.evm_env.block_env.timestamp); } Ok(()) } @@ -3021,7 +3085,7 @@ impl TransactionValidator for Backend { &self, pending: &PendingTransaction, account: &AccountInfo, - env: &EnvWithHandlerCfg, + env: &Env, ) -> Result<(), InvalidTransactionError> { let tx = &pending.transaction; @@ -3030,7 +3094,7 @@ impl TransactionValidator for Backend { if chain_id.to::() != tx_chain_id { if let Some(legacy) = tx.as_legacy() { // - if env.handler_cfg.spec_id >= SpecId::SPURIOUS_DRAGON && + if env.evm_env.cfg_env.spec >= SpecId::SPURIOUS_DRAGON && legacy.tx().chain_id.is_none() { warn!(target: "backend", ?chain_id, ?tx_chain_id, "incompatible EIP155-based V"); @@ -3049,7 +3113,9 @@ impl TransactionValidator for Backend { } // Check gas limit, iff block gas limit is set. - if !env.cfg.disable_block_gas_limit && tx.gas_limit() > env.block.gas_limit.to::() { + if !env.evm_env.cfg_env.disable_block_gas_limit && + tx.gas_limit() > env.evm_env.block_env.gas_limit + { warn!(target: "backend", "[{:?}] gas too high", tx.hash()); return Err(InvalidTransactionError::GasTooHigh(ErrDetail { detail: String::from("tx.gas_limit > env.block.gas_limit"), @@ -3065,9 +3131,9 @@ impl TransactionValidator for Backend { return Err(InvalidTransactionError::NonceTooLow); } - if (env.handler_cfg.spec_id as u8) >= (SpecId::LONDON as u8) { - if tx.gas_price() < env.block.basefee.to::() && !is_deposit_tx { - warn!(target: "backend", "max fee per gas={}, too low, block basefee={}",tx.gas_price(), env.block.basefee); + if env.evm_env.cfg_env.spec >= SpecId::LONDON { + if tx.gas_price() < env.evm_env.block_env.basefee.into() && !is_deposit_tx { + warn!(target: "backend", "max fee per gas={}, too low, block basefee={}",tx.gas_price(), env.evm_env.block_env.basefee); return Err(InvalidTransactionError::FeeCapTooLow); } @@ -3082,10 +3148,10 @@ impl TransactionValidator for Backend { } // EIP-4844 Cancun hard fork validation steps - if env.spec_id() >= SpecId::CANCUN && tx.transaction.is_eip4844() { + if env.evm_env.cfg_env.spec >= SpecId::CANCUN && tx.transaction.is_eip4844() { // Light checks first: see if the blob fee cap is too low. if let Some(max_fee_per_blob_gas) = tx.essentials().max_fee_per_blob_gas { - if let Some(blob_gas_and_price) = &env.block.blob_excess_gas_and_price { + if let Some(blob_gas_and_price) = &env.evm_env.block_env.blob_excess_gas_and_price { if max_fee_per_blob_gas < blob_gas_and_price.blob_gasprice { warn!(target: "backend", "max fee per blob gas={}, too low, block blob gas price={}", max_fee_per_blob_gas, blob_gas_and_price.blob_gasprice); return Err(InvalidTransactionError::BlobFeeCapTooLow); @@ -3108,12 +3174,12 @@ impl TransactionValidator for Backend { // Ensure the tx does not exceed the max blobs per block. if blob_count > MAX_BLOBS_PER_BLOCK { - return Err(InvalidTransactionError::TooManyBlobs(blob_count)) + return Err(InvalidTransactionError::TooManyBlobs(blob_count, MAX_BLOBS_PER_BLOCK)) } // Check for any blob validation errors if not impersonating. if !self.skip_blob_validation(Some(*pending.sender())) { - if let Err(err) = tx.validate(env.cfg.kzg_settings.get()) { + if let Err(err) = tx.validate(EnvKzgSettings::default().get()) { return Err(InvalidTransactionError::BlobTransactionValidationError(err)) } } @@ -3154,7 +3220,7 @@ impl TransactionValidator for Backend { &self, tx: &PendingTransaction, account: &AccountInfo, - env: &EnvWithHandlerCfg, + env: &Env, ) -> Result<(), InvalidTransactionError> { self.validate_pool_transaction_for(tx, account, env)?; if tx.nonce() > account.nonce { @@ -3347,3 +3413,10 @@ pub fn is_arbitrum(chain_id: u64) -> bool { } false } + +pub fn op_haltreason_to_instruction_result(op_reason: OpHaltReason) -> InstructionResult { + match op_reason { + OpHaltReason::Base(eth_h) => eth_h.into(), + OpHaltReason::FailedDeposit => InstructionResult::Stop, + } +} diff --git a/crates/anvil/src/eth/backend/mem/state.rs b/crates/anvil/src/eth/backend/mem/state.rs index aea154a7bd573..33db0b746a316 100644 --- a/crates/anvil/src/eth/backend/mem/state.rs +++ b/crates/anvil/src/eth/backend/mem/state.rs @@ -1,16 +1,15 @@ //! Support for generating the state root for memdb storage use crate::eth::error::BlockchainError; -use alloy_primitives::{keccak256, Address, B256, U256}; +use alloy_primitives::{keccak256, map::HashMap, Address, B256, U256}; use alloy_rlp::Encodable; use alloy_rpc_types::state::StateOverride; use alloy_trie::{HashBuilder, Nibbles}; -use foundry_evm::{ - backend::DatabaseError, - revm::{ - db::{CacheDB, DatabaseRef, DbAccount}, - primitives::{AccountInfo, Bytecode, HashMap}, - }, +use foundry_evm::backend::DatabaseError; +use revm::{ + bytecode::Bytecode, + database::{CacheDB, DatabaseRef, DbAccount}, + state::AccountInfo, }; pub fn build_root(values: impl IntoIterator)>) -> B256 { diff --git a/crates/anvil/src/eth/backend/mem/storage.rs b/crates/anvil/src/eth/backend/mem/storage.rs index e024d97505467..7c2695fa275fb 100644 --- a/crates/anvil/src/eth/backend/mem/storage.rs +++ b/crates/anvil/src/eth/backend/mem/storage.rs @@ -5,6 +5,7 @@ use crate::eth::{ MaybeFullDatabase, SerializableBlock, SerializableHistoricalStates, SerializableTransaction, StateDb, }, + env::Env, mem::cache::DiskStateCache, }, error::BlockchainError, @@ -14,7 +15,7 @@ use alloy_consensus::constants::EMPTY_WITHDRAWALS; use alloy_eips::eip7685::EMPTY_REQUESTS_HASH; use alloy_primitives::{ map::{B256HashMap, HashMap}, - Bytes, B256, U256, U64, + Bytes, B256, U256, }; use alloy_rpc_types::{ trace::{ @@ -34,13 +35,12 @@ use anvil_core::eth::{ use anvil_rpc::error::RpcError; use foundry_evm::{ backend::MemDb, - revm::primitives::Env, traces::{ CallKind, FourByteInspector, GethTraceBuilder, ParityTraceBuilder, TracingInspectorConfig, }, }; use parking_lot::RwLock; -use revm::primitives::SpecId; +use revm::{context::Block as RevmBlock, primitives::hardfork::SpecId}; use std::{collections::VecDeque, fmt, path::PathBuf, sync::Arc, time::Duration}; // use yansi::Paint; @@ -255,11 +255,11 @@ pub struct BlockchainStorage { /// all stored blocks (block hash -> block) pub blocks: B256HashMap, /// mapping from block number -> block hash - pub hashes: HashMap, + pub hashes: HashMap, /// The current best hash pub best_hash: B256, /// The current best block number - pub best_number: U64, + pub best_number: u64, /// genesis hash of the chain pub genesis_hash: B256, /// Mapping from the transaction hash to a tuple containing the transaction as well as the @@ -286,11 +286,11 @@ impl BlockchainStorage { let partial_header = PartialHeader { timestamp, base_fee, - gas_limit: env.block.gas_limit.to::(), - beneficiary: env.block.coinbase, - difficulty: env.block.difficulty, - blob_gas_used: env.block.blob_excess_gas_and_price.as_ref().map(|_| 0), - excess_blob_gas: env.block.get_blob_excess_gas(), + gas_limit: env.evm_env.block_env.gas_limit, + beneficiary: env.evm_env.block_env.beneficiary, + difficulty: env.evm_env.block_env.difficulty, + blob_gas_used: env.evm_env.block_env.blob_excess_gas_and_price.as_ref().map(|_| 0), + excess_blob_gas: env.evm_env.block_env.blob_excess_gas(), number: genesis_number, parent_beacon_block_root: is_cancun.then_some(Default::default()), withdrawals_root: is_shanghai.then_some(EMPTY_WITHDRAWALS), @@ -300,7 +300,7 @@ impl BlockchainStorage { let block = Block::new::(partial_header, vec![]); let genesis_hash = block.header.hash_slow(); let best_hash = genesis_hash; - let best_number: U64 = U64::from(genesis_number); + let best_number = genesis_number; let mut blocks = B256HashMap::default(); blocks.insert(genesis_hash, block); @@ -320,13 +320,13 @@ impl BlockchainStorage { pub fn forked(block_number: u64, block_hash: B256, total_difficulty: U256) -> Self { let mut hashes = HashMap::default(); - hashes.insert(U64::from(block_number), block_hash); + hashes.insert(block_number, block_hash); Self { blocks: B256HashMap::default(), hashes, best_hash: block_hash, - best_number: U64::from(block_number), + best_number: block_number, genesis_hash: Default::default(), transactions: Default::default(), total_difficulty, @@ -338,16 +338,16 @@ impl BlockchainStorage { /// The block identified by `block_number` and `block_hash` is __non-inclusive__, i.e. it will /// remain in the state. pub fn unwind_to(&mut self, block_number: u64, block_hash: B256) { - let best_num: u64 = self.best_number.try_into().unwrap_or(0); + let best_num: u64 = self.best_number; for i in (block_number + 1)..=best_num { - if let Some(hash) = self.hashes.remove(&U64::from(i)) { + if let Some(hash) = self.hashes.remove(&i) { if let Some(block) = self.blocks.remove(&hash) { self.remove_block_transactions_by_number(block.header.number); } } } self.best_hash = block_hash; - self.best_number = U64::from(block_number); + self.best_number = block_number; } pub fn empty() -> Self { @@ -364,7 +364,7 @@ impl BlockchainStorage { /// Removes all stored transactions for the given block number pub fn remove_block_transactions_by_number(&mut self, num: u64) { - if let Some(hash) = self.hashes.get(&(U64::from(num))).copied() { + if let Some(hash) = self.hashes.get(&num).copied() { self.remove_block_transactions(hash); } } @@ -383,12 +383,12 @@ impl BlockchainStorage { impl BlockchainStorage { /// Returns the hash for [BlockNumberOrTag] pub fn hash(&self, number: BlockNumberOrTag) -> Option { - let slots_in_an_epoch = U64::from(32u64); + let slots_in_an_epoch = 32; match number { BlockNumberOrTag::Latest => Some(self.best_hash), BlockNumberOrTag::Earliest => Some(self.genesis_hash), BlockNumberOrTag::Pending => None, - BlockNumberOrTag::Number(num) => self.hashes.get(&U64::from(num)).copied(), + BlockNumberOrTag::Number(num) => self.hashes.get(&num).copied(), BlockNumberOrTag::Safe => { if self.best_number > (slots_in_an_epoch) { self.hashes.get(&(self.best_number - (slots_in_an_epoch))).copied() @@ -397,10 +397,8 @@ impl BlockchainStorage { } } BlockNumberOrTag::Finalized => { - if self.best_number > (slots_in_an_epoch * U64::from(2)) { - self.hashes - .get(&(self.best_number - (slots_in_an_epoch * U64::from(2)))) - .copied() + if self.best_number > (slots_in_an_epoch * 2) { + self.hashes.get(&(self.best_number - (slots_in_an_epoch * 2))).copied() } else { Some(self.genesis_hash) } @@ -423,7 +421,7 @@ impl BlockchainStorage { let block_hash = block.header.hash_slow(); let block_number = block.header.number; self.blocks.insert(block_hash, block); - self.hashes.insert(U64::from(block_number), block_hash); + self.hashes.insert(block_number, block_hash); } } @@ -499,7 +497,7 @@ impl Blockchain { #[derive(Clone, Debug)] pub struct MinedBlockOutcome { /// The block that was mined - pub block_number: U64, + pub block_number: u64, /// All transactions included in the block pub included: Vec>, /// All transactions that were attempted to be included but were invalid at the time of @@ -611,16 +609,11 @@ pub struct MinedTransactionReceipt { mod tests { use super::*; use crate::eth::backend::db::Db; - use alloy_primitives::{hex, Address}; + use alloy_primitives::{hex, Address, U256}; use alloy_rlp::Decodable; use anvil_core::eth::transaction::TypedTransaction; - use foundry_evm::{ - backend::MemDb, - revm::{ - db::DatabaseRef, - primitives::{AccountInfo, U256}, - }, - }; + use foundry_evm::backend::MemDb; + use revm::{database::DatabaseRef, state::AccountInfo}; #[test] fn test_interval_update() { diff --git a/crates/anvil/src/eth/backend/mod.rs b/crates/anvil/src/eth/backend/mod.rs index 48b08e07cd1ec..be2c90b576800 100644 --- a/crates/anvil/src/eth/backend/mod.rs +++ b/crates/anvil/src/eth/backend/mod.rs @@ -8,6 +8,7 @@ pub mod mem; pub mod cheats; pub mod time; +pub mod env; pub mod executor; pub mod fork; pub mod genesis; diff --git a/crates/anvil/src/eth/backend/validate.rs b/crates/anvil/src/eth/backend/validate.rs index eca3fd9e3bfe9..0a22ea5f5a880 100644 --- a/crates/anvil/src/eth/backend/validate.rs +++ b/crates/anvil/src/eth/backend/validate.rs @@ -1,8 +1,11 @@ //! Support for validating transactions at certain stages -use crate::eth::error::{BlockchainError, InvalidTransactionError}; +use crate::eth::{ + backend::env::Env, + error::{BlockchainError, InvalidTransactionError}, +}; use anvil_core::eth::transaction::PendingTransaction; -use foundry_evm::revm::primitives::{AccountInfo, EnvWithHandlerCfg}; +use revm::state::AccountInfo; /// A trait for validating transactions #[async_trait::async_trait] @@ -21,7 +24,7 @@ pub trait TransactionValidator { &self, tx: &PendingTransaction, account: &AccountInfo, - env: &EnvWithHandlerCfg, + env: &Env, ) -> Result<(), InvalidTransactionError>; /// Validates the transaction against a specific account @@ -31,6 +34,6 @@ pub trait TransactionValidator { &self, tx: &PendingTransaction, account: &AccountInfo, - env: &EnvWithHandlerCfg, + env: &Env, ) -> Result<(), InvalidTransactionError>; } diff --git a/crates/anvil/src/eth/error.rs b/crates/anvil/src/eth/error.rs index 6666f8021dcfe..f9343d520ecfa 100644 --- a/crates/anvil/src/eth/error.rs +++ b/crates/anvil/src/eth/error.rs @@ -10,13 +10,11 @@ use anvil_rpc::{ error::{ErrorCode, RpcError}, response::ResponseResult, }; -use foundry_evm::{ - backend::DatabaseError, - decode::RevertDecoder, - revm::{ - interpreter::InstructionResult, - primitives::{EVMError, InvalidHeader}, - }, +use foundry_evm::{backend::DatabaseError, decode::RevertDecoder}; +use op_revm::OpTransactionError; +use revm::{ + context_interface::result::{EVMError, InvalidHeader, InvalidTransaction}, + interpreter::InstructionResult, }; use serde::Serialize; @@ -122,7 +120,31 @@ where InvalidHeader::PrevrandaoNotSet => Self::PrevrandaoNotSet, }, EVMError::Database(err) => err.into(), - EVMError::Precompile(err) => Self::Message(err), + EVMError::Custom(err) => Self::Message(err), + } + } +} + +impl From> for BlockchainError +where + T: Into, +{ + fn from(err: EVMError) -> Self { + match err { + EVMError::Transaction(err) => match err { + OpTransactionError::Base(err) => InvalidTransactionError::from(err).into(), + OpTransactionError::DepositSystemTxPostRegolith => { + Self::DepositTransactionUnsupported + } + OpTransactionError::HaltedDepositPostRegolith => { + Self::DepositTransactionUnsupported + } + }, + EVMError::Header(err) => match err { + InvalidHeader::ExcessBlobGasNotSet => Self::ExcessBlobGasNotSet, + InvalidHeader::PrevrandaoNotSet => Self::PrevrandaoNotSet, + }, + EVMError::Database(err) => err.into(), EVMError::Custom(err) => Self::Message(err), } } @@ -246,8 +268,8 @@ pub enum InvalidTransactionError { /// Thrown when there are no `blob_hashes` in the transaction, and it is an EIP-4844 tx. #[error("`blob_hashes` are required for EIP-4844 transactions")] NoBlobHashes, - #[error("too many blobs in one transaction, have: {0}")] - TooManyBlobs(usize), + #[error("too many blobs in one transaction, have: {0}, max: {1}")] + TooManyBlobs(usize, usize), /// Thrown when there's a blob validation error #[error(transparent)] BlobTransactionValidationError(#[from] alloy_consensus::BlobTransactionValidationError), @@ -265,12 +287,14 @@ pub enum InvalidTransactionError { AuthorizationListNotSupported, /// Forwards error from the revm #[error(transparent)] - Revm(revm::primitives::InvalidTransaction), + Revm(revm::context_interface::result::InvalidTransaction), + /// Deposit transaction error post regolith + #[error("op-deposit failure post regolith")] + DepositTxErrorPostRegolith, } -impl From for InvalidTransactionError { - fn from(err: revm::primitives::InvalidTransaction) -> Self { - use revm::primitives::InvalidTransaction; +impl From for InvalidTransactionError { + fn from(err: InvalidTransaction) -> Self { match err { InvalidTransaction::InvalidChainId => Self::InvalidChainId, InvalidTransaction::PriorityFeeGreaterThanMaxFee => Self::TipAboveFeeCap, @@ -278,10 +302,10 @@ impl From for InvalidTransactionError { InvalidTransaction::CallerGasLimitMoreThanBlock => { Self::GasTooHigh(ErrDetail { detail: String::from("CallerGasLimitMoreThanBlock") }) } - InvalidTransaction::CallGasCostMoreThanGasLimit => { + InvalidTransaction::CallGasCostMoreThanGasLimit { .. } => { Self::GasTooHigh(ErrDetail { detail: String::from("CallGasCostMoreThanGasLimit") }) } - InvalidTransaction::GasFloorMoreThanGasLimit => { + InvalidTransaction::GasFloorMoreThanGasLimit { .. } => { Self::GasTooHigh(ErrDetail { detail: String::from("CallGasCostMoreThanGasLimit") }) } InvalidTransaction::RejectCallerWithCode => Self::SenderNoEOA, @@ -300,18 +324,30 @@ impl From for InvalidTransactionError { InvalidTransaction::BlobCreateTransaction => Self::BlobCreateTransaction, InvalidTransaction::BlobVersionNotSupported => Self::BlobVersionNotSupported, InvalidTransaction::EmptyBlobs => Self::EmptyBlobs, - InvalidTransaction::TooManyBlobs { have } => Self::TooManyBlobs(have), + InvalidTransaction::TooManyBlobs { have, max } => Self::TooManyBlobs(have, max), InvalidTransaction::AuthorizationListNotSupported => { Self::AuthorizationListNotSupported } InvalidTransaction::AuthorizationListInvalidFields | - InvalidTransaction::OptimismError(_) | - InvalidTransaction::EofCrateShouldHaveToAddress | + InvalidTransaction::Eip1559NotSupported | + InvalidTransaction::Eip2930NotSupported | + InvalidTransaction::Eip4844NotSupported | + InvalidTransaction::Eip7702NotSupported | + InvalidTransaction::EofCreateShouldHaveToAddress | InvalidTransaction::EmptyAuthorizationList => Self::Revm(err), } } } +impl From for InvalidTransactionError { + fn from(value: OpTransactionError) -> Self { + match value { + OpTransactionError::Base(err) => err.into(), + OpTransactionError::DepositSystemTxPostRegolith | + OpTransactionError::HaltedDepositPostRegolith => Self::DepositTxErrorPostRegolith, + } + } +} /// Helper trait to easily convert results to rpc results pub(crate) trait ToRpcResponseResult { fn to_rpc_result(self) -> ResponseResult; diff --git a/crates/anvil/src/eth/fees.rs b/crates/anvil/src/eth/fees.rs index bb405f62d1ef1..bb9272f5f41c4 100644 --- a/crates/anvil/src/eth/fees.rs +++ b/crates/anvil/src/eth/fees.rs @@ -1,7 +1,12 @@ -use crate::eth::{ - backend::{info::StorageInfo, notifications::NewBlockNotifications}, - error::BlockchainError, +use std::{ + collections::BTreeMap, + fmt, + future::Future, + pin::Pin, + sync::Arc, + task::{Context, Poll}, }; + use alloy_consensus::Header; use alloy_eips::{ calc_next_block_base_fee, eip1559::BaseFeeParams, eip4844::MAX_DATA_GAS_PER_BLOCK, @@ -9,16 +14,13 @@ use alloy_eips::{ }; use alloy_primitives::B256; use anvil_core::eth::transaction::TypedTransaction; -use foundry_evm::revm::primitives::{BlobExcessGasAndPrice, SpecId}; use futures::StreamExt; use parking_lot::{Mutex, RwLock}; -use std::{ - collections::BTreeMap, - fmt, - future::Future, - pin::Pin, - sync::Arc, - task::{Context, Poll}, +use revm::{context_interface::block::BlobExcessGasAndPrice, primitives::hardfork::SpecId}; + +use crate::eth::{ + backend::{info::StorageInfo, notifications::NewBlockNotifications}, + error::BlockchainError, }; /// Maximum number of entries in the fee history cache @@ -54,7 +56,7 @@ pub struct FeeManager { /// Tracks the excess blob gas, and the base fee, for the next block post Cancun /// /// This value will be updated after a new block was mined - blob_excess_gas_and_price: Arc>, + blob_excess_gas_and_price: Arc>, /// The base price to use Pre London /// /// This will be constant value unless changed manually @@ -121,7 +123,7 @@ impl FeeManager { pub fn excess_blob_gas_and_price(&self) -> Option { if self.is_eip4844() { - Some(self.blob_excess_gas_and_price.read().clone()) + Some(*self.blob_excess_gas_and_price.read()) } else { None } @@ -158,8 +160,8 @@ impl FeeManager { /// Calculates the base fee for the next block pub fn get_next_block_base_fee_per_gas( &self, - gas_used: u128, - gas_limit: u128, + gas_used: u64, + gas_limit: u64, last_fee_per_gas: u64, ) -> u64 { // It's naturally impossible for base fee to be 0; @@ -178,18 +180,14 @@ impl FeeManager { /// Calculates the next block blob excess gas, using the provided parent blob gas used and /// parent blob excess gas - pub fn get_next_block_blob_excess_gas( - &self, - blob_gas_used: u128, - blob_excess_gas: u128, - ) -> u64 { - alloy_eips::eip4844::calc_excess_blob_gas(blob_gas_used as u64, blob_excess_gas as u64) + pub fn get_next_block_blob_excess_gas(&self, blob_gas_used: u64, blob_excess_gas: u64) -> u64 { + alloy_eips::eip4844::calc_excess_blob_gas(blob_gas_used, blob_excess_gas) } } /// Calculate base fee for next block. [EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md) spec -pub fn calculate_next_block_base_fee(gas_used: u128, gas_limit: u128, base_fee: u64) -> u64 { - calc_next_block_base_fee(gas_used as u64, gas_limit as u64, base_fee, BaseFeeParams::ethereum()) +pub fn calculate_next_block_base_fee(gas_used: u64, gas_limit: u64, base_fee: u64) -> u64 { + calc_next_block_base_fee(gas_used, gas_limit, base_fee, BaseFeeParams::ethereum()) } /// An async service that takes care of the `FeeHistory` cache diff --git a/crates/anvil/src/eth/pool/mod.rs b/crates/anvil/src/eth/pool/mod.rs index 544d7eac9df37..2133ea083df24 100644 --- a/crates/anvil/src/eth/pool/mod.rs +++ b/crates/anvil/src/eth/pool/mod.rs @@ -36,7 +36,7 @@ use crate::{ }, mem::storage::MinedBlockOutcome, }; -use alloy_primitives::{Address, TxHash, U64}; +use alloy_primitives::{Address, TxHash}; use alloy_rpc_types::txpool::TxpoolStatus; use anvil_core::eth::transaction::PendingTransaction; use futures::channel::mpsc::{channel, Receiver, Sender}; @@ -102,7 +102,7 @@ impl Pool { /// directly or are a dependency of the transaction associated with that marker. pub fn prune_markers( &self, - block_number: U64, + block_number: u64, markers: impl IntoIterator, ) -> PruneResult { debug!(target: "txpool", ?block_number, "pruning transactions"); diff --git a/crates/anvil/src/eth/pool/transactions.rs b/crates/anvil/src/eth/pool/transactions.rs index 36e421d7a50e1..6cafa4c4cd3ce 100644 --- a/crates/anvil/src/eth/pool/transactions.rs +++ b/crates/anvil/src/eth/pool/transactions.rs @@ -98,6 +98,11 @@ impl PoolTransaction { pub fn gas_price(&self) -> u128 { self.pending_transaction.transaction.gas_price() } + + /// Returns the type of the transaction + pub fn tx_type(&self) -> u8 { + self.pending_transaction.transaction.r#type().unwrap_or_default() + } } impl fmt::Debug for PoolTransaction { diff --git a/crates/anvil/src/eth/util.rs b/crates/anvil/src/eth/util.rs index ca66f2ed3d3c5..beb73276c3b4d 100644 --- a/crates/anvil/src/eth/util.rs +++ b/crates/anvil/src/eth/util.rs @@ -1,7 +1,7 @@ use alloy_primitives::Address; -use foundry_evm::revm::{ +use revm::{ precompile::{PrecompileSpecId, Precompiles}, - primitives::SpecId, + primitives::hardfork::SpecId, }; use std::fmt; diff --git a/crates/anvil/src/evm.rs b/crates/anvil/src/evm.rs index eef0800eae119..53ace61eaf858 100644 --- a/crates/anvil/src/evm.rs +++ b/crates/anvil/src/evm.rs @@ -1,81 +1,84 @@ +use std::fmt::Debug; + use alloy_primitives::Address; -use foundry_evm::revm::precompile::Precompile; -use std::{fmt::Debug, sync::Arc}; +use revm::precompile::Precompiles; /// Object-safe trait that enables injecting extra precompiles when using /// `anvil` as a library. pub trait PrecompileFactory: Send + Sync + Unpin + Debug { /// Returns a set of precompiles to extend the EVM with. - fn precompiles(&self) -> Vec<(Address, Precompile)>; + fn precompiles(&self) -> Vec<(Address, Precompiles)>; } -/// Appends a handler register to `evm` that injects the given `precompiles`. -/// -/// This will add an additional handler that extends the default precompiles with the given set of -/// precompiles. -pub fn inject_precompiles( - evm: &mut revm::Evm<'_, I, DB>, - precompiles: Vec<(Address, Precompile)>, -) { - evm.handler.append_handler_register_box(Box::new(move |handler| { - let precompiles = precompiles.clone(); - let prev = handler.pre_execution.load_precompiles.clone(); - handler.pre_execution.load_precompiles = Arc::new(move || { - let mut cx = prev(); - cx.extend(precompiles.iter().cloned().map(|(a, b)| (a, b.into()))); - cx - }); - })); -} +// /// Appends a handler register to `evm` that injects the given `precompiles`. +// /// +// /// This will add an additional handler that extends the default precompiles with the given set +// of /// precompiles. +// pub fn inject_precompiles( +// evm: &mut revm::Evm<'_, I, DB>, +// precompiles: Precompiles, +// ) { +// evm.handler.append_handler_register_box(Box::new(move |handler| { +// let precompiles = precompiles.clone(); +// let prev = handler.pre_execution.load_precompiles.clone(); +// handler.pre_execution.load_precompiles = Arc::new(move || { +// let mut cx = prev(); +// cx.extend(precompiles.iter().cloned().map(|(a, b)| (a, b.into()))); +// cx +// }); +// })); +// } -#[cfg(test)] -mod tests { - use crate::{evm::inject_precompiles, PrecompileFactory}; - use alloy_primitives::Address; - use foundry_evm::revm::primitives::{address, Bytes, Precompile, PrecompileResult, SpecId}; - use revm::primitives::PrecompileOutput; +// #[cfg(test)] +// mod tests { +// use crate::{evm::inject_precompiles, PrecompileFactory}; +// use alloy_primitives::{address, Address, Bytes}; +// use revm::{ +// precompile::{PrecompileOutput, PrecompileResult, Precompiles}, +// primitives::hardfork::SpecId, +// }; - #[test] - fn build_evm_with_extra_precompiles() { - const PRECOMPILE_ADDR: Address = address!("0x0000000000000000000000000000000000000071"); +// #[test] +// fn build_evm_with_extra_precompiles() { +// const PRECOMPILE_ADDR: Address = address!("0x0000000000000000000000000000000000000071"); - fn my_precompile(_bytes: &Bytes, _gas_limit: u64) -> PrecompileResult { - Ok(PrecompileOutput { bytes: Bytes::new(), gas_used: 0 }) - } +// fn my_precompile(_bytes: &Bytes, _gas_limit: u64) -> PrecompileResult { +// Ok(PrecompileOutput { bytes: Bytes::new(), gas_used: 0 }) +// } - #[derive(Debug)] - struct CustomPrecompileFactory; +// #[derive(Debug)] +// struct CustomPrecompileFactory; - impl PrecompileFactory for CustomPrecompileFactory { - fn precompiles(&self) -> Vec<(Address, Precompile)> { - vec![(PRECOMPILE_ADDR, Precompile::Standard(my_precompile))] - } - } +// impl PrecompileFactory for CustomPrecompileFactory { +// fn precompiles(&self) -> Vec<(Address, Precompile)> { +// vec![(PRECOMPILE_ADDR, Precompile::Standard(my_precompile))] +// } +// } - let db = revm::db::EmptyDB::default(); - let env = Box::::default(); - let spec = SpecId::LATEST; - let handler_cfg = revm::primitives::HandlerCfg::new(spec); - let inspector = revm::inspectors::NoOpInspector; - let context = revm::Context::new(revm::EvmContext::new_with_env(db, env), inspector); - let handler = revm::Handler::new(handler_cfg); - let mut evm = revm::Evm::new(context, handler); - assert!(!evm - .handler - .pre_execution() - .load_precompiles() - .addresses() - .any(|&addr| addr == PRECOMPILE_ADDR)); +// let db = revm::db::EmptyDB::default(); +// let env = Box::::default(); +// let spec = SpecId::default(); +// let handler_cfg = revm::primitives::HandlerCfg::new(spec); +// let inspector = revm::inspectors::NoOpInspector; +// let context = revm::Context::new(revm::EvmContext::new_with_env(db, env), inspector); +// let handler = revm::Handler::new(handler_cfg); +// let mut evm = revm::Evm::new(context, handler); +// assert!(!evm +// .handler +// .pre_execution() +// .load_precompiles() +// .addresses() +// .any(|&addr| addr == PRECOMPILE_ADDR)); - inject_precompiles(&mut evm, CustomPrecompileFactory.precompiles()); - assert!(evm - .handler - .pre_execution() - .load_precompiles() - .addresses() - .any(|&addr| addr == PRECOMPILE_ADDR)); +// inject_precompiles(&mut evm, CustomPrecompileFactory.precompiles()); +// assert!(evm +// .handler +// .pre_execution() +// .load_precompiles() +// .addresses() +// .any(|&addr| addr == PRECOMPILE_ADDR)); - let result = evm.transact().unwrap(); - assert!(result.result.is_success()); - } -} +// let result = evm.transact().unwrap(); +// assert!(result.result.is_success()); +// } +// } diff --git a/crates/anvil/src/hardfork.rs b/crates/anvil/src/hardfork.rs index d85e12f7decfa..53ddd4c6740df 100644 --- a/crates/anvil/src/hardfork.rs +++ b/crates/anvil/src/hardfork.rs @@ -1,7 +1,9 @@ +use std::str::FromStr; + use alloy_rpc_types::BlockNumberOrTag; use eyre::bail; -use foundry_evm::revm::primitives::SpecId; -use std::str::FromStr; +use op_revm::OpSpecId; +use revm::primitives::hardfork::SpecId; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum ChainHardfork { @@ -25,7 +27,7 @@ impl From for SpecId { fn from(fork: ChainHardfork) -> Self { match fork { ChainHardfork::Ethereum(hardfork) => hardfork.into(), - ChainHardfork::Optimism(hardfork) => hardfork.into(), + ChainHardfork::Optimism(hardfork) => hardfork.into_eth_spec(), } } } @@ -178,9 +180,15 @@ pub enum OptimismHardfork { Fjord, Granite, Holocene, - Isthmus, #[default] - Latest, + Isthmus, +} + +impl OptimismHardfork { + pub fn into_eth_spec(self) -> SpecId { + let op_spec: OpSpecId = self.into(); + op_spec.into_eth_spec() + } } impl FromStr for OptimismHardfork { @@ -197,14 +205,13 @@ impl FromStr for OptimismHardfork { "granite" => Self::Granite, "holocene" => Self::Holocene, "isthmus" => Self::Isthmus, - "latest" => Self::Latest, _ => bail!("Unknown hardfork {s}"), }; Ok(hardfork) } } -impl From for SpecId { +impl From for OpSpecId { fn from(fork: OptimismHardfork) -> Self { match fork { OptimismHardfork::Bedrock => Self::BEDROCK, @@ -215,7 +222,6 @@ impl From for SpecId { OptimismHardfork::Granite => Self::GRANITE, OptimismHardfork::Holocene => Self::HOLOCENE, OptimismHardfork::Isthmus => Self::ISTHMUS, - OptimismHardfork::Latest => Self::LATEST, } } } diff --git a/crates/anvil/src/lib.rs b/crates/anvil/src/lib.rs index d5576596e1ea0..b48ad1197569a 100644 --- a/crates/anvil/src/lib.rs +++ b/crates/anvil/src/lib.rs @@ -23,7 +23,6 @@ use alloy_signer_local::PrivateKeySigner; use eth::backend::fork::ClientFork; use eyre::Result; use foundry_common::provider::{ProviderBuilder, RetryProvider}; -use foundry_evm::revm; use futures::{FutureExt, TryFutureExt}; use parking_lot::Mutex; use server::try_spawn_ipc; @@ -48,13 +47,15 @@ pub use config::{ }; mod hardfork; -pub use hardfork::EthereumHardfork; +pub use hardfork::{EthereumHardfork, OptimismHardfork}; /// ethereum related implementations pub mod eth; /// Evm related abstractions mod evm; -pub use evm::{inject_precompiles, PrecompileFactory}; +// pub use evm::{inject_precompiles, PrecompileFactory}; +pub use evm::PrecompileFactory; + /// support for polling filters pub mod filter; /// commandline output diff --git a/crates/anvil/test-data/state-dump-legacy-stress.json b/crates/anvil/test-data/state-dump-legacy-stress.json index f6605d5add4e3..b7a18c94cad40 100644 --- a/crates/anvil/test-data/state-dump-legacy-stress.json +++ b/crates/anvil/test-data/state-dump-legacy-stress.json @@ -1 +1 @@ -{"block":{"number":"0x5","coinbase":"0x0000000000000000000000000000000000000000","timestamp":"0x66b200cb","gas_limit":"0x1c9c380","basefee":"0x12e09c7a","difficulty":"0x0","prevrandao":"0xe7ef87fc7c2090741a6749a087e4ca8092cb4d07136008799e4ebeac3b69e34a","blob_excess_gas_and_price":{"excess_blob_gas":0,"blob_gasprice":1}},"accounts":{"0x0000000000000000000000000000000000000000":{"nonce":0,"balance":"0x1088aa62285a00","code":"0x","storage":{}},"0x108f53faf774d7c4c56f5bce9ca6e605ce8aeadd":{"nonce":1,"balance":"0x0","code":"0x6080604052600080357fffffffff0000000000000000000000000000000000000000000000000000000016905060008160e01c610251565b60006379ba509782101561015e5781631627540c811461009857632a952b2d81146100b457633659cfe681146100d0576350c946fe81146100ec576353a47bb781146101085763625ca21c81146101245763718fe928811461014057610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc91505b5061024c565b816379ba509781146101a657638da5cb5b81146101c25763aaf10f4281146101de5763c7f62cda81146101fa5763daa250be81146102165763deba1b9881146102325761024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b738138ef7cf908021d117e542120b7a39065016107915061024a565b738138ef7cf908021d117e542120b7a3906501610791505b505b919050565b61025a81610037565b915050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036102ce57816040517fc2a825f50000000000000000000000000000000000000000000000000000000081526004016102c5919061032f565b60405180910390fd5b3660008037600080366000845af43d6000803e80600081146102ef573d6000f35b3d6000fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610329816102f4565b82525050565b60006020820190506103446000830184610320565b9291505056fea264697066735822122017a4b7fdaaab3897a7b47abaed8d2ee92d558883d3bb2a8454f9601b2ab2c3db64736f6c63430008150033","storage":{}},"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x19ba1fac55eea44d12a01372a8eb0c2ebbf9ca21":{"nonce":1,"balance":"0x21e19df7c2963f0ac6b","code":"0x","storage":{}},"0x19c6ab860dbe2bc433574193a4409770a8748bf6":{"nonce":1,"balance":"0x21e19df8da6b7bdc410","code":"0x","storage":{}},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x40567ec443c1d1872af5155755ac3803cc3fe61e":{"nonce":1,"balance":"0x21e19da82562f921b40","code":"0x","storage":{}},"0x47d08dad17ccb558b3ea74b1a0e73a9cc804a9dc":{"nonce":1,"balance":"0x0","code":"0x608060405234801561001057600080fd5b50600436106100885760003560e01c806379ba50971161005b57806379ba5097146100ed5780638da5cb5b146100f7578063aaf10f4214610115578063c7f62cda1461013357610088565b80631627540c1461008d5780633659cfe6146100a957806353a47bb7146100c5578063718fe928146100e3575b600080fd5b6100a760048036038101906100a29190610d25565b61014f565b005b6100c360048036038101906100be9190610d25565b6102d0565b005b6100cd6102e4565b6040516100da9190610d61565b60405180910390f35b6100eb610317565b005b6100f56103fe565b005b6100ff61058b565b60405161010c9190610d61565b60405180910390f35b61011d6105be565b60405161012a9190610d61565b60405180910390f35b61014d60048036038101906101489190610d25565b6105f1565b005b61015761084c565b600061016161081b565b9050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036101c9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610252576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22826040516102c49190610d61565b60405180910390a15050565b6102d861084c565b6102e1816108c5565b50565b60006102ee61081b565b60010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600061032161081b565b90503373ffffffffffffffffffffffffffffffffffffffff168160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146103b757336040517fa0e5a0d70000000000000000000000000000000000000000000000000000000081526004016103ae9190610d61565b60405180910390fd5b60008160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600061040861081b565b905060008160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146104a357336040517fa0e5a0d700000000000000000000000000000000000000000000000000000000815260040161049a9190610d61565b60405180910390fd5b7fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c8260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16826040516104f8929190610d7c565b60405180910390a1808260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008260010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b600061059561081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105c8610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105fb610b05565b905060018160000160146101000a81548160ff02191690831515021790555060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050828260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008373ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16633659cfe6846040516024016106cc9190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161071b9190610e16565b600060405180830381855af49150503d8060008114610756576040519150601f19603f3d011682016040523d82523d6000602084013e61075b565b606091505b505090508015806107c357508173ffffffffffffffffffffffffffffffffffffffff16610786610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b156107fa576040517fa1cfa5a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360000160146101000a81548160ff0219169083151502179055600080fd5b60008060405160200161082d90610eb0565b6040516020818303038152906040528051906020012090508091505090565b610854610b36565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108c357336040517f8e4a23d60000000000000000000000000000000000000000000000000000000081526004016108ba9190610d61565b60405180910390fd5b565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361092b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61093481610b69565b61097557806040517f8a8b41ec00000000000000000000000000000000000000000000000000000000815260040161096c9190610d61565b60405180910390fd5b600061097f610b05565b90508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610a0a576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000160149054906101000a900460ff16158015610a2e5750610a2d82610b7c565b5b15610a7057816040517f15504301000000000000000000000000000000000000000000000000000000008152600401610a679190610d61565b60405180910390fd5b818160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503073ffffffffffffffffffffffffffffffffffffffff167f5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c783604051610af99190610d61565b60405180910390a25050565b600080604051602001610b1790610f42565b6040516020818303038152906040528051906020012090508091505090565b6000610b4061081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080823b905060008111915050919050565b60008060003073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1663c7f62cda86604051602401610bc59190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610c149190610e16565b600060405180830381855af49150503d8060008114610c4f576040519150601f19603f3d011682016040523d82523d6000602084013e610c54565b606091505b509150915081158015610cb9575063a1cfa5a860e01b604051602001610c7a9190610faf565b6040516020818303038152906040528051906020012081604051602001610ca19190610e16565b60405160208183030381529060405280519060200120145b92505050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cf282610cc7565b9050919050565b610d0281610ce7565b8114610d0d57600080fd5b50565b600081359050610d1f81610cf9565b92915050565b600060208284031215610d3b57610d3a610cc2565b5b6000610d4984828501610d10565b91505092915050565b610d5b81610ce7565b82525050565b6000602082019050610d766000830184610d52565b92915050565b6000604082019050610d916000830185610d52565b610d9e6020830184610d52565b9392505050565b600081519050919050565b600081905092915050565b60005b83811015610dd9578082015181840152602081019050610dbe565b60008484015250505050565b6000610df082610da5565b610dfa8185610db0565b9350610e0a818560208601610dbb565b80840191505092915050565b6000610e228284610de5565b915081905092915050565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b6000610e9a602383610e2d565b9150610ea582610e3e565b604082019050919050565b60006020820190508181036000830152610ec981610e8d565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b6000610f2c602183610e2d565b9150610f3782610ed0565b604082019050919050565b60006020820190508181036000830152610f5b81610f1f565b9050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b610fa9610fa482610f62565b610f8e565b82525050565b6000610fbb8284610f98565b6004820191508190509291505056fea264697066735822122023a7c33d7b91dce35ffbcf8837693364ab22a3905d0fc00016833e5fac45ca2f64736f6c63430008110033","storage":{"0x5c7865864a2a990d80b5bb5c40e7b73a029960dc711fbb56120dfab976e92ea3":"0x0"}},"0x4e59b44847b379578588920ca78fbf26c0b4956c":{"nonce":2,"balance":"0x0","code":"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3","storage":{}},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x8138ef7cf908021d117e542120b7a39065016107":{"nonce":1,"balance":"0x0","code":"0x608060405234801561001057600080fd5b50600436106100575760003560e01c80632a952b2d1461005c57806350c946fe14610085578063625ca21c146100a5578063daa250be146100c6578063deba1b98146100d9575b600080fd5b61006f61006a366004613a63565b6100ec565b60405161007c9190613a7c565b60405180910390f35b610098610093366004613a63565b61011c565b60405161007c9190613b21565b6100b86100b3366004613c92565b610276565b60405190815260200161007c565b61006f6100d4366004613d5f565b6102bb565b6100b86100e7366004613c92565b6102d6565b6100f46139e4565b6040805160008082526020820190815281830190925261011691849190610310565b92915050565b6101416040805160608101909152806000815260200160608152602001606081525090565b61014a82610ab6565b60408051606081019091528154909190829060ff16600981111561017057610170613aa7565b600981111561018157610181613aa7565b815260200160018201805461019590613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546101c190613dc2565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561026657602002820191906000526020600020905b815481526020019060010190808311610252575b5050505050815250509050919050565b600080604051806060016040528086600981111561029657610296613aa7565b81526020018581526020018481525090506102b081610ac1565b9150505b9392505050565b6102c36139e4565b6102ce848484610310565b949350505050565b60008060405180606001604052808660098111156102f6576102f6613aa7565b81526020018581526020018481525090506102b081610acc565b6103186139e4565b81518351146103a05760408051634bab873760e11b81526004810191909152600d60448201526c72756e74696d6556616c75657360981b606482015260806024820152602260848201527f6d7573742062652073616d65206c656e6774682061732072756e74696d654b6560a482015261797360f01b60c482015260e4015b60405180910390fd5b60006103ab85610c26565b805490915060ff1660018160098111156103c7576103c7613aa7565b036104755761046c6103da838787610c84565b8360010180546103e990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461041590613dc2565b80156104625780601f1061043757610100808354040283529160200191610462565b820191906000526020600020905b81548152906001019060200180831161044557829003601f168201915b5050505050610d46565b925050506102b4565b600281600981111561048957610489613aa7565b036105305761046c61049c838787610c84565b8360010180546104ab90613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546104d790613dc2565b80156105245780601f106104f957610100808354040283529160200191610524565b820191906000526020600020905b81548152906001019060200180831161050757829003601f168201915b50505050508787610ebb565b600381600981111561054457610544613aa7565b036105de5761046c82600101805461055b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461058790613dc2565b80156105d45780601f106105a9576101008083540402835291602001916105d4565b820191906000526020600020905b8154815290600101906020018083116105b757829003601f168201915b5050505050610f59565b60048160098111156105f2576105f2613aa7565b0361068c5761046c82600101805461060990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461063590613dc2565b80156106825780601f1061065757610100808354040283529160200191610682565b820191906000526020600020905b81548152906001019060200180831161066557829003601f168201915b5050505050611087565b60058160098111156106a0576106a0613aa7565b0361073a5761046c8260010180546106b790613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546106e390613dc2565b80156107305780601f1061070557610100808354040283529160200191610730565b820191906000526020600020905b81548152906001019060200180831161071357829003601f168201915b505050505061131e565b600981600981111561074e5761074e613aa7565b036107ea5761046c82600101805461076590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461079190613dc2565b80156107de5780601f106107b3576101008083540402835291602001916107de565b820191906000526020600020905b8154815290600101906020018083116107c157829003601f168201915b505050505086866114b5565b60068160098111156107fe576107fe613aa7565b036108a35761046c610811838787610c84565b83600101805461082090613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461084c90613dc2565b80156108995780601f1061086e57610100808354040283529160200191610899565b820191906000526020600020905b81548152906001019060200180831161087c57829003601f168201915b50505050506115c7565b60078160098111156108b7576108b7613aa7565b036109ec576040805160608101909152825461046c91908490829060ff1660098111156108e6576108e6613aa7565b60098111156108f7576108f7613aa7565b815260200160018201805461090b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461093790613dc2565b80156109845780601f1061095957610100808354040283529160200191610984565b820191906000526020600020905b81548152906001019060200180831161096757829003601f168201915b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156109dc57602002820191906000526020600020905b8154815260200190600101908083116109c8575b5050505050815250508686611728565b6008816009811115610a0057610a00613aa7565b03610a9a5761046c826001018054610a1790613dc2565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4390613dc2565b8015610a905780601f10610a6557610100808354040283529160200191610a90565b820191906000526020600020905b815481529060010190602001808311610a7357829003601f168201915b50505050506118a5565b6040516323a9bbc960e01b815260048101879052602401610397565b600061011682610c26565b6000610116826118ea565b6000610ad782610ac1565b9050610ae28161192a565b15610b35577fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e81836000015184602001518560400151604051610b289493929190613e32565b60405180910390a1919050565b610b3e82611a8c565b610b5d578160405163382bbbc960e11b81526004016103979190613b21565b60005b826040015151811015610bd957610b9383604001518281518110610b8657610b86613e6a565b602002602001015161192a565b610bd15782604001518181518110610bad57610bad613e6a565b6020026020010151604051632f19f96160e11b815260040161039791815260200190565b600101610b60565b50610be382611c31565b8351602085015160408087015190519395507fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e9450610b28938693929190613e32565b604080516020808201839052606082018190527f696f2e73796e7468657469782e6f7261636c652d6d616e616765722e4e6f6465608080840191909152828401949094528251808303909401845260a0909101909152815191012090565b600283015460609067ffffffffffffffff811115610ca457610ca4613b9a565b604051908082528060200260200182016040528015610cdd57816020015b610cca6139e4565b815260200190600190039081610cc25790505b50905060005b6002850154811015610d3e57610d19856002018281548110610d0757610d07613e6a565b90600052602060002001548585610310565b828281518110610d2b57610d2b613e6a565b6020908102919091010152600101610ce3565b509392505050565b610d4e6139e4565b600082806020019051810190610d649190613e80565b90506000816008811115610d7a57610d7a613aa7565b03610d9057610d8884611ca5565b915050610116565b6001816008811115610da457610da4613aa7565b03610db257610d8884611d0d565b6002816008811115610dc657610dc6613aa7565b03610dd457610d8884611d90565b6003816008811115610de857610de8613aa7565b03610df657610d8884611e13565b6004816008811115610e0a57610e0a613aa7565b03610e1857610d8884611ec9565b6005816008811115610e2c57610e2c613aa7565b03610e3a57610d8884612009565b6006816008811115610e4e57610e4e613aa7565b03610e5c57610d88846120e4565b6007816008811115610e7057610e70613aa7565b03610e7e57610d888461220c565b6008816008811115610e9257610e92613aa7565b03610ea057610d88846122ce565b80604051631be413d360e11b81526004016103979190613ea1565b610ec36139e4565b600084806020019051810190610ed99190613ed3565b604051631ecba7c360e31b81529091506001600160a01b0382169063f65d3e1890610f0e908990899089908990600401613ef0565b608060405180830381865afa158015610f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4f9190613f91565b9695505050505050565b610f616139e4565b600080600084806020019051810190610f7a9190613fe8565b92509250925060008390506000806000836001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fec9190614041565b509350509250925060008660001461100f5761100a8585858a6123c7565b611011565b825b905060128660ff161161103b5761103661102f60ff881660126140a7565b82906124c2565b611053565b61105361104c601260ff89166140a7565b82906124dc565b9050604051806080016040528082815260200183815260200160008152602001600081525098505050505050505050919050565b61108f6139e4565b600080600080600080878060200190518101906110ac91906140ba565b604080516002808252606082018352979d50959b50939950919750955093506000929060208301908036833701905050905081816000815181106110f2576110f2613e6a565b602002602001019063ffffffff16908163ffffffff168152505060008160018151811061112157611121613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526000906001600160a01b0385169063883bdbfd90611165908590600401614143565b600060405180830381865afa158015611182573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111aa91908101906141f5565b5090506000816000815181106111c2576111c2613e6a565b6020026020010151826001815181106111dd576111dd613e6a565b60200260200101516111ef91906142c1565b9050600061121761120563ffffffff87166124f6565b61120f9084614304565b60060b61252d565b905060008260060b12801561124c575061123b63ffffffff8616612569565b612569565b8260060b6112499190614342565b15155b1561125f578061125b81614356565b9150505b600061126d6012600a61445d565b9050600061128061123684848f8f612593565b905060006112908a60ff16612569565b61129c8c60ff16612569565b6112a6919061446c565b905060008082136112d1576112cc6112c56112c084614493565b612686565b84906124dc565b6112e4565b6112e46112dd83612686565b84906124c2565b905060405180608001604052808281526020014281526020016000815260200160008152509e505050505050505050505050505050919050565b6113266139e4565b60008060008480602001905181019061133f91906144bf565b91945092509050826000826113bc576040516396834ad360e01b8152600481018590526001600160a01b038316906396834ad390602401608060405180830381865afa158015611393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b791906144f5565b611425565b604051639474f45b60e01b8152600481018590526001600160a01b03831690639474f45b90602401608060405180830381865afa158015611401573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142591906144f5565b90506000816040015160030b601261143d919061456f565b90506000808213611467576114626114576112c084614493565b845160070b906124dc565b61147e565b61147e61147383612686565b845160070b906124c2565b9050604051806080016040528082815260200184606001518152602001600081526020016000815250975050505050505050919050565b6114bd6139e4565b6000806000868060200190518101906114d69190614597565b92509250925060005b8651811015611545578681815181106114fa576114fa613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b0361153d5785818151811061152f5761152f613e6a565b602002602001015160001c91505b6001016114df565b5060408051600180825281830190925260009160208083019080368337019050509050828160008151811061157c5761157c613e6a565b602002602001018181525050836001838360405160200161159f939291906145ce565b60408051601f198184030181529082905263cf2cabdf60e01b82526103979291600401614603565b6115cf6139e4565b6000828060200190518101906115e59190614627565b90506000846000815181106115fc576115fc613e6a565b602002602001015160000151905060008560018151811061161f5761161f613e6a565b6020026020010151600001519050808214611702576000611653601261164d611648858761446c565b6126a9565b906124c2565b905082158061167b5750611666836126a9565b6116709082614640565b61167985612569565b125b15611700576002875111156116b0578660028151811061169d5761169d613e6a565b6020026020010151945050505050610116565b826000036116d15760405163014cc07160e01b815260040160405180910390fd5b6116da836126a9565b6116e49082614640565b60405163dcac091960e01b815260040161039791815260200190565b505b8560008151811061171557611715613e6a565b6020026020010151935050505092915050565b6117306139e4565b6000846020015180602001905181019061174a9190614627565b905060005b84518110156117bc5784818151811061176a5761176a613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b036117b4576117ad8482815181106117a2576117a2613e6a565b602002602001015190565b91506117bc565b60010161174f565b50600085604001516000815181106117d6576117d6613e6a565b6020026020010151905060006117ed828787610310565b60208101519091506117ff84426140a7565b1161180e5792506102b4915050565b86604001515160010361187157866040015160008151811061183257611832613e6a565b602002602001015181600001518260200151604051631808066560e21b8152600401610397939291909283526020830191909152604082015260600190565b61189a876040015160018151811061188b5761188b613e6a565b60200260200101518787610310565b979650505050505050565b6118ad6139e4565b6040518060800160405280838060200190518101906118cc9190614627565b81526020014281526020016000815260200160008152509050919050565b600081600001518260200151836040015160405160200161190d9392919061466e565b604051602081830303815290604052805190602001209050919050565b60008061193683610c26565b60408051606081019091528154909190829060ff16600981111561195c5761195c613aa7565b600981111561196d5761196d613aa7565b815260200160018201805461198190613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546119ad90613dc2565b80156119fa5780601f106119cf576101008083540402835291602001916119fa565b820191906000526020600020905b8154815290600101906020018083116119dd57829003601f168201915b5050505050815260200160028201805480602002602001604051908101604052809291908181526020018280548015611a5257602002820191906000526020600020905b815481526020019060010190808311611a3e575b505050505081525050905060006009811115611a7057611a70613aa7565b81516009811115611a8357611a83613aa7565b14159392505050565b6000600182516009811115611aa357611aa3613aa7565b1480611ac15750600682516009811115611abf57611abf613aa7565b145b80611ade5750600782516009811115611adc57611adc613aa7565b145b15611aee57611aec826126c1565b505b600182516009811115611b0357611b03613aa7565b03611b11576101168261284a565b600282516009811115611b2657611b26613aa7565b03611b3457610116826128a5565b600382516009811115611b4957611b49613aa7565b03611b575761011682612973565b600482516009811115611b6c57611b6c613aa7565b03611b7a5761011682612aae565b600582516009811115611b8f57611b8f613aa7565b03611b9d5761011682612e92565b600982516009811115611bb257611bb2613aa7565b03611bc05761011682612fcb565b600682516009811115611bd557611bd5613aa7565b03611be3576101168261300e565b600782516009811115611bf857611bf8613aa7565b03611c065761011682613052565b600882516009811115611c1b57611c1b613aa7565b03611c295761011682613078565b506000919050565b600080611c3d836118ea565b9050611c4881610c26565b8351815491935090839060ff19166001836009811115611c6a57611c6a613aa7565b021790555060208301516001830190611c8390826146ed565b5060408301518051611c9f916002850191602090910190613a0c565b50915091565b611cad6139e4565b60005b8251811015611d07578160200151838281518110611cd057611cd0613e6a565b6020026020010151602001511115611cff57828181518110611cf457611cf4613e6a565b602002602001015191505b600101611cb0565b50919050565b611d156139e4565b81600081518110611d2857611d28613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611d5957611d59613e6a565b6020026020010151600001511215611d8857828181518110611d7d57611d7d613e6a565b602002602001015191505b600101611d39565b611d986139e4565b81600081518110611dab57611dab613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611ddc57611ddc613e6a565b6020026020010151600001511315611e0b57828181518110611e0057611e00613e6a565b602002602001015191505b600101611dbc565b611e1b6139e4565b60005b8251811015611e9557828181518110611e3957611e39613e6a565b60200260200101516000015182600001818151611e56919061456f565b9052508251839082908110611e6d57611e6d613e6a565b60200260200101516020015182602001818151611e8a91906147ad565b905250600101611e1e565b50611ea08251612569565b8151611eac9190614640565b815281516020820151611ebf91906147c0565b6020820152919050565b611ed16139e4565b611eed826000611ee86001865161123691906140a7565b6130a4565b60028251611efb91906147d4565b600003611fd65760408051600280825260608201909252600091816020015b611f226139e4565b815260200190600190039081611f1a57905050905082600160028551611f4891906147c0565b611f5291906140a7565b81518110611f6257611f62613e6a565b602002602001015181600081518110611f7d57611f7d613e6a565b60200260200101819052508260028451611f9791906147c0565b81518110611fa757611fa7613e6a565b602002602001015181600181518110611fc257611fc2613e6a565b60200260200101819052506102b481611e13565b8160028351611fe591906147c0565b81518110611ff557611ff5613e6a565b60200260200101519050919050565b919050565b6120116139e4565b8160008151811061202457612024613e6a565b60209081029190910101515181528151829060009061204557612045613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061207657612076613e6a565b6020026020010151600001518260000181815161209391906147e8565b90525082518390829081106120aa576120aa613e6a565b602002602001015160200151826020018181516120c791906147ad565b90525060010161205b565b5081518160200151611ebf91906147c0565b6120ec6139e4565b816000815181106120ff576120ff613e6a565b60209081029190910101515181528151829060009061212057612120613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061215157612151613e6a565b60200260200101516000015160000361219e5782818151811061217657612176613e6a565b6020026020010151600001516040516338ee04a760e01b815260040161039791815260200190565b8281815181106121b0576121b0613e6a565b602002602001015160000151826000018181516121cd9190614640565b90525082518390829081106121e4576121e4613e6a565b6020026020010151602001518260200181815161220191906147ad565b905250600101612136565b6122146139e4565b8160008151811061222757612227613e6a565b60209081029190910101515181528151829060009061224857612248613e6a565b6020908102919091018101518101519082015260015b82518110156120d25761229083828151811061227c5761227c613e6a565b602090810291909101015151835190613264565b825282518390829081106122a6576122a6613e6a565b602002602001015160200151826020018181516122c391906147ad565b90525060010161225e565b6122d66139e4565b816000815181106122e9576122e9613e6a565b60209081029190910101515181528151829060009061230a5761230a613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061233b5761233b613e6a565b6020026020010151600001516000036123605782818151811061217657612176613e6a565b61238983828151811061237557612375613e6a565b602090810291909101015151835190613283565b8252825183908290811061239f5761239f613e6a565b602002602001015160200151826020018181516123bc91906147ad565b905250600101612320565b6000826001826123d785426140a7565b90505b69ffffffffffffffffffff8716156124a3576001600160a01b038816639a6fc8f561240489614818565b6040516001600160e01b031960e084901b16815269ffffffffffffffffffff8216600482015290995060240160a060405180830381865afa925050508015612469575060408051601f3d908101601f1916820190925261246691810190614041565b60015b156124a357858210156124805750505050506124a3565b61248a848961456f565b97508661249681614834565b97505050505050506123da565b6124ac82612569565b6124b69084614640565b98975050505050505050565b60006124d261123683600a61484d565b6102b490846147e8565b60006124ec61123683600a61484d565b6102b49084614640565b6000667fffffffffffff66ffffffffffffff83161115612529576040516329d2678160e21b815260040160405180910390fd5b5090565b6000627fffff19600683900b128061254b5750627fffff600683900b135b1561252957604051630d962f7960e21b815260040160405180910390fd5b60006001600160ff1b038211156125295760405163677c430560e11b815260040160405180910390fd5b60008061259f86613298565b90506fffffffffffffffffffffffffffffffff6001600160a01b0382161161261c5760006125d66001600160a01b03831680614859565b9050836001600160a01b0316856001600160a01b03161061260557612600600160c01b87836136cd565b612614565b6126148187600160c01b6136cd565b92505061267d565b600061263b6001600160a01b03831680680100000000000000006136cd565b9050836001600160a01b0316856001600160a01b03161061266a57612665600160801b87836136cd565b612679565b6126798187600160801b6136cd565b9250505b50949350505050565b6000808212156125295760405163029f024d60e31b815260040160405180910390fd5b600080821215612529576126bc82614493565b610116565b6000805b8260400151518110156128415760006126fa846040015183815181106126ed576126ed613e6a565b6020026020010151610ab6565b60408051606081019091528154909190829060ff16600981111561272057612720613aa7565b600981111561273157612731613aa7565b815260200160018201805461274590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461277190613dc2565b80156127be5780601f10612793576101008083540402835291602001916127be565b820191906000526020600020905b8154815290600101906020018083116127a157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561281657602002820191906000526020600020905b815481526020019060010190808311612802575b505050505081525050905061282a81611a8c565b612838575060009392505050565b506001016126c5565b50600192915050565b60006002826040015151101561286257506000919050565b81602001515160201461287757506000919050565b600082602001518060200190518101906128919190614627565b905060088111156128415750600092915050565b6000602082602001515110156128bd57506000919050565b600082602001518060200190518101906128d79190613ed3565b90506128ea816306e7ea3960e21b6138e2565b6128f75750600092915050565b604051633b70a5bf60e21b81526001600160a01b0382169063edc296fc90612923908690600401613b21565b6020604051808303816000875af1158015612942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129669190614870565b6128415750600092915050565b6040810151516000901561298957506000919050565b81602001515160601461299e57506000919050565b60008083602001518060200190518101906129b99190613fe8565b92505091506000829050806001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612a01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a259190614041565b5050505050806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8c919061488b565b60ff168260ff1614612aa357506000949350505050565b506001949350505050565b60408101515160009015612ac457506000919050565b81602001515160c014612ad957506000919050565b6000806000806000808760200151806020019051810190612afa91906140ba565b9550955095509550955095508360ff16866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6c919061488b565b60ff1614612b8257506000979650505050505050565b8260ff16856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612be8919061488b565b60ff1614612bfe57506000979650505050505050565b6000826001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c629190613ed3565b90506000836001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc89190613ed3565b9050876001600160a01b0316826001600160a01b0316148015612cfc5750866001600160a01b0316816001600160a01b0316145b158015612d385750866001600160a01b0316826001600160a01b0316148015612d365750876001600160a01b0316816001600160a01b0316145b155b15612d4d575060009998505050505050505050565b60128660ff161180612d62575060128560ff16115b15612d77575060009998505050505050505050565b8263ffffffff16600003612d95575060009998505050505050505050565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612dca57612dca613e6a565b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110612df957612df9613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526001600160a01b0386169063883bdbfd90612e3a908490600401614143565b600060405180830381865afa158015612e57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e7f91908101906141f5565b5060019c9b505050505050505050505050565b60408101515160009015612ea857506000919050565b816020015151606014612ebd57506000919050565b60008060008460200151806020019051810190612eda91906144bf565b919450925090508281612f55576040516396834ad360e01b8152600481018490526001600160a01b038216906396834ad390602401608060405180830381865afa158015612f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f5091906144f5565b612fbe565b604051639474f45b60e01b8152600481018490526001600160a01b03821690639474f45b90602401608060405180830381865afa158015612f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbe91906144f5565b5060019695505050505050565b60408101515160009015612fe157506000919050565b816020015151606014612ff657506000919050565b8160200151806020019051810190612aa39190614597565b60008160400151516002148061302957508160400151516003145b61303557506000919050565b81602001515160201461304a57506000919050565b506001919050565b600081604001515160011480613029575081604001515160021461303557506000919050565b6040810151516000901561308e57506000919050565b6020826020015151101561304a57506000919050565b81818082036130b4575050505050565b6000856130da60026130c6888861446c565b6130d09190614640565b6112c0908861456f565b815181106130ea576130ea613e6a565b60200260200101516000015190505b818313613236575b808661310c85612686565b8151811061311c5761311c613e6a565b60200260200101516000015112156131405782613138816148a6565b935050613101565b8561314a83612686565b8151811061315a5761315a613e6a565b60200260200101516000015181121561317f5781613177816148be565b925050613140565b818313613231578561319083612686565b815181106131a0576131a0613e6a565b6020026020010151866131b285612686565b815181106131c2576131c2613e6a565b6020026020010151876131d486612686565b815181106131e4576131e4613e6a565b60200260200101886131f586612686565b8151811061320557613205613e6a565b602002602001018290528290525050828061321f906148a6565b935050818061322d906148be565b9250505b6130f9565b81851215613249576132498686846130a4565b8383121561325c5761325c8684866130a4565b505050505050565b6000670de0b6b3a764000061327983856147e8565b6102b49190614640565b600081613279670de0b6b3a7640000856147e8565b60008060008360020b126132b8576132b3600284900b612686565b6132c8565b6132c86112c0600285900b614493565b90506132e36112c06132dd620d89e7196148db565b60020b90565b8111156133165760405162461bcd60e51b81526020600482015260016024820152601560fa1b6044820152606401610397565b60008160011660000361332d57600160801b61333f565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff169050600282161561337e576080613379826ffff97272373d413259a46990580e213a614859565b901c90505b60048216156133a85760806133a3826ffff2e50f5f656932ef12357cf3c7fdcc614859565b901c90505b60088216156133d25760806133cd826fffe5caca7e10e4e61c3624eaa0941cd0614859565b901c90505b60108216156133fc5760806133f7826fffcb9843d60f6159c9db58835c926644614859565b901c90505b6020821615613426576080613421826fff973b41fa98c081472e6896dfb254c0614859565b901c90505b604082161561345057608061344b826fff2ea16466c96a3843ec78b326b52861614859565b901c90505b608082161561347a576080613475826ffe5dee046a99a2a811c461f1969c3053614859565b901c90505b6101008216156134a55760806134a0826ffcbe86c7900a88aedcffc83b479aa3a4614859565b901c90505b6102008216156134d05760806134cb826ff987a7253ac413176f2b074cf7815e54614859565b901c90505b6104008216156134fb5760806134f6826ff3392b0822b70005940c7a398e4b70f3614859565b901c90505b610800821615613526576080613521826fe7159475a2c29b7443b29c7fa6e889d9614859565b901c90505b61100082161561355157608061354c826fd097f3bdfd2022b8845ad8f792aa5825614859565b901c90505b61200082161561357c576080613577826fa9f746462d870fdf8a65dc1f90e061e5614859565b901c90505b6140008216156135a75760806135a2826f70d869a156d2a1b890bb3df62baf32f7614859565b901c90505b6180008216156135d25760806135cd826f31be135f97d08fd981231505542fcfa6614859565b901c90505b620100008216156135fe5760806135f9826f09aa508b5b7a84e1c677de54f3e99bc9614859565b901c90505b62020000821615613629576080613624826e5d6af8dedb81196699c329225ee604614859565b901c90505b6204000082161561365357608061364e826d2216e584f5fa1ea926041bedfe98614859565b901c90505b6208000082161561367b576080613676826b048a170391f7dc42444e8fa2614859565b901c90505b60008460020b131561369657613693816000196147c0565b90505b6102ce6136a8640100000000836147d4565b156136b45760016136b7565b60005b6136c89060ff16602084901c6147ad565b6139ba565b6000808060001985870985870292508281108382030391505080600003613749576000841161373e5760405162461bcd60e51b815260206004820152601960248201527f48616e646c65206e6f6e2d6f766572666c6f77206361736573000000000000006044820152606401610397565b5082900490506102b4565b8084116137985760405162461bcd60e51b815260206004820152601960248201527f70726576656e74732064656e6f6d696e61746f72203d3d2030000000000000006044820152606401610397565b60008486880980840393811190920391905060006137d06137b887612569565b6137c188612569565b6137ca90614493565b16612686565b9586900495938490049360008190030460010190506137ef8184614859565b909317926000613800876003614859565b600218905061380f8188614859565b61381a9060026140a7565b6138249082614859565b90506138308188614859565b61383b9060026140a7565b6138459082614859565b90506138518188614859565b61385c9060026140a7565b6138669082614859565b90506138728188614859565b61387d9060026140a7565b6138879082614859565b90506138938188614859565b61389e9060026140a7565b6138a89082614859565b90506138b48188614859565b6138bf9060026140a7565b6138c99082614859565b90506138d58186614859565b9998505050505050505050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b1790529051600091829182916001600160a01b0387169161394391906148fd565b6000604051808303816000865af19150503d8060008114613980576040519150601f19603f3d011682016040523d82523d6000602084013e613985565b606091505b50915091508161399a57600092505050610116565b80516000036139ae57600092505050610116565b60200151949350505050565b60006001600160a01b038211156125295760405163dccde8ed60e01b815260040160405180910390fd5b6040518060800160405280600081526020016000815260200160008152602001600081525090565b828054828255906000526020600020908101928215613a47579160200282015b82811115613a47578251825591602001919060010190613a2c565b506125299291505b808211156125295760008155600101613a4f565b600060208284031215613a7557600080fd5b5035919050565b8151815260208083015190820152604080830151908201526060808301519082015260808101610116565b634e487b7160e01b600052602160045260246000fd5b600a8110613acd57613acd613aa7565b9052565b60005b83811015613aec578181015183820152602001613ad4565b50506000910152565b60008151808452613b0d816020860160208601613ad1565b601f01601f19169290920160200192915050565b60006020808352613b358184018551613abd565b8084015160606040850152613b4d6080850182613af5565b6040860151858203601f19016060870152805180835290840192506000918401905b80831015613b8f5783518252928401926001929092019190840190613b6f565b509695505050505050565b634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715613bd357613bd3613b9a565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613c0257613c02613b9a565b604052919050565b600067ffffffffffffffff821115613c2457613c24613b9a565b5060051b60200190565b600082601f830112613c3f57600080fd5b81356020613c54613c4f83613c0a565b613bd9565b8083825260208201915060208460051b870101935086841115613c7657600080fd5b602086015b84811015613b8f5780358352918301918301613c7b565b600080600060608486031215613ca757600080fd5b8335600a8110613cb657600080fd5b925060208481013567ffffffffffffffff80821115613cd457600080fd5b818701915087601f830112613ce857600080fd5b813581811115613cfa57613cfa613b9a565b613d0c601f8201601f19168501613bd9565b8181528985838601011115613d2057600080fd5b818585018683013760009181019094015291935060408601359180831115613d4757600080fd5b5050613d5586828701613c2e565b9150509250925092565b600080600060608486031215613d7457600080fd5b83359250602084013567ffffffffffffffff80821115613d9357600080fd5b613d9f87838801613c2e565b93506040860135915080821115613db557600080fd5b50613d5586828701613c2e565b600181811c90821680613dd657607f821691505b602082108103611d0757634e487b7160e01b600052602260045260246000fd5b60008151808452602080850194506020840160005b83811015613e2757815187529582019590820190600101613e0b565b509495945050505050565b848152613e426020820185613abd565b608060408201526000613e586080830185613af5565b828103606084015261189a8185613df6565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613e9257600080fd5b8151600981106102b457600080fd5b6020810160098310613eb557613eb5613aa7565b91905290565b6001600160a01b0381168114613ed057600080fd5b50565b600060208284031215613ee557600080fd5b81516102b481613ebb565b608080825285518282018190526000919060209060a0850190828a01855b82811015613f5257613f42848351805182526020810151602083015260408101516040830152606081015160608301525050565b9285019290840190600101613f0e565b5050508481036020860152613f678189613af5565b925050508281036040840152613f7d8186613df6565b9050828103606084015261189a8185613df6565b600060808284031215613fa357600080fd5b613fab613bb0565b825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b805160ff8116811461200457600080fd5b600080600060608486031215613ffd57600080fd5b835161400881613ebb565b6020850151909350915061401e60408501613fd7565b90509250925092565b805169ffffffffffffffffffff8116811461200457600080fd5b600080600080600060a0868803121561405957600080fd5b61406286614027565b945060208601519350604086015192506060860151915061408560808701614027565b90509295509295909350565b634e487b7160e01b600052601160045260246000fd5b8181038181111561011657610116614091565b60008060008060008060c087890312156140d357600080fd5b86516140de81613ebb565b60208801519096506140ef81613ebb565b94506140fd60408801613fd7565b935061410b60608801613fd7565b9250608087015161411b81613ebb565b60a088015190925063ffffffff8116811461413557600080fd5b809150509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561418157835163ffffffff168352928401929184019160010161415f565b50909695505050505050565b600082601f83011261419e57600080fd5b815160206141ae613c4f83613c0a565b8083825260208201915060208460051b8701019350868411156141d057600080fd5b602086015b84811015613b8f5780516141e881613ebb565b83529183019183016141d5565b6000806040838503121561420857600080fd5b825167ffffffffffffffff8082111561422057600080fd5b818501915085601f83011261423457600080fd5b81516020614244613c4f83613c0a565b82815260059290921b8401810191818101908984111561426357600080fd5b948201945b838610156142915785518060060b81146142825760008081fd5b82529482019490820190614268565b918801519196509093505050808211156142aa57600080fd5b506142b78582860161418d565b9150509250929050565b600682810b9082900b03667fffffffffffff198112667fffffffffffff8213171561011657610116614091565b634e487b7160e01b600052601260045260246000fd5b60008160060b8360060b8061431b5761431b6142ee565b667fffffffffffff1982146000198214161561433957614339614091565b90059392505050565b600082614351576143516142ee565b500790565b60008160020b627fffff19810361436f5761436f614091565b6000190192915050565b600181815b808511156143b457816000190482111561439a5761439a614091565b808516156143a757918102915b93841c939080029061437e565b509250929050565b6000826143cb57506001610116565b816143d857506000610116565b81600181146143ee57600281146143f857614414565b6001915050610116565b60ff84111561440957614409614091565b50506001821b610116565b5060208310610133831016604e8410600b8410161715614437575081810a610116565b6144418383614379565b806000190482111561445557614455614091565b029392505050565b60006102b460ff8416836143bc565b818103600083128015838313168383128216171561448c5761448c614091565b5092915050565b6000600160ff1b82016144a8576144a8614091565b5060000390565b8051801515811461200457600080fd5b6000806000606084860312156144d457600080fd5b83516144df81613ebb565b6020850151909350915061401e604085016144af565b60006080828403121561450757600080fd5b61450f613bb0565b82518060070b811461452057600080fd5b8152602083015167ffffffffffffffff8116811461453d57600080fd5b60208201526040830151600381900b811461455757600080fd5b60408201526060928301519281019290925250919050565b808201828112600083128015821682158216171561458f5761458f614091565b505092915050565b6000806000606084860312156145ac57600080fd5b83516145b781613ebb565b602085015160409095015190969495509392505050565b60ff8416815267ffffffffffffffff831660208201526060604082015260006145fa6060830184613df6565b95945050505050565b6001600160a01b03831681526040602082018190526000906102ce90830184613af5565b60006020828403121561463957600080fd5b5051919050565b60008261464f5761464f6142ee565b600160ff1b82146000198414161561466957614669614091565b500590565b6146788185613abd565b60606020820152600061468e6060830185613af5565b8281036040840152610f4f8185613df6565b601f8211156146e8576000816000526020600020601f850160051c810160208610156146c95750805b601f850160051c820191505b8181101561325c578281556001016146d5565b505050565b815167ffffffffffffffff81111561470757614707613b9a565b61471b816147158454613dc2565b846146a0565b602080601f83116001811461475057600084156147385750858301515b600019600386901b1c1916600185901b17855561325c565b600085815260208120601f198616915b8281101561477f57888601518255948401946001909101908401614760565b508582101561479d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8082018082111561011657610116614091565b6000826147cf576147cf6142ee565b500490565b6000826147e3576147e36142ee565b500690565b80820260008212600160ff1b8414161561480457614804614091565b818105831482151761011657610116614091565b600069ffffffffffffffffffff82168061436f5761436f614091565b60006001820161484657614846614091565b5060010190565b60006102b483836143bc565b808202811582820484141761011657610116614091565b60006020828403121561488257600080fd5b6102b4826144af565b60006020828403121561489d57600080fd5b6102b482613fd7565b60006001600160ff1b01820161484657614846614091565b6000600160ff1b82016148d3576148d3614091565b506000190190565b60008160020b627fffff1981036148f4576148f4614091565b60000392915050565b6000825161490f818460208701613ad1565b919091019291505056fea264697066735822122074f32fef384fdc296b0859f1c1f941c8e736c6cb972aa9e2b894956ebd6a80b364736f6c63430008160033","storage":{}},"0x83a0444b93927c3afcbe46e522280390f748e171":{"nonce":1,"balance":"0x0","code":"0x6080604052366100135761001161001d565b005b61001b61001d565b005b6000610027610093565b90503660008037600080366000845af43d6000803e806000811461004a573d6000f35b3d6000fd5b600080823b905060008111915050919050565b6000806040516020016100749061017a565b6040516020818303038152906040528051906020012090508091505090565b600061009d6100c6565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000806040516020016100d89061020c565b6040516020818303038152906040528051906020012090508091505090565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b60006101646023836100f7565b915061016f82610108565b604082019050919050565b6000602082019050818103600083015261019381610157565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b60006101f66021836100f7565b91506102018261019a565b604082019050919050565b60006020820190508181036000830152610225816101e9565b905091905056fea2646970667358221220800da1f73cebd5e4afa07496d9bca6b6c4f526bdd3f4014ec15c70fe3a1c441364736f6c63430008110033","storage":{"0x5a648c35a2f5512218b4683cf10e03f5b7c9dc7346e1bf77d304ae97f60f592b":"0x108f53faf774d7c4c56f5bce9ca6e605ce8aeadd","0x5c7865864a2a990d80b5bb5c40e7b73a029960dc711fbb56120dfab976e92ea3":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266"}},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xc67e2bd3108604cf0168c0e5ef9cd6d78b9bb14b":{"nonce":1,"balance":"0x21e19c6edb7e2445f20","code":"0x","storage":{}},"0xeb045d78d273107348b0300c01d29b7552d622ab":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"nonce":1,"balance":"0x21e19e08b86820a43ea","code":"0x","storage":{}}},"best_block_number":"0x5","blocks":[{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0xcd346446ed010523161f40a5f2b512def549bfb79e165b4354488738416481f2","transactionsRoot":"0xb3a4689832e0b599260ae70362ffcf224b60571b35ff8836904a3d81e2675d66","receiptsRoot":"0x2d13fdc120ab90536fed583939de7fb68b64926a306c1f629593ca9c2c93b198","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x3ea90d","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x2e0b6260","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gas":"0x3ea90d","maxFeePerGas":"0x83215600","maxPriorityFeePerGas":"0x3b9aca00","value":"0x0","accessList":[],"input":"0x608060405234801561001057600080fd5b5061494f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80632a952b2d1461005c57806350c946fe14610085578063625ca21c146100a5578063daa250be146100c6578063deba1b98146100d9575b600080fd5b61006f61006a366004613a63565b6100ec565b60405161007c9190613a7c565b60405180910390f35b610098610093366004613a63565b61011c565b60405161007c9190613b21565b6100b86100b3366004613c92565b610276565b60405190815260200161007c565b61006f6100d4366004613d5f565b6102bb565b6100b86100e7366004613c92565b6102d6565b6100f46139e4565b6040805160008082526020820190815281830190925261011691849190610310565b92915050565b6101416040805160608101909152806000815260200160608152602001606081525090565b61014a82610ab6565b60408051606081019091528154909190829060ff16600981111561017057610170613aa7565b600981111561018157610181613aa7565b815260200160018201805461019590613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546101c190613dc2565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561026657602002820191906000526020600020905b815481526020019060010190808311610252575b5050505050815250509050919050565b600080604051806060016040528086600981111561029657610296613aa7565b81526020018581526020018481525090506102b081610ac1565b9150505b9392505050565b6102c36139e4565b6102ce848484610310565b949350505050565b60008060405180606001604052808660098111156102f6576102f6613aa7565b81526020018581526020018481525090506102b081610acc565b6103186139e4565b81518351146103a05760408051634bab873760e11b81526004810191909152600d60448201526c72756e74696d6556616c75657360981b606482015260806024820152602260848201527f6d7573742062652073616d65206c656e6774682061732072756e74696d654b6560a482015261797360f01b60c482015260e4015b60405180910390fd5b60006103ab85610c26565b805490915060ff1660018160098111156103c7576103c7613aa7565b036104755761046c6103da838787610c84565b8360010180546103e990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461041590613dc2565b80156104625780601f1061043757610100808354040283529160200191610462565b820191906000526020600020905b81548152906001019060200180831161044557829003601f168201915b5050505050610d46565b925050506102b4565b600281600981111561048957610489613aa7565b036105305761046c61049c838787610c84565b8360010180546104ab90613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546104d790613dc2565b80156105245780601f106104f957610100808354040283529160200191610524565b820191906000526020600020905b81548152906001019060200180831161050757829003601f168201915b50505050508787610ebb565b600381600981111561054457610544613aa7565b036105de5761046c82600101805461055b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461058790613dc2565b80156105d45780601f106105a9576101008083540402835291602001916105d4565b820191906000526020600020905b8154815290600101906020018083116105b757829003601f168201915b5050505050610f59565b60048160098111156105f2576105f2613aa7565b0361068c5761046c82600101805461060990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461063590613dc2565b80156106825780601f1061065757610100808354040283529160200191610682565b820191906000526020600020905b81548152906001019060200180831161066557829003601f168201915b5050505050611087565b60058160098111156106a0576106a0613aa7565b0361073a5761046c8260010180546106b790613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546106e390613dc2565b80156107305780601f1061070557610100808354040283529160200191610730565b820191906000526020600020905b81548152906001019060200180831161071357829003601f168201915b505050505061131e565b600981600981111561074e5761074e613aa7565b036107ea5761046c82600101805461076590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461079190613dc2565b80156107de5780601f106107b3576101008083540402835291602001916107de565b820191906000526020600020905b8154815290600101906020018083116107c157829003601f168201915b505050505086866114b5565b60068160098111156107fe576107fe613aa7565b036108a35761046c610811838787610c84565b83600101805461082090613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461084c90613dc2565b80156108995780601f1061086e57610100808354040283529160200191610899565b820191906000526020600020905b81548152906001019060200180831161087c57829003601f168201915b50505050506115c7565b60078160098111156108b7576108b7613aa7565b036109ec576040805160608101909152825461046c91908490829060ff1660098111156108e6576108e6613aa7565b60098111156108f7576108f7613aa7565b815260200160018201805461090b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461093790613dc2565b80156109845780601f1061095957610100808354040283529160200191610984565b820191906000526020600020905b81548152906001019060200180831161096757829003601f168201915b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156109dc57602002820191906000526020600020905b8154815260200190600101908083116109c8575b5050505050815250508686611728565b6008816009811115610a0057610a00613aa7565b03610a9a5761046c826001018054610a1790613dc2565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4390613dc2565b8015610a905780601f10610a6557610100808354040283529160200191610a90565b820191906000526020600020905b815481529060010190602001808311610a7357829003601f168201915b50505050506118a5565b6040516323a9bbc960e01b815260048101879052602401610397565b600061011682610c26565b6000610116826118ea565b6000610ad782610ac1565b9050610ae28161192a565b15610b35577fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e81836000015184602001518560400151604051610b289493929190613e32565b60405180910390a1919050565b610b3e82611a8c565b610b5d578160405163382bbbc960e11b81526004016103979190613b21565b60005b826040015151811015610bd957610b9383604001518281518110610b8657610b86613e6a565b602002602001015161192a565b610bd15782604001518181518110610bad57610bad613e6a565b6020026020010151604051632f19f96160e11b815260040161039791815260200190565b600101610b60565b50610be382611c31565b8351602085015160408087015190519395507fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e9450610b28938693929190613e32565b604080516020808201839052606082018190527f696f2e73796e7468657469782e6f7261636c652d6d616e616765722e4e6f6465608080840191909152828401949094528251808303909401845260a0909101909152815191012090565b600283015460609067ffffffffffffffff811115610ca457610ca4613b9a565b604051908082528060200260200182016040528015610cdd57816020015b610cca6139e4565b815260200190600190039081610cc25790505b50905060005b6002850154811015610d3e57610d19856002018281548110610d0757610d07613e6a565b90600052602060002001548585610310565b828281518110610d2b57610d2b613e6a565b6020908102919091010152600101610ce3565b509392505050565b610d4e6139e4565b600082806020019051810190610d649190613e80565b90506000816008811115610d7a57610d7a613aa7565b03610d9057610d8884611ca5565b915050610116565b6001816008811115610da457610da4613aa7565b03610db257610d8884611d0d565b6002816008811115610dc657610dc6613aa7565b03610dd457610d8884611d90565b6003816008811115610de857610de8613aa7565b03610df657610d8884611e13565b6004816008811115610e0a57610e0a613aa7565b03610e1857610d8884611ec9565b6005816008811115610e2c57610e2c613aa7565b03610e3a57610d8884612009565b6006816008811115610e4e57610e4e613aa7565b03610e5c57610d88846120e4565b6007816008811115610e7057610e70613aa7565b03610e7e57610d888461220c565b6008816008811115610e9257610e92613aa7565b03610ea057610d88846122ce565b80604051631be413d360e11b81526004016103979190613ea1565b610ec36139e4565b600084806020019051810190610ed99190613ed3565b604051631ecba7c360e31b81529091506001600160a01b0382169063f65d3e1890610f0e908990899089908990600401613ef0565b608060405180830381865afa158015610f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4f9190613f91565b9695505050505050565b610f616139e4565b600080600084806020019051810190610f7a9190613fe8565b92509250925060008390506000806000836001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fec9190614041565b509350509250925060008660001461100f5761100a8585858a6123c7565b611011565b825b905060128660ff161161103b5761103661102f60ff881660126140a7565b82906124c2565b611053565b61105361104c601260ff89166140a7565b82906124dc565b9050604051806080016040528082815260200183815260200160008152602001600081525098505050505050505050919050565b61108f6139e4565b600080600080600080878060200190518101906110ac91906140ba565b604080516002808252606082018352979d50959b50939950919750955093506000929060208301908036833701905050905081816000815181106110f2576110f2613e6a565b602002602001019063ffffffff16908163ffffffff168152505060008160018151811061112157611121613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526000906001600160a01b0385169063883bdbfd90611165908590600401614143565b600060405180830381865afa158015611182573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111aa91908101906141f5565b5090506000816000815181106111c2576111c2613e6a565b6020026020010151826001815181106111dd576111dd613e6a565b60200260200101516111ef91906142c1565b9050600061121761120563ffffffff87166124f6565b61120f9084614304565b60060b61252d565b905060008260060b12801561124c575061123b63ffffffff8616612569565b612569565b8260060b6112499190614342565b15155b1561125f578061125b81614356565b9150505b600061126d6012600a61445d565b9050600061128061123684848f8f612593565b905060006112908a60ff16612569565b61129c8c60ff16612569565b6112a6919061446c565b905060008082136112d1576112cc6112c56112c084614493565b612686565b84906124dc565b6112e4565b6112e46112dd83612686565b84906124c2565b905060405180608001604052808281526020014281526020016000815260200160008152509e505050505050505050505050505050919050565b6113266139e4565b60008060008480602001905181019061133f91906144bf565b91945092509050826000826113bc576040516396834ad360e01b8152600481018590526001600160a01b038316906396834ad390602401608060405180830381865afa158015611393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b791906144f5565b611425565b604051639474f45b60e01b8152600481018590526001600160a01b03831690639474f45b90602401608060405180830381865afa158015611401573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142591906144f5565b90506000816040015160030b601261143d919061456f565b90506000808213611467576114626114576112c084614493565b845160070b906124dc565b61147e565b61147e61147383612686565b845160070b906124c2565b9050604051806080016040528082815260200184606001518152602001600081526020016000815250975050505050505050919050565b6114bd6139e4565b6000806000868060200190518101906114d69190614597565b92509250925060005b8651811015611545578681815181106114fa576114fa613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b0361153d5785818151811061152f5761152f613e6a565b602002602001015160001c91505b6001016114df565b5060408051600180825281830190925260009160208083019080368337019050509050828160008151811061157c5761157c613e6a565b602002602001018181525050836001838360405160200161159f939291906145ce565b60408051601f198184030181529082905263cf2cabdf60e01b82526103979291600401614603565b6115cf6139e4565b6000828060200190518101906115e59190614627565b90506000846000815181106115fc576115fc613e6a565b602002602001015160000151905060008560018151811061161f5761161f613e6a565b6020026020010151600001519050808214611702576000611653601261164d611648858761446c565b6126a9565b906124c2565b905082158061167b5750611666836126a9565b6116709082614640565b61167985612569565b125b15611700576002875111156116b0578660028151811061169d5761169d613e6a565b6020026020010151945050505050610116565b826000036116d15760405163014cc07160e01b815260040160405180910390fd5b6116da836126a9565b6116e49082614640565b60405163dcac091960e01b815260040161039791815260200190565b505b8560008151811061171557611715613e6a565b6020026020010151935050505092915050565b6117306139e4565b6000846020015180602001905181019061174a9190614627565b905060005b84518110156117bc5784818151811061176a5761176a613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b036117b4576117ad8482815181106117a2576117a2613e6a565b602002602001015190565b91506117bc565b60010161174f565b50600085604001516000815181106117d6576117d6613e6a565b6020026020010151905060006117ed828787610310565b60208101519091506117ff84426140a7565b1161180e5792506102b4915050565b86604001515160010361187157866040015160008151811061183257611832613e6a565b602002602001015181600001518260200151604051631808066560e21b8152600401610397939291909283526020830191909152604082015260600190565b61189a876040015160018151811061188b5761188b613e6a565b60200260200101518787610310565b979650505050505050565b6118ad6139e4565b6040518060800160405280838060200190518101906118cc9190614627565b81526020014281526020016000815260200160008152509050919050565b600081600001518260200151836040015160405160200161190d9392919061466e565b604051602081830303815290604052805190602001209050919050565b60008061193683610c26565b60408051606081019091528154909190829060ff16600981111561195c5761195c613aa7565b600981111561196d5761196d613aa7565b815260200160018201805461198190613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546119ad90613dc2565b80156119fa5780601f106119cf576101008083540402835291602001916119fa565b820191906000526020600020905b8154815290600101906020018083116119dd57829003601f168201915b5050505050815260200160028201805480602002602001604051908101604052809291908181526020018280548015611a5257602002820191906000526020600020905b815481526020019060010190808311611a3e575b505050505081525050905060006009811115611a7057611a70613aa7565b81516009811115611a8357611a83613aa7565b14159392505050565b6000600182516009811115611aa357611aa3613aa7565b1480611ac15750600682516009811115611abf57611abf613aa7565b145b80611ade5750600782516009811115611adc57611adc613aa7565b145b15611aee57611aec826126c1565b505b600182516009811115611b0357611b03613aa7565b03611b11576101168261284a565b600282516009811115611b2657611b26613aa7565b03611b3457610116826128a5565b600382516009811115611b4957611b49613aa7565b03611b575761011682612973565b600482516009811115611b6c57611b6c613aa7565b03611b7a5761011682612aae565b600582516009811115611b8f57611b8f613aa7565b03611b9d5761011682612e92565b600982516009811115611bb257611bb2613aa7565b03611bc05761011682612fcb565b600682516009811115611bd557611bd5613aa7565b03611be3576101168261300e565b600782516009811115611bf857611bf8613aa7565b03611c065761011682613052565b600882516009811115611c1b57611c1b613aa7565b03611c295761011682613078565b506000919050565b600080611c3d836118ea565b9050611c4881610c26565b8351815491935090839060ff19166001836009811115611c6a57611c6a613aa7565b021790555060208301516001830190611c8390826146ed565b5060408301518051611c9f916002850191602090910190613a0c565b50915091565b611cad6139e4565b60005b8251811015611d07578160200151838281518110611cd057611cd0613e6a565b6020026020010151602001511115611cff57828181518110611cf457611cf4613e6a565b602002602001015191505b600101611cb0565b50919050565b611d156139e4565b81600081518110611d2857611d28613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611d5957611d59613e6a565b6020026020010151600001511215611d8857828181518110611d7d57611d7d613e6a565b602002602001015191505b600101611d39565b611d986139e4565b81600081518110611dab57611dab613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611ddc57611ddc613e6a565b6020026020010151600001511315611e0b57828181518110611e0057611e00613e6a565b602002602001015191505b600101611dbc565b611e1b6139e4565b60005b8251811015611e9557828181518110611e3957611e39613e6a565b60200260200101516000015182600001818151611e56919061456f565b9052508251839082908110611e6d57611e6d613e6a565b60200260200101516020015182602001818151611e8a91906147ad565b905250600101611e1e565b50611ea08251612569565b8151611eac9190614640565b815281516020820151611ebf91906147c0565b6020820152919050565b611ed16139e4565b611eed826000611ee86001865161123691906140a7565b6130a4565b60028251611efb91906147d4565b600003611fd65760408051600280825260608201909252600091816020015b611f226139e4565b815260200190600190039081611f1a57905050905082600160028551611f4891906147c0565b611f5291906140a7565b81518110611f6257611f62613e6a565b602002602001015181600081518110611f7d57611f7d613e6a565b60200260200101819052508260028451611f9791906147c0565b81518110611fa757611fa7613e6a565b602002602001015181600181518110611fc257611fc2613e6a565b60200260200101819052506102b481611e13565b8160028351611fe591906147c0565b81518110611ff557611ff5613e6a565b60200260200101519050919050565b919050565b6120116139e4565b8160008151811061202457612024613e6a565b60209081029190910101515181528151829060009061204557612045613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061207657612076613e6a565b6020026020010151600001518260000181815161209391906147e8565b90525082518390829081106120aa576120aa613e6a565b602002602001015160200151826020018181516120c791906147ad565b90525060010161205b565b5081518160200151611ebf91906147c0565b6120ec6139e4565b816000815181106120ff576120ff613e6a565b60209081029190910101515181528151829060009061212057612120613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061215157612151613e6a565b60200260200101516000015160000361219e5782818151811061217657612176613e6a565b6020026020010151600001516040516338ee04a760e01b815260040161039791815260200190565b8281815181106121b0576121b0613e6a565b602002602001015160000151826000018181516121cd9190614640565b90525082518390829081106121e4576121e4613e6a565b6020026020010151602001518260200181815161220191906147ad565b905250600101612136565b6122146139e4565b8160008151811061222757612227613e6a565b60209081029190910101515181528151829060009061224857612248613e6a565b6020908102919091018101518101519082015260015b82518110156120d25761229083828151811061227c5761227c613e6a565b602090810291909101015151835190613264565b825282518390829081106122a6576122a6613e6a565b602002602001015160200151826020018181516122c391906147ad565b90525060010161225e565b6122d66139e4565b816000815181106122e9576122e9613e6a565b60209081029190910101515181528151829060009061230a5761230a613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061233b5761233b613e6a565b6020026020010151600001516000036123605782818151811061217657612176613e6a565b61238983828151811061237557612375613e6a565b602090810291909101015151835190613283565b8252825183908290811061239f5761239f613e6a565b602002602001015160200151826020018181516123bc91906147ad565b905250600101612320565b6000826001826123d785426140a7565b90505b69ffffffffffffffffffff8716156124a3576001600160a01b038816639a6fc8f561240489614818565b6040516001600160e01b031960e084901b16815269ffffffffffffffffffff8216600482015290995060240160a060405180830381865afa925050508015612469575060408051601f3d908101601f1916820190925261246691810190614041565b60015b156124a357858210156124805750505050506124a3565b61248a848961456f565b97508661249681614834565b97505050505050506123da565b6124ac82612569565b6124b69084614640565b98975050505050505050565b60006124d261123683600a61484d565b6102b490846147e8565b60006124ec61123683600a61484d565b6102b49084614640565b6000667fffffffffffff66ffffffffffffff83161115612529576040516329d2678160e21b815260040160405180910390fd5b5090565b6000627fffff19600683900b128061254b5750627fffff600683900b135b1561252957604051630d962f7960e21b815260040160405180910390fd5b60006001600160ff1b038211156125295760405163677c430560e11b815260040160405180910390fd5b60008061259f86613298565b90506fffffffffffffffffffffffffffffffff6001600160a01b0382161161261c5760006125d66001600160a01b03831680614859565b9050836001600160a01b0316856001600160a01b03161061260557612600600160c01b87836136cd565b612614565b6126148187600160c01b6136cd565b92505061267d565b600061263b6001600160a01b03831680680100000000000000006136cd565b9050836001600160a01b0316856001600160a01b03161061266a57612665600160801b87836136cd565b612679565b6126798187600160801b6136cd565b9250505b50949350505050565b6000808212156125295760405163029f024d60e31b815260040160405180910390fd5b600080821215612529576126bc82614493565b610116565b6000805b8260400151518110156128415760006126fa846040015183815181106126ed576126ed613e6a565b6020026020010151610ab6565b60408051606081019091528154909190829060ff16600981111561272057612720613aa7565b600981111561273157612731613aa7565b815260200160018201805461274590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461277190613dc2565b80156127be5780601f10612793576101008083540402835291602001916127be565b820191906000526020600020905b8154815290600101906020018083116127a157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561281657602002820191906000526020600020905b815481526020019060010190808311612802575b505050505081525050905061282a81611a8c565b612838575060009392505050565b506001016126c5565b50600192915050565b60006002826040015151101561286257506000919050565b81602001515160201461287757506000919050565b600082602001518060200190518101906128919190614627565b905060088111156128415750600092915050565b6000602082602001515110156128bd57506000919050565b600082602001518060200190518101906128d79190613ed3565b90506128ea816306e7ea3960e21b6138e2565b6128f75750600092915050565b604051633b70a5bf60e21b81526001600160a01b0382169063edc296fc90612923908690600401613b21565b6020604051808303816000875af1158015612942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129669190614870565b6128415750600092915050565b6040810151516000901561298957506000919050565b81602001515160601461299e57506000919050565b60008083602001518060200190518101906129b99190613fe8565b92505091506000829050806001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612a01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a259190614041565b5050505050806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8c919061488b565b60ff168260ff1614612aa357506000949350505050565b506001949350505050565b60408101515160009015612ac457506000919050565b81602001515160c014612ad957506000919050565b6000806000806000808760200151806020019051810190612afa91906140ba565b9550955095509550955095508360ff16866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6c919061488b565b60ff1614612b8257506000979650505050505050565b8260ff16856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612be8919061488b565b60ff1614612bfe57506000979650505050505050565b6000826001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c629190613ed3565b90506000836001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc89190613ed3565b9050876001600160a01b0316826001600160a01b0316148015612cfc5750866001600160a01b0316816001600160a01b0316145b158015612d385750866001600160a01b0316826001600160a01b0316148015612d365750876001600160a01b0316816001600160a01b0316145b155b15612d4d575060009998505050505050505050565b60128660ff161180612d62575060128560ff16115b15612d77575060009998505050505050505050565b8263ffffffff16600003612d95575060009998505050505050505050565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612dca57612dca613e6a565b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110612df957612df9613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526001600160a01b0386169063883bdbfd90612e3a908490600401614143565b600060405180830381865afa158015612e57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e7f91908101906141f5565b5060019c9b505050505050505050505050565b60408101515160009015612ea857506000919050565b816020015151606014612ebd57506000919050565b60008060008460200151806020019051810190612eda91906144bf565b919450925090508281612f55576040516396834ad360e01b8152600481018490526001600160a01b038216906396834ad390602401608060405180830381865afa158015612f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f5091906144f5565b612fbe565b604051639474f45b60e01b8152600481018490526001600160a01b03821690639474f45b90602401608060405180830381865afa158015612f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbe91906144f5565b5060019695505050505050565b60408101515160009015612fe157506000919050565b816020015151606014612ff657506000919050565b8160200151806020019051810190612aa39190614597565b60008160400151516002148061302957508160400151516003145b61303557506000919050565b81602001515160201461304a57506000919050565b506001919050565b600081604001515160011480613029575081604001515160021461303557506000919050565b6040810151516000901561308e57506000919050565b6020826020015151101561304a57506000919050565b81818082036130b4575050505050565b6000856130da60026130c6888861446c565b6130d09190614640565b6112c0908861456f565b815181106130ea576130ea613e6a565b60200260200101516000015190505b818313613236575b808661310c85612686565b8151811061311c5761311c613e6a565b60200260200101516000015112156131405782613138816148a6565b935050613101565b8561314a83612686565b8151811061315a5761315a613e6a565b60200260200101516000015181121561317f5781613177816148be565b925050613140565b818313613231578561319083612686565b815181106131a0576131a0613e6a565b6020026020010151866131b285612686565b815181106131c2576131c2613e6a565b6020026020010151876131d486612686565b815181106131e4576131e4613e6a565b60200260200101886131f586612686565b8151811061320557613205613e6a565b602002602001018290528290525050828061321f906148a6565b935050818061322d906148be565b9250505b6130f9565b81851215613249576132498686846130a4565b8383121561325c5761325c8684866130a4565b505050505050565b6000670de0b6b3a764000061327983856147e8565b6102b49190614640565b600081613279670de0b6b3a7640000856147e8565b60008060008360020b126132b8576132b3600284900b612686565b6132c8565b6132c86112c0600285900b614493565b90506132e36112c06132dd620d89e7196148db565b60020b90565b8111156133165760405162461bcd60e51b81526020600482015260016024820152601560fa1b6044820152606401610397565b60008160011660000361332d57600160801b61333f565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff169050600282161561337e576080613379826ffff97272373d413259a46990580e213a614859565b901c90505b60048216156133a85760806133a3826ffff2e50f5f656932ef12357cf3c7fdcc614859565b901c90505b60088216156133d25760806133cd826fffe5caca7e10e4e61c3624eaa0941cd0614859565b901c90505b60108216156133fc5760806133f7826fffcb9843d60f6159c9db58835c926644614859565b901c90505b6020821615613426576080613421826fff973b41fa98c081472e6896dfb254c0614859565b901c90505b604082161561345057608061344b826fff2ea16466c96a3843ec78b326b52861614859565b901c90505b608082161561347a576080613475826ffe5dee046a99a2a811c461f1969c3053614859565b901c90505b6101008216156134a55760806134a0826ffcbe86c7900a88aedcffc83b479aa3a4614859565b901c90505b6102008216156134d05760806134cb826ff987a7253ac413176f2b074cf7815e54614859565b901c90505b6104008216156134fb5760806134f6826ff3392b0822b70005940c7a398e4b70f3614859565b901c90505b610800821615613526576080613521826fe7159475a2c29b7443b29c7fa6e889d9614859565b901c90505b61100082161561355157608061354c826fd097f3bdfd2022b8845ad8f792aa5825614859565b901c90505b61200082161561357c576080613577826fa9f746462d870fdf8a65dc1f90e061e5614859565b901c90505b6140008216156135a75760806135a2826f70d869a156d2a1b890bb3df62baf32f7614859565b901c90505b6180008216156135d25760806135cd826f31be135f97d08fd981231505542fcfa6614859565b901c90505b620100008216156135fe5760806135f9826f09aa508b5b7a84e1c677de54f3e99bc9614859565b901c90505b62020000821615613629576080613624826e5d6af8dedb81196699c329225ee604614859565b901c90505b6204000082161561365357608061364e826d2216e584f5fa1ea926041bedfe98614859565b901c90505b6208000082161561367b576080613676826b048a170391f7dc42444e8fa2614859565b901c90505b60008460020b131561369657613693816000196147c0565b90505b6102ce6136a8640100000000836147d4565b156136b45760016136b7565b60005b6136c89060ff16602084901c6147ad565b6139ba565b6000808060001985870985870292508281108382030391505080600003613749576000841161373e5760405162461bcd60e51b815260206004820152601960248201527f48616e646c65206e6f6e2d6f766572666c6f77206361736573000000000000006044820152606401610397565b5082900490506102b4565b8084116137985760405162461bcd60e51b815260206004820152601960248201527f70726576656e74732064656e6f6d696e61746f72203d3d2030000000000000006044820152606401610397565b60008486880980840393811190920391905060006137d06137b887612569565b6137c188612569565b6137ca90614493565b16612686565b9586900495938490049360008190030460010190506137ef8184614859565b909317926000613800876003614859565b600218905061380f8188614859565b61381a9060026140a7565b6138249082614859565b90506138308188614859565b61383b9060026140a7565b6138459082614859565b90506138518188614859565b61385c9060026140a7565b6138669082614859565b90506138728188614859565b61387d9060026140a7565b6138879082614859565b90506138938188614859565b61389e9060026140a7565b6138a89082614859565b90506138b48188614859565b6138bf9060026140a7565b6138c99082614859565b90506138d58186614859565b9998505050505050505050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b1790529051600091829182916001600160a01b0387169161394391906148fd565b6000604051808303816000865af19150503d8060008114613980576040519150601f19603f3d011682016040523d82523d6000602084013e613985565b606091505b50915091508161399a57600092505050610116565b80516000036139ae57600092505050610116565b60200151949350505050565b60006001600160a01b038211156125295760405163dccde8ed60e01b815260040160405180910390fd5b6040518060800160405280600081526020016000815260200160008152602001600081525090565b828054828255906000526020600020908101928215613a47579160200282015b82811115613a47578251825591602001919060010190613a2c565b506125299291505b808211156125295760008155600101613a4f565b600060208284031215613a7557600080fd5b5035919050565b8151815260208083015190820152604080830151908201526060808301519082015260808101610116565b634e487b7160e01b600052602160045260246000fd5b600a8110613acd57613acd613aa7565b9052565b60005b83811015613aec578181015183820152602001613ad4565b50506000910152565b60008151808452613b0d816020860160208601613ad1565b601f01601f19169290920160200192915050565b60006020808352613b358184018551613abd565b8084015160606040850152613b4d6080850182613af5565b6040860151858203601f19016060870152805180835290840192506000918401905b80831015613b8f5783518252928401926001929092019190840190613b6f565b509695505050505050565b634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715613bd357613bd3613b9a565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613c0257613c02613b9a565b604052919050565b600067ffffffffffffffff821115613c2457613c24613b9a565b5060051b60200190565b600082601f830112613c3f57600080fd5b81356020613c54613c4f83613c0a565b613bd9565b8083825260208201915060208460051b870101935086841115613c7657600080fd5b602086015b84811015613b8f5780358352918301918301613c7b565b600080600060608486031215613ca757600080fd5b8335600a8110613cb657600080fd5b925060208481013567ffffffffffffffff80821115613cd457600080fd5b818701915087601f830112613ce857600080fd5b813581811115613cfa57613cfa613b9a565b613d0c601f8201601f19168501613bd9565b8181528985838601011115613d2057600080fd5b818585018683013760009181019094015291935060408601359180831115613d4757600080fd5b5050613d5586828701613c2e565b9150509250925092565b600080600060608486031215613d7457600080fd5b83359250602084013567ffffffffffffffff80821115613d9357600080fd5b613d9f87838801613c2e565b93506040860135915080821115613db557600080fd5b50613d5586828701613c2e565b600181811c90821680613dd657607f821691505b602082108103611d0757634e487b7160e01b600052602260045260246000fd5b60008151808452602080850194506020840160005b83811015613e2757815187529582019590820190600101613e0b565b509495945050505050565b848152613e426020820185613abd565b608060408201526000613e586080830185613af5565b828103606084015261189a8185613df6565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613e9257600080fd5b8151600981106102b457600080fd5b6020810160098310613eb557613eb5613aa7565b91905290565b6001600160a01b0381168114613ed057600080fd5b50565b600060208284031215613ee557600080fd5b81516102b481613ebb565b608080825285518282018190526000919060209060a0850190828a01855b82811015613f5257613f42848351805182526020810151602083015260408101516040830152606081015160608301525050565b9285019290840190600101613f0e565b5050508481036020860152613f678189613af5565b925050508281036040840152613f7d8186613df6565b9050828103606084015261189a8185613df6565b600060808284031215613fa357600080fd5b613fab613bb0565b825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b805160ff8116811461200457600080fd5b600080600060608486031215613ffd57600080fd5b835161400881613ebb565b6020850151909350915061401e60408501613fd7565b90509250925092565b805169ffffffffffffffffffff8116811461200457600080fd5b600080600080600060a0868803121561405957600080fd5b61406286614027565b945060208601519350604086015192506060860151915061408560808701614027565b90509295509295909350565b634e487b7160e01b600052601160045260246000fd5b8181038181111561011657610116614091565b60008060008060008060c087890312156140d357600080fd5b86516140de81613ebb565b60208801519096506140ef81613ebb565b94506140fd60408801613fd7565b935061410b60608801613fd7565b9250608087015161411b81613ebb565b60a088015190925063ffffffff8116811461413557600080fd5b809150509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561418157835163ffffffff168352928401929184019160010161415f565b50909695505050505050565b600082601f83011261419e57600080fd5b815160206141ae613c4f83613c0a565b8083825260208201915060208460051b8701019350868411156141d057600080fd5b602086015b84811015613b8f5780516141e881613ebb565b83529183019183016141d5565b6000806040838503121561420857600080fd5b825167ffffffffffffffff8082111561422057600080fd5b818501915085601f83011261423457600080fd5b81516020614244613c4f83613c0a565b82815260059290921b8401810191818101908984111561426357600080fd5b948201945b838610156142915785518060060b81146142825760008081fd5b82529482019490820190614268565b918801519196509093505050808211156142aa57600080fd5b506142b78582860161418d565b9150509250929050565b600682810b9082900b03667fffffffffffff198112667fffffffffffff8213171561011657610116614091565b634e487b7160e01b600052601260045260246000fd5b60008160060b8360060b8061431b5761431b6142ee565b667fffffffffffff1982146000198214161561433957614339614091565b90059392505050565b600082614351576143516142ee565b500790565b60008160020b627fffff19810361436f5761436f614091565b6000190192915050565b600181815b808511156143b457816000190482111561439a5761439a614091565b808516156143a757918102915b93841c939080029061437e565b509250929050565b6000826143cb57506001610116565b816143d857506000610116565b81600181146143ee57600281146143f857614414565b6001915050610116565b60ff84111561440957614409614091565b50506001821b610116565b5060208310610133831016604e8410600b8410161715614437575081810a610116565b6144418383614379565b806000190482111561445557614455614091565b029392505050565b60006102b460ff8416836143bc565b818103600083128015838313168383128216171561448c5761448c614091565b5092915050565b6000600160ff1b82016144a8576144a8614091565b5060000390565b8051801515811461200457600080fd5b6000806000606084860312156144d457600080fd5b83516144df81613ebb565b6020850151909350915061401e604085016144af565b60006080828403121561450757600080fd5b61450f613bb0565b82518060070b811461452057600080fd5b8152602083015167ffffffffffffffff8116811461453d57600080fd5b60208201526040830151600381900b811461455757600080fd5b60408201526060928301519281019290925250919050565b808201828112600083128015821682158216171561458f5761458f614091565b505092915050565b6000806000606084860312156145ac57600080fd5b83516145b781613ebb565b602085015160409095015190969495509392505050565b60ff8416815267ffffffffffffffff831660208201526060604082015260006145fa6060830184613df6565b95945050505050565b6001600160a01b03831681526040602082018190526000906102ce90830184613af5565b60006020828403121561463957600080fd5b5051919050565b60008261464f5761464f6142ee565b600160ff1b82146000198414161561466957614669614091565b500590565b6146788185613abd565b60606020820152600061468e6060830185613af5565b8281036040840152610f4f8185613df6565b601f8211156146e8576000816000526020600020601f850160051c810160208610156146c95750805b601f850160051c820191505b8181101561325c578281556001016146d5565b505050565b815167ffffffffffffffff81111561470757614707613b9a565b61471b816147158454613dc2565b846146a0565b602080601f83116001811461475057600084156147385750858301515b600019600386901b1c1916600185901b17855561325c565b600085815260208120601f198616915b8281101561477f57888601518255948401946001909101908401614760565b508582101561479d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8082018082111561011657610116614091565b6000826147cf576147cf6142ee565b500490565b6000826147e3576147e36142ee565b500690565b80820260008212600160ff1b8414161561480457614804614091565b818105831482151761011657610116614091565b600069ffffffffffffffffffff82168061436f5761436f614091565b60006001820161484657614846614091565b5060010190565b60006102b483836143bc565b808202811582820484141761011657610116614091565b60006020828403121561488257600080fd5b6102b4826144af565b60006020828403121561489d57600080fd5b6102b482613fd7565b60006001600160ff1b01820161484657614846614091565b6000600160ff1b82016148d3576148d3614091565b506000190190565b60008160020b627fffff1981036148f4576148f4614091565b60000392915050565b6000825161490f818460208701613ad1565b919091019291505056fea264697066735822122074f32fef384fdc296b0859f1c1f941c8e736c6cb972aa9e2b894956ebd6a80b364736f6c63430008160033","r":"0x1","s":"0x1","yParity":"0x0","hash":"0xbc73db80bf4b8784ba10a8910a0b7ef85f6846d102b41dd990969ea205335354"}}],"ommers":[]},{"header":{"parentHash":"0x026ae0c6ae91f186a9befa1ac8be30eea35e30e77de51a731085221e5cd39209","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0xb6003e7ba07a15a9e35f63daa484728ec4ceeded0c4d10ac1b04e9552d412b3c","transactionsRoot":"0x6e4969a136061ca7a390d12830d47a151585325a8d396819fb2b958ff85e9f8f","receiptsRoot":"0xc3e81df67d3e2a6c8345a954ef250cfcc41abcc2292a5aa263071124533fc9ad","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x3","gasLimit":"0x1c9c380","gasUsed":"0x3c0f6","timestamp":"0x66b200ce","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x18993a68","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gas":"0x3c0f6","maxFeePerGas":"0x5d4285cd","maxPriorityFeePerGas":"0x3b9aca00","value":"0x0","accessList":[],"input":"0x608060405234801561001057600080fd5b50610380806100206000396000f3fe6080604052600080357fffffffff0000000000000000000000000000000000000000000000000000000016905060008160e01c610251565b60006379ba509782101561015e5781631627540c811461009857632a952b2d81146100b457633659cfe681146100d0576350c946fe81146100ec576353a47bb781146101085763625ca21c81146101245763718fe928811461014057610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc91505b5061024c565b816379ba509781146101a657638da5cb5b81146101c25763aaf10f4281146101de5763c7f62cda81146101fa5763daa250be81146102165763deba1b9881146102325761024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b738138ef7cf908021d117e542120b7a39065016107915061024a565b738138ef7cf908021d117e542120b7a3906501610791505b505b919050565b61025a81610037565b915050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036102ce57816040517fc2a825f50000000000000000000000000000000000000000000000000000000081526004016102c5919061032f565b60405180910390fd5b3660008037600080366000845af43d6000803e80600081146102ef573d6000f35b3d6000fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610329816102f4565b82525050565b60006020820190506103446000830184610320565b9291505056fea264697066735822122017a4b7fdaaab3897a7b47abaed8d2ee92d558883d3bb2a8454f9601b2ab2c3db64736f6c63430008150033","r":"0x1","s":"0x1","yParity":"0x0","hash":"0x2476e039803622aeb040f924f04c493f559aed3d6c9372ab405cb33c8c695328"}}],"ommers":[]},{"header":{"parentHash":"0x3d22100ac0ee8d5cde334f7f926191a861b0648971ebc179547df28a0224c6d0","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x9511d4711e5c30a72b0bff38a261daa75dcc5ba8b772d970a5c742244b4c861b","transactionsRoot":"0xba5fff578d3d6c2cd63acbe9bca353eaa6fe22a5c408956eff49106e0a96c507","receiptsRoot":"0xbae111f01cb07677e3a8c5031546138407c01bc964d3493d732dc4edf47d36d3","logsBloom":"0x00000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000020000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000001000000000000000000000400000001000010000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x5","gasLimit":"0x1c9c380","gasUsed":"0xcae7","timestamp":"0x66b200cb","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x12e09c7a","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gas":"0xcc4d","maxFeePerGas":"0x557e5ec4","maxPriorityFeePerGas":"0x3b9aca00","to":"0x83a0444b93927c3afcbe46e522280390f748e171","value":"0x0","accessList":[],"input":"0x3659cfe6000000000000000000000000108f53faf774d7c4c56f5bce9ca6e605ce8aeadd","r":"0x1","s":"0x1","yParity":"0x0","hash":"0xf88e7b19ee347145c257e0cf7ac4ecc2bae83ca79d7edaa231e71d3213aeb151"}}],"ommers":[]},{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x9c8eaf493f8b4edce2ba1647343eadcc0989cf461e712c0a6253ff2ca1842bb7","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0xdd07c07470e1deff3749831f0f1ad8d4b6e35505e83b3c6ea14181716197cd8a","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x29aa352e71b139e83b397bdd3dcf9b65d74770edaf3a9624d0dbc4f96f868680","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200cb","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x24a1ab52","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x0","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200c9","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0xf6930be4847cac5017bbcbec2756eed19f36b4196526a98a88e311c296e3a9be","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x29aa352e71b139e83b397bdd3dcf9b65d74770edaf3a9624d0dbc4f96f868680","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200cc","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x200d75e8","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0xb6003e7ba07a15a9e35f63daa484728ec4ceeded0c4d10ac1b04e9552d412b3c","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x4","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x1592fbf9","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x149d41e3b89d8324cef3feff98ef308e97bafe8745cc8461c60172bc7d4c44ba","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x510f2275449c013534a25ad0b13c867caf720947b68bcbcd4863f7b172a5d023","transactionsRoot":"0x0b44110186e52ff0ceb6b0776ca2992c94144a4ed712eef65ea038260ef0fcc7","receiptsRoot":"0xc2823b8eb4730d9f2657137cc2ddc2c4f22ab68e0ab826236cf6a1551ca2b3a5","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0xe61f9","timestamp":"0x66b200cb","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x342770c0","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gas":"0xe94d1","maxFeePerGas":"0x83215600","maxPriorityFeePerGas":"0x3b9aca00","to":"0x4e59b44847b379578588920ca78fbf26c0b4956c","value":"0x0","accessList":[],"input":"0x4786e4342646b3ba97c1790b6cf5a55087a36240b22570f5d3a5d6bcc929d93b608060405234801561001057600080fd5b5060008061002661006d60201b61081b1760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610141565b60008060405160200161007f90610121565b6040516020818303038152906040528051906020012090508091505090565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b600061010b60238361009e565b9150610116826100af565b604082019050919050565b6000602082019050818103600083015261013a816100fe565b9050919050565b611000806101506000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c806379ba50971161005b57806379ba5097146100ed5780638da5cb5b146100f7578063aaf10f4214610115578063c7f62cda1461013357610088565b80631627540c1461008d5780633659cfe6146100a957806353a47bb7146100c5578063718fe928146100e3575b600080fd5b6100a760048036038101906100a29190610d25565b61014f565b005b6100c360048036038101906100be9190610d25565b6102d0565b005b6100cd6102e4565b6040516100da9190610d61565b60405180910390f35b6100eb610317565b005b6100f56103fe565b005b6100ff61058b565b60405161010c9190610d61565b60405180910390f35b61011d6105be565b60405161012a9190610d61565b60405180910390f35b61014d60048036038101906101489190610d25565b6105f1565b005b61015761084c565b600061016161081b565b9050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036101c9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610252576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22826040516102c49190610d61565b60405180910390a15050565b6102d861084c565b6102e1816108c5565b50565b60006102ee61081b565b60010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600061032161081b565b90503373ffffffffffffffffffffffffffffffffffffffff168160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146103b757336040517fa0e5a0d70000000000000000000000000000000000000000000000000000000081526004016103ae9190610d61565b60405180910390fd5b60008160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600061040861081b565b905060008160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146104a357336040517fa0e5a0d700000000000000000000000000000000000000000000000000000000815260040161049a9190610d61565b60405180910390fd5b7fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c8260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16826040516104f8929190610d7c565b60405180910390a1808260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008260010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b600061059561081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105c8610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105fb610b05565b905060018160000160146101000a81548160ff02191690831515021790555060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050828260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008373ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16633659cfe6846040516024016106cc9190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161071b9190610e16565b600060405180830381855af49150503d8060008114610756576040519150601f19603f3d011682016040523d82523d6000602084013e61075b565b606091505b505090508015806107c357508173ffffffffffffffffffffffffffffffffffffffff16610786610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b156107fa576040517fa1cfa5a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360000160146101000a81548160ff0219169083151502179055600080fd5b60008060405160200161082d90610eb0565b6040516020818303038152906040528051906020012090508091505090565b610854610b36565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108c357336040517f8e4a23d60000000000000000000000000000000000000000000000000000000081526004016108ba9190610d61565b60405180910390fd5b565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361092b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61093481610b69565b61097557806040517f8a8b41ec00000000000000000000000000000000000000000000000000000000815260040161096c9190610d61565b60405180910390fd5b600061097f610b05565b90508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610a0a576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000160149054906101000a900460ff16158015610a2e5750610a2d82610b7c565b5b15610a7057816040517f15504301000000000000000000000000000000000000000000000000000000008152600401610a679190610d61565b60405180910390fd5b818160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503073ffffffffffffffffffffffffffffffffffffffff167f5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c783604051610af99190610d61565b60405180910390a25050565b600080604051602001610b1790610f42565b6040516020818303038152906040528051906020012090508091505090565b6000610b4061081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080823b905060008111915050919050565b60008060003073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1663c7f62cda86604051602401610bc59190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610c149190610e16565b600060405180830381855af49150503d8060008114610c4f576040519150601f19603f3d011682016040523d82523d6000602084013e610c54565b606091505b509150915081158015610cb9575063a1cfa5a860e01b604051602001610c7a9190610faf565b6040516020818303038152906040528051906020012081604051602001610ca19190610e16565b60405160208183030381529060405280519060200120145b92505050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cf282610cc7565b9050919050565b610d0281610ce7565b8114610d0d57600080fd5b50565b600081359050610d1f81610cf9565b92915050565b600060208284031215610d3b57610d3a610cc2565b5b6000610d4984828501610d10565b91505092915050565b610d5b81610ce7565b82525050565b6000602082019050610d766000830184610d52565b92915050565b6000604082019050610d916000830185610d52565b610d9e6020830184610d52565b9392505050565b600081519050919050565b600081905092915050565b60005b83811015610dd9578082015181840152602081019050610dbe565b60008484015250505050565b6000610df082610da5565b610dfa8185610db0565b9350610e0a818560208601610dbb565b80840191505092915050565b6000610e228284610de5565b915081905092915050565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b6000610e9a602383610e2d565b9150610ea582610e3e565b604082019050919050565b60006020820190508181036000830152610ec981610e8d565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b6000610f2c602183610e2d565b9150610f3782610ed0565b604082019050919050565b60006020820190508181036000830152610f5b81610f1f565b9050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b610fa9610fa482610f62565b610f8e565b82525050565b6000610fbb8284610f98565b6004820191508190509291505056fea264697066735822122023a7c33d7b91dce35ffbcf8837693364ab22a3905d0fc00016833e5fac45ca2f64736f6c63430008110033","r":"0x1","s":"0x1","yParity":"0x0","hash":"0x4feae6769d748b4f0f7c9bf21d782236c88f13906789a3ec602961296e4c3e43"}}],"ommers":[]},{"header":{"parentHash":"0xb3535af5103fd1c2bbd6dc7ff23f0799037a6542c231ebcb85abd776560fa512","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x23d74fb99ff6e42cbb5c33f92b078e37be6af2b6092459b103ff7059a6517ebc","transactionsRoot":"0x9eab45eca206fe11c107ea985c7d02fcfa442836aea3e04ba11dc4df587d5aa6","receiptsRoot":"0xe25abcfa973db8c55f73292137c626430de130a382ad4466337fefb0f7c8fde0","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x3ce3f","timestamp":"0x66b200cd","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x1c0bc72b","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gas":"0x3d8a8","maxFeePerGas":"0x6211577c","maxPriorityFeePerGas":"0x3b9aca00","to":"0x4e59b44847b379578588920ca78fbf26c0b4956c","value":"0x0","accessList":[],"input":"0x4786e4342646b3ba97c1790b6cf5a55087a36240b22570f5d3a5d6bcc929d93b608060405234801561001057600080fd5b5060405161068538038061068583398181016040528101906100329190610275565b818181600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361009b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6100ae8161019d60201b61004f1760201c565b6100ef57806040517f8a8b41ec0000000000000000000000000000000000000000000000000000000081526004016100e691906102c4565b60405180910390fd5b806100fe6101b060201b60201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050806101536101e160201b6100621760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050610414565b600080823b905060008111915050919050565b6000806040516020016101c290610362565b6040516020818303038152906040528051906020012090508091505090565b6000806040516020016101f3906103f4565b6040516020818303038152906040528051906020012090508091505090565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061024282610217565b9050919050565b61025281610237565b811461025d57600080fd5b50565b60008151905061026f81610249565b92915050565b6000806040838503121561028c5761028b610212565b5b600061029a85828601610260565b92505060206102ab85828601610260565b9150509250929050565b6102be81610237565b82525050565b60006020820190506102d960008301846102b5565b92915050565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b600061034c6021836102df565b9150610357826102f0565b604082019050919050565b6000602082019050818103600083015261037b8161033f565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b60006103de6023836102df565b91506103e982610382565b604082019050919050565b6000602082019050818103600083015261040d816103d1565b9050919050565b610262806104236000396000f3fe6080604052366100135761001161001d565b005b61001b61001d565b005b6000610027610093565b90503660008037600080366000845af43d6000803e806000811461004a573d6000f35b3d6000fd5b600080823b905060008111915050919050565b6000806040516020016100749061017a565b6040516020818303038152906040528051906020012090508091505090565b600061009d6100c6565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000806040516020016100d89061020c565b6040516020818303038152906040528051906020012090508091505090565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b60006101646023836100f7565b915061016f82610108565b604082019050919050565b6000602082019050818103600083015261019381610157565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b60006101f66021836100f7565b91506102018261019a565b604082019050919050565b60006020820190508181036000830152610225816101e9565b905091905056fea2646970667358221220800da1f73cebd5e4afa07496d9bca6b6c4f526bdd3f4014ec15c70fe3a1c441364736f6c6343000811003300000000000000000000000047d08dad17ccb558b3ea74b1a0e73a9cc804a9dc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266","r":"0x1","s":"0x1","yParity":"0x0","hash":"0xb6794d5c7abed6f91d447e8efb72ef2580595a6d7c8dee57ba1dbb330970146a"}}],"ommers":[]},{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x510f2275449c013534a25ad0b13c867caf720947b68bcbcd4863f7b172a5d023","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x3","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x29dd5614","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]}]} \ No newline at end of file +{"block":{"number":5,"beneficiary":"0x0000000000000000000000000000000000000000","timestamp":1722941643,"gas_limit":30000000,"basefee":316710010,"difficulty":"0x0","prevrandao":"0xe7ef87fc7c2090741a6749a087e4ca8092cb4d07136008799e4ebeac3b69e34a","blob_excess_gas_and_price":{"excess_blob_gas":0,"blob_gasprice":1}},"accounts":{"0x0000000000000000000000000000000000000000":{"nonce":0,"balance":"0x1088aa62285a00","code":"0x","storage":{}},"0x108f53faf774d7c4c56f5bce9ca6e605ce8aeadd":{"nonce":1,"balance":"0x0","code":"0x6080604052600080357fffffffff0000000000000000000000000000000000000000000000000000000016905060008160e01c610251565b60006379ba509782101561015e5781631627540c811461009857632a952b2d81146100b457633659cfe681146100d0576350c946fe81146100ec576353a47bb781146101085763625ca21c81146101245763718fe928811461014057610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc91505b5061024c565b816379ba509781146101a657638da5cb5b81146101c25763aaf10f4281146101de5763c7f62cda81146101fa5763daa250be81146102165763deba1b9881146102325761024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b738138ef7cf908021d117e542120b7a39065016107915061024a565b738138ef7cf908021d117e542120b7a3906501610791505b505b919050565b61025a81610037565b915050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036102ce57816040517fc2a825f50000000000000000000000000000000000000000000000000000000081526004016102c5919061032f565b60405180910390fd5b3660008037600080366000845af43d6000803e80600081146102ef573d6000f35b3d6000fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610329816102f4565b82525050565b60006020820190506103446000830184610320565b9291505056fea264697066735822122017a4b7fdaaab3897a7b47abaed8d2ee92d558883d3bb2a8454f9601b2ab2c3db64736f6c63430008150033","storage":{}},"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x19ba1fac55eea44d12a01372a8eb0c2ebbf9ca21":{"nonce":1,"balance":"0x21e19df7c2963f0ac6b","code":"0x","storage":{}},"0x19c6ab860dbe2bc433574193a4409770a8748bf6":{"nonce":1,"balance":"0x21e19df8da6b7bdc410","code":"0x","storage":{}},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x40567ec443c1d1872af5155755ac3803cc3fe61e":{"nonce":1,"balance":"0x21e19da82562f921b40","code":"0x","storage":{}},"0x47d08dad17ccb558b3ea74b1a0e73a9cc804a9dc":{"nonce":1,"balance":"0x0","code":"0x608060405234801561001057600080fd5b50600436106100885760003560e01c806379ba50971161005b57806379ba5097146100ed5780638da5cb5b146100f7578063aaf10f4214610115578063c7f62cda1461013357610088565b80631627540c1461008d5780633659cfe6146100a957806353a47bb7146100c5578063718fe928146100e3575b600080fd5b6100a760048036038101906100a29190610d25565b61014f565b005b6100c360048036038101906100be9190610d25565b6102d0565b005b6100cd6102e4565b6040516100da9190610d61565b60405180910390f35b6100eb610317565b005b6100f56103fe565b005b6100ff61058b565b60405161010c9190610d61565b60405180910390f35b61011d6105be565b60405161012a9190610d61565b60405180910390f35b61014d60048036038101906101489190610d25565b6105f1565b005b61015761084c565b600061016161081b565b9050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036101c9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610252576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22826040516102c49190610d61565b60405180910390a15050565b6102d861084c565b6102e1816108c5565b50565b60006102ee61081b565b60010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600061032161081b565b90503373ffffffffffffffffffffffffffffffffffffffff168160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146103b757336040517fa0e5a0d70000000000000000000000000000000000000000000000000000000081526004016103ae9190610d61565b60405180910390fd5b60008160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600061040861081b565b905060008160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146104a357336040517fa0e5a0d700000000000000000000000000000000000000000000000000000000815260040161049a9190610d61565b60405180910390fd5b7fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c8260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16826040516104f8929190610d7c565b60405180910390a1808260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008260010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b600061059561081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105c8610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105fb610b05565b905060018160000160146101000a81548160ff02191690831515021790555060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050828260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008373ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16633659cfe6846040516024016106cc9190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161071b9190610e16565b600060405180830381855af49150503d8060008114610756576040519150601f19603f3d011682016040523d82523d6000602084013e61075b565b606091505b505090508015806107c357508173ffffffffffffffffffffffffffffffffffffffff16610786610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b156107fa576040517fa1cfa5a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360000160146101000a81548160ff0219169083151502179055600080fd5b60008060405160200161082d90610eb0565b6040516020818303038152906040528051906020012090508091505090565b610854610b36565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108c357336040517f8e4a23d60000000000000000000000000000000000000000000000000000000081526004016108ba9190610d61565b60405180910390fd5b565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361092b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61093481610b69565b61097557806040517f8a8b41ec00000000000000000000000000000000000000000000000000000000815260040161096c9190610d61565b60405180910390fd5b600061097f610b05565b90508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610a0a576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000160149054906101000a900460ff16158015610a2e5750610a2d82610b7c565b5b15610a7057816040517f15504301000000000000000000000000000000000000000000000000000000008152600401610a679190610d61565b60405180910390fd5b818160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503073ffffffffffffffffffffffffffffffffffffffff167f5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c783604051610af99190610d61565b60405180910390a25050565b600080604051602001610b1790610f42565b6040516020818303038152906040528051906020012090508091505090565b6000610b4061081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080823b905060008111915050919050565b60008060003073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1663c7f62cda86604051602401610bc59190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610c149190610e16565b600060405180830381855af49150503d8060008114610c4f576040519150601f19603f3d011682016040523d82523d6000602084013e610c54565b606091505b509150915081158015610cb9575063a1cfa5a860e01b604051602001610c7a9190610faf565b6040516020818303038152906040528051906020012081604051602001610ca19190610e16565b60405160208183030381529060405280519060200120145b92505050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cf282610cc7565b9050919050565b610d0281610ce7565b8114610d0d57600080fd5b50565b600081359050610d1f81610cf9565b92915050565b600060208284031215610d3b57610d3a610cc2565b5b6000610d4984828501610d10565b91505092915050565b610d5b81610ce7565b82525050565b6000602082019050610d766000830184610d52565b92915050565b6000604082019050610d916000830185610d52565b610d9e6020830184610d52565b9392505050565b600081519050919050565b600081905092915050565b60005b83811015610dd9578082015181840152602081019050610dbe565b60008484015250505050565b6000610df082610da5565b610dfa8185610db0565b9350610e0a818560208601610dbb565b80840191505092915050565b6000610e228284610de5565b915081905092915050565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b6000610e9a602383610e2d565b9150610ea582610e3e565b604082019050919050565b60006020820190508181036000830152610ec981610e8d565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b6000610f2c602183610e2d565b9150610f3782610ed0565b604082019050919050565b60006020820190508181036000830152610f5b81610f1f565b9050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b610fa9610fa482610f62565b610f8e565b82525050565b6000610fbb8284610f98565b6004820191508190509291505056fea264697066735822122023a7c33d7b91dce35ffbcf8837693364ab22a3905d0fc00016833e5fac45ca2f64736f6c63430008110033","storage":{"0x5c7865864a2a990d80b5bb5c40e7b73a029960dc711fbb56120dfab976e92ea3":"0x0"}},"0x4e59b44847b379578588920ca78fbf26c0b4956c":{"nonce":2,"balance":"0x0","code":"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3","storage":{}},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x8138ef7cf908021d117e542120b7a39065016107":{"nonce":1,"balance":"0x0","code":"0x608060405234801561001057600080fd5b50600436106100575760003560e01c80632a952b2d1461005c57806350c946fe14610085578063625ca21c146100a5578063daa250be146100c6578063deba1b98146100d9575b600080fd5b61006f61006a366004613a63565b6100ec565b60405161007c9190613a7c565b60405180910390f35b610098610093366004613a63565b61011c565b60405161007c9190613b21565b6100b86100b3366004613c92565b610276565b60405190815260200161007c565b61006f6100d4366004613d5f565b6102bb565b6100b86100e7366004613c92565b6102d6565b6100f46139e4565b6040805160008082526020820190815281830190925261011691849190610310565b92915050565b6101416040805160608101909152806000815260200160608152602001606081525090565b61014a82610ab6565b60408051606081019091528154909190829060ff16600981111561017057610170613aa7565b600981111561018157610181613aa7565b815260200160018201805461019590613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546101c190613dc2565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561026657602002820191906000526020600020905b815481526020019060010190808311610252575b5050505050815250509050919050565b600080604051806060016040528086600981111561029657610296613aa7565b81526020018581526020018481525090506102b081610ac1565b9150505b9392505050565b6102c36139e4565b6102ce848484610310565b949350505050565b60008060405180606001604052808660098111156102f6576102f6613aa7565b81526020018581526020018481525090506102b081610acc565b6103186139e4565b81518351146103a05760408051634bab873760e11b81526004810191909152600d60448201526c72756e74696d6556616c75657360981b606482015260806024820152602260848201527f6d7573742062652073616d65206c656e6774682061732072756e74696d654b6560a482015261797360f01b60c482015260e4015b60405180910390fd5b60006103ab85610c26565b805490915060ff1660018160098111156103c7576103c7613aa7565b036104755761046c6103da838787610c84565b8360010180546103e990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461041590613dc2565b80156104625780601f1061043757610100808354040283529160200191610462565b820191906000526020600020905b81548152906001019060200180831161044557829003601f168201915b5050505050610d46565b925050506102b4565b600281600981111561048957610489613aa7565b036105305761046c61049c838787610c84565b8360010180546104ab90613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546104d790613dc2565b80156105245780601f106104f957610100808354040283529160200191610524565b820191906000526020600020905b81548152906001019060200180831161050757829003601f168201915b50505050508787610ebb565b600381600981111561054457610544613aa7565b036105de5761046c82600101805461055b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461058790613dc2565b80156105d45780601f106105a9576101008083540402835291602001916105d4565b820191906000526020600020905b8154815290600101906020018083116105b757829003601f168201915b5050505050610f59565b60048160098111156105f2576105f2613aa7565b0361068c5761046c82600101805461060990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461063590613dc2565b80156106825780601f1061065757610100808354040283529160200191610682565b820191906000526020600020905b81548152906001019060200180831161066557829003601f168201915b5050505050611087565b60058160098111156106a0576106a0613aa7565b0361073a5761046c8260010180546106b790613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546106e390613dc2565b80156107305780601f1061070557610100808354040283529160200191610730565b820191906000526020600020905b81548152906001019060200180831161071357829003601f168201915b505050505061131e565b600981600981111561074e5761074e613aa7565b036107ea5761046c82600101805461076590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461079190613dc2565b80156107de5780601f106107b3576101008083540402835291602001916107de565b820191906000526020600020905b8154815290600101906020018083116107c157829003601f168201915b505050505086866114b5565b60068160098111156107fe576107fe613aa7565b036108a35761046c610811838787610c84565b83600101805461082090613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461084c90613dc2565b80156108995780601f1061086e57610100808354040283529160200191610899565b820191906000526020600020905b81548152906001019060200180831161087c57829003601f168201915b50505050506115c7565b60078160098111156108b7576108b7613aa7565b036109ec576040805160608101909152825461046c91908490829060ff1660098111156108e6576108e6613aa7565b60098111156108f7576108f7613aa7565b815260200160018201805461090b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461093790613dc2565b80156109845780601f1061095957610100808354040283529160200191610984565b820191906000526020600020905b81548152906001019060200180831161096757829003601f168201915b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156109dc57602002820191906000526020600020905b8154815260200190600101908083116109c8575b5050505050815250508686611728565b6008816009811115610a0057610a00613aa7565b03610a9a5761046c826001018054610a1790613dc2565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4390613dc2565b8015610a905780601f10610a6557610100808354040283529160200191610a90565b820191906000526020600020905b815481529060010190602001808311610a7357829003601f168201915b50505050506118a5565b6040516323a9bbc960e01b815260048101879052602401610397565b600061011682610c26565b6000610116826118ea565b6000610ad782610ac1565b9050610ae28161192a565b15610b35577fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e81836000015184602001518560400151604051610b289493929190613e32565b60405180910390a1919050565b610b3e82611a8c565b610b5d578160405163382bbbc960e11b81526004016103979190613b21565b60005b826040015151811015610bd957610b9383604001518281518110610b8657610b86613e6a565b602002602001015161192a565b610bd15782604001518181518110610bad57610bad613e6a565b6020026020010151604051632f19f96160e11b815260040161039791815260200190565b600101610b60565b50610be382611c31565b8351602085015160408087015190519395507fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e9450610b28938693929190613e32565b604080516020808201839052606082018190527f696f2e73796e7468657469782e6f7261636c652d6d616e616765722e4e6f6465608080840191909152828401949094528251808303909401845260a0909101909152815191012090565b600283015460609067ffffffffffffffff811115610ca457610ca4613b9a565b604051908082528060200260200182016040528015610cdd57816020015b610cca6139e4565b815260200190600190039081610cc25790505b50905060005b6002850154811015610d3e57610d19856002018281548110610d0757610d07613e6a565b90600052602060002001548585610310565b828281518110610d2b57610d2b613e6a565b6020908102919091010152600101610ce3565b509392505050565b610d4e6139e4565b600082806020019051810190610d649190613e80565b90506000816008811115610d7a57610d7a613aa7565b03610d9057610d8884611ca5565b915050610116565b6001816008811115610da457610da4613aa7565b03610db257610d8884611d0d565b6002816008811115610dc657610dc6613aa7565b03610dd457610d8884611d90565b6003816008811115610de857610de8613aa7565b03610df657610d8884611e13565b6004816008811115610e0a57610e0a613aa7565b03610e1857610d8884611ec9565b6005816008811115610e2c57610e2c613aa7565b03610e3a57610d8884612009565b6006816008811115610e4e57610e4e613aa7565b03610e5c57610d88846120e4565b6007816008811115610e7057610e70613aa7565b03610e7e57610d888461220c565b6008816008811115610e9257610e92613aa7565b03610ea057610d88846122ce565b80604051631be413d360e11b81526004016103979190613ea1565b610ec36139e4565b600084806020019051810190610ed99190613ed3565b604051631ecba7c360e31b81529091506001600160a01b0382169063f65d3e1890610f0e908990899089908990600401613ef0565b608060405180830381865afa158015610f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4f9190613f91565b9695505050505050565b610f616139e4565b600080600084806020019051810190610f7a9190613fe8565b92509250925060008390506000806000836001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fec9190614041565b509350509250925060008660001461100f5761100a8585858a6123c7565b611011565b825b905060128660ff161161103b5761103661102f60ff881660126140a7565b82906124c2565b611053565b61105361104c601260ff89166140a7565b82906124dc565b9050604051806080016040528082815260200183815260200160008152602001600081525098505050505050505050919050565b61108f6139e4565b600080600080600080878060200190518101906110ac91906140ba565b604080516002808252606082018352979d50959b50939950919750955093506000929060208301908036833701905050905081816000815181106110f2576110f2613e6a565b602002602001019063ffffffff16908163ffffffff168152505060008160018151811061112157611121613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526000906001600160a01b0385169063883bdbfd90611165908590600401614143565b600060405180830381865afa158015611182573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111aa91908101906141f5565b5090506000816000815181106111c2576111c2613e6a565b6020026020010151826001815181106111dd576111dd613e6a565b60200260200101516111ef91906142c1565b9050600061121761120563ffffffff87166124f6565b61120f9084614304565b60060b61252d565b905060008260060b12801561124c575061123b63ffffffff8616612569565b612569565b8260060b6112499190614342565b15155b1561125f578061125b81614356565b9150505b600061126d6012600a61445d565b9050600061128061123684848f8f612593565b905060006112908a60ff16612569565b61129c8c60ff16612569565b6112a6919061446c565b905060008082136112d1576112cc6112c56112c084614493565b612686565b84906124dc565b6112e4565b6112e46112dd83612686565b84906124c2565b905060405180608001604052808281526020014281526020016000815260200160008152509e505050505050505050505050505050919050565b6113266139e4565b60008060008480602001905181019061133f91906144bf565b91945092509050826000826113bc576040516396834ad360e01b8152600481018590526001600160a01b038316906396834ad390602401608060405180830381865afa158015611393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b791906144f5565b611425565b604051639474f45b60e01b8152600481018590526001600160a01b03831690639474f45b90602401608060405180830381865afa158015611401573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142591906144f5565b90506000816040015160030b601261143d919061456f565b90506000808213611467576114626114576112c084614493565b845160070b906124dc565b61147e565b61147e61147383612686565b845160070b906124c2565b9050604051806080016040528082815260200184606001518152602001600081526020016000815250975050505050505050919050565b6114bd6139e4565b6000806000868060200190518101906114d69190614597565b92509250925060005b8651811015611545578681815181106114fa576114fa613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b0361153d5785818151811061152f5761152f613e6a565b602002602001015160001c91505b6001016114df565b5060408051600180825281830190925260009160208083019080368337019050509050828160008151811061157c5761157c613e6a565b602002602001018181525050836001838360405160200161159f939291906145ce565b60408051601f198184030181529082905263cf2cabdf60e01b82526103979291600401614603565b6115cf6139e4565b6000828060200190518101906115e59190614627565b90506000846000815181106115fc576115fc613e6a565b602002602001015160000151905060008560018151811061161f5761161f613e6a565b6020026020010151600001519050808214611702576000611653601261164d611648858761446c565b6126a9565b906124c2565b905082158061167b5750611666836126a9565b6116709082614640565b61167985612569565b125b15611700576002875111156116b0578660028151811061169d5761169d613e6a565b6020026020010151945050505050610116565b826000036116d15760405163014cc07160e01b815260040160405180910390fd5b6116da836126a9565b6116e49082614640565b60405163dcac091960e01b815260040161039791815260200190565b505b8560008151811061171557611715613e6a565b6020026020010151935050505092915050565b6117306139e4565b6000846020015180602001905181019061174a9190614627565b905060005b84518110156117bc5784818151811061176a5761176a613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b036117b4576117ad8482815181106117a2576117a2613e6a565b602002602001015190565b91506117bc565b60010161174f565b50600085604001516000815181106117d6576117d6613e6a565b6020026020010151905060006117ed828787610310565b60208101519091506117ff84426140a7565b1161180e5792506102b4915050565b86604001515160010361187157866040015160008151811061183257611832613e6a565b602002602001015181600001518260200151604051631808066560e21b8152600401610397939291909283526020830191909152604082015260600190565b61189a876040015160018151811061188b5761188b613e6a565b60200260200101518787610310565b979650505050505050565b6118ad6139e4565b6040518060800160405280838060200190518101906118cc9190614627565b81526020014281526020016000815260200160008152509050919050565b600081600001518260200151836040015160405160200161190d9392919061466e565b604051602081830303815290604052805190602001209050919050565b60008061193683610c26565b60408051606081019091528154909190829060ff16600981111561195c5761195c613aa7565b600981111561196d5761196d613aa7565b815260200160018201805461198190613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546119ad90613dc2565b80156119fa5780601f106119cf576101008083540402835291602001916119fa565b820191906000526020600020905b8154815290600101906020018083116119dd57829003601f168201915b5050505050815260200160028201805480602002602001604051908101604052809291908181526020018280548015611a5257602002820191906000526020600020905b815481526020019060010190808311611a3e575b505050505081525050905060006009811115611a7057611a70613aa7565b81516009811115611a8357611a83613aa7565b14159392505050565b6000600182516009811115611aa357611aa3613aa7565b1480611ac15750600682516009811115611abf57611abf613aa7565b145b80611ade5750600782516009811115611adc57611adc613aa7565b145b15611aee57611aec826126c1565b505b600182516009811115611b0357611b03613aa7565b03611b11576101168261284a565b600282516009811115611b2657611b26613aa7565b03611b3457610116826128a5565b600382516009811115611b4957611b49613aa7565b03611b575761011682612973565b600482516009811115611b6c57611b6c613aa7565b03611b7a5761011682612aae565b600582516009811115611b8f57611b8f613aa7565b03611b9d5761011682612e92565b600982516009811115611bb257611bb2613aa7565b03611bc05761011682612fcb565b600682516009811115611bd557611bd5613aa7565b03611be3576101168261300e565b600782516009811115611bf857611bf8613aa7565b03611c065761011682613052565b600882516009811115611c1b57611c1b613aa7565b03611c295761011682613078565b506000919050565b600080611c3d836118ea565b9050611c4881610c26565b8351815491935090839060ff19166001836009811115611c6a57611c6a613aa7565b021790555060208301516001830190611c8390826146ed565b5060408301518051611c9f916002850191602090910190613a0c565b50915091565b611cad6139e4565b60005b8251811015611d07578160200151838281518110611cd057611cd0613e6a565b6020026020010151602001511115611cff57828181518110611cf457611cf4613e6a565b602002602001015191505b600101611cb0565b50919050565b611d156139e4565b81600081518110611d2857611d28613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611d5957611d59613e6a565b6020026020010151600001511215611d8857828181518110611d7d57611d7d613e6a565b602002602001015191505b600101611d39565b611d986139e4565b81600081518110611dab57611dab613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611ddc57611ddc613e6a565b6020026020010151600001511315611e0b57828181518110611e0057611e00613e6a565b602002602001015191505b600101611dbc565b611e1b6139e4565b60005b8251811015611e9557828181518110611e3957611e39613e6a565b60200260200101516000015182600001818151611e56919061456f565b9052508251839082908110611e6d57611e6d613e6a565b60200260200101516020015182602001818151611e8a91906147ad565b905250600101611e1e565b50611ea08251612569565b8151611eac9190614640565b815281516020820151611ebf91906147c0565b6020820152919050565b611ed16139e4565b611eed826000611ee86001865161123691906140a7565b6130a4565b60028251611efb91906147d4565b600003611fd65760408051600280825260608201909252600091816020015b611f226139e4565b815260200190600190039081611f1a57905050905082600160028551611f4891906147c0565b611f5291906140a7565b81518110611f6257611f62613e6a565b602002602001015181600081518110611f7d57611f7d613e6a565b60200260200101819052508260028451611f9791906147c0565b81518110611fa757611fa7613e6a565b602002602001015181600181518110611fc257611fc2613e6a565b60200260200101819052506102b481611e13565b8160028351611fe591906147c0565b81518110611ff557611ff5613e6a565b60200260200101519050919050565b919050565b6120116139e4565b8160008151811061202457612024613e6a565b60209081029190910101515181528151829060009061204557612045613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061207657612076613e6a565b6020026020010151600001518260000181815161209391906147e8565b90525082518390829081106120aa576120aa613e6a565b602002602001015160200151826020018181516120c791906147ad565b90525060010161205b565b5081518160200151611ebf91906147c0565b6120ec6139e4565b816000815181106120ff576120ff613e6a565b60209081029190910101515181528151829060009061212057612120613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061215157612151613e6a565b60200260200101516000015160000361219e5782818151811061217657612176613e6a565b6020026020010151600001516040516338ee04a760e01b815260040161039791815260200190565b8281815181106121b0576121b0613e6a565b602002602001015160000151826000018181516121cd9190614640565b90525082518390829081106121e4576121e4613e6a565b6020026020010151602001518260200181815161220191906147ad565b905250600101612136565b6122146139e4565b8160008151811061222757612227613e6a565b60209081029190910101515181528151829060009061224857612248613e6a565b6020908102919091018101518101519082015260015b82518110156120d25761229083828151811061227c5761227c613e6a565b602090810291909101015151835190613264565b825282518390829081106122a6576122a6613e6a565b602002602001015160200151826020018181516122c391906147ad565b90525060010161225e565b6122d66139e4565b816000815181106122e9576122e9613e6a565b60209081029190910101515181528151829060009061230a5761230a613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061233b5761233b613e6a565b6020026020010151600001516000036123605782818151811061217657612176613e6a565b61238983828151811061237557612375613e6a565b602090810291909101015151835190613283565b8252825183908290811061239f5761239f613e6a565b602002602001015160200151826020018181516123bc91906147ad565b905250600101612320565b6000826001826123d785426140a7565b90505b69ffffffffffffffffffff8716156124a3576001600160a01b038816639a6fc8f561240489614818565b6040516001600160e01b031960e084901b16815269ffffffffffffffffffff8216600482015290995060240160a060405180830381865afa925050508015612469575060408051601f3d908101601f1916820190925261246691810190614041565b60015b156124a357858210156124805750505050506124a3565b61248a848961456f565b97508661249681614834565b97505050505050506123da565b6124ac82612569565b6124b69084614640565b98975050505050505050565b60006124d261123683600a61484d565b6102b490846147e8565b60006124ec61123683600a61484d565b6102b49084614640565b6000667fffffffffffff66ffffffffffffff83161115612529576040516329d2678160e21b815260040160405180910390fd5b5090565b6000627fffff19600683900b128061254b5750627fffff600683900b135b1561252957604051630d962f7960e21b815260040160405180910390fd5b60006001600160ff1b038211156125295760405163677c430560e11b815260040160405180910390fd5b60008061259f86613298565b90506fffffffffffffffffffffffffffffffff6001600160a01b0382161161261c5760006125d66001600160a01b03831680614859565b9050836001600160a01b0316856001600160a01b03161061260557612600600160c01b87836136cd565b612614565b6126148187600160c01b6136cd565b92505061267d565b600061263b6001600160a01b03831680680100000000000000006136cd565b9050836001600160a01b0316856001600160a01b03161061266a57612665600160801b87836136cd565b612679565b6126798187600160801b6136cd565b9250505b50949350505050565b6000808212156125295760405163029f024d60e31b815260040160405180910390fd5b600080821215612529576126bc82614493565b610116565b6000805b8260400151518110156128415760006126fa846040015183815181106126ed576126ed613e6a565b6020026020010151610ab6565b60408051606081019091528154909190829060ff16600981111561272057612720613aa7565b600981111561273157612731613aa7565b815260200160018201805461274590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461277190613dc2565b80156127be5780601f10612793576101008083540402835291602001916127be565b820191906000526020600020905b8154815290600101906020018083116127a157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561281657602002820191906000526020600020905b815481526020019060010190808311612802575b505050505081525050905061282a81611a8c565b612838575060009392505050565b506001016126c5565b50600192915050565b60006002826040015151101561286257506000919050565b81602001515160201461287757506000919050565b600082602001518060200190518101906128919190614627565b905060088111156128415750600092915050565b6000602082602001515110156128bd57506000919050565b600082602001518060200190518101906128d79190613ed3565b90506128ea816306e7ea3960e21b6138e2565b6128f75750600092915050565b604051633b70a5bf60e21b81526001600160a01b0382169063edc296fc90612923908690600401613b21565b6020604051808303816000875af1158015612942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129669190614870565b6128415750600092915050565b6040810151516000901561298957506000919050565b81602001515160601461299e57506000919050565b60008083602001518060200190518101906129b99190613fe8565b92505091506000829050806001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612a01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a259190614041565b5050505050806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8c919061488b565b60ff168260ff1614612aa357506000949350505050565b506001949350505050565b60408101515160009015612ac457506000919050565b81602001515160c014612ad957506000919050565b6000806000806000808760200151806020019051810190612afa91906140ba565b9550955095509550955095508360ff16866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6c919061488b565b60ff1614612b8257506000979650505050505050565b8260ff16856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612be8919061488b565b60ff1614612bfe57506000979650505050505050565b6000826001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c629190613ed3565b90506000836001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc89190613ed3565b9050876001600160a01b0316826001600160a01b0316148015612cfc5750866001600160a01b0316816001600160a01b0316145b158015612d385750866001600160a01b0316826001600160a01b0316148015612d365750876001600160a01b0316816001600160a01b0316145b155b15612d4d575060009998505050505050505050565b60128660ff161180612d62575060128560ff16115b15612d77575060009998505050505050505050565b8263ffffffff16600003612d95575060009998505050505050505050565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612dca57612dca613e6a565b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110612df957612df9613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526001600160a01b0386169063883bdbfd90612e3a908490600401614143565b600060405180830381865afa158015612e57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e7f91908101906141f5565b5060019c9b505050505050505050505050565b60408101515160009015612ea857506000919050565b816020015151606014612ebd57506000919050565b60008060008460200151806020019051810190612eda91906144bf565b919450925090508281612f55576040516396834ad360e01b8152600481018490526001600160a01b038216906396834ad390602401608060405180830381865afa158015612f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f5091906144f5565b612fbe565b604051639474f45b60e01b8152600481018490526001600160a01b03821690639474f45b90602401608060405180830381865afa158015612f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbe91906144f5565b5060019695505050505050565b60408101515160009015612fe157506000919050565b816020015151606014612ff657506000919050565b8160200151806020019051810190612aa39190614597565b60008160400151516002148061302957508160400151516003145b61303557506000919050565b81602001515160201461304a57506000919050565b506001919050565b600081604001515160011480613029575081604001515160021461303557506000919050565b6040810151516000901561308e57506000919050565b6020826020015151101561304a57506000919050565b81818082036130b4575050505050565b6000856130da60026130c6888861446c565b6130d09190614640565b6112c0908861456f565b815181106130ea576130ea613e6a565b60200260200101516000015190505b818313613236575b808661310c85612686565b8151811061311c5761311c613e6a565b60200260200101516000015112156131405782613138816148a6565b935050613101565b8561314a83612686565b8151811061315a5761315a613e6a565b60200260200101516000015181121561317f5781613177816148be565b925050613140565b818313613231578561319083612686565b815181106131a0576131a0613e6a565b6020026020010151866131b285612686565b815181106131c2576131c2613e6a565b6020026020010151876131d486612686565b815181106131e4576131e4613e6a565b60200260200101886131f586612686565b8151811061320557613205613e6a565b602002602001018290528290525050828061321f906148a6565b935050818061322d906148be565b9250505b6130f9565b81851215613249576132498686846130a4565b8383121561325c5761325c8684866130a4565b505050505050565b6000670de0b6b3a764000061327983856147e8565b6102b49190614640565b600081613279670de0b6b3a7640000856147e8565b60008060008360020b126132b8576132b3600284900b612686565b6132c8565b6132c86112c0600285900b614493565b90506132e36112c06132dd620d89e7196148db565b60020b90565b8111156133165760405162461bcd60e51b81526020600482015260016024820152601560fa1b6044820152606401610397565b60008160011660000361332d57600160801b61333f565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff169050600282161561337e576080613379826ffff97272373d413259a46990580e213a614859565b901c90505b60048216156133a85760806133a3826ffff2e50f5f656932ef12357cf3c7fdcc614859565b901c90505b60088216156133d25760806133cd826fffe5caca7e10e4e61c3624eaa0941cd0614859565b901c90505b60108216156133fc5760806133f7826fffcb9843d60f6159c9db58835c926644614859565b901c90505b6020821615613426576080613421826fff973b41fa98c081472e6896dfb254c0614859565b901c90505b604082161561345057608061344b826fff2ea16466c96a3843ec78b326b52861614859565b901c90505b608082161561347a576080613475826ffe5dee046a99a2a811c461f1969c3053614859565b901c90505b6101008216156134a55760806134a0826ffcbe86c7900a88aedcffc83b479aa3a4614859565b901c90505b6102008216156134d05760806134cb826ff987a7253ac413176f2b074cf7815e54614859565b901c90505b6104008216156134fb5760806134f6826ff3392b0822b70005940c7a398e4b70f3614859565b901c90505b610800821615613526576080613521826fe7159475a2c29b7443b29c7fa6e889d9614859565b901c90505b61100082161561355157608061354c826fd097f3bdfd2022b8845ad8f792aa5825614859565b901c90505b61200082161561357c576080613577826fa9f746462d870fdf8a65dc1f90e061e5614859565b901c90505b6140008216156135a75760806135a2826f70d869a156d2a1b890bb3df62baf32f7614859565b901c90505b6180008216156135d25760806135cd826f31be135f97d08fd981231505542fcfa6614859565b901c90505b620100008216156135fe5760806135f9826f09aa508b5b7a84e1c677de54f3e99bc9614859565b901c90505b62020000821615613629576080613624826e5d6af8dedb81196699c329225ee604614859565b901c90505b6204000082161561365357608061364e826d2216e584f5fa1ea926041bedfe98614859565b901c90505b6208000082161561367b576080613676826b048a170391f7dc42444e8fa2614859565b901c90505b60008460020b131561369657613693816000196147c0565b90505b6102ce6136a8640100000000836147d4565b156136b45760016136b7565b60005b6136c89060ff16602084901c6147ad565b6139ba565b6000808060001985870985870292508281108382030391505080600003613749576000841161373e5760405162461bcd60e51b815260206004820152601960248201527f48616e646c65206e6f6e2d6f766572666c6f77206361736573000000000000006044820152606401610397565b5082900490506102b4565b8084116137985760405162461bcd60e51b815260206004820152601960248201527f70726576656e74732064656e6f6d696e61746f72203d3d2030000000000000006044820152606401610397565b60008486880980840393811190920391905060006137d06137b887612569565b6137c188612569565b6137ca90614493565b16612686565b9586900495938490049360008190030460010190506137ef8184614859565b909317926000613800876003614859565b600218905061380f8188614859565b61381a9060026140a7565b6138249082614859565b90506138308188614859565b61383b9060026140a7565b6138459082614859565b90506138518188614859565b61385c9060026140a7565b6138669082614859565b90506138728188614859565b61387d9060026140a7565b6138879082614859565b90506138938188614859565b61389e9060026140a7565b6138a89082614859565b90506138b48188614859565b6138bf9060026140a7565b6138c99082614859565b90506138d58186614859565b9998505050505050505050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b1790529051600091829182916001600160a01b0387169161394391906148fd565b6000604051808303816000865af19150503d8060008114613980576040519150601f19603f3d011682016040523d82523d6000602084013e613985565b606091505b50915091508161399a57600092505050610116565b80516000036139ae57600092505050610116565b60200151949350505050565b60006001600160a01b038211156125295760405163dccde8ed60e01b815260040160405180910390fd5b6040518060800160405280600081526020016000815260200160008152602001600081525090565b828054828255906000526020600020908101928215613a47579160200282015b82811115613a47578251825591602001919060010190613a2c565b506125299291505b808211156125295760008155600101613a4f565b600060208284031215613a7557600080fd5b5035919050565b8151815260208083015190820152604080830151908201526060808301519082015260808101610116565b634e487b7160e01b600052602160045260246000fd5b600a8110613acd57613acd613aa7565b9052565b60005b83811015613aec578181015183820152602001613ad4565b50506000910152565b60008151808452613b0d816020860160208601613ad1565b601f01601f19169290920160200192915050565b60006020808352613b358184018551613abd565b8084015160606040850152613b4d6080850182613af5565b6040860151858203601f19016060870152805180835290840192506000918401905b80831015613b8f5783518252928401926001929092019190840190613b6f565b509695505050505050565b634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715613bd357613bd3613b9a565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613c0257613c02613b9a565b604052919050565b600067ffffffffffffffff821115613c2457613c24613b9a565b5060051b60200190565b600082601f830112613c3f57600080fd5b81356020613c54613c4f83613c0a565b613bd9565b8083825260208201915060208460051b870101935086841115613c7657600080fd5b602086015b84811015613b8f5780358352918301918301613c7b565b600080600060608486031215613ca757600080fd5b8335600a8110613cb657600080fd5b925060208481013567ffffffffffffffff80821115613cd457600080fd5b818701915087601f830112613ce857600080fd5b813581811115613cfa57613cfa613b9a565b613d0c601f8201601f19168501613bd9565b8181528985838601011115613d2057600080fd5b818585018683013760009181019094015291935060408601359180831115613d4757600080fd5b5050613d5586828701613c2e565b9150509250925092565b600080600060608486031215613d7457600080fd5b83359250602084013567ffffffffffffffff80821115613d9357600080fd5b613d9f87838801613c2e565b93506040860135915080821115613db557600080fd5b50613d5586828701613c2e565b600181811c90821680613dd657607f821691505b602082108103611d0757634e487b7160e01b600052602260045260246000fd5b60008151808452602080850194506020840160005b83811015613e2757815187529582019590820190600101613e0b565b509495945050505050565b848152613e426020820185613abd565b608060408201526000613e586080830185613af5565b828103606084015261189a8185613df6565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613e9257600080fd5b8151600981106102b457600080fd5b6020810160098310613eb557613eb5613aa7565b91905290565b6001600160a01b0381168114613ed057600080fd5b50565b600060208284031215613ee557600080fd5b81516102b481613ebb565b608080825285518282018190526000919060209060a0850190828a01855b82811015613f5257613f42848351805182526020810151602083015260408101516040830152606081015160608301525050565b9285019290840190600101613f0e565b5050508481036020860152613f678189613af5565b925050508281036040840152613f7d8186613df6565b9050828103606084015261189a8185613df6565b600060808284031215613fa357600080fd5b613fab613bb0565b825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b805160ff8116811461200457600080fd5b600080600060608486031215613ffd57600080fd5b835161400881613ebb565b6020850151909350915061401e60408501613fd7565b90509250925092565b805169ffffffffffffffffffff8116811461200457600080fd5b600080600080600060a0868803121561405957600080fd5b61406286614027565b945060208601519350604086015192506060860151915061408560808701614027565b90509295509295909350565b634e487b7160e01b600052601160045260246000fd5b8181038181111561011657610116614091565b60008060008060008060c087890312156140d357600080fd5b86516140de81613ebb565b60208801519096506140ef81613ebb565b94506140fd60408801613fd7565b935061410b60608801613fd7565b9250608087015161411b81613ebb565b60a088015190925063ffffffff8116811461413557600080fd5b809150509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561418157835163ffffffff168352928401929184019160010161415f565b50909695505050505050565b600082601f83011261419e57600080fd5b815160206141ae613c4f83613c0a565b8083825260208201915060208460051b8701019350868411156141d057600080fd5b602086015b84811015613b8f5780516141e881613ebb565b83529183019183016141d5565b6000806040838503121561420857600080fd5b825167ffffffffffffffff8082111561422057600080fd5b818501915085601f83011261423457600080fd5b81516020614244613c4f83613c0a565b82815260059290921b8401810191818101908984111561426357600080fd5b948201945b838610156142915785518060060b81146142825760008081fd5b82529482019490820190614268565b918801519196509093505050808211156142aa57600080fd5b506142b78582860161418d565b9150509250929050565b600682810b9082900b03667fffffffffffff198112667fffffffffffff8213171561011657610116614091565b634e487b7160e01b600052601260045260246000fd5b60008160060b8360060b8061431b5761431b6142ee565b667fffffffffffff1982146000198214161561433957614339614091565b90059392505050565b600082614351576143516142ee565b500790565b60008160020b627fffff19810361436f5761436f614091565b6000190192915050565b600181815b808511156143b457816000190482111561439a5761439a614091565b808516156143a757918102915b93841c939080029061437e565b509250929050565b6000826143cb57506001610116565b816143d857506000610116565b81600181146143ee57600281146143f857614414565b6001915050610116565b60ff84111561440957614409614091565b50506001821b610116565b5060208310610133831016604e8410600b8410161715614437575081810a610116565b6144418383614379565b806000190482111561445557614455614091565b029392505050565b60006102b460ff8416836143bc565b818103600083128015838313168383128216171561448c5761448c614091565b5092915050565b6000600160ff1b82016144a8576144a8614091565b5060000390565b8051801515811461200457600080fd5b6000806000606084860312156144d457600080fd5b83516144df81613ebb565b6020850151909350915061401e604085016144af565b60006080828403121561450757600080fd5b61450f613bb0565b82518060070b811461452057600080fd5b8152602083015167ffffffffffffffff8116811461453d57600080fd5b60208201526040830151600381900b811461455757600080fd5b60408201526060928301519281019290925250919050565b808201828112600083128015821682158216171561458f5761458f614091565b505092915050565b6000806000606084860312156145ac57600080fd5b83516145b781613ebb565b602085015160409095015190969495509392505050565b60ff8416815267ffffffffffffffff831660208201526060604082015260006145fa6060830184613df6565b95945050505050565b6001600160a01b03831681526040602082018190526000906102ce90830184613af5565b60006020828403121561463957600080fd5b5051919050565b60008261464f5761464f6142ee565b600160ff1b82146000198414161561466957614669614091565b500590565b6146788185613abd565b60606020820152600061468e6060830185613af5565b8281036040840152610f4f8185613df6565b601f8211156146e8576000816000526020600020601f850160051c810160208610156146c95750805b601f850160051c820191505b8181101561325c578281556001016146d5565b505050565b815167ffffffffffffffff81111561470757614707613b9a565b61471b816147158454613dc2565b846146a0565b602080601f83116001811461475057600084156147385750858301515b600019600386901b1c1916600185901b17855561325c565b600085815260208120601f198616915b8281101561477f57888601518255948401946001909101908401614760565b508582101561479d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8082018082111561011657610116614091565b6000826147cf576147cf6142ee565b500490565b6000826147e3576147e36142ee565b500690565b80820260008212600160ff1b8414161561480457614804614091565b818105831482151761011657610116614091565b600069ffffffffffffffffffff82168061436f5761436f614091565b60006001820161484657614846614091565b5060010190565b60006102b483836143bc565b808202811582820484141761011657610116614091565b60006020828403121561488257600080fd5b6102b4826144af565b60006020828403121561489d57600080fd5b6102b482613fd7565b60006001600160ff1b01820161484657614846614091565b6000600160ff1b82016148d3576148d3614091565b506000190190565b60008160020b627fffff1981036148f4576148f4614091565b60000392915050565b6000825161490f818460208701613ad1565b919091019291505056fea264697066735822122074f32fef384fdc296b0859f1c1f941c8e736c6cb972aa9e2b894956ebd6a80b364736f6c63430008160033","storage":{}},"0x83a0444b93927c3afcbe46e522280390f748e171":{"nonce":1,"balance":"0x0","code":"0x6080604052366100135761001161001d565b005b61001b61001d565b005b6000610027610093565b90503660008037600080366000845af43d6000803e806000811461004a573d6000f35b3d6000fd5b600080823b905060008111915050919050565b6000806040516020016100749061017a565b6040516020818303038152906040528051906020012090508091505090565b600061009d6100c6565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000806040516020016100d89061020c565b6040516020818303038152906040528051906020012090508091505090565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b60006101646023836100f7565b915061016f82610108565b604082019050919050565b6000602082019050818103600083015261019381610157565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b60006101f66021836100f7565b91506102018261019a565b604082019050919050565b60006020820190508181036000830152610225816101e9565b905091905056fea2646970667358221220800da1f73cebd5e4afa07496d9bca6b6c4f526bdd3f4014ec15c70fe3a1c441364736f6c63430008110033","storage":{"0x5a648c35a2f5512218b4683cf10e03f5b7c9dc7346e1bf77d304ae97f60f592b":"0x108f53faf774d7c4c56f5bce9ca6e605ce8aeadd","0x5c7865864a2a990d80b5bb5c40e7b73a029960dc711fbb56120dfab976e92ea3":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266"}},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xc67e2bd3108604cf0168c0e5ef9cd6d78b9bb14b":{"nonce":1,"balance":"0x21e19c6edb7e2445f20","code":"0x","storage":{}},"0xeb045d78d273107348b0300c01d29b7552d622ab":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"nonce":1,"balance":"0x21e19e08b86820a43ea","code":"0x","storage":{}}},"best_block_number":5,"blocks":[{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0xcd346446ed010523161f40a5f2b512def549bfb79e165b4354488738416481f2","transactionsRoot":"0xb3a4689832e0b599260ae70362ffcf224b60571b35ff8836904a3d81e2675d66","receiptsRoot":"0x2d13fdc120ab90536fed583939de7fb68b64926a306c1f629593ca9c2c93b198","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x3ea90d","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x2e0b6260","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gas":"0x3ea90d","maxFeePerGas":"0x83215600","maxPriorityFeePerGas":"0x3b9aca00","value":"0x0","accessList":[],"input":"0x608060405234801561001057600080fd5b5061494f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80632a952b2d1461005c57806350c946fe14610085578063625ca21c146100a5578063daa250be146100c6578063deba1b98146100d9575b600080fd5b61006f61006a366004613a63565b6100ec565b60405161007c9190613a7c565b60405180910390f35b610098610093366004613a63565b61011c565b60405161007c9190613b21565b6100b86100b3366004613c92565b610276565b60405190815260200161007c565b61006f6100d4366004613d5f565b6102bb565b6100b86100e7366004613c92565b6102d6565b6100f46139e4565b6040805160008082526020820190815281830190925261011691849190610310565b92915050565b6101416040805160608101909152806000815260200160608152602001606081525090565b61014a82610ab6565b60408051606081019091528154909190829060ff16600981111561017057610170613aa7565b600981111561018157610181613aa7565b815260200160018201805461019590613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546101c190613dc2565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561026657602002820191906000526020600020905b815481526020019060010190808311610252575b5050505050815250509050919050565b600080604051806060016040528086600981111561029657610296613aa7565b81526020018581526020018481525090506102b081610ac1565b9150505b9392505050565b6102c36139e4565b6102ce848484610310565b949350505050565b60008060405180606001604052808660098111156102f6576102f6613aa7565b81526020018581526020018481525090506102b081610acc565b6103186139e4565b81518351146103a05760408051634bab873760e11b81526004810191909152600d60448201526c72756e74696d6556616c75657360981b606482015260806024820152602260848201527f6d7573742062652073616d65206c656e6774682061732072756e74696d654b6560a482015261797360f01b60c482015260e4015b60405180910390fd5b60006103ab85610c26565b805490915060ff1660018160098111156103c7576103c7613aa7565b036104755761046c6103da838787610c84565b8360010180546103e990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461041590613dc2565b80156104625780601f1061043757610100808354040283529160200191610462565b820191906000526020600020905b81548152906001019060200180831161044557829003601f168201915b5050505050610d46565b925050506102b4565b600281600981111561048957610489613aa7565b036105305761046c61049c838787610c84565b8360010180546104ab90613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546104d790613dc2565b80156105245780601f106104f957610100808354040283529160200191610524565b820191906000526020600020905b81548152906001019060200180831161050757829003601f168201915b50505050508787610ebb565b600381600981111561054457610544613aa7565b036105de5761046c82600101805461055b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461058790613dc2565b80156105d45780601f106105a9576101008083540402835291602001916105d4565b820191906000526020600020905b8154815290600101906020018083116105b757829003601f168201915b5050505050610f59565b60048160098111156105f2576105f2613aa7565b0361068c5761046c82600101805461060990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461063590613dc2565b80156106825780601f1061065757610100808354040283529160200191610682565b820191906000526020600020905b81548152906001019060200180831161066557829003601f168201915b5050505050611087565b60058160098111156106a0576106a0613aa7565b0361073a5761046c8260010180546106b790613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546106e390613dc2565b80156107305780601f1061070557610100808354040283529160200191610730565b820191906000526020600020905b81548152906001019060200180831161071357829003601f168201915b505050505061131e565b600981600981111561074e5761074e613aa7565b036107ea5761046c82600101805461076590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461079190613dc2565b80156107de5780601f106107b3576101008083540402835291602001916107de565b820191906000526020600020905b8154815290600101906020018083116107c157829003601f168201915b505050505086866114b5565b60068160098111156107fe576107fe613aa7565b036108a35761046c610811838787610c84565b83600101805461082090613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461084c90613dc2565b80156108995780601f1061086e57610100808354040283529160200191610899565b820191906000526020600020905b81548152906001019060200180831161087c57829003601f168201915b50505050506115c7565b60078160098111156108b7576108b7613aa7565b036109ec576040805160608101909152825461046c91908490829060ff1660098111156108e6576108e6613aa7565b60098111156108f7576108f7613aa7565b815260200160018201805461090b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461093790613dc2565b80156109845780601f1061095957610100808354040283529160200191610984565b820191906000526020600020905b81548152906001019060200180831161096757829003601f168201915b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156109dc57602002820191906000526020600020905b8154815260200190600101908083116109c8575b5050505050815250508686611728565b6008816009811115610a0057610a00613aa7565b03610a9a5761046c826001018054610a1790613dc2565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4390613dc2565b8015610a905780601f10610a6557610100808354040283529160200191610a90565b820191906000526020600020905b815481529060010190602001808311610a7357829003601f168201915b50505050506118a5565b6040516323a9bbc960e01b815260048101879052602401610397565b600061011682610c26565b6000610116826118ea565b6000610ad782610ac1565b9050610ae28161192a565b15610b35577fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e81836000015184602001518560400151604051610b289493929190613e32565b60405180910390a1919050565b610b3e82611a8c565b610b5d578160405163382bbbc960e11b81526004016103979190613b21565b60005b826040015151811015610bd957610b9383604001518281518110610b8657610b86613e6a565b602002602001015161192a565b610bd15782604001518181518110610bad57610bad613e6a565b6020026020010151604051632f19f96160e11b815260040161039791815260200190565b600101610b60565b50610be382611c31565b8351602085015160408087015190519395507fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e9450610b28938693929190613e32565b604080516020808201839052606082018190527f696f2e73796e7468657469782e6f7261636c652d6d616e616765722e4e6f6465608080840191909152828401949094528251808303909401845260a0909101909152815191012090565b600283015460609067ffffffffffffffff811115610ca457610ca4613b9a565b604051908082528060200260200182016040528015610cdd57816020015b610cca6139e4565b815260200190600190039081610cc25790505b50905060005b6002850154811015610d3e57610d19856002018281548110610d0757610d07613e6a565b90600052602060002001548585610310565b828281518110610d2b57610d2b613e6a565b6020908102919091010152600101610ce3565b509392505050565b610d4e6139e4565b600082806020019051810190610d649190613e80565b90506000816008811115610d7a57610d7a613aa7565b03610d9057610d8884611ca5565b915050610116565b6001816008811115610da457610da4613aa7565b03610db257610d8884611d0d565b6002816008811115610dc657610dc6613aa7565b03610dd457610d8884611d90565b6003816008811115610de857610de8613aa7565b03610df657610d8884611e13565b6004816008811115610e0a57610e0a613aa7565b03610e1857610d8884611ec9565b6005816008811115610e2c57610e2c613aa7565b03610e3a57610d8884612009565b6006816008811115610e4e57610e4e613aa7565b03610e5c57610d88846120e4565b6007816008811115610e7057610e70613aa7565b03610e7e57610d888461220c565b6008816008811115610e9257610e92613aa7565b03610ea057610d88846122ce565b80604051631be413d360e11b81526004016103979190613ea1565b610ec36139e4565b600084806020019051810190610ed99190613ed3565b604051631ecba7c360e31b81529091506001600160a01b0382169063f65d3e1890610f0e908990899089908990600401613ef0565b608060405180830381865afa158015610f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4f9190613f91565b9695505050505050565b610f616139e4565b600080600084806020019051810190610f7a9190613fe8565b92509250925060008390506000806000836001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fec9190614041565b509350509250925060008660001461100f5761100a8585858a6123c7565b611011565b825b905060128660ff161161103b5761103661102f60ff881660126140a7565b82906124c2565b611053565b61105361104c601260ff89166140a7565b82906124dc565b9050604051806080016040528082815260200183815260200160008152602001600081525098505050505050505050919050565b61108f6139e4565b600080600080600080878060200190518101906110ac91906140ba565b604080516002808252606082018352979d50959b50939950919750955093506000929060208301908036833701905050905081816000815181106110f2576110f2613e6a565b602002602001019063ffffffff16908163ffffffff168152505060008160018151811061112157611121613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526000906001600160a01b0385169063883bdbfd90611165908590600401614143565b600060405180830381865afa158015611182573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111aa91908101906141f5565b5090506000816000815181106111c2576111c2613e6a565b6020026020010151826001815181106111dd576111dd613e6a565b60200260200101516111ef91906142c1565b9050600061121761120563ffffffff87166124f6565b61120f9084614304565b60060b61252d565b905060008260060b12801561124c575061123b63ffffffff8616612569565b612569565b8260060b6112499190614342565b15155b1561125f578061125b81614356565b9150505b600061126d6012600a61445d565b9050600061128061123684848f8f612593565b905060006112908a60ff16612569565b61129c8c60ff16612569565b6112a6919061446c565b905060008082136112d1576112cc6112c56112c084614493565b612686565b84906124dc565b6112e4565b6112e46112dd83612686565b84906124c2565b905060405180608001604052808281526020014281526020016000815260200160008152509e505050505050505050505050505050919050565b6113266139e4565b60008060008480602001905181019061133f91906144bf565b91945092509050826000826113bc576040516396834ad360e01b8152600481018590526001600160a01b038316906396834ad390602401608060405180830381865afa158015611393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b791906144f5565b611425565b604051639474f45b60e01b8152600481018590526001600160a01b03831690639474f45b90602401608060405180830381865afa158015611401573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142591906144f5565b90506000816040015160030b601261143d919061456f565b90506000808213611467576114626114576112c084614493565b845160070b906124dc565b61147e565b61147e61147383612686565b845160070b906124c2565b9050604051806080016040528082815260200184606001518152602001600081526020016000815250975050505050505050919050565b6114bd6139e4565b6000806000868060200190518101906114d69190614597565b92509250925060005b8651811015611545578681815181106114fa576114fa613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b0361153d5785818151811061152f5761152f613e6a565b602002602001015160001c91505b6001016114df565b5060408051600180825281830190925260009160208083019080368337019050509050828160008151811061157c5761157c613e6a565b602002602001018181525050836001838360405160200161159f939291906145ce565b60408051601f198184030181529082905263cf2cabdf60e01b82526103979291600401614603565b6115cf6139e4565b6000828060200190518101906115e59190614627565b90506000846000815181106115fc576115fc613e6a565b602002602001015160000151905060008560018151811061161f5761161f613e6a565b6020026020010151600001519050808214611702576000611653601261164d611648858761446c565b6126a9565b906124c2565b905082158061167b5750611666836126a9565b6116709082614640565b61167985612569565b125b15611700576002875111156116b0578660028151811061169d5761169d613e6a565b6020026020010151945050505050610116565b826000036116d15760405163014cc07160e01b815260040160405180910390fd5b6116da836126a9565b6116e49082614640565b60405163dcac091960e01b815260040161039791815260200190565b505b8560008151811061171557611715613e6a565b6020026020010151935050505092915050565b6117306139e4565b6000846020015180602001905181019061174a9190614627565b905060005b84518110156117bc5784818151811061176a5761176a613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b036117b4576117ad8482815181106117a2576117a2613e6a565b602002602001015190565b91506117bc565b60010161174f565b50600085604001516000815181106117d6576117d6613e6a565b6020026020010151905060006117ed828787610310565b60208101519091506117ff84426140a7565b1161180e5792506102b4915050565b86604001515160010361187157866040015160008151811061183257611832613e6a565b602002602001015181600001518260200151604051631808066560e21b8152600401610397939291909283526020830191909152604082015260600190565b61189a876040015160018151811061188b5761188b613e6a565b60200260200101518787610310565b979650505050505050565b6118ad6139e4565b6040518060800160405280838060200190518101906118cc9190614627565b81526020014281526020016000815260200160008152509050919050565b600081600001518260200151836040015160405160200161190d9392919061466e565b604051602081830303815290604052805190602001209050919050565b60008061193683610c26565b60408051606081019091528154909190829060ff16600981111561195c5761195c613aa7565b600981111561196d5761196d613aa7565b815260200160018201805461198190613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546119ad90613dc2565b80156119fa5780601f106119cf576101008083540402835291602001916119fa565b820191906000526020600020905b8154815290600101906020018083116119dd57829003601f168201915b5050505050815260200160028201805480602002602001604051908101604052809291908181526020018280548015611a5257602002820191906000526020600020905b815481526020019060010190808311611a3e575b505050505081525050905060006009811115611a7057611a70613aa7565b81516009811115611a8357611a83613aa7565b14159392505050565b6000600182516009811115611aa357611aa3613aa7565b1480611ac15750600682516009811115611abf57611abf613aa7565b145b80611ade5750600782516009811115611adc57611adc613aa7565b145b15611aee57611aec826126c1565b505b600182516009811115611b0357611b03613aa7565b03611b11576101168261284a565b600282516009811115611b2657611b26613aa7565b03611b3457610116826128a5565b600382516009811115611b4957611b49613aa7565b03611b575761011682612973565b600482516009811115611b6c57611b6c613aa7565b03611b7a5761011682612aae565b600582516009811115611b8f57611b8f613aa7565b03611b9d5761011682612e92565b600982516009811115611bb257611bb2613aa7565b03611bc05761011682612fcb565b600682516009811115611bd557611bd5613aa7565b03611be3576101168261300e565b600782516009811115611bf857611bf8613aa7565b03611c065761011682613052565b600882516009811115611c1b57611c1b613aa7565b03611c295761011682613078565b506000919050565b600080611c3d836118ea565b9050611c4881610c26565b8351815491935090839060ff19166001836009811115611c6a57611c6a613aa7565b021790555060208301516001830190611c8390826146ed565b5060408301518051611c9f916002850191602090910190613a0c565b50915091565b611cad6139e4565b60005b8251811015611d07578160200151838281518110611cd057611cd0613e6a565b6020026020010151602001511115611cff57828181518110611cf457611cf4613e6a565b602002602001015191505b600101611cb0565b50919050565b611d156139e4565b81600081518110611d2857611d28613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611d5957611d59613e6a565b6020026020010151600001511215611d8857828181518110611d7d57611d7d613e6a565b602002602001015191505b600101611d39565b611d986139e4565b81600081518110611dab57611dab613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611ddc57611ddc613e6a565b6020026020010151600001511315611e0b57828181518110611e0057611e00613e6a565b602002602001015191505b600101611dbc565b611e1b6139e4565b60005b8251811015611e9557828181518110611e3957611e39613e6a565b60200260200101516000015182600001818151611e56919061456f565b9052508251839082908110611e6d57611e6d613e6a565b60200260200101516020015182602001818151611e8a91906147ad565b905250600101611e1e565b50611ea08251612569565b8151611eac9190614640565b815281516020820151611ebf91906147c0565b6020820152919050565b611ed16139e4565b611eed826000611ee86001865161123691906140a7565b6130a4565b60028251611efb91906147d4565b600003611fd65760408051600280825260608201909252600091816020015b611f226139e4565b815260200190600190039081611f1a57905050905082600160028551611f4891906147c0565b611f5291906140a7565b81518110611f6257611f62613e6a565b602002602001015181600081518110611f7d57611f7d613e6a565b60200260200101819052508260028451611f9791906147c0565b81518110611fa757611fa7613e6a565b602002602001015181600181518110611fc257611fc2613e6a565b60200260200101819052506102b481611e13565b8160028351611fe591906147c0565b81518110611ff557611ff5613e6a565b60200260200101519050919050565b919050565b6120116139e4565b8160008151811061202457612024613e6a565b60209081029190910101515181528151829060009061204557612045613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061207657612076613e6a565b6020026020010151600001518260000181815161209391906147e8565b90525082518390829081106120aa576120aa613e6a565b602002602001015160200151826020018181516120c791906147ad565b90525060010161205b565b5081518160200151611ebf91906147c0565b6120ec6139e4565b816000815181106120ff576120ff613e6a565b60209081029190910101515181528151829060009061212057612120613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061215157612151613e6a565b60200260200101516000015160000361219e5782818151811061217657612176613e6a565b6020026020010151600001516040516338ee04a760e01b815260040161039791815260200190565b8281815181106121b0576121b0613e6a565b602002602001015160000151826000018181516121cd9190614640565b90525082518390829081106121e4576121e4613e6a565b6020026020010151602001518260200181815161220191906147ad565b905250600101612136565b6122146139e4565b8160008151811061222757612227613e6a565b60209081029190910101515181528151829060009061224857612248613e6a565b6020908102919091018101518101519082015260015b82518110156120d25761229083828151811061227c5761227c613e6a565b602090810291909101015151835190613264565b825282518390829081106122a6576122a6613e6a565b602002602001015160200151826020018181516122c391906147ad565b90525060010161225e565b6122d66139e4565b816000815181106122e9576122e9613e6a565b60209081029190910101515181528151829060009061230a5761230a613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061233b5761233b613e6a565b6020026020010151600001516000036123605782818151811061217657612176613e6a565b61238983828151811061237557612375613e6a565b602090810291909101015151835190613283565b8252825183908290811061239f5761239f613e6a565b602002602001015160200151826020018181516123bc91906147ad565b905250600101612320565b6000826001826123d785426140a7565b90505b69ffffffffffffffffffff8716156124a3576001600160a01b038816639a6fc8f561240489614818565b6040516001600160e01b031960e084901b16815269ffffffffffffffffffff8216600482015290995060240160a060405180830381865afa925050508015612469575060408051601f3d908101601f1916820190925261246691810190614041565b60015b156124a357858210156124805750505050506124a3565b61248a848961456f565b97508661249681614834565b97505050505050506123da565b6124ac82612569565b6124b69084614640565b98975050505050505050565b60006124d261123683600a61484d565b6102b490846147e8565b60006124ec61123683600a61484d565b6102b49084614640565b6000667fffffffffffff66ffffffffffffff83161115612529576040516329d2678160e21b815260040160405180910390fd5b5090565b6000627fffff19600683900b128061254b5750627fffff600683900b135b1561252957604051630d962f7960e21b815260040160405180910390fd5b60006001600160ff1b038211156125295760405163677c430560e11b815260040160405180910390fd5b60008061259f86613298565b90506fffffffffffffffffffffffffffffffff6001600160a01b0382161161261c5760006125d66001600160a01b03831680614859565b9050836001600160a01b0316856001600160a01b03161061260557612600600160c01b87836136cd565b612614565b6126148187600160c01b6136cd565b92505061267d565b600061263b6001600160a01b03831680680100000000000000006136cd565b9050836001600160a01b0316856001600160a01b03161061266a57612665600160801b87836136cd565b612679565b6126798187600160801b6136cd565b9250505b50949350505050565b6000808212156125295760405163029f024d60e31b815260040160405180910390fd5b600080821215612529576126bc82614493565b610116565b6000805b8260400151518110156128415760006126fa846040015183815181106126ed576126ed613e6a565b6020026020010151610ab6565b60408051606081019091528154909190829060ff16600981111561272057612720613aa7565b600981111561273157612731613aa7565b815260200160018201805461274590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461277190613dc2565b80156127be5780601f10612793576101008083540402835291602001916127be565b820191906000526020600020905b8154815290600101906020018083116127a157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561281657602002820191906000526020600020905b815481526020019060010190808311612802575b505050505081525050905061282a81611a8c565b612838575060009392505050565b506001016126c5565b50600192915050565b60006002826040015151101561286257506000919050565b81602001515160201461287757506000919050565b600082602001518060200190518101906128919190614627565b905060088111156128415750600092915050565b6000602082602001515110156128bd57506000919050565b600082602001518060200190518101906128d79190613ed3565b90506128ea816306e7ea3960e21b6138e2565b6128f75750600092915050565b604051633b70a5bf60e21b81526001600160a01b0382169063edc296fc90612923908690600401613b21565b6020604051808303816000875af1158015612942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129669190614870565b6128415750600092915050565b6040810151516000901561298957506000919050565b81602001515160601461299e57506000919050565b60008083602001518060200190518101906129b99190613fe8565b92505091506000829050806001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612a01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a259190614041565b5050505050806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8c919061488b565b60ff168260ff1614612aa357506000949350505050565b506001949350505050565b60408101515160009015612ac457506000919050565b81602001515160c014612ad957506000919050565b6000806000806000808760200151806020019051810190612afa91906140ba565b9550955095509550955095508360ff16866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6c919061488b565b60ff1614612b8257506000979650505050505050565b8260ff16856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612be8919061488b565b60ff1614612bfe57506000979650505050505050565b6000826001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c629190613ed3565b90506000836001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc89190613ed3565b9050876001600160a01b0316826001600160a01b0316148015612cfc5750866001600160a01b0316816001600160a01b0316145b158015612d385750866001600160a01b0316826001600160a01b0316148015612d365750876001600160a01b0316816001600160a01b0316145b155b15612d4d575060009998505050505050505050565b60128660ff161180612d62575060128560ff16115b15612d77575060009998505050505050505050565b8263ffffffff16600003612d95575060009998505050505050505050565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612dca57612dca613e6a565b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110612df957612df9613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526001600160a01b0386169063883bdbfd90612e3a908490600401614143565b600060405180830381865afa158015612e57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e7f91908101906141f5565b5060019c9b505050505050505050505050565b60408101515160009015612ea857506000919050565b816020015151606014612ebd57506000919050565b60008060008460200151806020019051810190612eda91906144bf565b919450925090508281612f55576040516396834ad360e01b8152600481018490526001600160a01b038216906396834ad390602401608060405180830381865afa158015612f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f5091906144f5565b612fbe565b604051639474f45b60e01b8152600481018490526001600160a01b03821690639474f45b90602401608060405180830381865afa158015612f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbe91906144f5565b5060019695505050505050565b60408101515160009015612fe157506000919050565b816020015151606014612ff657506000919050565b8160200151806020019051810190612aa39190614597565b60008160400151516002148061302957508160400151516003145b61303557506000919050565b81602001515160201461304a57506000919050565b506001919050565b600081604001515160011480613029575081604001515160021461303557506000919050565b6040810151516000901561308e57506000919050565b6020826020015151101561304a57506000919050565b81818082036130b4575050505050565b6000856130da60026130c6888861446c565b6130d09190614640565b6112c0908861456f565b815181106130ea576130ea613e6a565b60200260200101516000015190505b818313613236575b808661310c85612686565b8151811061311c5761311c613e6a565b60200260200101516000015112156131405782613138816148a6565b935050613101565b8561314a83612686565b8151811061315a5761315a613e6a565b60200260200101516000015181121561317f5781613177816148be565b925050613140565b818313613231578561319083612686565b815181106131a0576131a0613e6a565b6020026020010151866131b285612686565b815181106131c2576131c2613e6a565b6020026020010151876131d486612686565b815181106131e4576131e4613e6a565b60200260200101886131f586612686565b8151811061320557613205613e6a565b602002602001018290528290525050828061321f906148a6565b935050818061322d906148be565b9250505b6130f9565b81851215613249576132498686846130a4565b8383121561325c5761325c8684866130a4565b505050505050565b6000670de0b6b3a764000061327983856147e8565b6102b49190614640565b600081613279670de0b6b3a7640000856147e8565b60008060008360020b126132b8576132b3600284900b612686565b6132c8565b6132c86112c0600285900b614493565b90506132e36112c06132dd620d89e7196148db565b60020b90565b8111156133165760405162461bcd60e51b81526020600482015260016024820152601560fa1b6044820152606401610397565b60008160011660000361332d57600160801b61333f565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff169050600282161561337e576080613379826ffff97272373d413259a46990580e213a614859565b901c90505b60048216156133a85760806133a3826ffff2e50f5f656932ef12357cf3c7fdcc614859565b901c90505b60088216156133d25760806133cd826fffe5caca7e10e4e61c3624eaa0941cd0614859565b901c90505b60108216156133fc5760806133f7826fffcb9843d60f6159c9db58835c926644614859565b901c90505b6020821615613426576080613421826fff973b41fa98c081472e6896dfb254c0614859565b901c90505b604082161561345057608061344b826fff2ea16466c96a3843ec78b326b52861614859565b901c90505b608082161561347a576080613475826ffe5dee046a99a2a811c461f1969c3053614859565b901c90505b6101008216156134a55760806134a0826ffcbe86c7900a88aedcffc83b479aa3a4614859565b901c90505b6102008216156134d05760806134cb826ff987a7253ac413176f2b074cf7815e54614859565b901c90505b6104008216156134fb5760806134f6826ff3392b0822b70005940c7a398e4b70f3614859565b901c90505b610800821615613526576080613521826fe7159475a2c29b7443b29c7fa6e889d9614859565b901c90505b61100082161561355157608061354c826fd097f3bdfd2022b8845ad8f792aa5825614859565b901c90505b61200082161561357c576080613577826fa9f746462d870fdf8a65dc1f90e061e5614859565b901c90505b6140008216156135a75760806135a2826f70d869a156d2a1b890bb3df62baf32f7614859565b901c90505b6180008216156135d25760806135cd826f31be135f97d08fd981231505542fcfa6614859565b901c90505b620100008216156135fe5760806135f9826f09aa508b5b7a84e1c677de54f3e99bc9614859565b901c90505b62020000821615613629576080613624826e5d6af8dedb81196699c329225ee604614859565b901c90505b6204000082161561365357608061364e826d2216e584f5fa1ea926041bedfe98614859565b901c90505b6208000082161561367b576080613676826b048a170391f7dc42444e8fa2614859565b901c90505b60008460020b131561369657613693816000196147c0565b90505b6102ce6136a8640100000000836147d4565b156136b45760016136b7565b60005b6136c89060ff16602084901c6147ad565b6139ba565b6000808060001985870985870292508281108382030391505080600003613749576000841161373e5760405162461bcd60e51b815260206004820152601960248201527f48616e646c65206e6f6e2d6f766572666c6f77206361736573000000000000006044820152606401610397565b5082900490506102b4565b8084116137985760405162461bcd60e51b815260206004820152601960248201527f70726576656e74732064656e6f6d696e61746f72203d3d2030000000000000006044820152606401610397565b60008486880980840393811190920391905060006137d06137b887612569565b6137c188612569565b6137ca90614493565b16612686565b9586900495938490049360008190030460010190506137ef8184614859565b909317926000613800876003614859565b600218905061380f8188614859565b61381a9060026140a7565b6138249082614859565b90506138308188614859565b61383b9060026140a7565b6138459082614859565b90506138518188614859565b61385c9060026140a7565b6138669082614859565b90506138728188614859565b61387d9060026140a7565b6138879082614859565b90506138938188614859565b61389e9060026140a7565b6138a89082614859565b90506138b48188614859565b6138bf9060026140a7565b6138c99082614859565b90506138d58186614859565b9998505050505050505050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b1790529051600091829182916001600160a01b0387169161394391906148fd565b6000604051808303816000865af19150503d8060008114613980576040519150601f19603f3d011682016040523d82523d6000602084013e613985565b606091505b50915091508161399a57600092505050610116565b80516000036139ae57600092505050610116565b60200151949350505050565b60006001600160a01b038211156125295760405163dccde8ed60e01b815260040160405180910390fd5b6040518060800160405280600081526020016000815260200160008152602001600081525090565b828054828255906000526020600020908101928215613a47579160200282015b82811115613a47578251825591602001919060010190613a2c565b506125299291505b808211156125295760008155600101613a4f565b600060208284031215613a7557600080fd5b5035919050565b8151815260208083015190820152604080830151908201526060808301519082015260808101610116565b634e487b7160e01b600052602160045260246000fd5b600a8110613acd57613acd613aa7565b9052565b60005b83811015613aec578181015183820152602001613ad4565b50506000910152565b60008151808452613b0d816020860160208601613ad1565b601f01601f19169290920160200192915050565b60006020808352613b358184018551613abd565b8084015160606040850152613b4d6080850182613af5565b6040860151858203601f19016060870152805180835290840192506000918401905b80831015613b8f5783518252928401926001929092019190840190613b6f565b509695505050505050565b634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715613bd357613bd3613b9a565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613c0257613c02613b9a565b604052919050565b600067ffffffffffffffff821115613c2457613c24613b9a565b5060051b60200190565b600082601f830112613c3f57600080fd5b81356020613c54613c4f83613c0a565b613bd9565b8083825260208201915060208460051b870101935086841115613c7657600080fd5b602086015b84811015613b8f5780358352918301918301613c7b565b600080600060608486031215613ca757600080fd5b8335600a8110613cb657600080fd5b925060208481013567ffffffffffffffff80821115613cd457600080fd5b818701915087601f830112613ce857600080fd5b813581811115613cfa57613cfa613b9a565b613d0c601f8201601f19168501613bd9565b8181528985838601011115613d2057600080fd5b818585018683013760009181019094015291935060408601359180831115613d4757600080fd5b5050613d5586828701613c2e565b9150509250925092565b600080600060608486031215613d7457600080fd5b83359250602084013567ffffffffffffffff80821115613d9357600080fd5b613d9f87838801613c2e565b93506040860135915080821115613db557600080fd5b50613d5586828701613c2e565b600181811c90821680613dd657607f821691505b602082108103611d0757634e487b7160e01b600052602260045260246000fd5b60008151808452602080850194506020840160005b83811015613e2757815187529582019590820190600101613e0b565b509495945050505050565b848152613e426020820185613abd565b608060408201526000613e586080830185613af5565b828103606084015261189a8185613df6565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613e9257600080fd5b8151600981106102b457600080fd5b6020810160098310613eb557613eb5613aa7565b91905290565b6001600160a01b0381168114613ed057600080fd5b50565b600060208284031215613ee557600080fd5b81516102b481613ebb565b608080825285518282018190526000919060209060a0850190828a01855b82811015613f5257613f42848351805182526020810151602083015260408101516040830152606081015160608301525050565b9285019290840190600101613f0e565b5050508481036020860152613f678189613af5565b925050508281036040840152613f7d8186613df6565b9050828103606084015261189a8185613df6565b600060808284031215613fa357600080fd5b613fab613bb0565b825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b805160ff8116811461200457600080fd5b600080600060608486031215613ffd57600080fd5b835161400881613ebb565b6020850151909350915061401e60408501613fd7565b90509250925092565b805169ffffffffffffffffffff8116811461200457600080fd5b600080600080600060a0868803121561405957600080fd5b61406286614027565b945060208601519350604086015192506060860151915061408560808701614027565b90509295509295909350565b634e487b7160e01b600052601160045260246000fd5b8181038181111561011657610116614091565b60008060008060008060c087890312156140d357600080fd5b86516140de81613ebb565b60208801519096506140ef81613ebb565b94506140fd60408801613fd7565b935061410b60608801613fd7565b9250608087015161411b81613ebb565b60a088015190925063ffffffff8116811461413557600080fd5b809150509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561418157835163ffffffff168352928401929184019160010161415f565b50909695505050505050565b600082601f83011261419e57600080fd5b815160206141ae613c4f83613c0a565b8083825260208201915060208460051b8701019350868411156141d057600080fd5b602086015b84811015613b8f5780516141e881613ebb565b83529183019183016141d5565b6000806040838503121561420857600080fd5b825167ffffffffffffffff8082111561422057600080fd5b818501915085601f83011261423457600080fd5b81516020614244613c4f83613c0a565b82815260059290921b8401810191818101908984111561426357600080fd5b948201945b838610156142915785518060060b81146142825760008081fd5b82529482019490820190614268565b918801519196509093505050808211156142aa57600080fd5b506142b78582860161418d565b9150509250929050565b600682810b9082900b03667fffffffffffff198112667fffffffffffff8213171561011657610116614091565b634e487b7160e01b600052601260045260246000fd5b60008160060b8360060b8061431b5761431b6142ee565b667fffffffffffff1982146000198214161561433957614339614091565b90059392505050565b600082614351576143516142ee565b500790565b60008160020b627fffff19810361436f5761436f614091565b6000190192915050565b600181815b808511156143b457816000190482111561439a5761439a614091565b808516156143a757918102915b93841c939080029061437e565b509250929050565b6000826143cb57506001610116565b816143d857506000610116565b81600181146143ee57600281146143f857614414565b6001915050610116565b60ff84111561440957614409614091565b50506001821b610116565b5060208310610133831016604e8410600b8410161715614437575081810a610116565b6144418383614379565b806000190482111561445557614455614091565b029392505050565b60006102b460ff8416836143bc565b818103600083128015838313168383128216171561448c5761448c614091565b5092915050565b6000600160ff1b82016144a8576144a8614091565b5060000390565b8051801515811461200457600080fd5b6000806000606084860312156144d457600080fd5b83516144df81613ebb565b6020850151909350915061401e604085016144af565b60006080828403121561450757600080fd5b61450f613bb0565b82518060070b811461452057600080fd5b8152602083015167ffffffffffffffff8116811461453d57600080fd5b60208201526040830151600381900b811461455757600080fd5b60408201526060928301519281019290925250919050565b808201828112600083128015821682158216171561458f5761458f614091565b505092915050565b6000806000606084860312156145ac57600080fd5b83516145b781613ebb565b602085015160409095015190969495509392505050565b60ff8416815267ffffffffffffffff831660208201526060604082015260006145fa6060830184613df6565b95945050505050565b6001600160a01b03831681526040602082018190526000906102ce90830184613af5565b60006020828403121561463957600080fd5b5051919050565b60008261464f5761464f6142ee565b600160ff1b82146000198414161561466957614669614091565b500590565b6146788185613abd565b60606020820152600061468e6060830185613af5565b8281036040840152610f4f8185613df6565b601f8211156146e8576000816000526020600020601f850160051c810160208610156146c95750805b601f850160051c820191505b8181101561325c578281556001016146d5565b505050565b815167ffffffffffffffff81111561470757614707613b9a565b61471b816147158454613dc2565b846146a0565b602080601f83116001811461475057600084156147385750858301515b600019600386901b1c1916600185901b17855561325c565b600085815260208120601f198616915b8281101561477f57888601518255948401946001909101908401614760565b508582101561479d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8082018082111561011657610116614091565b6000826147cf576147cf6142ee565b500490565b6000826147e3576147e36142ee565b500690565b80820260008212600160ff1b8414161561480457614804614091565b818105831482151761011657610116614091565b600069ffffffffffffffffffff82168061436f5761436f614091565b60006001820161484657614846614091565b5060010190565b60006102b483836143bc565b808202811582820484141761011657610116614091565b60006020828403121561488257600080fd5b6102b4826144af565b60006020828403121561489d57600080fd5b6102b482613fd7565b60006001600160ff1b01820161484657614846614091565b6000600160ff1b82016148d3576148d3614091565b506000190190565b60008160020b627fffff1981036148f4576148f4614091565b60000392915050565b6000825161490f818460208701613ad1565b919091019291505056fea264697066735822122074f32fef384fdc296b0859f1c1f941c8e736c6cb972aa9e2b894956ebd6a80b364736f6c63430008160033","r":"0x1","s":"0x1","yParity":"0x0","hash":"0xbc73db80bf4b8784ba10a8910a0b7ef85f6846d102b41dd990969ea205335354"}}],"ommers":[]},{"header":{"parentHash":"0x026ae0c6ae91f186a9befa1ac8be30eea35e30e77de51a731085221e5cd39209","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0xb6003e7ba07a15a9e35f63daa484728ec4ceeded0c4d10ac1b04e9552d412b3c","transactionsRoot":"0x6e4969a136061ca7a390d12830d47a151585325a8d396819fb2b958ff85e9f8f","receiptsRoot":"0xc3e81df67d3e2a6c8345a954ef250cfcc41abcc2292a5aa263071124533fc9ad","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x3","gasLimit":"0x1c9c380","gasUsed":"0x3c0f6","timestamp":"0x66b200ce","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x18993a68","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gas":"0x3c0f6","maxFeePerGas":"0x5d4285cd","maxPriorityFeePerGas":"0x3b9aca00","value":"0x0","accessList":[],"input":"0x608060405234801561001057600080fd5b50610380806100206000396000f3fe6080604052600080357fffffffff0000000000000000000000000000000000000000000000000000000016905060008160e01c610251565b60006379ba509782101561015e5781631627540c811461009857632a952b2d81146100b457633659cfe681146100d0576350c946fe81146100ec576353a47bb781146101085763625ca21c81146101245763718fe928811461014057610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc91505b5061024c565b816379ba509781146101a657638da5cb5b81146101c25763aaf10f4281146101de5763c7f62cda81146101fa5763daa250be81146102165763deba1b9881146102325761024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b738138ef7cf908021d117e542120b7a39065016107915061024a565b738138ef7cf908021d117e542120b7a3906501610791505b505b919050565b61025a81610037565b915050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036102ce57816040517fc2a825f50000000000000000000000000000000000000000000000000000000081526004016102c5919061032f565b60405180910390fd5b3660008037600080366000845af43d6000803e80600081146102ef573d6000f35b3d6000fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610329816102f4565b82525050565b60006020820190506103446000830184610320565b9291505056fea264697066735822122017a4b7fdaaab3897a7b47abaed8d2ee92d558883d3bb2a8454f9601b2ab2c3db64736f6c63430008150033","r":"0x1","s":"0x1","yParity":"0x0","hash":"0x2476e039803622aeb040f924f04c493f559aed3d6c9372ab405cb33c8c695328"}}],"ommers":[]},{"header":{"parentHash":"0x3d22100ac0ee8d5cde334f7f926191a861b0648971ebc179547df28a0224c6d0","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x9511d4711e5c30a72b0bff38a261daa75dcc5ba8b772d970a5c742244b4c861b","transactionsRoot":"0xba5fff578d3d6c2cd63acbe9bca353eaa6fe22a5c408956eff49106e0a96c507","receiptsRoot":"0xbae111f01cb07677e3a8c5031546138407c01bc964d3493d732dc4edf47d36d3","logsBloom":"0x00000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000020000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000001000000000000000000000400000001000010000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x5","gasLimit":"0x1c9c380","gasUsed":"0xcae7","timestamp":"0x66b200cb","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x12e09c7a","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gas":"0xcc4d","maxFeePerGas":"0x557e5ec4","maxPriorityFeePerGas":"0x3b9aca00","to":"0x83a0444b93927c3afcbe46e522280390f748e171","value":"0x0","accessList":[],"input":"0x3659cfe6000000000000000000000000108f53faf774d7c4c56f5bce9ca6e605ce8aeadd","r":"0x1","s":"0x1","yParity":"0x0","hash":"0xf88e7b19ee347145c257e0cf7ac4ecc2bae83ca79d7edaa231e71d3213aeb151"}}],"ommers":[]},{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x9c8eaf493f8b4edce2ba1647343eadcc0989cf461e712c0a6253ff2ca1842bb7","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0xdd07c07470e1deff3749831f0f1ad8d4b6e35505e83b3c6ea14181716197cd8a","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x29aa352e71b139e83b397bdd3dcf9b65d74770edaf3a9624d0dbc4f96f868680","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200cb","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x24a1ab52","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x0","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200c9","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0xf6930be4847cac5017bbcbec2756eed19f36b4196526a98a88e311c296e3a9be","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x29aa352e71b139e83b397bdd3dcf9b65d74770edaf3a9624d0dbc4f96f868680","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200cc","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x200d75e8","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0xb6003e7ba07a15a9e35f63daa484728ec4ceeded0c4d10ac1b04e9552d412b3c","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x4","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x1592fbf9","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x149d41e3b89d8324cef3feff98ef308e97bafe8745cc8461c60172bc7d4c44ba","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x510f2275449c013534a25ad0b13c867caf720947b68bcbcd4863f7b172a5d023","transactionsRoot":"0x0b44110186e52ff0ceb6b0776ca2992c94144a4ed712eef65ea038260ef0fcc7","receiptsRoot":"0xc2823b8eb4730d9f2657137cc2ddc2c4f22ab68e0ab826236cf6a1551ca2b3a5","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0xe61f9","timestamp":"0x66b200cb","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x342770c0","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gas":"0xe94d1","maxFeePerGas":"0x83215600","maxPriorityFeePerGas":"0x3b9aca00","to":"0x4e59b44847b379578588920ca78fbf26c0b4956c","value":"0x0","accessList":[],"input":"0x4786e4342646b3ba97c1790b6cf5a55087a36240b22570f5d3a5d6bcc929d93b608060405234801561001057600080fd5b5060008061002661006d60201b61081b1760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610141565b60008060405160200161007f90610121565b6040516020818303038152906040528051906020012090508091505090565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b600061010b60238361009e565b9150610116826100af565b604082019050919050565b6000602082019050818103600083015261013a816100fe565b9050919050565b611000806101506000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c806379ba50971161005b57806379ba5097146100ed5780638da5cb5b146100f7578063aaf10f4214610115578063c7f62cda1461013357610088565b80631627540c1461008d5780633659cfe6146100a957806353a47bb7146100c5578063718fe928146100e3575b600080fd5b6100a760048036038101906100a29190610d25565b61014f565b005b6100c360048036038101906100be9190610d25565b6102d0565b005b6100cd6102e4565b6040516100da9190610d61565b60405180910390f35b6100eb610317565b005b6100f56103fe565b005b6100ff61058b565b60405161010c9190610d61565b60405180910390f35b61011d6105be565b60405161012a9190610d61565b60405180910390f35b61014d60048036038101906101489190610d25565b6105f1565b005b61015761084c565b600061016161081b565b9050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036101c9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610252576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22826040516102c49190610d61565b60405180910390a15050565b6102d861084c565b6102e1816108c5565b50565b60006102ee61081b565b60010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600061032161081b565b90503373ffffffffffffffffffffffffffffffffffffffff168160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146103b757336040517fa0e5a0d70000000000000000000000000000000000000000000000000000000081526004016103ae9190610d61565b60405180910390fd5b60008160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600061040861081b565b905060008160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146104a357336040517fa0e5a0d700000000000000000000000000000000000000000000000000000000815260040161049a9190610d61565b60405180910390fd5b7fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c8260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16826040516104f8929190610d7c565b60405180910390a1808260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008260010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b600061059561081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105c8610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105fb610b05565b905060018160000160146101000a81548160ff02191690831515021790555060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050828260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008373ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16633659cfe6846040516024016106cc9190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161071b9190610e16565b600060405180830381855af49150503d8060008114610756576040519150601f19603f3d011682016040523d82523d6000602084013e61075b565b606091505b505090508015806107c357508173ffffffffffffffffffffffffffffffffffffffff16610786610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b156107fa576040517fa1cfa5a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360000160146101000a81548160ff0219169083151502179055600080fd5b60008060405160200161082d90610eb0565b6040516020818303038152906040528051906020012090508091505090565b610854610b36565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108c357336040517f8e4a23d60000000000000000000000000000000000000000000000000000000081526004016108ba9190610d61565b60405180910390fd5b565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361092b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61093481610b69565b61097557806040517f8a8b41ec00000000000000000000000000000000000000000000000000000000815260040161096c9190610d61565b60405180910390fd5b600061097f610b05565b90508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610a0a576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000160149054906101000a900460ff16158015610a2e5750610a2d82610b7c565b5b15610a7057816040517f15504301000000000000000000000000000000000000000000000000000000008152600401610a679190610d61565b60405180910390fd5b818160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503073ffffffffffffffffffffffffffffffffffffffff167f5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c783604051610af99190610d61565b60405180910390a25050565b600080604051602001610b1790610f42565b6040516020818303038152906040528051906020012090508091505090565b6000610b4061081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080823b905060008111915050919050565b60008060003073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1663c7f62cda86604051602401610bc59190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610c149190610e16565b600060405180830381855af49150503d8060008114610c4f576040519150601f19603f3d011682016040523d82523d6000602084013e610c54565b606091505b509150915081158015610cb9575063a1cfa5a860e01b604051602001610c7a9190610faf565b6040516020818303038152906040528051906020012081604051602001610ca19190610e16565b60405160208183030381529060405280519060200120145b92505050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cf282610cc7565b9050919050565b610d0281610ce7565b8114610d0d57600080fd5b50565b600081359050610d1f81610cf9565b92915050565b600060208284031215610d3b57610d3a610cc2565b5b6000610d4984828501610d10565b91505092915050565b610d5b81610ce7565b82525050565b6000602082019050610d766000830184610d52565b92915050565b6000604082019050610d916000830185610d52565b610d9e6020830184610d52565b9392505050565b600081519050919050565b600081905092915050565b60005b83811015610dd9578082015181840152602081019050610dbe565b60008484015250505050565b6000610df082610da5565b610dfa8185610db0565b9350610e0a818560208601610dbb565b80840191505092915050565b6000610e228284610de5565b915081905092915050565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b6000610e9a602383610e2d565b9150610ea582610e3e565b604082019050919050565b60006020820190508181036000830152610ec981610e8d565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b6000610f2c602183610e2d565b9150610f3782610ed0565b604082019050919050565b60006020820190508181036000830152610f5b81610f1f565b9050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b610fa9610fa482610f62565b610f8e565b82525050565b6000610fbb8284610f98565b6004820191508190509291505056fea264697066735822122023a7c33d7b91dce35ffbcf8837693364ab22a3905d0fc00016833e5fac45ca2f64736f6c63430008110033","r":"0x1","s":"0x1","yParity":"0x0","hash":"0x4feae6769d748b4f0f7c9bf21d782236c88f13906789a3ec602961296e4c3e43"}}],"ommers":[]},{"header":{"parentHash":"0xb3535af5103fd1c2bbd6dc7ff23f0799037a6542c231ebcb85abd776560fa512","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x23d74fb99ff6e42cbb5c33f92b078e37be6af2b6092459b103ff7059a6517ebc","transactionsRoot":"0x9eab45eca206fe11c107ea985c7d02fcfa442836aea3e04ba11dc4df587d5aa6","receiptsRoot":"0xe25abcfa973db8c55f73292137c626430de130a382ad4466337fefb0f7c8fde0","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x3ce3f","timestamp":"0x66b200cd","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x1c0bc72b","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gas":"0x3d8a8","maxFeePerGas":"0x6211577c","maxPriorityFeePerGas":"0x3b9aca00","to":"0x4e59b44847b379578588920ca78fbf26c0b4956c","value":"0x0","accessList":[],"input":"0x4786e4342646b3ba97c1790b6cf5a55087a36240b22570f5d3a5d6bcc929d93b608060405234801561001057600080fd5b5060405161068538038061068583398181016040528101906100329190610275565b818181600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361009b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6100ae8161019d60201b61004f1760201c565b6100ef57806040517f8a8b41ec0000000000000000000000000000000000000000000000000000000081526004016100e691906102c4565b60405180910390fd5b806100fe6101b060201b60201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050806101536101e160201b6100621760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050610414565b600080823b905060008111915050919050565b6000806040516020016101c290610362565b6040516020818303038152906040528051906020012090508091505090565b6000806040516020016101f3906103f4565b6040516020818303038152906040528051906020012090508091505090565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061024282610217565b9050919050565b61025281610237565b811461025d57600080fd5b50565b60008151905061026f81610249565b92915050565b6000806040838503121561028c5761028b610212565b5b600061029a85828601610260565b92505060206102ab85828601610260565b9150509250929050565b6102be81610237565b82525050565b60006020820190506102d960008301846102b5565b92915050565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b600061034c6021836102df565b9150610357826102f0565b604082019050919050565b6000602082019050818103600083015261037b8161033f565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b60006103de6023836102df565b91506103e982610382565b604082019050919050565b6000602082019050818103600083015261040d816103d1565b9050919050565b610262806104236000396000f3fe6080604052366100135761001161001d565b005b61001b61001d565b005b6000610027610093565b90503660008037600080366000845af43d6000803e806000811461004a573d6000f35b3d6000fd5b600080823b905060008111915050919050565b6000806040516020016100749061017a565b6040516020818303038152906040528051906020012090508091505090565b600061009d6100c6565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000806040516020016100d89061020c565b6040516020818303038152906040528051906020012090508091505090565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b60006101646023836100f7565b915061016f82610108565b604082019050919050565b6000602082019050818103600083015261019381610157565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b60006101f66021836100f7565b91506102018261019a565b604082019050919050565b60006020820190508181036000830152610225816101e9565b905091905056fea2646970667358221220800da1f73cebd5e4afa07496d9bca6b6c4f526bdd3f4014ec15c70fe3a1c441364736f6c6343000811003300000000000000000000000047d08dad17ccb558b3ea74b1a0e73a9cc804a9dc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266","r":"0x1","s":"0x1","yParity":"0x0","hash":"0xb6794d5c7abed6f91d447e8efb72ef2580595a6d7c8dee57ba1dbb330970146a"}}],"ommers":[]},{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x510f2275449c013534a25ad0b13c867caf720947b68bcbcd4863f7b172a5d023","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x3","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x29dd5614","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]}]} \ No newline at end of file diff --git a/crates/anvil/test-data/state-dump-legacy.json b/crates/anvil/test-data/state-dump-legacy.json index 273442701292e..26fa019b20fb5 100644 --- a/crates/anvil/test-data/state-dump-legacy.json +++ b/crates/anvil/test-data/state-dump-legacy.json @@ -1 +1 @@ -{"block":{"number":"0x2","coinbase":"0x0000000000000000000000000000000000000000","timestamp":"0x66cdc823","gas_limit":"0x1c9c380","basefee":"0x342a1c58","difficulty":"0x0","prevrandao":"0xb92480171c0235f8c6710a4047d7ee14a3be58c630839fb4422826ff3a013e44","blob_excess_gas_and_price":{"excess_blob_gas":0,"blob_gasprice":1}},"accounts":{"0x0000000000000000000000000000000000000000":{"nonce":0,"balance":"0xa410","code":"0x","storage":{}},"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x4e59b44847b379578588920ca78fbf26c0b4956c":{"nonce":0,"balance":"0x0","code":"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3","storage":{}},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"nonce":1,"balance":"0x21e19e0b90393da9b38","code":"0x","storage":{}},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"nonce":1,"balance":"0x21e19e0b6a140b55df8","code":"0x","storage":{}}},"best_block_number":"0x2","blocks":[{"header":{"parentHash":"0xceb0fe420d6f14a8eeec4319515b89acbb0bb4861cad9983d529ab4b1e4af929","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1","transactionsRoot":"0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdc823","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x342a1c58","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gas":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","value":"0x0","accessList":[],"input":"0x","r":"0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0","s":"0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd","yParity":"0x0","hash":"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515"}}],"ommers":[]},{"header":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x0","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66cdc80e","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0xa00dc0c9ee9a888e67ea32d8772f8cc28eff62448c9ec985ee941fcbc921ba59","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x6e5f60b37eeaece7dedfc42cc394731a0ae3ed3d3be93c402780b2e23e141175","transactionsRoot":"0x9ceaeb1b16b924afbf4bf4df4c2c49dc9cfbe23ac7a40bf26a704158ea2d352f","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdc814","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gas":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","value":"0x0","accessList":[],"input":"0x","r":"0x703a4b4d6dbff2fa2345df73263df2098faa7214863b5ec82c4c07162d87b853","s":"0x17dea762c4ce600ad1d9d2c9ae6dd35b9e526d03c875f868ad0792fd4fad72e0","yParity":"0x0","hash":"0xf8d5fb22350f52ae8c30cd7f6969eb73de849c8dc010f4215d4c5c24824fe2b3"}}],"ommers":[]}]} \ No newline at end of file +{"block":{"number":2,"beneficiary":"0x0000000000000000000000000000000000000000","timestamp":1724762147,"gas_limit":30000000,"basefee":875175000,"difficulty":"0x0","prevrandao":"0xb92480171c0235f8c6710a4047d7ee14a3be58c630839fb4422826ff3a013e44","blob_excess_gas_and_price":{"excess_blob_gas":0,"blob_gasprice":1}},"accounts":{"0x0000000000000000000000000000000000000000":{"nonce":0,"balance":"0xa410","code":"0x","storage":{}},"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x4e59b44847b379578588920ca78fbf26c0b4956c":{"nonce":0,"balance":"0x0","code":"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3","storage":{}},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"nonce":1,"balance":"0x21e19e0b90393da9b38","code":"0x","storage":{}},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"nonce":1,"balance":"0x21e19e0b6a140b55df8","code":"0x","storage":{}}},"best_block_number":2,"blocks":[{"header":{"parentHash":"0xceb0fe420d6f14a8eeec4319515b89acbb0bb4861cad9983d529ab4b1e4af929","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1","transactionsRoot":"0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdc823","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x342a1c58","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gas":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","value":"0x0","accessList":[],"input":"0x","r":"0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0","s":"0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd","yParity":"0x0","hash":"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515"}}],"ommers":[]},{"header":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x0","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66cdc80e","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0xa00dc0c9ee9a888e67ea32d8772f8cc28eff62448c9ec985ee941fcbc921ba59","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x6e5f60b37eeaece7dedfc42cc394731a0ae3ed3d3be93c402780b2e23e141175","transactionsRoot":"0x9ceaeb1b16b924afbf4bf4df4c2c49dc9cfbe23ac7a40bf26a704158ea2d352f","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdc814","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gas":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","value":"0x0","accessList":[],"input":"0x","r":"0x703a4b4d6dbff2fa2345df73263df2098faa7214863b5ec82c4c07162d87b853","s":"0x17dea762c4ce600ad1d9d2c9ae6dd35b9e526d03c875f868ad0792fd4fad72e0","yParity":"0x0","hash":"0xf8d5fb22350f52ae8c30cd7f6969eb73de849c8dc010f4215d4c5c24824fe2b3"}}],"ommers":[]}]} \ No newline at end of file diff --git a/crates/anvil/test-data/state-dump.json b/crates/anvil/test-data/state-dump.json index e868bf2efea51..4b7e66b17f56d 100644 --- a/crates/anvil/test-data/state-dump.json +++ b/crates/anvil/test-data/state-dump.json @@ -1 +1 @@ -{"block":{"number":"0x2","coinbase":"0x0000000000000000000000000000000000000000","timestamp":"0x66cdcc2b","gas_limit":"0x1c9c380","basefee":"0x342a1c58","difficulty":"0x0","prevrandao":"0xdb639d7f8af4f0ff2aa9cc49861820e72f5f8bfeeed677d1e3569f6b1625df4a","blob_excess_gas_and_price":{"excess_blob_gas":0,"blob_gasprice":1}},"accounts":{"0x0000000000000000000000000000000000000000":{"nonce":0,"balance":"0xa410","code":"0x","storage":{}},"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x4e59b44847b379578588920ca78fbf26c0b4956c":{"nonce":0,"balance":"0x0","code":"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3","storage":{}},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"nonce":1,"balance":"0x21e19e0b90393da9b38","code":"0x","storage":{}},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"nonce":1,"balance":"0x21e19e0b6a140b55df8","code":"0x","storage":{}}},"best_block_number":"0x2","blocks":[{"header":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x0","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66cdcc25","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x3a52101c98a4319c419681131d3585d70a6cf13a9af25136be20d451eed5480a","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x6e5f60b37eeaece7dedfc42cc394731a0ae3ed3d3be93c402780b2e23e141175","transactionsRoot":"0x9ceaeb1b16b924afbf4bf4df4c2c49dc9cfbe23ac7a40bf26a704158ea2d352f","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdcc29","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"transaction":{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gas":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","value":"0x0","accessList":[],"input":"0x","r":"0x703a4b4d6dbff2fa2345df73263df2098faa7214863b5ec82c4c07162d87b853","s":"0x17dea762c4ce600ad1d9d2c9ae6dd35b9e526d03c875f868ad0792fd4fad72e0","yParity":"0x0","hash":"0xf8d5fb22350f52ae8c30cd7f6969eb73de849c8dc010f4215d4c5c24824fe2b3"}},"impersonated_sender":null}],"ommers":[]},{"header":{"parentHash":"0x0d575f9ca968cd483549172245483a12343afc3cabef80f0fa39855b10b98c70","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1","transactionsRoot":"0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdcc2b","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x342a1c58","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"transaction":{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gas":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","value":"0x0","accessList":[],"input":"0x","r":"0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0","s":"0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd","yParity":"0x0","hash":"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515"}},"impersonated_sender":null}],"ommers":[]}],"transactions":[{"info":{"transaction_hash":"0xf8d5fb22350f52ae8c30cd7f6969eb73de849c8dc010f4215d4c5c24824fe2b3","transaction_index":0,"from":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","to":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","contract_address":null,"traces":[{"parent":null,"children":[],"idx":0,"trace":{"depth":0,"success":true,"caller":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","address":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","maybe_precompile":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x","output":"0x","gas_used":0,"gas_limit":1,"status":"Stop","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[]}],"exit":"Stop","out":"0x","nonce":0,"gas_used":21000},"receipt":{"type":"0x2","status":"0x1","cumulativeGasUsed":"0x5208","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"block_hash":"0x0d575f9ca968cd483549172245483a12343afc3cabef80f0fa39855b10b98c70","block_number":1},{"info":{"transaction_hash":"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515","transaction_index":0,"from":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","to":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","contract_address":null,"traces":[{"parent":null,"children":[],"idx":0,"trace":{"depth":0,"success":true,"caller":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","address":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","maybe_precompile":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x","output":"0x","gas_used":0,"gas_limit":1,"status":"Stop","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[]}],"exit":"Stop","out":"0x","nonce":0,"gas_used":21000},"receipt":{"type":"0x2","status":"0x1","cumulativeGasUsed":"0x5208","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"block_hash":"0x1f435a603c1bf6d544a90156b572b96d7a1730028422d800839bae78bb3506d0","block_number":2}]} \ No newline at end of file +{"block":{"number":2,"beneficiary":"0x0000000000000000000000000000000000000000","timestamp":1724763179,"gas_limit":30000000,"basefee":875175000,"difficulty":"0x0","prevrandao":"0xdb639d7f8af4f0ff2aa9cc49861820e72f5f8bfeeed677d1e3569f6b1625df4a","blob_excess_gas_and_price":{"excess_blob_gas":0,"blob_gasprice":1}},"accounts":{"0x0000000000000000000000000000000000000000":{"nonce":0,"balance":"0xa410","code":"0x","storage":{}},"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x4e59b44847b379578588920ca78fbf26c0b4956c":{"nonce":0,"balance":"0x0","code":"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3","storage":{}},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"nonce":1,"balance":"0x21e19e0b90393da9b38","code":"0x","storage":{}},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"nonce":1,"balance":"0x21e19e0b6a140b55df8","code":"0x","storage":{}}},"best_block_number":2,"blocks":[{"header":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x0","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66cdcc25","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x3a52101c98a4319c419681131d3585d70a6cf13a9af25136be20d451eed5480a","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x6e5f60b37eeaece7dedfc42cc394731a0ae3ed3d3be93c402780b2e23e141175","transactionsRoot":"0x9ceaeb1b16b924afbf4bf4df4c2c49dc9cfbe23ac7a40bf26a704158ea2d352f","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdcc29","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"transaction":{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gas":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","value":"0x0","accessList":[],"input":"0x","r":"0x703a4b4d6dbff2fa2345df73263df2098faa7214863b5ec82c4c07162d87b853","s":"0x17dea762c4ce600ad1d9d2c9ae6dd35b9e526d03c875f868ad0792fd4fad72e0","yParity":"0x0","hash":"0xf8d5fb22350f52ae8c30cd7f6969eb73de849c8dc010f4215d4c5c24824fe2b3"}},"impersonated_sender":null}],"ommers":[]},{"header":{"parentHash":"0x0d575f9ca968cd483549172245483a12343afc3cabef80f0fa39855b10b98c70","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1","transactionsRoot":"0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdcc2b","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x342a1c58","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"transaction":{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gas":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","value":"0x0","accessList":[],"input":"0x","r":"0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0","s":"0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd","yParity":"0x0","hash":"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515"}},"impersonated_sender":null}],"ommers":[]}],"transactions":[{"info":{"transaction_hash":"0xf8d5fb22350f52ae8c30cd7f6969eb73de849c8dc010f4215d4c5c24824fe2b3","transaction_index":0,"from":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","to":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","contract_address":null,"traces":[{"parent":null,"children":[],"idx":0,"trace":{"depth":0,"success":true,"caller":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","address":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","maybe_precompile":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x","output":"0x","gas_used":0,"gas_limit":1,"status":"Stop","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[]}],"exit":"Stop","out":"0x","nonce":0,"gas_used":21000},"receipt":{"type":"0x2","status":"0x1","cumulativeGasUsed":"0x5208","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"block_hash":"0x0d575f9ca968cd483549172245483a12343afc3cabef80f0fa39855b10b98c70","block_number":1},{"info":{"transaction_hash":"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515","transaction_index":0,"from":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","to":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","contract_address":null,"traces":[{"parent":null,"children":[],"idx":0,"trace":{"depth":0,"success":true,"caller":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","address":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","maybe_precompile":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x","output":"0x","gas_used":0,"gas_limit":1,"status":"Stop","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[]}],"exit":"Stop","out":"0x","nonce":0,"gas_used":21000},"receipt":{"type":"0x2","status":"0x1","cumulativeGasUsed":"0x5208","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"block_hash":"0x1f435a603c1bf6d544a90156b572b96d7a1730028422d800839bae78bb3506d0","block_number":2}]} \ No newline at end of file diff --git a/crates/anvil/tests/it/anvil_api.rs b/crates/anvil/tests/it/anvil_api.rs index 22179d505a9b6..68d4550d6bbd6 100644 --- a/crates/anvil/tests/it/anvil_api.rs +++ b/crates/anvil/tests/it/anvil_api.rs @@ -30,7 +30,7 @@ use anvil_core::{ }, types::{ReorgOptions, TransactionData}, }; -use foundry_evm::revm::primitives::SpecId; +use revm::primitives::hardfork::SpecId; use std::{ future::IntoFuture, str::FromStr, diff --git a/crates/anvil/tests/it/fork.rs b/crates/anvil/tests/it/fork.rs index cda5fc805cf8c..a0bc8aa05cff1 100644 --- a/crates/anvil/tests/it/fork.rs +++ b/crates/anvil/tests/it/fork.rs @@ -61,7 +61,7 @@ pub fn fork_config() -> NodeConfig { #[tokio::test(flavor = "multi_thread")] async fn test_fork_gas_limit_applied_from_config() { - let (api, _handle) = spawn(fork_config().with_gas_limit(Some(10_000_000_u128))).await; + let (api, _handle) = spawn(fork_config().with_gas_limit(Some(10_000_000))).await; assert_eq!(api.gas_limit(), uint!(10_000_000_U256)); } @@ -1329,6 +1329,7 @@ async fn test_immutable_fork_transaction_hash() { use std::str::FromStr; // Fork to a block with a specific transaction + // let fork_tx_hash = TxHash::from_str("2ac736ce725d628ef20569a1bb501726b42b33f9d171f60b92b69de3ce705845") .unwrap(); diff --git a/crates/anvil/tests/it/gas.rs b/crates/anvil/tests/it/gas.rs index 623654537d3d2..f3bcd01ddfe47 100644 --- a/crates/anvil/tests/it/gas.rs +++ b/crates/anvil/tests/it/gas.rs @@ -8,7 +8,7 @@ use alloy_rpc_types::{BlockId, TransactionRequest}; use alloy_serde::WithOtherFields; use anvil::{eth::fees::INITIAL_BASE_FEE, spawn, NodeConfig}; -const GAS_TRANSFER: u128 = 21_000; +const GAS_TRANSFER: u64 = 21_000; #[tokio::test(flavor = "multi_thread")] async fn test_gas_limit_applied_from_config() { diff --git a/crates/anvil/tests/it/state.rs b/crates/anvil/tests/it/state.rs index d642582269e68..95bdddf57f566 100644 --- a/crates/anvil/tests/it/state.rs +++ b/crates/anvil/tests/it/state.rs @@ -2,7 +2,7 @@ use crate::abi::Greeter; use alloy_network::{ReceiptResponse, TransactionBuilder}; -use alloy_primitives::{address, utils::Unit, Bytes, Uint, U256, U64}; +use alloy_primitives::{address, utils::Unit, Bytes, Uint, U256}; use alloy_provider::Provider; use alloy_rpc_types::{BlockId, TransactionRequest}; use alloy_serde::WithOtherFields; @@ -262,7 +262,7 @@ async fn test_fork_load_state_with_greater_state_block() { let serialized_state = api.serialized_state(false).await.unwrap(); - assert_eq!(serialized_state.best_block_number, Some(block_number.to::())); + assert_eq!(serialized_state.best_block_number, Some(block_number.to::())); let (api, _handle) = spawn( NodeConfig::test() diff --git a/crates/anvil/tests/it/traces.rs b/crates/anvil/tests/it/traces.rs index 297f188f7ddbd..849956cabe5dd 100644 --- a/crates/anvil/tests/it/traces.rs +++ b/crates/anvil/tests/it/traces.rs @@ -138,7 +138,11 @@ async fn test_transfer_debug_trace_call() { let traces = handle .http_provider() - .debug_trace_call(tx, BlockId::latest(), GethDebugTracingCallOptions::default()) + .debug_trace_call( + WithOtherFields::new(tx), + BlockId::latest(), + GethDebugTracingCallOptions::default(), + ) .await .unwrap(); @@ -183,7 +187,7 @@ async fn test_call_tracer_debug_trace_call() { let internal_call_tx_traces = handle .http_provider() .debug_trace_call( - internal_call_tx.clone(), + WithOtherFields::new(internal_call_tx.clone()), BlockId::latest(), GethDebugTracingCallOptions::default().with_tracing_options( GethDebugTracingOptions::default() @@ -211,7 +215,7 @@ async fn test_call_tracer_debug_trace_call() { let internal_call_only_top_call_tx_traces = handle .http_provider() .debug_trace_call( - internal_call_tx.clone(), + WithOtherFields::new(internal_call_tx.clone()), BlockId::latest(), GethDebugTracingCallOptions::default().with_tracing_options( GethDebugTracingOptions::default() @@ -240,7 +244,7 @@ async fn test_call_tracer_debug_trace_call() { let direct_call_tx_traces = handle .http_provider() .debug_trace_call( - direct_call_tx, + WithOtherFields::new(direct_call_tx), BlockId::latest(), GethDebugTracingCallOptions::default().with_tracing_options( GethDebugTracingOptions::default() @@ -284,7 +288,7 @@ async fn test_debug_trace_call_state_override() { let tx_traces = handle .http_provider() .debug_trace_call( - tx.clone(), + WithOtherFields::new(tx.clone()), BlockId::latest(), GethDebugTracingCallOptions::default() .with_tracing_options(GethDebugTracingOptions::default()) diff --git a/crates/anvil/tests/it/transaction.rs b/crates/anvil/tests/it/transaction.rs index 4c58170454601..d01bfa02aa3af 100644 --- a/crates/anvil/tests/it/transaction.rs +++ b/crates/anvil/tests/it/transaction.rs @@ -237,7 +237,7 @@ async fn can_mine_large_gas_limit() { let from = accounts[0].address(); let to = accounts[1].address(); - let gas_limit = anvil::DEFAULT_GAS_LIMIT as u64; + let gas_limit = anvil::DEFAULT_GAS_LIMIT; let amount = handle.genesis_balance().checked_div(U256::from(3u64)).unwrap(); let tx = diff --git a/crates/cast/Cargo.toml b/crates/cast/Cargo.toml index fc6e4368a8d8f..23315bfa30f2b 100644 --- a/crates/cast/Cargo.toml +++ b/crates/cast/Cargo.toml @@ -26,6 +26,7 @@ foundry-block-explorers.workspace = true foundry-common.workspace = true foundry-compilers.workspace = true foundry-config.workspace = true +foundry-evm-core.workspace = true foundry-evm.workspace = true foundry-wallets.workspace = true @@ -55,6 +56,7 @@ alloy-transport.workspace = true chrono.workspace = true eyre.workspace = true futures.workspace = true +revm.workspace = true rand.workspace = true rayon.workspace = true serde_json.workspace = true diff --git a/crates/cast/src/cmd/call.rs b/crates/cast/src/cmd/call.rs index b005a8af0f8c8..7499efe0ccee9 100644 --- a/crates/cast/src/cmd/call.rs +++ b/crates/cast/src/cmd/call.rs @@ -30,6 +30,7 @@ use foundry_evm::{ traces::{InternalTraceMode, TraceMode}, }; use regex::Regex; +use revm::context::TransactionType; use std::{str::FromStr, sync::LazyLock}; // matches override pattern
:: @@ -242,8 +243,8 @@ impl CallArgs { TracingExecutor::get_fork_material(&config, evm_opts).await?; // modify settings that usually set in eth_call - env.cfg.disable_block_gas_limit = true; - env.block.gas_limit = U256::MAX; + env.evm_env.cfg_env.disable_block_gas_limit = true; + env.evm_env.block_env.gas_limit = u64::MAX; let trace_mode = TraceMode::Call .with_debug(debug) @@ -265,9 +266,18 @@ impl CallArgs { let value = tx.value.unwrap_or_default(); let input = tx.inner.input.into_input().unwrap_or_default(); let tx_kind = tx.inner.to.expect("set by builder"); + let env_tx = &mut executor.env_mut().tx; + + if let Some(tx_type) = tx.inner.transaction_type { + env_tx.tx_type = tx_type; + } if let Some(access_list) = tx.inner.access_list { - executor.env_mut().tx.access_list = access_list.0 + env_tx.access_list = access_list; + + if env_tx.tx_type == TransactionType::Legacy as u8 { + env_tx.tx_type = TransactionType::Eip2930 as u8; + } } let trace = match tx_kind { diff --git a/crates/cast/src/cmd/run.rs b/crates/cast/src/cmd/run.rs index 90470ef31ed97..c586cf4c9ded4 100644 --- a/crates/cast/src/cmd/run.rs +++ b/crates/cast/src/cmd/run.rs @@ -1,9 +1,5 @@ -use crate::{ - revm::primitives::EnvWithHandlerCfg, utils::apply_chain_and_block_specific_env_changes, -}; use alloy_consensus::Transaction; use alloy_network::{AnyNetwork, TransactionResponse}; -use alloy_primitives::U256; use alloy_provider::Provider; use alloy_rpc_types::BlockTransactions; use clap::Parser; @@ -27,7 +23,11 @@ use foundry_evm::{ opts::EvmOpts, traces::{InternalTraceMode, TraceMode}, utils::configure_tx_env, + Env, }; +use foundry_evm_core::env::AsEnvMut; + +use crate::utils::apply_chain_and_block_specific_env_changes; /// CLI arguments for `cast run`. #[derive(Clone, Debug, Parser)] @@ -149,16 +149,16 @@ impl RunArgs { TracingExecutor::get_fork_material(&config, evm_opts).await?; let mut evm_version = self.evm_version; - env.cfg.disable_block_gas_limit = self.disable_block_gas_limit; - env.block.number = U256::from(tx_block_number); + env.evm_env.cfg_env.disable_block_gas_limit = self.disable_block_gas_limit; + env.evm_env.block_env.number = tx_block_number; if let Some(block) = &block { - env.block.timestamp = U256::from(block.header.timestamp); - env.block.coinbase = block.header.beneficiary; - env.block.difficulty = block.header.difficulty; - env.block.prevrandao = Some(block.header.mix_hash.unwrap_or_default()); - env.block.basefee = U256::from(block.header.base_fee_per_gas.unwrap_or_default()); - env.block.gas_limit = U256::from(block.header.gas_limit); + env.evm_env.block_env.timestamp = block.header.timestamp; + env.evm_env.block_env.beneficiary = block.header.beneficiary; + env.evm_env.block_env.difficulty = block.header.difficulty; + env.evm_env.block_env.prevrandao = Some(block.header.mix_hash.unwrap_or_default()); + env.evm_env.block_env.basefee = block.header.base_fee_per_gas.unwrap_or_default(); + env.evm_env.block_env.gas_limit = block.header.gas_limit; // TODO: we need a smarter way to map the block to the corresponding evm_version for // commonly used chains @@ -168,7 +168,7 @@ impl RunArgs { evm_version = Some(EvmVersion::Cancun); } } - apply_chain_and_block_specific_env_changes::(&mut env, block); + apply_chain_and_block_specific_env_changes::(env.as_env_mut(), block); } let trace_mode = TraceMode::Call @@ -187,8 +187,12 @@ impl RunArgs { odyssey, create2_deployer, )?; - let mut env = - EnvWithHandlerCfg::new_with_spec_id(Box::new(env.clone()), executor.spec_id()); + let mut env = Env::new_with_spec_id( + env.evm_env.cfg_env.clone(), + env.evm_env.block_env.clone(), + env.tx.clone(), + executor.spec_id(), + ); // Set the state to the moment right before the transaction if !self.quick { @@ -218,7 +222,7 @@ impl RunArgs { break; } - configure_tx_env(&mut env, &tx.inner); + configure_tx_env(&mut env.as_env_mut(), &tx.inner); if let Some(to) = Transaction::to(tx) { trace!(tx=?tx.tx_hash(),?to, "executing previous call transaction"); @@ -226,7 +230,7 @@ impl RunArgs { format!( "Failed to execute transaction: {:?} in block {}", tx.tx_hash(), - env.block.number + env.evm_env.block_env.number ) })?; } else { @@ -240,7 +244,7 @@ impl RunArgs { format!( "Failed to deploy transaction: {:?} in block {}", tx.tx_hash(), - env.block.number + env.evm_env.block_env.number ) }) } @@ -257,7 +261,7 @@ impl RunArgs { let result = { executor.set_trace_printer(self.trace_printer); - configure_tx_env(&mut env, &tx.inner); + configure_tx_env(&mut env.as_env_mut(), &tx.inner); if let Some(to) = Transaction::to(&tx) { trace!(tx=?tx.tx_hash(), to=?to, "executing call transaction"); diff --git a/crates/cast/src/cmd/wallet/mod.rs b/crates/cast/src/cmd/wallet/mod.rs index 71cdcabac2825..532de5eea0a37 100644 --- a/crates/cast/src/cmd/wallet/mod.rs +++ b/crates/cast/src/cmd/wallet/mod.rs @@ -1,8 +1,8 @@ -use crate::revm::primitives::Authorization; use alloy_chains::Chain; use alloy_dyn_abi::TypedData; use alloy_primitives::{hex, Address, PrimitiveSignature as Signature, B256, U256}; use alloy_provider::Provider; +use alloy_rpc_types::Authorization; use alloy_signer::{ k256::{elliptic_curve::sec1::ToEncodedPoint, SecretKey}, Signer, diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 70447311c719e..7ad227e0c8ab9 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -34,6 +34,7 @@ use foundry_common::{ }; use foundry_compilers::flatten::Flattener; use foundry_config::Chain; +use foundry_evm_core::ic::decode_instructions; use futures::{future::Either, FutureExt, StreamExt}; use rayon::prelude::*; use std::{ @@ -46,7 +47,6 @@ use std::{ time::Duration, }; use tokio::signal::ctrl_c; -use utils::decode_instructions; use foundry_common::abi::encode_function_args_packed; pub use foundry_evm::*; diff --git a/crates/cheatcodes/Cargo.toml b/crates/cheatcodes/Cargo.toml index 49611dcca071c..c5a784c338dec 100644 --- a/crates/cheatcodes/Cargo.toml +++ b/crates/cheatcodes/Cargo.toml @@ -25,6 +25,7 @@ foundry-wallets.workspace = true forge-script-sequence.workspace = true alloy-dyn-abi.workspace = true +alloy-evm.workspace = true alloy-json-abi.workspace = true alloy-primitives.workspace = true alloy-genesis.workspace = true diff --git a/crates/cheatcodes/src/error.rs b/crates/cheatcodes/src/error.rs index b77c889d59ab7..4bb9f1395bf2b 100644 --- a/crates/cheatcodes/src/error.rs +++ b/crates/cheatcodes/src/error.rs @@ -8,7 +8,7 @@ use foundry_config::UnresolvedEnvVarError; use foundry_evm_core::backend::{BackendError, DatabaseError}; use foundry_wallets::error::WalletSignerError; use k256::ecdsa::signature::Error as SignatureError; -use revm::primitives::EVMError; +use revm::context_interface::result::EVMError; use std::{borrow::Cow, fmt}; /// Cheatcode result type. diff --git a/crates/cheatcodes/src/evm.rs b/crates/cheatcodes/src/evm.rs index 543b6189784e9..456c4337e4bff 100644 --- a/crates/cheatcodes/src/evm.rs +++ b/crates/cheatcodes/src/evm.rs @@ -1,7 +1,7 @@ //! Implementations of [`Evm`](spec::Group::Evm) cheatcodes. use crate::{ - inspector::{InnerEcx, RecordDebugStepInfo}, + inspector::{Ecx, RecordDebugStepInfo}, BroadcastableTransaction, Cheatcode, Cheatcodes, CheatcodesExecutor, CheatsCtxt, Error, Result, Vm::*, }; @@ -14,11 +14,17 @@ use foundry_common::fs::{read_json_file, write_json_file}; use foundry_evm_core::{ backend::{DatabaseExt, RevertStateSnapshotAction}, constants::{CALLER, CHEATCODE_ADDRESS, HARDHAT_CONSOLE_ADDRESS, TEST_CONTRACT_ADDRESS}, + ContextExt, }; use foundry_evm_traces::StackSnapshotType; use itertools::Itertools; use rand::Rng; -use revm::primitives::{Account, Bytecode, SpecId, KECCAK_EMPTY}; +use revm::{ + bytecode::Bytecode, + context::{Block, JournalTr}, + primitives::{hardfork::SpecId, KECCAK_EMPTY}, + state::Account, +}; use std::{ collections::{btree_map::Entry, BTreeMap}, fmt::Display, @@ -74,7 +80,7 @@ pub struct GasRecord { /// The total gas used in the gas snapshot. pub gas_used: u64, /// Depth at which the gas snapshot was taken. - pub depth: u64, + pub depth: usize, } /// Records `deal` cheatcodes @@ -178,8 +184,8 @@ impl Cheatcode for loadCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { target, slot } = *self; ensure_not_precompile!(&target, ccx); - ccx.ecx.load_account(target)?; - let mut val = ccx.ecx.sload(target, slot.into())?; + ccx.ecx.journaled_state.load_account(target)?; + let mut val = ccx.ecx.journaled_state.sload(target, slot.into())?; if val.is_cold && val.data.is_zero() { if ccx.state.has_arbitrary_storage(&target) { @@ -229,9 +235,8 @@ impl Cheatcode for loadAllocsCall { }; // Then, load the allocs into the database. - ccx.ecx - .db - .load_allocs(&allocs, &mut ccx.ecx.journaled_state) + let (db, journal, _) = ccx.ecx.as_db_env_and_journal(); + db.load_allocs(&allocs, journal) .map(|()| Vec::default()) .map_err(|e| fmt_err!("failed to load allocs: {e}")) } @@ -241,14 +246,12 @@ impl Cheatcode for cloneAccountCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { source, target } = self; - let account = ccx.ecx.journaled_state.load_account(*source, &mut ccx.ecx.db)?; - ccx.ecx.db.clone_account( - &genesis_account(account.data), - target, - &mut ccx.ecx.journaled_state, - )?; + let (db, journal, _) = ccx.ecx.as_db_env_and_journal(); + let account = journal.load_account(db, *source)?; + let genesis = &genesis_account(account.data); + db.clone_account(genesis, target, journal)?; // Cloned account should persist in forked envs. - ccx.ecx.db.add_persistent_account(*target); + ccx.ecx.journaled_state.database.add_persistent_account(*target); Ok(Default::default()) } } @@ -363,7 +366,7 @@ impl Cheatcode for chainIdCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { newChainId } = self; ensure!(*newChainId <= U256::from(u64::MAX), "chain ID must be less than 2^64 - 1"); - ccx.ecx.env.cfg.chain_id = newChainId.to(); + ccx.ecx.cfg.chain_id = newChainId.to(); Ok(Default::default()) } } @@ -371,7 +374,7 @@ impl Cheatcode for chainIdCall { impl Cheatcode for coinbaseCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { newCoinbase } = self; - ccx.ecx.env.block.coinbase = *newCoinbase; + ccx.ecx.block.beneficiary = *newCoinbase; Ok(Default::default()) } } @@ -380,11 +383,11 @@ impl Cheatcode for difficultyCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { newDifficulty } = self; ensure!( - ccx.ecx.spec_id() < SpecId::MERGE, + ccx.ecx.cfg.spec < SpecId::MERGE, "`difficulty` is not supported after the Paris hard fork, use `prevrandao` instead; \ see EIP-4399: https://eips.ethereum.org/EIPS/eip-4399" ); - ccx.ecx.env.block.difficulty = *newDifficulty; + ccx.ecx.block.difficulty = *newDifficulty; Ok(Default::default()) } } @@ -392,7 +395,8 @@ impl Cheatcode for difficultyCall { impl Cheatcode for feeCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { newBasefee } = self; - ccx.ecx.env.block.basefee = *newBasefee; + ensure!(*newBasefee <= U256::from(u64::MAX), "base fee must be less than 2^64 - 1"); + ccx.ecx.block.basefee = newBasefee.saturating_to(); Ok(Default::default()) } } @@ -401,11 +405,11 @@ impl Cheatcode for prevrandao_0Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { newPrevrandao } = self; ensure!( - ccx.ecx.spec_id() >= SpecId::MERGE, + ccx.ecx.cfg.spec >= SpecId::MERGE, "`prevrandao` is not supported before the Paris hard fork, use `difficulty` instead; \ see EIP-4399: https://eips.ethereum.org/EIPS/eip-4399" ); - ccx.ecx.env.block.prevrandao = Some(*newPrevrandao); + ccx.ecx.block.prevrandao = Some(*newPrevrandao); Ok(Default::default()) } } @@ -414,11 +418,11 @@ impl Cheatcode for prevrandao_1Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { newPrevrandao } = self; ensure!( - ccx.ecx.spec_id() >= SpecId::MERGE, + ccx.ecx.cfg.spec >= SpecId::MERGE, "`prevrandao` is not supported before the Paris hard fork, use `difficulty` instead; \ see EIP-4399: https://eips.ethereum.org/EIPS/eip-4399" ); - ccx.ecx.env.block.prevrandao = Some((*newPrevrandao).into()); + ccx.ecx.block.prevrandao = Some((*newPrevrandao).into()); Ok(Default::default()) } } @@ -427,11 +431,11 @@ impl Cheatcode for blobhashesCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { hashes } = self; ensure!( - ccx.ecx.spec_id() >= SpecId::CANCUN, + ccx.ecx.cfg.spec >= SpecId::CANCUN, "`blobhashes` is not supported before the Cancun hard fork; \ see EIP-4844: https://eips.ethereum.org/EIPS/eip-4844" ); - ccx.ecx.env.tx.blob_hashes.clone_from(hashes); + ccx.ecx.tx.blob_hashes.clone_from(hashes); Ok(Default::default()) } } @@ -440,18 +444,19 @@ impl Cheatcode for getBlobhashesCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self {} = self; ensure!( - ccx.ecx.spec_id() >= SpecId::CANCUN, + ccx.ecx.cfg.spec >= SpecId::CANCUN, "`getBlobhashes` is not supported before the Cancun hard fork; \ see EIP-4844: https://eips.ethereum.org/EIPS/eip-4844" ); - Ok(ccx.ecx.env.tx.blob_hashes.clone().abi_encode()) + Ok(ccx.ecx.tx.blob_hashes.clone().abi_encode()) } } impl Cheatcode for rollCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { newHeight } = self; - ccx.ecx.env.block.number = *newHeight; + ensure!(*newHeight <= U256::from(u64::MAX), "block height must be less than 2^64 - 1"); + ccx.ecx.block.number = newHeight.saturating_to(); Ok(Default::default()) } } @@ -459,14 +464,15 @@ impl Cheatcode for rollCall { impl Cheatcode for getBlockNumberCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self {} = self; - Ok(ccx.ecx.env.block.number.abi_encode()) + Ok(ccx.ecx.block.number.abi_encode()) } } impl Cheatcode for txGasPriceCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { newGasPrice } = self; - ccx.ecx.env.tx.gas_price = *newGasPrice; + ensure!(*newGasPrice <= U256::from(u64::MAX), "gas price must be less than 2^64 - 1"); + ccx.ecx.tx.gas_price = newGasPrice.saturating_to(); Ok(Default::default()) } } @@ -474,7 +480,8 @@ impl Cheatcode for txGasPriceCall { impl Cheatcode for warpCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { newTimestamp } = self; - ccx.ecx.env.block.timestamp = *newTimestamp; + ensure!(*newTimestamp <= U256::from(u64::MAX), "timestamp must be less than 2^64 - 1"); + ccx.ecx.block.timestamp = newTimestamp.saturating_to(); Ok(Default::default()) } } @@ -482,7 +489,7 @@ impl Cheatcode for warpCall { impl Cheatcode for getBlockTimestampCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self {} = self; - Ok(ccx.ecx.env.block.timestamp.abi_encode()) + Ok(ccx.ecx.block.timestamp.abi_encode()) } } @@ -490,14 +497,12 @@ impl Cheatcode for blobBaseFeeCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { newBlobBaseFee } = self; ensure!( - ccx.ecx.spec_id() >= SpecId::CANCUN, + ccx.ecx.cfg.spec >= SpecId::CANCUN, "`blobBaseFee` is not supported before the Cancun hard fork; \ see EIP-4844: https://eips.ethereum.org/EIPS/eip-4844" ); - ccx.ecx.env.block.set_blob_excess_gas_and_price( - (*newBlobBaseFee).to(), - ccx.ecx.spec_id() >= SpecId::PRAGUE, - ); + let is_prague = ccx.ecx.cfg.spec >= SpecId::PRAGUE; + ccx.ecx.block.set_blob_excess_gas_and_price((*newBlobBaseFee).to(), is_prague); Ok(Default::default()) } } @@ -505,7 +510,7 @@ impl Cheatcode for blobBaseFeeCall { impl Cheatcode for getBlobBaseFeeCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self {} = self; - Ok(ccx.ecx.env.block.get_blob_excess_gas().unwrap_or(0).abi_encode()) + Ok(ccx.ecx.block.blob_excess_gas().unwrap_or(0).abi_encode()) } } @@ -524,7 +529,7 @@ impl Cheatcode for etchCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { target, newRuntimeBytecode } = self; ensure_not_precompile!(target, ccx); - ccx.ecx.load_account(*target)?; + ccx.ecx.journaled_state.load_account(*target)?; let bytecode = Bytecode::new_raw_checked(Bytes::copy_from_slice(newRuntimeBytecode)) .map_err(|e| fmt_err!("failed to create bytecode: {e}"))?; ccx.ecx.journaled_state.set_code(*target, bytecode); @@ -578,7 +583,7 @@ impl Cheatcode for storeCall { ensure_not_precompile!(&target, ccx); // ensure the account is touched let _ = journaled_account(ccx.ecx, target)?; - ccx.ecx.sstore(target, slot.into(), value.into())?; + ccx.ecx.journaled_state.sstore(target, slot.into(), value.into())?; Ok(Default::default()) } } @@ -639,7 +644,7 @@ impl Cheatcode for coolSlotCall { impl Cheatcode for readCallersCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self {} = self; - read_callers(ccx.state, &ccx.ecx.env.tx.caller, ccx.ecx.journaled_state.depth()) + read_callers(ccx.state, &ccx.ecx.tx.caller, ccx.ecx.journaled_state.depth()) } } @@ -831,16 +836,17 @@ impl Cheatcode for broadcastRawTransactionCall { let tx = TxEnvelope::decode(&mut self.data.as_ref()) .map_err(|err| fmt_err!("failed to decode RLP-encoded transaction: {err}"))?; - ccx.ecx.db.transact_from_tx( + let (db, journal, env) = ccx.ecx.as_db_env_and_journal(); + db.transact_from_tx( &tx.clone().into(), - (*ccx.ecx.env).clone(), - &mut ccx.ecx.journaled_state, + env.to_owned(), + journal, &mut *executor.get_inspector(ccx.state), )?; if ccx.state.broadcast.is_some() { ccx.state.broadcastable_transactions.push_back(BroadcastableTransaction { - rpc: ccx.db.active_fork_url(), + rpc: ccx.ecx.journaled_state.database.active_fork_url(), transaction: tx.try_into()?, }); } @@ -852,12 +858,13 @@ impl Cheatcode for broadcastRawTransactionCall { impl Cheatcode for setBlockhashCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { blockNumber, blockHash } = *self; + ensure!(blockNumber <= U256::from(u64::MAX), "blockNumber must be less than 2^64 - 1"); ensure!( - blockNumber <= ccx.ecx.env.block.number, + blockNumber <= U256::from(ccx.ecx.block.number), "block number must be less than or equal to the current block number" ); - ccx.ecx.db.set_blockhash(blockNumber, blockHash); + ccx.ecx.journaled_state.database.set_blockhash(blockNumber, blockHash); Ok(Default::default()) } @@ -930,23 +937,22 @@ impl Cheatcode for stopAndReturnDebugTraceRecordingCall { } pub(super) fn get_nonce(ccx: &mut CheatsCtxt, address: &Address) -> Result { - let account = ccx.ecx.journaled_state.load_account(*address, &mut ccx.ecx.db)?; + let account = ccx.ecx.journaled_state.load_account(*address)?; Ok(account.info.nonce.abi_encode()) } fn inner_snapshot_state(ccx: &mut CheatsCtxt) -> Result { - Ok(ccx.ecx.db.snapshot_state(&ccx.ecx.journaled_state, &ccx.ecx.env).abi_encode()) + let (db, journal, mut env) = ccx.ecx.as_db_env_and_journal(); + Ok(db.snapshot_state(journal, &mut env).abi_encode()) } fn inner_revert_to_state(ccx: &mut CheatsCtxt, snapshot_id: U256) -> Result { - let result = if let Some(journaled_state) = ccx.ecx.db.revert_state( - snapshot_id, - &ccx.ecx.journaled_state, - &mut ccx.ecx.env, - RevertStateSnapshotAction::RevertKeep, - ) { + let (db, journal, mut env) = ccx.ecx.as_db_env_and_journal(); + let result = if let Some(journaled_state) = + db.revert_state(snapshot_id, &*journal, &mut env, RevertStateSnapshotAction::RevertKeep) + { // we reset the evm's journaled_state to the state of the snapshot previous state - ccx.ecx.journaled_state = journaled_state; + ccx.ecx.journaled_state.inner = journaled_state; true } else { false @@ -955,14 +961,13 @@ fn inner_revert_to_state(ccx: &mut CheatsCtxt, snapshot_id: U256) -> Result { } fn inner_revert_to_state_and_delete(ccx: &mut CheatsCtxt, snapshot_id: U256) -> Result { - let result = if let Some(journaled_state) = ccx.ecx.db.revert_state( - snapshot_id, - &ccx.ecx.journaled_state, - &mut ccx.ecx.env, - RevertStateSnapshotAction::RevertRemove, - ) { + let (db, journal, mut env) = ccx.ecx.as_db_env_and_journal(); + + let result = if let Some(journaled_state) = + db.revert_state(snapshot_id, &*journal, &mut env, RevertStateSnapshotAction::RevertRemove) + { // we reset the evm's journaled_state to the state of the snapshot previous state - ccx.ecx.journaled_state = journaled_state; + ccx.ecx.journaled_state.inner = journaled_state; true } else { false @@ -971,12 +976,12 @@ fn inner_revert_to_state_and_delete(ccx: &mut CheatsCtxt, snapshot_id: U256) -> } fn inner_delete_state_snapshot(ccx: &mut CheatsCtxt, snapshot_id: U256) -> Result { - let result = ccx.ecx.db.delete_state_snapshot(snapshot_id); + let result = ccx.ecx.journaled_state.database.delete_state_snapshot(snapshot_id); Ok(result.abi_encode()) } fn inner_delete_state_snapshots(ccx: &mut CheatsCtxt) -> Result { - ccx.ecx.db.delete_state_snapshots(); + ccx.ecx.journaled_state.database.delete_state_snapshots(); Ok(Default::default()) } @@ -1119,7 +1124,7 @@ fn derive_snapshot_name( /// - If no caller modification is active: /// - caller_mode will be equal to [CallerMode::None], /// - `msg.sender` and `tx.origin` will be equal to the default sender address. -fn read_callers(state: &Cheatcodes, default_sender: &Address, call_depth: u64) -> Result { +fn read_callers(state: &Cheatcodes, default_sender: &Address, call_depth: usize) -> Result { let mut mode = CallerMode::None; let mut new_caller = default_sender; let mut new_origin = default_sender; @@ -1144,11 +1149,11 @@ fn read_callers(state: &Cheatcodes, default_sender: &Address, call_depth: u64) - /// Ensures the `Account` is loaded and touched. pub(super) fn journaled_account<'a>( - ecx: InnerEcx<'a, '_, '_>, + ecx: Ecx<'a, '_, '_>, addr: Address, ) -> Result<&'a mut Account> { - ecx.load_account(addr)?; - ecx.journaled_state.touch(&addr); + ecx.journaled_state.load_account(addr)?; + ecx.journaled_state.touch(addr); Ok(ecx.journaled_state.state.get_mut(&addr).expect("account is loaded")) } diff --git a/crates/cheatcodes/src/evm/fork.rs b/crates/cheatcodes/src/evm/fork.rs index e78aa3be9f697..65a7a04d401cc 100644 --- a/crates/cheatcodes/src/evm/fork.rs +++ b/crates/cheatcodes/src/evm/fork.rs @@ -8,13 +8,14 @@ use alloy_provider::Provider; use alloy_rpc_types::Filter; use alloy_sol_types::SolValue; use foundry_common::provider::ProviderBuilder; -use foundry_evm_core::fork::CreateFork; +use foundry_evm_core::{fork::CreateFork, AsEnvMut, ContextExt}; impl Cheatcode for activeForkCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self {} = self; ccx.ecx - .db + .journaled_state + .database .active_fork_id() .map(|id| id.abi_encode()) .ok_or_else(|| fmt_err!("no active fork")) @@ -67,12 +68,8 @@ impl Cheatcode for rollFork_0Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { blockNumber } = self; persist_caller(ccx); - ccx.ecx.db.roll_fork( - None, - (*blockNumber).to(), - &mut ccx.ecx.env, - &mut ccx.ecx.journaled_state, - )?; + let (db, journal, mut env) = ccx.ecx.as_db_env_and_journal(); + db.roll_fork(None, (*blockNumber).to(), &mut env, journal)?; Ok(Default::default()) } } @@ -81,12 +78,8 @@ impl Cheatcode for rollFork_1Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { txHash } = self; persist_caller(ccx); - ccx.ecx.db.roll_fork_to_transaction( - None, - *txHash, - &mut ccx.ecx.env, - &mut ccx.ecx.journaled_state, - )?; + let (db, journal, mut env) = ccx.ecx.as_db_env_and_journal(); + db.roll_fork_to_transaction(None, *txHash, &mut env, journal)?; Ok(Default::default()) } } @@ -95,12 +88,8 @@ impl Cheatcode for rollFork_2Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { forkId, blockNumber } = self; persist_caller(ccx); - ccx.ecx.db.roll_fork( - Some(*forkId), - (*blockNumber).to(), - &mut ccx.ecx.env, - &mut ccx.ecx.journaled_state, - )?; + let (db, journal, mut env) = ccx.ecx.as_db_env_and_journal(); + db.roll_fork(Some(*forkId), (*blockNumber).to(), &mut env, journal)?; Ok(Default::default()) } } @@ -109,12 +98,8 @@ impl Cheatcode for rollFork_3Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { forkId, txHash } = self; persist_caller(ccx); - ccx.ecx.db.roll_fork_to_transaction( - Some(*forkId), - *txHash, - &mut ccx.ecx.env, - &mut ccx.ecx.journaled_state, - )?; + let (db, journal, mut env) = ccx.ecx.as_db_env_and_journal(); + db.roll_fork_to_transaction(Some(*forkId), *txHash, &mut env, journal)?; Ok(Default::default()) } } @@ -124,8 +109,8 @@ impl Cheatcode for selectForkCall { let Self { forkId } = self; persist_caller(ccx); check_broadcast(ccx.state)?; - - ccx.ecx.db.select_fork(*forkId, &mut ccx.ecx.env, &mut ccx.ecx.journaled_state)?; + let (db, journal, mut env) = ccx.ecx.as_db_env_and_journal(); + db.select_fork(*forkId, &mut env, journal)?; Ok(Default::default()) } } @@ -147,7 +132,7 @@ impl Cheatcode for transact_1Call { impl Cheatcode for allowCheatcodesCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { account } = self; - ccx.ecx.db.allow_cheatcode_access(*account); + ccx.ecx.journaled_state.database.allow_cheatcode_access(*account); Ok(Default::default()) } } @@ -155,7 +140,7 @@ impl Cheatcode for allowCheatcodesCall { impl Cheatcode for makePersistent_0Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { account } = self; - ccx.ecx.db.add_persistent_account(*account); + ccx.ecx.journaled_state.database.add_persistent_account(*account); Ok(Default::default()) } } @@ -163,8 +148,8 @@ impl Cheatcode for makePersistent_0Call { impl Cheatcode for makePersistent_1Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { account0, account1 } = self; - ccx.ecx.db.add_persistent_account(*account0); - ccx.ecx.db.add_persistent_account(*account1); + ccx.ecx.journaled_state.database.add_persistent_account(*account0); + ccx.ecx.journaled_state.database.add_persistent_account(*account1); Ok(Default::default()) } } @@ -172,9 +157,9 @@ impl Cheatcode for makePersistent_1Call { impl Cheatcode for makePersistent_2Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { account0, account1, account2 } = self; - ccx.ecx.db.add_persistent_account(*account0); - ccx.ecx.db.add_persistent_account(*account1); - ccx.ecx.db.add_persistent_account(*account2); + ccx.ecx.journaled_state.database.add_persistent_account(*account0); + ccx.ecx.journaled_state.database.add_persistent_account(*account1); + ccx.ecx.journaled_state.database.add_persistent_account(*account2); Ok(Default::default()) } } @@ -183,7 +168,7 @@ impl Cheatcode for makePersistent_3Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { accounts } = self; for account in accounts { - ccx.ecx.db.add_persistent_account(*account); + ccx.ecx.journaled_state.database.add_persistent_account(*account); } Ok(Default::default()) } @@ -192,7 +177,7 @@ impl Cheatcode for makePersistent_3Call { impl Cheatcode for revokePersistent_0Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { account } = self; - ccx.ecx.db.remove_persistent_account(account); + ccx.ecx.journaled_state.database.remove_persistent_account(account); Ok(Default::default()) } } @@ -201,7 +186,7 @@ impl Cheatcode for revokePersistent_1Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { accounts } = self; for account in accounts { - ccx.ecx.db.remove_persistent_account(account); + ccx.ecx.journaled_state.database.remove_persistent_account(account); } Ok(Default::default()) } @@ -210,15 +195,19 @@ impl Cheatcode for revokePersistent_1Call { impl Cheatcode for isPersistentCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { account } = self; - Ok(ccx.ecx.db.is_persistent(account).abi_encode()) + Ok(ccx.ecx.journaled_state.database.is_persistent(account).abi_encode()) } } impl Cheatcode for rpc_0Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { method, params } = self; - let url = - ccx.ecx.db.active_fork_url().ok_or_else(|| fmt_err!("no active fork URL found"))?; + let url = ccx + .ecx + .journaled_state + .database + .active_fork_url() + .ok_or_else(|| fmt_err!("no active fork URL found"))?; rpc_call(&url, method, params) } } @@ -243,8 +232,12 @@ impl Cheatcode for eth_getLogsCall { bail!("topics array must contain at most 4 elements") } - let url = - ccx.ecx.db.active_fork_url().ok_or_else(|| fmt_err!("no active fork URL found"))?; + let url = ccx + .ecx + .journaled_state + .database + .active_fork_url() + .ok_or_else(|| fmt_err!("no active fork URL found"))?; let provider = ProviderBuilder::new(&url).build()?; let mut filter = Filter::new().address(*target).from_block(from_block).to_block(to_block); for (i, &topic) in topics.iter().enumerate() { @@ -278,14 +271,15 @@ fn create_select_fork(ccx: &mut CheatsCtxt, url_or_alias: &str, block: Option) -> Result { let fork = create_fork_request(ccx, url_or_alias, block)?; - let id = ccx.ecx.db.create_fork(fork)?; + let id = ccx.ecx.journaled_state.database.create_fork(fork)?; Ok(id.abi_encode()) } @@ -298,12 +292,8 @@ fn create_select_fork_at_transaction( check_broadcast(ccx.state)?; let fork = create_fork_request(ccx, url_or_alias, None)?; - let id = ccx.ecx.db.create_select_fork_at_transaction( - fork, - &mut ccx.ecx.env, - &mut ccx.ecx.journaled_state, - *transaction, - )?; + let (db, journal, mut env) = ccx.ecx.as_db_env_and_journal(); + let id = db.create_select_fork_at_transaction(fork, &mut env, journal, *transaction)?; Ok(id.abi_encode()) } @@ -314,7 +304,7 @@ fn create_fork_at_transaction( transaction: &B256, ) -> Result { let fork = create_fork_request(ccx, url_or_alias, None)?; - let id = ccx.ecx.db.create_fork_at_transaction(fork, *transaction)?; + let id = ccx.ecx.journaled_state.database.create_fork_at_transaction(fork, *transaction)?; Ok(id.abi_encode()) } @@ -339,7 +329,7 @@ fn create_fork_request( enable_caching: !ccx.state.config.no_storage_caching && ccx.state.config.rpc_storage_caching.enable_for_endpoint(&url), url, - env: (*ccx.ecx.env).clone(), + env: ccx.ecx.as_env_mut().to_owned(), evm_opts, }; Ok(fork) @@ -359,11 +349,12 @@ fn transact( transaction: B256, fork_id: Option, ) -> Result { - ccx.ecx.db.transact( + let (db, journal, env) = ccx.ecx.as_db_env_and_journal(); + db.transact( fork_id, transaction, - (*ccx.ecx.env).clone(), - &mut ccx.ecx.journaled_state, + env.to_owned(), + journal, &mut *executor.get_inspector(ccx.state), )?; Ok(Default::default()) @@ -374,7 +365,7 @@ fn transact( // Applies to create, select and roll forks actions. // https://github.com/foundry-rs/foundry/issues/8004 fn persist_caller(ccx: &mut CheatsCtxt) { - ccx.ecx.db.add_persistent_account(ccx.caller); + ccx.ecx.journaled_state.database.add_persistent_account(ccx.caller); } /// Performs an Ethereum JSON-RPC request to the given endpoint. diff --git a/crates/cheatcodes/src/evm/mapping.rs b/crates/cheatcodes/src/evm/mapping.rs index e8525908e847a..569d0e0cb7724 100644 --- a/crates/cheatcodes/src/evm/mapping.rs +++ b/crates/cheatcodes/src/evm/mapping.rs @@ -5,7 +5,13 @@ use alloy_primitives::{ Address, B256, U256, }; use alloy_sol_types::SolValue; -use revm::interpreter::{opcode, Interpreter}; +use revm::{ + bytecode::opcode, + interpreter::{ + interpreter_types::{Jumps, MemoryTr}, + Interpreter, + }, +}; /// Recorded mapping slots. #[derive(Clone, Debug, Default)] @@ -117,22 +123,21 @@ fn slot_child<'a>( #[cold] pub(crate) fn step(mapping_slots: &mut AddressHashMap, interpreter: &Interpreter) { - match interpreter.current_opcode() { + match interpreter.bytecode.opcode() { opcode::KECCAK256 => { if interpreter.stack.peek(1) == Ok(U256::from(0x40)) { - let address = interpreter.contract.target_address; + let address = interpreter.input.target_address; let offset = interpreter.stack.peek(0).expect("stack size > 1").saturating_to(); - let data = interpreter.shared_memory.slice(offset, 0x40); + let data = interpreter.memory.slice_len(offset, 0x40); let low = B256::from_slice(&data[..0x20]); let high = B256::from_slice(&data[0x20..]); - let result = keccak256(data); + let result = keccak256(&*data); mapping_slots.entry(address).or_default().seen_sha3.insert(result, (low, high)); } } opcode::SSTORE => { - if let Some(mapping_slots) = mapping_slots.get_mut(&interpreter.contract.target_address) - { + if let Some(mapping_slots) = mapping_slots.get_mut(&interpreter.input.target_address) { if let Ok(slot) = interpreter.stack.peek(0) { mapping_slots.insert(slot.into()); } diff --git a/crates/cheatcodes/src/evm/mock.rs b/crates/cheatcodes/src/evm/mock.rs index fcfea7a9ce87c..dc2c2137ba524 100644 --- a/crates/cheatcodes/src/evm/mock.rs +++ b/crates/cheatcodes/src/evm/mock.rs @@ -1,6 +1,6 @@ -use crate::{inspector::InnerEcx, Cheatcode, Cheatcodes, CheatsCtxt, Result, Vm::*}; +use crate::{Cheatcode, Cheatcodes, CheatsCtxt, Result, Vm::*}; use alloy_primitives::{Address, Bytes, U256}; -use revm::{interpreter::InstructionResult, primitives::Bytecode}; +use revm::{bytecode::Bytecode, context::JournalTr, interpreter::InstructionResult}; use std::{cmp::Ordering, collections::VecDeque}; /// Mocked call data. @@ -49,7 +49,7 @@ impl Cheatcode for clearMockedCallsCall { impl Cheatcode for mockCall_0Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { callee, data, returnData } = self; - let _ = make_acc_non_empty(callee, ccx.ecx)?; + let _ = make_acc_non_empty(callee, ccx)?; mock_call(ccx.state, callee, data, None, returnData, InstructionResult::Return); Ok(Default::default()) @@ -59,7 +59,7 @@ impl Cheatcode for mockCall_0Call { impl Cheatcode for mockCall_1Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { callee, msgValue, data, returnData } = self; - ccx.ecx.load_account(*callee)?; + ccx.ecx.journaled_state.load_account(*callee)?; mock_call(ccx.state, callee, data, Some(msgValue), returnData, InstructionResult::Return); Ok(Default::default()) } @@ -68,7 +68,7 @@ impl Cheatcode for mockCall_1Call { impl Cheatcode for mockCall_2Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { callee, data, returnData } = self; - let _ = make_acc_non_empty(callee, ccx.ecx)?; + let _ = make_acc_non_empty(callee, ccx)?; mock_call( ccx.state, @@ -85,7 +85,7 @@ impl Cheatcode for mockCall_2Call { impl Cheatcode for mockCall_3Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { callee, msgValue, data, returnData } = self; - ccx.ecx.load_account(*callee)?; + ccx.ecx.journaled_state.load_account(*callee)?; mock_call( ccx.state, callee, @@ -101,7 +101,7 @@ impl Cheatcode for mockCall_3Call { impl Cheatcode for mockCalls_0Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { callee, data, returnData } = self; - let _ = make_acc_non_empty(callee, ccx.ecx)?; + let _ = make_acc_non_empty(callee, ccx)?; mock_calls(ccx.state, callee, data, None, returnData, InstructionResult::Return); Ok(Default::default()) @@ -111,7 +111,7 @@ impl Cheatcode for mockCalls_0Call { impl Cheatcode for mockCalls_1Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { callee, msgValue, data, returnData } = self; - ccx.ecx.load_account(*callee)?; + ccx.ecx.journaled_state.load_account(*callee)?; mock_calls(ccx.state, callee, data, Some(msgValue), returnData, InstructionResult::Return); Ok(Default::default()) } @@ -120,7 +120,7 @@ impl Cheatcode for mockCalls_1Call { impl Cheatcode for mockCallRevert_0Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { callee, data, revertData } = self; - let _ = make_acc_non_empty(callee, ccx.ecx)?; + let _ = make_acc_non_empty(callee, ccx)?; mock_call(ccx.state, callee, data, None, revertData, InstructionResult::Revert); Ok(Default::default()) @@ -130,7 +130,7 @@ impl Cheatcode for mockCallRevert_0Call { impl Cheatcode for mockCallRevert_1Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { callee, msgValue, data, revertData } = self; - let _ = make_acc_non_empty(callee, ccx.ecx)?; + let _ = make_acc_non_empty(callee, ccx)?; mock_call(ccx.state, callee, data, Some(msgValue), revertData, InstructionResult::Revert); Ok(Default::default()) @@ -140,7 +140,7 @@ impl Cheatcode for mockCallRevert_1Call { impl Cheatcode for mockCallRevert_2Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { callee, data, revertData } = self; - let _ = make_acc_non_empty(callee, ccx.ecx)?; + let _ = make_acc_non_empty(callee, ccx)?; mock_call( ccx.state, @@ -157,7 +157,7 @@ impl Cheatcode for mockCallRevert_2Call { impl Cheatcode for mockCallRevert_3Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { callee, msgValue, data, revertData } = self; - let _ = make_acc_non_empty(callee, ccx.ecx)?; + let _ = make_acc_non_empty(callee, ccx)?; mock_call( ccx.state, @@ -210,8 +210,8 @@ fn mock_calls( // Etches a single byte onto the account if it is empty to circumvent the `extcodesize` // check Solidity might perform. -fn make_acc_non_empty(callee: &Address, ecx: InnerEcx) -> Result { - let acc = ecx.load_account(*callee)?; +fn make_acc_non_empty(callee: &Address, ecx: &mut CheatsCtxt) -> Result { + let acc = ecx.journaled_state.load_account(*callee)?; let empty_bytecode = acc.info.code.as_ref().is_none_or(Bytecode::is_empty); if empty_bytecode { diff --git a/crates/cheatcodes/src/evm/prank.rs b/crates/cheatcodes/src/evm/prank.rs index 195760e702f46..96ab6cb9df925 100644 --- a/crates/cheatcodes/src/evm/prank.rs +++ b/crates/cheatcodes/src/evm/prank.rs @@ -1,5 +1,6 @@ use crate::{Cheatcode, CheatsCtxt, Result, Vm::*}; use alloy_primitives::Address; +use revm::{context::JournalTr, interpreter::Host}; /// Prank information. #[derive(Clone, Copy, Debug, Default)] @@ -13,7 +14,7 @@ pub struct Prank { /// The address to assign to `tx.origin` pub new_origin: Option
, /// The depth at which the prank was called - pub depth: u64, + pub depth: usize, /// Whether the prank stops by itself after the next call pub single_call: bool, /// Whether the prank should be applied to delegate call @@ -29,7 +30,7 @@ impl Prank { prank_origin: Address, new_caller: Address, new_origin: Option
, - depth: u64, + depth: usize, single_call: bool, delegate_call: bool, ) -> Self { @@ -129,8 +130,11 @@ fn prank( ) -> Result { // Ensure that code exists at `msg.sender` if delegate calling. if delegate_call { - let code = ccx.code(*new_caller)?; - ensure!(!code.is_empty(), "cannot `prank` delegate call from an EOA"); + let code = ccx + .load_account_code(*new_caller) + .ok_or_else(|| eyre::eyre!("cannot `prank` delegate call from an EOA"))?; + + ensure!(!code.data.is_empty(), "cannot `prank` delegate call from an EOA"); } let depth = ccx.ecx.journaled_state.depth(); @@ -147,7 +151,7 @@ fn prank( let prank = Prank::new( ccx.caller, - ccx.ecx.env.tx.caller, + ccx.ecx.tx.caller, *new_caller, new_origin.copied(), depth, diff --git a/crates/cheatcodes/src/evm/record_debug_step.rs b/crates/cheatcodes/src/evm/record_debug_step.rs index 1b1756936652e..bc78c2425c414 100644 --- a/crates/cheatcodes/src/evm/record_debug_step.rs +++ b/crates/cheatcodes/src/evm/record_debug_step.rs @@ -1,7 +1,7 @@ use alloy_primitives::{Bytes, U256}; use foundry_evm_traces::CallTraceArena; -use revm::interpreter::{InstructionResult, OpCode}; +use revm::{bytecode::opcode::OpCode, interpreter::InstructionResult}; use foundry_evm_core::buffer::{get_buffer_accesses, BufferKind}; use revm_inspectors::tracing::types::{CallTraceStep, RecordedMemory, TraceMemberOrder}; diff --git a/crates/cheatcodes/src/fs.rs b/crates/cheatcodes/src/fs.rs index 940d5f6d8ef3c..f1985eb32bbc1 100644 --- a/crates/cheatcodes/src/fs.rs +++ b/crates/cheatcodes/src/fs.rs @@ -12,7 +12,7 @@ use dialoguer::{Input, Password}; use forge_script_sequence::{BroadcastReader, TransactionWithMetadata}; use foundry_common::fs; use foundry_config::fs_permissions::FsAccessKind; -use revm::interpreter::CreateInputs; +use revm::{context::CreateScheme, interpreter::CreateInputs}; use revm_inspectors::tracing::types::CallKind; use semver::Version; use std::{ @@ -97,7 +97,7 @@ impl Cheatcode for closeFileCall { let Self { path } = self; let path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?; - state.context.opened_read_files.remove(&path); + state.test_context.opened_read_files.remove(&path); Ok(Default::default()) } @@ -167,7 +167,7 @@ impl Cheatcode for readLineCall { let path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?; // Get reader for previously opened file to continue reading OR initialize new reader - let reader = match state.context.opened_read_files.entry(path.clone()) { + let reader = match state.test_context.opened_read_files.entry(path.clone()) { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => entry.insert(BufReader::new(fs::open(path)?)), }; @@ -212,7 +212,7 @@ impl Cheatcode for removeFileCall { state.config.ensure_not_foundry_toml(&path)?; // also remove from the set if opened previously - state.context.opened_read_files.remove(&path); + state.test_context.opened_read_files.remove(&path); if state.fs_commit { fs::remove_file(&path)?; @@ -365,11 +365,8 @@ fn deploy_code( bytecode.extend_from_slice(args); } - let scheme = if let Some(salt) = salt { - revm::primitives::CreateScheme::Create2 { salt } - } else { - revm::primitives::CreateScheme::Create - }; + let scheme = + if let Some(salt) = salt { CreateScheme::Create2 { salt } } else { CreateScheme::Create }; let outcome = executor.exec_create( CreateInputs { @@ -753,7 +750,7 @@ impl Cheatcode for getBroadcasts_1Call { impl Cheatcode for getDeployment_0Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { contractName } = self; - let chain_id = ccx.ecx.env.cfg.chain_id; + let chain_id = ccx.ecx.cfg.chain_id; let latest_broadcast = latest_broadcast( contractName, diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index 4664f4da15d7c..e940300b43b25 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -22,6 +22,7 @@ use crate::{ Vm::{self, AccountAccess}, }; use alloy_consensus::BlobTransactionSidecar; +use alloy_evm::eth::EthEvmContext; use alloy_network::TransactionBuilder4844; use alloy_primitives::{ hex, @@ -38,7 +39,7 @@ use foundry_evm_core::{ abi::Vm::stopExpectSafeMemoryCall, backend::{DatabaseError, DatabaseExt, RevertDiagnostic}, constants::{CHEATCODE_ADDRESS, HARDHAT_CONSOLE_ADDRESS, MAGIC_ASSUME}, - utils::new_evm_with_existing_context, + evm::{new_evm_with_existing_context, FoundryEvm}, InspectorExt, }; use foundry_evm_traces::{TracingInspector, TracingInspectorConfig}; @@ -47,16 +48,20 @@ use itertools::Itertools; use proptest::test_runner::{RngAlgorithm, TestRng, TestRunner}; use rand::Rng; use revm::{ + self, + bytecode::{opcode as op, EOF_MAGIC_BYTES}, + context::{result::EVMError, BlockEnv, JournalTr}, + context_interface::{transaction::SignedAuthorization, CreateScheme}, + handler::FrameResult, interpreter::{ - opcode as op, CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, - EOFCreateInputs, EOFCreateKind, Gas, InstructionResult, Interpreter, InterpreterAction, + interpreter_types::{Jumps, LoopControl, MemoryTr}, + CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, EOFCreateInputs, + EOFCreateKind, FrameInput, Gas, Host, InstructionResult, Interpreter, InterpreterAction, InterpreterResult, }, - primitives::{ - BlockEnv, CreateScheme, EVMError, EvmStorageSlot, SignedAuthorization, SpecId, - EOF_MAGIC_BYTES, - }, - EvmContext, InnerEvmContext, Inspector, + primitives::hardfork::SpecId, + state::EvmStorageSlot, + Inspector, Journal, }; use serde_json::Value; use std::{ @@ -71,8 +76,7 @@ use std::{ mod utils; -pub type Ecx<'a, 'b, 'c> = &'a mut EvmContext<&'b mut (dyn DatabaseExt + 'c)>; -pub type InnerEcx<'a, 'b, 'c> = &'a mut InnerEvmContext<&'b mut (dyn DatabaseExt + 'c)>; +pub type Ecx<'a, 'b, 'c> = &'a mut EthEvmContext<&'b mut (dyn DatabaseExt + 'c)>; /// Helper trait for obtaining complete [revm::Inspector] instance from mutable reference to /// [Cheatcodes]. @@ -84,46 +88,36 @@ pub trait CheatcodesExecutor { /// [revm::Inspector]. fn get_inspector<'a>(&'a mut self, cheats: &'a mut Cheatcodes) -> Box; - /// Obtains [revm::Evm] instance and executes the given CREATE frame. + /// Obtains [FoundryEvm] instance and executes the given CREATE frame. fn exec_create( &mut self, inputs: CreateInputs, ccx: &mut CheatsCtxt, ) -> Result> { with_evm(self, ccx, |evm| { - evm.context.evm.inner.journaled_state.depth += 1; + evm.inner.data.ctx.journaled_state.depth += 1; // Handle EOF bytecode - let first_frame_or_result = if evm.handler.cfg.spec_id.is_enabled_in(SpecId::OSAKA) && + let frame = if evm.inner.data.ctx.cfg.spec.is_enabled_in(SpecId::OSAKA) && inputs.scheme == CreateScheme::Create && inputs.init_code.starts_with(&EOF_MAGIC_BYTES) { - evm.handler.execution().eofcreate( - &mut evm.context, - Box::new(EOFCreateInputs::new( - inputs.caller, - inputs.value, - inputs.gas_limit, - EOFCreateKind::Tx { initdata: inputs.init_code }, - )), - )? + FrameInput::EOFCreate(Box::new(EOFCreateInputs::new( + inputs.caller, + inputs.value, + inputs.gas_limit, + EOFCreateKind::Tx { initdata: inputs.init_code }, + ))) } else { - evm.handler.execution().create(&mut evm.context, Box::new(inputs))? - }; - - let mut result = match first_frame_or_result { - revm::FrameOrResult::Frame(first_frame) => evm.run_the_loop(first_frame)?, - revm::FrameOrResult::Result(result) => result, + FrameInput::Create(Box::new(inputs)) }; - evm.handler.execution().last_frame_return(&mut evm.context, &mut result)?; - - let outcome = match result { - revm::FrameResult::Call(_) => unreachable!(), - revm::FrameResult::Create(create) | revm::FrameResult::EOFCreate(create) => create, + let outcome = match evm.run_execution(frame)? { + FrameResult::Call(_) => unreachable!(), + FrameResult::Create(create) | FrameResult::EOFCreate(create) => create, }; - evm.context.evm.inner.journaled_state.depth -= 1; + evm.inner.data.ctx.journaled_state.depth -= 1; Ok(outcome) }) @@ -139,7 +133,7 @@ pub trait CheatcodesExecutor { } } -/// Constructs [revm::Evm] and runs a given closure with it. +/// Constructs [FoundryEvm] and runs a given closure with it. fn with_evm( executor: &mut E, ccx: &mut CheatsCtxt, @@ -148,32 +142,33 @@ fn with_evm( where E: CheatcodesExecutor + ?Sized, F: for<'a, 'b> FnOnce( - &mut revm::Evm<'_, &'b mut dyn InspectorExt, &'a mut dyn DatabaseExt>, + &mut FoundryEvm<'a, &'b mut dyn InspectorExt>, ) -> Result>, { let mut inspector = executor.get_inspector(ccx.state); let error = std::mem::replace(&mut ccx.ecx.error, Ok(())); - let l1_block_info = std::mem::take(&mut ccx.ecx.l1_block_info); - - let inner = revm::InnerEvmContext { - env: ccx.ecx.env.clone(), - journaled_state: std::mem::replace( - &mut ccx.ecx.journaled_state, - revm::JournaledState::new(Default::default(), Default::default()), - ), - db: &mut ccx.ecx.db as &mut dyn DatabaseExt, + + let ctx = EthEvmContext { + block: ccx.ecx.block.clone(), + cfg: ccx.ecx.cfg.clone(), + tx: ccx.ecx.tx.clone(), + journaled_state: Journal { + inner: ccx.ecx.journaled_state.inner.clone(), + database: &mut *ccx.ecx.journaled_state.database as &mut dyn DatabaseExt, + }, + chain: (), error, - l1_block_info, }; - let mut evm = new_evm_with_existing_context(inner, &mut *inspector); + let mut evm = new_evm_with_existing_context(ctx, &mut *inspector); let res = f(&mut evm)?; - ccx.ecx.journaled_state = evm.context.evm.inner.journaled_state; - ccx.ecx.env = evm.context.evm.inner.env; - ccx.ecx.l1_block_info = evm.context.evm.inner.l1_block_info; - ccx.ecx.error = evm.context.evm.inner.error; + ccx.ecx.journaled_state.inner = evm.inner.data.ctx.journaled_state.inner; + ccx.ecx.block = evm.inner.data.ctx.block; + ccx.ecx.tx = evm.inner.data.ctx.tx; + ccx.ecx.cfg = evm.inner.data.ctx.cfg; + ccx.ecx.error = evm.inner.data.ctx.error; Ok(res) } @@ -200,19 +195,19 @@ macro_rules! try_or_return { /// Contains additional, test specific resources that should be kept for the duration of the test #[derive(Debug, Default)] -pub struct Context { +pub struct TestContext { /// Buffered readers for files opened for reading (path => BufReader mapping) pub opened_read_files: HashMap>, } /// Every time we clone `Context`, we want it to be empty -impl Clone for Context { +impl Clone for TestContext { fn clone(&self) -> Self { Default::default() } } -impl Context { +impl TestContext { /// Clears the context. #[inline] pub fn clear(&mut self) { @@ -328,9 +323,9 @@ impl ArbitraryStorage { /// Saves arbitrary storage value for a given address: /// - store value in changed values cache. /// - update account's storage with given value. - pub fn save(&mut self, ecx: InnerEcx, address: Address, slot: U256, data: U256) { + pub fn save(&mut self, ecx: Ecx, address: Address, slot: U256, data: U256) { self.values.get_mut(&address).expect("missing arbitrary address entry").insert(slot, data); - if let Ok(mut account) = ecx.load_account(address) { + if let Ok(mut account) = ecx.journaled_state.load_account(address) { account.storage.insert(slot, EvmStorageSlot::new(data)); } } @@ -340,7 +335,7 @@ impl ArbitraryStorage { /// existing value. /// - if no value was yet generated for given slot, then save new value in cache and update both /// source and target storages. - pub fn copy(&mut self, ecx: InnerEcx, target: Address, slot: U256, new_value: U256) -> U256 { + pub fn copy(&mut self, ecx: Ecx, target: Address, slot: U256, new_value: U256) -> U256 { let source = self.copies.get(&target).expect("missing arbitrary copy target entry"); let storage_cache = self.values.get_mut(source).expect("missing arbitrary source storage"); let value = match storage_cache.get(&slot) { @@ -348,14 +343,14 @@ impl ArbitraryStorage { None => { storage_cache.insert(slot, new_value); // Update source storage with new value. - if let Ok(mut source_account) = ecx.load_account(*source) { + if let Ok(mut source_account) = ecx.journaled_state.load_account(*source) { source_account.storage.insert(slot, EvmStorageSlot::new(new_value)); } new_value } }; // Update target storage with new value. - if let Ok(mut target_account) = ecx.load_account(target) { + if let Ok(mut target_account) = ecx.journaled_state.load_account(target) { target_account.storage.insert(slot, EvmStorageSlot::new(value)); } value @@ -402,13 +397,13 @@ pub struct Cheatcodes { /// /// Used in the cheatcode handler to overwrite the gas price separately from the gas price /// in the execution environment. - pub gas_price: Option, + pub gas_price: Option, /// Address labels pub labels: AddressHashMap, /// Prank information, mapped to the call depth where pranks were added. - pub pranks: BTreeMap, + pub pranks: BTreeMap, /// Expected revert information pub expected_revert: Option, @@ -468,7 +463,7 @@ pub struct Cheatcodes { pub config: Arc, /// Test-scoped context holding data that needs to be reset every test run - pub context: Context, + pub test_context: TestContext, /// Whether to commit FS changes such as file creations, writes and deletes. /// Used to prevent duplicate changes file executing non-committing calls. @@ -554,7 +549,7 @@ impl Cheatcodes { broadcast: Default::default(), broadcastable_transactions: Default::default(), access_list: Default::default(), - context: Default::default(), + test_context: Default::default(), serialized_jsons: Default::default(), eth_deals: Default::default(), gas_metering: Default::default(), @@ -574,7 +569,7 @@ impl Cheatcodes { /// Returns the configured prank at given depth or the first prank configured at a lower depth. /// For example, if pranks configured for depth 1, 3 and 5, the prank for depth 4 is the one /// configured at depth 3. - pub fn get_prank(&self, depth: u64) -> Option<&Prank> { + pub fn get_prank(&self, depth: usize) -> Option<&Prank> { self.pranks.range(..=depth).last().map(|(_, prank)| prank) } @@ -612,17 +607,11 @@ impl Cheatcodes { // ensure the caller is allowed to execute cheatcodes, // but only if the backend is in forking mode - ecx.db.ensure_cheatcode_access_forking_mode(&caller)?; + ecx.journaled_state.database.ensure_cheatcode_access_forking_mode(&caller)?; apply_dispatch( &decoded, - &mut CheatsCtxt { - state: self, - ecx: &mut ecx.inner, - precompiles: &mut ecx.precompiles, - gas_limit: call.gas_limit, - caller, - }, + &mut CheatsCtxt { state: self, ecx, gas_limit: call.gas_limit, caller }, executor, ) } @@ -632,9 +621,11 @@ impl Cheatcodes { /// /// There may be cheatcodes in the constructor of the new contract, in order to allow them /// automatically we need to determine the new address. - fn allow_cheatcodes_on_create(&self, ecx: InnerEcx, caller: Address, created_address: Address) { - if ecx.journaled_state.depth <= 1 || ecx.db.has_cheatcode_access(&caller) { - ecx.db.allow_cheatcode_access(created_address); + fn allow_cheatcodes_on_create(&self, ecx: Ecx, caller: Address, created_address: Address) { + if ecx.journaled_state.depth <= 1 || + ecx.journaled_state.database.has_cheatcode_access(&caller) + { + ecx.journaled_state.database.allow_cheatcode_access(created_address); } } @@ -689,7 +680,6 @@ impl Cheatcodes { }); } - let ecx = &mut ecx.inner; let gas = Gas::new(input.gas_limit()); let curr_depth = ecx.journaled_state.depth(); @@ -699,14 +689,14 @@ impl Cheatcodes { let mut prank_applied = false; // At the target depth we set `msg.sender` - if ecx.journaled_state.depth() == prank.depth { + if curr_depth == prank.depth { input.set_caller(prank.new_caller); prank_applied = true; } // At the target depth, or deeper, we set `tx.origin` if let Some(new_origin) = prank.new_origin { - ecx.env.tx.caller = new_origin; + ecx.tx.caller = new_origin; prank_applied = true; } @@ -721,15 +711,13 @@ impl Cheatcodes { // Apply EIP-2930 access lists. if let Some(access_list) = &self.access_list { - ecx.env.tx.access_list = access_list.to_vec(); + ecx.tx.access_list = access_list.clone() } // Apply our broadcast if let Some(broadcast) = &self.broadcast { if curr_depth >= broadcast.depth && input.caller() == broadcast.original_caller { - if let Err(err) = - ecx.journaled_state.load_account(broadcast.new_origin, &mut ecx.db) - { + if let Err(err) = ecx.journaled_state.load_account(broadcast.new_origin) { return Some(CreateOutcome { result: InterpreterResult { result: InstructionResult::Revert, @@ -740,15 +728,15 @@ impl Cheatcodes { }); } - ecx.env.tx.caller = broadcast.new_origin; + ecx.tx.caller = broadcast.new_origin; if curr_depth == broadcast.depth { input.set_caller(broadcast.new_origin); - let is_fixed_gas_limit = check_if_fixed_gas_limit(ecx, input.gas_limit()); + let is_fixed_gas_limit = check_if_fixed_gas_limit(&ecx, input.gas_limit()); - let account = &ecx.journaled_state.state()[&broadcast.new_origin]; + let account = &ecx.journaled_state.inner.state()[&broadcast.new_origin]; self.broadcastable_transactions.push_back(BroadcastableTransaction { - rpc: ecx.db.active_fork_url(), + rpc: ecx.journaled_state.database.active_fork_url(), transaction: TransactionRequest { from: Some(broadcast.new_origin), to: None, @@ -773,8 +761,8 @@ impl Cheatcodes { if let Some(recorded_account_diffs_stack) = &mut self.recorded_account_diffs_stack { recorded_account_diffs_stack.push(vec![AccountAccess { chainInfo: crate::Vm::ChainInfo { - forkId: ecx.db.active_fork_id().unwrap_or_default(), - chainId: U256::from(ecx.env.cfg.chain_id), + forkId: ecx.journaled_state.db().active_fork_id().unwrap_or_default(), + chainId: U256::from(ecx.cfg.chain_id), }, accessor: input.caller(), account: address, @@ -787,7 +775,7 @@ impl Cheatcodes { reverted: false, deployedCode: Bytes::new(), // updated on (eof)create_end storageAccesses: vec![], // updated on (eof)create_end - depth: curr_depth, + depth: curr_depth as u64, }]); } @@ -799,16 +787,14 @@ impl Cheatcodes { &mut self, ecx: Ecx, call: Option<&CreateInputs>, - mut outcome: CreateOutcome, - ) -> CreateOutcome -where { - let ecx = &mut ecx.inner; + outcome: &mut CreateOutcome, + ) { let curr_depth = ecx.journaled_state.depth(); // Clean up pranks if let Some(prank) = &self.get_prank(curr_depth) { if curr_depth == prank.depth { - ecx.env.tx.caller = prank.prank_origin; + ecx.tx.caller = prank.prank_origin; // Clean single-call prank once we have returned to the original depth if prank.single_call { @@ -820,7 +806,7 @@ where { // Clean up broadcasts if let Some(broadcast) = &self.broadcast { if curr_depth == broadcast.depth { - ecx.env.tx.caller = broadcast.original_origin; + ecx.tx.caller = broadcast.original_origin; // Clean single-call broadcast once we have returned to the original depth if broadcast.single_call { @@ -853,12 +839,10 @@ where { outcome.result.result = InstructionResult::Return; outcome.result.output = retdata; outcome.address = address; - outcome } Err(err) => { outcome.result.result = InstructionResult::Revert; outcome.result.output = err.abi_encode().into(); - outcome } }; } @@ -887,15 +871,14 @@ where { // changes. Depending on what depth the cheat was called at, there // may not be any pending calls to update if execution has // percolated up to a higher depth. - if create_access.depth == ecx.journaled_state.depth() { + let depth = ecx.journaled_state.depth(); + if create_access.depth == depth as u64 { debug_assert_eq!( create_access.kind as u8, crate::Vm::AccountAccessKind::Create as u8 ); if let Some(address) = outcome.address { - if let Ok(created_acc) = - ecx.journaled_state.load_account(address, &mut ecx.db) - { + if let Ok(created_acc) = ecx.journaled_state.load_account(address) { create_access.newBalance = created_acc.info.balance; create_access.deployedCode = created_acc .info @@ -923,13 +906,13 @@ where { // Match the create against expected_creates if !self.expected_creates.is_empty() { if let (Some(address), Some(call)) = (outcome.address, call) { - if let Ok(created_acc) = ecx.journaled_state.load_account(address, &mut ecx.db) { + if let Ok(created_acc) = ecx.journaled_state.load_account(address) { let bytecode = created_acc.info.code.clone().unwrap_or_default().original_bytes(); if let Some((index, _)) = self.expected_creates.iter().find_position(|expected_create| { expected_create.deployer == call.caller && - expected_create.create_scheme.eq(call.scheme) && + expected_create.create_scheme.eq(call.scheme.into()) && expected_create.bytecode == bytecode }) { @@ -938,8 +921,6 @@ where { } } } - - outcome } pub fn call_with_executor( @@ -955,7 +936,7 @@ where { // decreasing sender nonce to ensure that it matches on-chain nonce once we start // broadcasting. if curr_depth == 0 { - let sender = ecx.env.tx.caller; + let sender = ecx.tx.caller; let account = match super::evm::journaled_account(ecx, sender) { Ok(account) => account, Err(err) => { @@ -996,8 +977,6 @@ where { }; } - let ecx = &mut ecx.inner; - if call.target_address == HARDHAT_CONSOLE_ADDRESS { return None; } @@ -1069,7 +1048,7 @@ where { call.target_address = prank.new_caller; call.caller = prank.new_caller; if let Some(new_origin) = prank.new_origin { - ecx.env.tx.caller = new_origin; + ecx.tx.caller = new_origin; } } } @@ -1085,7 +1064,7 @@ where { // At the target depth, or deeper, we set `tx.origin` if let Some(new_origin) = prank.new_origin { - ecx.env.tx.caller = new_origin; + ecx.tx.caller = new_origin; prank_applied = true; } @@ -1100,7 +1079,7 @@ where { // Apply EIP-2930 access lists. if let Some(access_list) = &self.access_list { - ecx.env.tx.access_list = access_list.to_vec(); + ecx.tx.access_list = access_list.clone() } // Apply our broadcast @@ -1113,7 +1092,7 @@ where { // At the target depth we set `msg.sender` & tx.origin. // We are simulating the caller as being an EOA, so *both* must be set to the // broadcast.origin. - ecx.env.tx.caller = broadcast.new_origin; + ecx.tx.caller = broadcast.new_origin; call.caller = broadcast.new_origin; // Add a `legacy` transaction to the VecDeque. We use a legacy transaction here @@ -1121,7 +1100,7 @@ where { // into 1559, in the cli package, relatively easily once we // know the target chain supports EIP-1559. if !call.is_static { - if let Err(err) = ecx.load_account(broadcast.new_origin) { + if let Err(err) = ecx.journaled_state.load_account(broadcast.new_origin) { return Some(CallOutcome { result: InterpreterResult { result: InstructionResult::Revert, @@ -1132,10 +1111,10 @@ where { }); } - let is_fixed_gas_limit = check_if_fixed_gas_limit(ecx, call.gas_limit); + let is_fixed_gas_limit = check_if_fixed_gas_limit(&ecx, call.gas_limit); let account = - ecx.journaled_state.state().get_mut(&broadcast.new_origin).unwrap(); + ecx.journaled_state.inner.state().get_mut(&broadcast.new_origin).unwrap(); let mut tx_req = TransactionRequest { from: Some(broadcast.new_origin), @@ -1143,7 +1122,7 @@ where { value: call.transfer_value(), input: TransactionInput::new(call.input.clone()), nonce: Some(account.info.nonce), - chain_id: Some(ecx.env.cfg.chain_id), + chain_id: Some(ecx.cfg.chain_id), gas: if is_fixed_gas_limit { Some(call.gas_limit) } else { None }, ..Default::default() }; @@ -1178,7 +1157,7 @@ where { } self.broadcastable_transactions.push_back(BroadcastableTransaction { - rpc: ecx.db.active_fork_url(), + rpc: ecx.journaled_state.database.active_fork_url(), transaction: tx_req.into(), }); debug!(target: "cheatcodes", tx=?self.broadcastable_transactions.back().unwrap(), "broadcastable call"); @@ -1210,7 +1189,7 @@ where { // nonce, a non-zero KECCAK_EMPTY codehash, or non-empty code let initialized; let old_balance; - if let Ok(acc) = ecx.load_account(call.target_address) { + if let Ok(acc) = ecx.journaled_state.load_account(call.target_address) { initialized = acc.info.exists(); old_balance = acc.info.balance; } else { @@ -1233,8 +1212,8 @@ where { // as "warm" if the call from which they were accessed is reverted recorded_account_diffs_stack.push(vec![AccountAccess { chainInfo: crate::Vm::ChainInfo { - forkId: ecx.db.active_fork_id().unwrap_or_default(), - chainId: U256::from(ecx.env.cfg.chain_id), + forkId: ecx.journaled_state.db().active_fork_id().unwrap_or_default(), + chainId: U256::from(ecx.cfg.chain_id), }, accessor: call.caller, account: call.bytecode_address, @@ -1247,7 +1226,11 @@ where { reverted: false, deployedCode: Bytes::new(), storageAccesses: vec![], // updated on step - depth: ecx.journaled_state.depth(), + depth: ecx + .journaled_state + .depth() + .try_into() + .expect("journaled state depth exceeds u64"), }]); } @@ -1312,21 +1295,21 @@ where { } } -impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { +impl Inspector> for Cheatcodes { #[inline] fn initialize_interp(&mut self, interpreter: &mut Interpreter, ecx: Ecx) { // When the first interpreter is initialized we've circumvented the balance and gas checks, // so we apply our actual block data with the correct fees and all. if let Some(block) = self.block.take() { - ecx.env.block = block; + ecx.block = block; } if let Some(gas_price) = self.gas_price.take() { - ecx.env.tx.gas_price = gas_price; + ecx.tx.gas_price = gas_price; } // Record gas for current frame. if self.gas_metering.paused { - self.gas_metering.paused_frames.push(interpreter.gas); + self.gas_metering.paused_frames.push(interpreter.control.gas); } // `expectRevert`: track the max call depth during `expectRevert` @@ -1337,7 +1320,7 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { #[inline] fn step(&mut self, interpreter: &mut Interpreter, ecx: Ecx) { - self.pc = interpreter.program_counter(); + self.pc = interpreter.bytecode.pc(); // `pauseGasMetering`: pause / resume interpreter gas. if self.gas_metering.paused { @@ -1361,7 +1344,10 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { // `expectSafeMemory`: check if the current opcode is allowed to interact with memory. if !self.allowed_mem_writes.is_empty() { - self.check_mem_opcodes(interpreter, ecx.journaled_state.depth()); + self.check_mem_opcodes( + interpreter, + ecx.journaled_state.depth().try_into().expect("journaled state depth exceeds u64"), + ); } // `startMappingRecording`: record SSTORE and KECCAK256. @@ -1391,9 +1377,9 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { } } - fn log(&mut self, interpreter: &mut Interpreter, _ecx: Ecx, log: &Log) { + fn log(&mut self, interpreter: &mut Interpreter, _ecx: Ecx, log: Log) { if !self.expected_emits.is_empty() { - expect::handle_expect_emit(self, log, interpreter); + expect::handle_expect_emit(self, &log, interpreter); } // `recordLogs` @@ -1410,8 +1396,7 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { Self::call_with_executor(self, ecx, inputs, &mut TransparentCheatcodesExecutor) } - fn call_end(&mut self, ecx: Ecx, call: &CallInputs, mut outcome: CallOutcome) -> CallOutcome { - let ecx = &mut ecx.inner; + fn call_end(&mut self, ecx: Ecx, call: &CallInputs, outcome: &mut CallOutcome) { let cheatcode_call = call.target_address == CHEATCODE_ADDRESS || call.target_address == HARDHAT_CONSOLE_ADDRESS; @@ -1423,7 +1408,7 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { let curr_depth = ecx.journaled_state.depth(); if let Some(prank) = &self.get_prank(curr_depth) { if curr_depth == prank.depth { - ecx.env.tx.caller = prank.prank_origin; + ecx.tx.caller = prank.prank_origin; // Clean single-call prank once we have returned to the original depth if prank.single_call { @@ -1434,8 +1419,8 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { // Clean up broadcast if let Some(broadcast) = &self.broadcast { - if ecx.journaled_state.depth() == broadcast.depth { - ecx.env.tx.caller = broadcast.original_origin; + if curr_depth == broadcast.depth { + ecx.tx.caller = broadcast.original_origin; // Clean single-call broadcast once we have returned to the original depth if broadcast.single_call { @@ -1452,8 +1437,10 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { if outcome.result.is_revert() && assume_no_revert.reverted_by.is_none() { assume_no_revert.reverted_by = Some(call.target_address); } + // allow multiple cheatcode calls at the same depth - if ecx.journaled_state.depth() <= assume_no_revert.depth && !cheatcode_call { + let curr_depth = ecx.journaled_state.depth(); + if curr_depth <= assume_no_revert.depth && !cheatcode_call { // Discard run if we're at the same depth as cheatcode, call reverted, and no // specific reason was supplied if outcome.result.is_revert() { @@ -1468,7 +1455,6 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { // to reject this run Ok(_) => { outcome.result.output = Error::from(MAGIC_ASSUME).abi_encode().into(); - outcome } // if result is Error, it was an unanticipated revert; should revert // normally @@ -1476,13 +1462,11 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { trace!(expected=?assume_no_revert, ?error, status=?outcome.result.result, "Expected revert mismatch"); outcome.result.result = InstructionResult::Revert; outcome.result.output = error.abi_encode().into(); - outcome } } } else { // Call didn't revert, reset `assume_no_revert` state. self.assume_no_revert = None; - return outcome; } } } @@ -1502,7 +1486,8 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { } } - if ecx.journaled_state.depth() <= expected_revert.depth { + let curr_depth = ecx.journaled_state.depth(); + if curr_depth <= expected_revert.depth { let needs_processing = match expected_revert.kind { ExpectedRevertKind::Default => !cheatcode_call, // `pending_processing` == true means that we're in the `call_end` hook for @@ -1527,7 +1512,6 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { trace!(expected=?expected_revert, ?error, status=?outcome.result.result, "Expected revert mismatch"); outcome.result.result = InstructionResult::Revert; outcome.result.output = error.abi_encode().into(); - outcome } Ok((_, retdata)) => { expected_revert.actual_count += 1; @@ -1536,7 +1520,6 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { } outcome.result.result = InstructionResult::Return; outcome.result.output = retdata; - outcome } }; } @@ -1554,7 +1537,7 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { // Exit early for calls to cheatcodes as other logic is not relevant for cheatcode // invocations if cheatcode_call { - return outcome; + return; } // Record the gas usage of the call, this allows the `lastCallGas` cheatcode to @@ -1591,8 +1574,9 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { // changes. Depending on the depth the cheat was // called at, there may not be any pending // calls to update if execution has percolated up to a higher depth. - if call_access.depth == ecx.journaled_state.depth() { - if let Ok(acc) = ecx.load_account(call.target_address) { + let curr_depth = ecx.journaled_state.depth(); + if call_access.depth == curr_depth as u64 { + if let Ok(acc) = ecx.journaled_state.load_account(call.target_address) { debug_assert!(access_is_call(call_access.kind)); call_access.newBalance = acc.info.balance; } @@ -1625,7 +1609,10 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { let should_check_emits = self .expected_emits .iter() - .any(|(expected, _)| expected.depth == ecx.journaled_state.depth()) && + .any(|(expected, _)| { + let curr_depth = ecx.journaled_state.depth(); + expected.depth == curr_depth + }) && // Ignore staticcalls !call.is_static; if should_check_emits { @@ -1661,7 +1648,7 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { { outcome.result.result = InstructionResult::Revert; outcome.result.output = "log != expected log".abi_encode().into(); - return outcome; + return; } if !expected_counts.is_empty() { @@ -1676,7 +1663,7 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { outcome.result.result = InstructionResult::Revert; outcome.result.output = Error::encode(msg); - return outcome; + return; } // All emits were found, we're good. @@ -1694,21 +1681,22 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { if outcome.result.is_revert() { if let Some(err) = diag { outcome.result.output = Error::encode(err.to_error_msg(&self.labels)); - return outcome; + return; } } // try to diagnose reverts in multi-fork mode where a call is made to an address that does // not exist - if let TxKind::Call(test_contract) = ecx.env.tx.transact_to { + if let TxKind::Call(test_contract) = ecx.tx.kind { // if a call to a different contract than the original test contract returned with // `Stop` we check if the contract actually exists on the active fork - if ecx.db.is_forked_mode() && + if ecx.journaled_state.db().is_forked_mode() && outcome.result.result == InstructionResult::Stop && call.target_address != test_contract { + let journaled_state = ecx.journaled_state.clone(); self.fork_revert_diagnostic = - ecx.db.diagnose_revert(call.target_address, &ecx.journaled_state); + ecx.journaled_state.db().diagnose_revert(call.target_address, &journaled_state); } } @@ -1718,7 +1706,7 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { // earlier error that happened first with unrelated information about // another error when using cheatcodes. if outcome.result.is_revert() { - return outcome; + return; } // If there's not a revert, we can continue on to run the last logic for expect* @@ -1768,7 +1756,7 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { outcome.result.result = InstructionResult::Revert; outcome.result.output = Error::encode(msg); - return outcome; + return; } } } @@ -1787,7 +1775,7 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { }; outcome.result.result = InstructionResult::Revert; outcome.result.output = Error::encode(msg); - return outcome; + return; } // Check for leftover expected creates @@ -1800,23 +1788,15 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { ); outcome.result.result = InstructionResult::Revert; outcome.result.output = Error::encode(msg); - return outcome; } } - - outcome } fn create(&mut self, ecx: Ecx, call: &mut CreateInputs) -> Option { self.create_common(ecx, call) } - fn create_end( - &mut self, - ecx: Ecx, - call: &CreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { + fn create_end(&mut self, ecx: Ecx, call: &CreateInputs, outcome: &mut CreateOutcome) { self.create_end_common(ecx, Some(call), outcome) } @@ -1824,18 +1804,13 @@ impl Inspector<&mut dyn DatabaseExt> for Cheatcodes { self.create_common(ecx, call) } - fn eofcreate_end( - &mut self, - ecx: Ecx, - _call: &EOFCreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { + fn eofcreate_end(&mut self, ecx: Ecx, _call: &EOFCreateInputs, outcome: &mut CreateOutcome) { self.create_end_common(ecx, None, outcome) } } impl InspectorExt for Cheatcodes { - fn should_use_create2_factory(&mut self, ecx: Ecx, inputs: &mut CreateInputs) -> bool { + fn should_use_create2_factory(&mut self, ecx: Ecx, inputs: &CreateInputs) -> bool { if let CreateScheme::Create2 { .. } = inputs.scheme { let depth = ecx.journaled_state.depth(); let target_depth = if let Some(prank) = &self.get_prank(depth) { @@ -1863,29 +1838,36 @@ impl Cheatcodes { fn meter_gas(&mut self, interpreter: &mut Interpreter) { if let Some(paused_gas) = self.gas_metering.paused_frames.last() { // Keep gas constant if paused. - interpreter.gas = *paused_gas; + // Make sure we record the memory changes so that memory expansion is not paused. + let memory = interpreter.control.gas.memory; + interpreter.control.gas = *paused_gas; + interpreter.control.gas.memory = memory; } else { // Record frame paused gas. - self.gas_metering.paused_frames.push(interpreter.gas); + self.gas_metering.paused_frames.push(interpreter.control.gas); } } #[cold] fn meter_gas_record(&mut self, interpreter: &mut Interpreter, ecx: Ecx) { - if matches!(interpreter.instruction_result, InstructionResult::Continue) { + if matches!(interpreter.control.instruction_result, InstructionResult::Continue) { self.gas_metering.gas_records.iter_mut().for_each(|record| { - if ecx.journaled_state.depth() == record.depth { + let curr_depth = ecx.journaled_state.depth(); + if curr_depth == record.depth { // Skip the first opcode of the first call frame as it includes the gas cost of // creating the snapshot. if self.gas_metering.last_gas_used != 0 { - let gas_diff = - interpreter.gas.spent().saturating_sub(self.gas_metering.last_gas_used); + let gas_diff = interpreter + .control + .gas + .spent() + .saturating_sub(self.gas_metering.last_gas_used); record.gas_used = record.gas_used.saturating_add(gas_diff); } // Update `last_gas_used` to the current spent gas for the next iteration to // compare against. - self.gas_metering.last_gas_used = interpreter.gas.spent(); + self.gas_metering.last_gas_used = interpreter.control.gas.spent(); } }); } @@ -1894,27 +1876,27 @@ impl Cheatcodes { #[cold] fn meter_gas_end(&mut self, interpreter: &mut Interpreter) { // Remove recorded gas if we exit frame. - if will_exit(interpreter.instruction_result) { + if will_exit(interpreter.control.instruction_result) { self.gas_metering.paused_frames.pop(); } } #[cold] fn meter_gas_reset(&mut self, interpreter: &mut Interpreter) { - interpreter.gas = Gas::new(interpreter.gas().limit()); + interpreter.control.gas = Gas::new(interpreter.control.gas().limit()); self.gas_metering.reset = false; } #[cold] fn meter_gas_check(&mut self, interpreter: &mut Interpreter) { - if will_exit(interpreter.instruction_result) { + if will_exit(interpreter.control.instruction_result) { // Reset gas if spent is less than refunded. // This can happen if gas was paused / resumed or reset. // https://github.com/foundry-rs/foundry/issues/4370 - if interpreter.gas.spent() < - u64::try_from(interpreter.gas.refunded()).unwrap_or_default() + if interpreter.control.gas.spent() < + u64::try_from(interpreter.control.gas.refunded()).unwrap_or_default() { - interpreter.gas = Gas::new(interpreter.gas.limit()); + interpreter.control.gas = Gas::new(interpreter.control.gas.limit()); } } } @@ -1928,13 +1910,13 @@ impl Cheatcodes { /// - generates arbitrary value and saves it in target address storage. #[cold] fn arbitrary_storage_end(&mut self, interpreter: &mut Interpreter, ecx: Ecx) { - let (key, target_address) = if interpreter.current_opcode() == op::SLOAD { - (try_or_return!(interpreter.stack().peek(0)), interpreter.contract().target_address) + let (key, target_address) = if interpreter.bytecode.opcode() == op::SLOAD { + (try_or_return!(interpreter.stack.peek(0)), interpreter.input.target_address) } else { return }; - let Ok(value) = ecx.sload(target_address, key) else { + let Some(value) = ecx.sload(target_address, key) else { return; }; @@ -1944,7 +1926,7 @@ impl Cheatcodes { if self.has_arbitrary_storage(&target_address) { let arbitrary_value = self.rng().gen(); self.arbitrary_storage.as_mut().unwrap().save( - &mut ecx.inner, + ecx, target_address, key, arbitrary_value, @@ -1952,7 +1934,7 @@ impl Cheatcodes { } else if self.is_arbitrary_storage_copy(&target_address) { let arbitrary_value = self.rng().gen(); self.arbitrary_storage.as_mut().unwrap().copy( - &mut ecx.inner, + ecx, target_address, key, arbitrary_value, @@ -1965,14 +1947,14 @@ impl Cheatcodes { #[cold] fn record_accesses(&mut self, interpreter: &mut Interpreter) { let access = &mut self.accesses; - match interpreter.current_opcode() { + match interpreter.bytecode.opcode() { op::SLOAD => { - let key = try_or_return!(interpreter.stack().peek(0)); - access.record_read(interpreter.contract().target_address, key); + let key = try_or_return!(interpreter.stack.peek(0)); + access.record_read(interpreter.input.target_address, key); } op::SSTORE => { - let key = try_or_return!(interpreter.stack().peek(0)); - access.record_write(interpreter.contract().target_address, key); + let key = try_or_return!(interpreter.stack.peek(0)); + access.record_write(interpreter.input.target_address, key); } _ => {} } @@ -1981,32 +1963,33 @@ impl Cheatcodes { #[cold] fn record_state_diffs(&mut self, interpreter: &mut Interpreter, ecx: Ecx) { let Some(account_accesses) = &mut self.recorded_account_diffs_stack else { return }; - match interpreter.current_opcode() { + match interpreter.bytecode.opcode() { op::SELFDESTRUCT => { // Ensure that we're not selfdestructing a context recording was initiated on let Some(last) = account_accesses.last_mut() else { return }; // get previous balance and initialized status of the target account - let target = try_or_return!(interpreter.stack().peek(0)); + let target = try_or_return!(interpreter.stack.peek(0)); let target = Address::from_word(B256::from(target)); let (initialized, old_balance) = ecx + .journaled_state .load_account(target) .map(|account| (account.info.exists(), account.info.balance)) .unwrap_or_default(); // load balance of this account let value = ecx - .balance(interpreter.contract().target_address) + .balance(interpreter.input.target_address) .map(|b| b.data) .unwrap_or(U256::ZERO); // register access for the target account last.push(crate::Vm::AccountAccess { chainInfo: crate::Vm::ChainInfo { - forkId: ecx.db.active_fork_id().unwrap_or_default(), - chainId: U256::from(ecx.env.cfg.chain_id), + forkId: ecx.journaled_state.database.active_fork_id().unwrap_or_default(), + chainId: U256::from(ecx.cfg.chain_id), }, - accessor: interpreter.contract().target_address, + accessor: interpreter.input.target_address, account: target, kind: crate::Vm::AccountAccessKind::SelfDestruct, initialized, @@ -2017,46 +2000,55 @@ impl Cheatcodes { reverted: false, deployedCode: Bytes::new(), storageAccesses: vec![], - depth: ecx.journaled_state.depth(), + depth: ecx + .journaled_state + .depth() + .try_into() + .expect("journaled state depth exceeds u64"), }); } op::SLOAD => { let Some(last) = account_accesses.last_mut() else { return }; - let key = try_or_return!(interpreter.stack().peek(0)); - let address = interpreter.contract().target_address; + let key = try_or_return!(interpreter.stack.peek(0)); + let address = interpreter.input.target_address; // Try to include present value for informational purposes, otherwise assume // it's not set (zero value) let mut present_value = U256::ZERO; // Try to load the account and the slot's present value - if ecx.load_account(address).is_ok() { - if let Ok(previous) = ecx.sload(address, key) { + if ecx.journaled_state.load_account(address).is_ok() { + if let Some(previous) = ecx.sload(address, key) { present_value = previous.data; } } let access = crate::Vm::StorageAccess { - account: interpreter.contract().target_address, + account: interpreter.input.target_address, slot: key.into(), isWrite: false, previousValue: present_value.into(), newValue: present_value.into(), reverted: false, }; - append_storage_access(last, access, ecx.journaled_state.depth()); + let curr_depth = ecx + .journaled_state + .depth() + .try_into() + .expect("journaled state depth exceeds u64"); + append_storage_access(last, access, curr_depth); } op::SSTORE => { let Some(last) = account_accesses.last_mut() else { return }; - let key = try_or_return!(interpreter.stack().peek(0)); - let value = try_or_return!(interpreter.stack().peek(1)); - let address = interpreter.contract().target_address; + let key = try_or_return!(interpreter.stack.peek(0)); + let value = try_or_return!(interpreter.stack.peek(1)); + let address = interpreter.input.target_address; // Try to load the account and the slot's previous value, otherwise, assume it's // not set (zero value) let mut previous_value = U256::ZERO; - if ecx.load_account(address).is_ok() { - if let Ok(previous) = ecx.sload(address, key) { + if ecx.journaled_state.load_account(address).is_ok() { + if let Some(previous) = ecx.sload(address, key) { previous_value = previous.data; } } @@ -2069,12 +2061,17 @@ impl Cheatcodes { newValue: value.into(), reverted: false, }; - append_storage_access(last, access, ecx.journaled_state.depth()); + let curr_depth = ecx + .journaled_state + .depth() + .try_into() + .expect("journaled state depth exceeds u64"); + append_storage_access(last, access, curr_depth); } // Record account accesses via the EXT family of opcodes op::EXTCODECOPY | op::EXTCODESIZE | op::EXTCODEHASH | op::BALANCE => { - let kind = match interpreter.current_opcode() { + let kind = match interpreter.bytecode.opcode() { op::EXTCODECOPY => crate::Vm::AccountAccessKind::Extcodecopy, op::EXTCODESIZE => crate::Vm::AccountAccessKind::Extcodesize, op::EXTCODEHASH => crate::Vm::AccountAccessKind::Extcodehash, @@ -2082,22 +2079,27 @@ impl Cheatcodes { _ => unreachable!(), }; let address = - Address::from_word(B256::from(try_or_return!(interpreter.stack().peek(0)))); + Address::from_word(B256::from(try_or_return!(interpreter.stack.peek(0)))); let initialized; let balance; - if let Ok(acc) = ecx.load_account(address) { + if let Ok(acc) = ecx.journaled_state.load_account(address) { initialized = acc.info.exists(); balance = acc.info.balance; } else { initialized = false; balance = U256::ZERO; } + let curr_depth = ecx + .journaled_state + .depth() + .try_into() + .expect("journaled state depth exceeds u64"); let account_access = crate::Vm::AccountAccess { chainInfo: crate::Vm::ChainInfo { - forkId: ecx.db.active_fork_id().unwrap_or_default(), - chainId: U256::from(ecx.env.cfg.chain_id), + forkId: ecx.journaled_state.database.active_fork_id().unwrap_or_default(), + chainId: U256::from(ecx.cfg.chain_id), }, - accessor: interpreter.contract().target_address, + accessor: interpreter.input.target_address, account: address, kind, initialized, @@ -2108,7 +2110,7 @@ impl Cheatcodes { reverted: false, deployedCode: Bytes::new(), storageAccesses: vec![], - depth: ecx.journaled_state.depth(), + depth: curr_depth, }; // Record the EXT* call as an account access at the current depth // (future storage accesses will be recorded in a new "Resume" context) @@ -2142,14 +2144,14 @@ impl Cheatcodes { // size of the memory write is implicit, so these cases are hard-coded. macro_rules! mem_opcode_match { ($(($opcode:ident, $offset_depth:expr, $size_depth:expr, $writes:expr)),* $(,)?) => { - match interpreter.current_opcode() { + match interpreter.bytecode.opcode() { //////////////////////////////////////////////////////////////// // OPERATIONS THAT CAN EXPAND/MUTATE MEMORY BY WRITING // //////////////////////////////////////////////////////////////// op::MSTORE => { // The offset of the mstore operation is at the top of the stack. - let offset = try_or_return!(interpreter.stack().peek(0)).saturating_to::(); + let offset = try_or_return!(interpreter.stack.peek(0)).saturating_to::(); // If none of the allowed ranges contain [offset, offset + 32), memory has been // unexpectedly mutated. @@ -2160,7 +2162,7 @@ impl Cheatcodes { // `stopExpectSafeMemory`, this is allowed. It will do so at the current free memory // pointer, which could have been updated to the exclusive upper bound during // execution. - let value = try_or_return!(interpreter.stack().peek(1)).to_be_bytes::<32>(); + let value = try_or_return!(interpreter.stack.peek(1)).to_be_bytes::<32>(); if value[..SELECTOR_LEN] == stopExpectSafeMemoryCall::SELECTOR { return } @@ -2171,7 +2173,7 @@ impl Cheatcodes { } op::MSTORE8 => { // The offset of the mstore8 operation is at the top of the stack. - let offset = try_or_return!(interpreter.stack().peek(0)).saturating_to::(); + let offset = try_or_return!(interpreter.stack.peek(0)).saturating_to::(); // If none of the allowed ranges contain the offset, memory has been // unexpectedly mutated. @@ -2187,12 +2189,12 @@ impl Cheatcodes { op::MLOAD => { // The offset of the mload operation is at the top of the stack - let offset = try_or_return!(interpreter.stack().peek(0)).saturating_to::(); + let offset = try_or_return!(interpreter.stack.peek(0)).saturating_to::(); // If the offset being loaded is >= than the memory size, the // memory is being expanded. If none of the allowed ranges contain // [offset, offset + 32), memory has been unexpectedly mutated. - if offset >= interpreter.shared_memory.len() as u64 && !ranges.iter().any(|range| { + if offset >= interpreter.memory.size() as u64 && !ranges.iter().any(|range| { range.contains(&offset) && range.contains(&(offset + 31)) }) { disallowed_mem_write(offset, 32, interpreter, ranges); @@ -2206,10 +2208,10 @@ impl Cheatcodes { op::CALL => { // The destination offset of the operation is the fifth element on the stack. - let dest_offset = try_or_return!(interpreter.stack().peek(5)).saturating_to::(); + let dest_offset = try_or_return!(interpreter.stack.peek(5)).saturating_to::(); // The size of the data that will be copied is the sixth element on the stack. - let size = try_or_return!(interpreter.stack().peek(6)).saturating_to::(); + let size = try_or_return!(interpreter.stack.peek(6)).saturating_to::(); // If none of the allowed ranges contain [dest_offset, dest_offset + size), // memory outside of the expected ranges has been touched. If the opcode @@ -2225,11 +2227,11 @@ impl Cheatcodes { // SPECIAL CASE: When a call to `stopExpectSafeMemory` is performed, this is allowed. // It allocated calldata at the current free memory pointer, and will attempt to read // from this memory region to perform the call. - let to = Address::from_word(try_or_return!(interpreter.stack().peek(1)).to_be_bytes::<32>().into()); + let to = Address::from_word(try_or_return!(interpreter.stack.peek(1)).to_be_bytes::<32>().into()); if to == CHEATCODE_ADDRESS { - let args_offset = try_or_return!(interpreter.stack().peek(3)).saturating_to::(); - let args_size = try_or_return!(interpreter.stack().peek(4)).saturating_to::(); - let memory_word = interpreter.shared_memory.slice(args_offset, args_size); + let args_offset = try_or_return!(interpreter.stack.peek(3)).saturating_to::(); + let args_size = try_or_return!(interpreter.stack.peek(4)).saturating_to::(); + let memory_word = interpreter.memory.slice_len(args_offset, args_size); if memory_word[..SELECTOR_LEN] == stopExpectSafeMemoryCall::SELECTOR { return } @@ -2242,10 +2244,10 @@ impl Cheatcodes { $(op::$opcode => { // The destination offset of the operation. - let dest_offset = try_or_return!(interpreter.stack().peek($offset_depth)).saturating_to::(); + let dest_offset = try_or_return!(interpreter.stack.peek($offset_depth)).saturating_to::(); // The size of the data that will be copied. - let size = try_or_return!(interpreter.stack().peek($size_depth)).saturating_to::(); + let size = try_or_return!(interpreter.stack.peek($size_depth)).saturating_to::(); // If none of the allowed ranges contain [dest_offset, dest_offset + size), // memory outside of the expected ranges has been touched. If the opcode @@ -2255,7 +2257,7 @@ impl Cheatcodes { range.contains(&(dest_offset + size.saturating_sub(1))) }) && ($writes || [dest_offset, (dest_offset + size).saturating_sub(1)].into_iter().any(|offset| { - offset >= interpreter.shared_memory.len() as u64 + offset >= interpreter.memory.size() as u64 }) ); @@ -2314,11 +2316,11 @@ fn disallowed_mem_write( ranges.iter().map(|r| format!("(0x{:02X}, 0x{:02X}]", r.start, r.end)).join(" U ") ); - interpreter.instruction_result = InstructionResult::Revert; - interpreter.next_action = InterpreterAction::Return { + interpreter.control.instruction_result = InstructionResult::Revert; + interpreter.control.next_action = InterpreterAction::Return { result: InterpreterResult { output: Error::encode(revert_string), - gas: interpreter.gas, + gas: interpreter.control.gas, result: InstructionResult::Revert, }, }; @@ -2326,13 +2328,13 @@ fn disallowed_mem_write( // Determines if the gas limit on a given call was manually set in the script and should therefore // not be overwritten by later estimations -fn check_if_fixed_gas_limit(ecx: InnerEcx, call_gas_limit: u64) -> bool { +fn check_if_fixed_gas_limit(ecx: &Ecx, call_gas_limit: u64) -> bool { // If the gas limit was not set in the source code it is set to the estimated gas left at the // time of the call, which should be rather close to configured gas limit. // TODO: Find a way to reliably make this determination. // For example by generating it in the compilation or EVM simulation process - U256::from(ecx.env.tx.gas_limit) > ecx.env.block.gas_limit && - U256::from(call_gas_limit) <= ecx.env.block.gas_limit + ecx.tx.gas_limit > ecx.block.gas_limit && + call_gas_limit <= ecx.block.gas_limit // Transfers in forge scripts seem to be estimated at 2300 by revm leading to "Intrinsic // gas too low" failure when simulated on chain && call_gas_limit > 2300 diff --git a/crates/cheatcodes/src/inspector/utils.rs b/crates/cheatcodes/src/inspector/utils.rs index a0d7820aa3e27..bd71b2b18622f 100644 --- a/crates/cheatcodes/src/inspector/utils.rs +++ b/crates/cheatcodes/src/inspector/utils.rs @@ -1,4 +1,4 @@ -use super::InnerEcx; +use super::Ecx; use crate::inspector::Cheatcodes; use alloy_primitives::{Address, Bytes, U256}; use revm::interpreter::{CreateInputs, CreateScheme, EOFCreateInputs, EOFCreateKind}; @@ -12,7 +12,7 @@ pub(crate) trait CommonCreateInput { fn scheme(&self) -> Option; fn set_caller(&mut self, caller: Address); fn log_debug(&self, cheatcode: &mut Cheatcodes, scheme: &CreateScheme); - fn allow_cheatcodes(&self, cheatcodes: &mut Cheatcodes, ecx: InnerEcx) -> Address; + fn allow_cheatcodes(&self, cheatcodes: &mut Cheatcodes, ecx: Ecx) -> Address; fn computed_created_address(&self) -> Option
; } @@ -42,7 +42,7 @@ impl CommonCreateInput for &mut CreateInputs { }; debug!(target: "cheatcodes", tx=?cheatcode.broadcastable_transactions.back().unwrap(), "broadcastable {kind}"); } - fn allow_cheatcodes(&self, cheatcodes: &mut Cheatcodes, ecx: InnerEcx) -> Address { + fn allow_cheatcodes(&self, cheatcodes: &mut Cheatcodes, ecx: Ecx) -> Address { let old_nonce = ecx .journaled_state .state @@ -83,7 +83,7 @@ impl CommonCreateInput for &mut EOFCreateInputs { fn log_debug(&self, cheatcode: &mut Cheatcodes, _scheme: &CreateScheme) { debug!(target: "cheatcodes", tx=?cheatcode.broadcastable_transactions.back().unwrap(), "broadcastable eofcreate"); } - fn allow_cheatcodes(&self, cheatcodes: &mut Cheatcodes, ecx: InnerEcx) -> Address { + fn allow_cheatcodes(&self, cheatcodes: &mut Cheatcodes, ecx: Ecx) -> Address { let created_address = <&mut EOFCreateInputs as CommonCreateInput>::computed_created_address(self) .unwrap_or_default(); diff --git a/crates/cheatcodes/src/lib.rs b/crates/cheatcodes/src/lib.rs index 732f55d7e2533..ca45a937b0b63 100644 --- a/crates/cheatcodes/src/lib.rs +++ b/crates/cheatcodes/src/lib.rs @@ -15,15 +15,15 @@ pub extern crate foundry_cheatcodes_spec as spec; #[macro_use] extern crate tracing; +use alloy_evm::eth::EthEvmContext; use alloy_primitives::Address; use foundry_evm_core::backend::DatabaseExt; -use revm::{ContextPrecompiles, InnerEvmContext}; use spec::Status; pub use config::CheatsConfig; pub use error::{Error, ErrorKind, Result}; pub use inspector::{ - BroadcastableTransaction, BroadcastableTransactions, Cheatcodes, CheatcodesExecutor, Context, + BroadcastableTransaction, BroadcastableTransactions, Cheatcodes, CheatcodesExecutor, }; pub use spec::{CheatcodeDef, Vm}; pub use Vm::ForgeContext; @@ -138,9 +138,7 @@ pub struct CheatsCtxt<'cheats, 'evm, 'db, 'db2> { /// The cheatcodes inspector state. pub(crate) state: &'cheats mut Cheatcodes, /// The EVM data. - pub(crate) ecx: &'evm mut InnerEvmContext<&'db mut (dyn DatabaseExt + 'db2)>, - /// The precompiles context. - pub(crate) precompiles: &'evm mut ContextPrecompiles<&'db mut (dyn DatabaseExt + 'db2)>, + pub(crate) ecx: &'evm mut EthEvmContext<&'db mut (dyn DatabaseExt + 'db2)>, /// The original `msg.sender`. pub(crate) caller: Address, /// Gas limit of the current cheatcode call. @@ -148,7 +146,7 @@ pub struct CheatsCtxt<'cheats, 'evm, 'db, 'db2> { } impl<'db, 'db2> std::ops::Deref for CheatsCtxt<'_, '_, 'db, 'db2> { - type Target = InnerEvmContext<&'db mut (dyn DatabaseExt + 'db2)>; + type Target = EthEvmContext<&'db mut (dyn DatabaseExt + 'db2)>; #[inline(always)] fn deref(&self) -> &Self::Target { @@ -166,6 +164,6 @@ impl std::ops::DerefMut for CheatsCtxt<'_, '_, '_, '_> { impl CheatsCtxt<'_, '_, '_, '_> { #[inline] pub(crate) fn is_precompile(&self, address: &Address) -> bool { - self.precompiles.contains(address) + self.ecx.journaled_state.inner.precompiles.contains(address) } } diff --git a/crates/cheatcodes/src/script.rs b/crates/cheatcodes/src/script.rs index 2b3d6fc8efc24..ce27b79253cd3 100644 --- a/crates/cheatcodes/src/script.rs +++ b/crates/cheatcodes/src/script.rs @@ -9,7 +9,12 @@ use alloy_signer_local::PrivateKeySigner; use alloy_sol_types::SolValue; use foundry_wallets::{multi_wallet::MultiWallet, WalletSigner}; use parking_lot::Mutex; -use revm::primitives::{Bytecode, SignedAuthorization, SpecId, KECCAK_EMPTY}; +use revm::{ + bytecode::Bytecode, + context::JournalTr, + context_interface::transaction::SignedAuthorization, + primitives::{hardfork::SpecId, KECCAK_EMPTY}, +}; use std::sync::Arc; impl Cheatcode for broadcast_0Call { @@ -98,7 +103,7 @@ fn attach_delegation( let SignedDelegation { v, r, s, nonce, implementation } = delegation; // Set chain id to 0 if universal deployment is preferred. // See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7702.md#protection-from-malleability-cross-chain - let chain_id = if cross_chain { U256::from(0) } else { U256::from(ccx.ecx.env.cfg.chain_id) }; + let chain_id = if cross_chain { U256::from(0) } else { U256::from(ccx.ecx.cfg.chain_id) }; let auth = Authorization { address: *implementation, nonce: *nonce, chain_id }; let signed_auth = SignedAuthorization::new_unchecked( @@ -126,12 +131,11 @@ fn sign_delegation( let nonce = if let Some(nonce) = nonce { nonce } else { - let authority_acc = - ccx.ecx.journaled_state.load_account(signer.address(), &mut ccx.ecx.db)?; + let authority_acc = ccx.ecx.journaled_state.load_account(signer.address())?; // If we don't have a nonce then use next auth account nonce. authority_acc.data.info.nonce + 1 }; - let chain_id = if cross_chain { U256::from(0) } else { U256::from(ccx.ecx.env.cfg.chain_id) }; + let chain_id = if cross_chain { U256::from(0) } else { U256::from(ccx.ecx.cfg.chain_id) }; let auth = Authorization { address: implementation, nonce, chain_id }; let sig = signer.sign_hash_sync(&auth.signature_hash())?; @@ -153,8 +157,7 @@ fn sign_delegation( fn write_delegation(ccx: &mut CheatsCtxt, auth: SignedAuthorization) -> Result<()> { let authority = auth.recover_authority().map_err(|e| format!("{e}"))?; - let authority_acc = ccx.ecx.journaled_state.load_account(authority, &mut ccx.ecx.db)?; - + let authority_acc = ccx.ecx.journaled_state.load_account(authority)?; if authority_acc.data.info.nonce + 1 != auth.nonce { return Err("invalid nonce".into()); } @@ -174,7 +177,7 @@ impl Cheatcode for attachBlobCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { blob } = self; ensure!( - ccx.ecx.spec_id() >= SpecId::CANCUN, + ccx.ecx.cfg.spec >= SpecId::CANCUN, "`attachBlob` is not supported before the Cancun hard fork; \ see EIP-4844: https://eips.ethereum.org/EIPS/eip-4844" ); @@ -233,7 +236,7 @@ pub struct Broadcast { /// Original `tx.origin` pub original_origin: Address, /// Depth of the broadcast - pub depth: u64, + pub depth: usize, /// Whether the prank stops by itself after the next call pub single_call: bool, } @@ -326,9 +329,9 @@ fn broadcast(ccx: &mut CheatsCtxt, new_origin: Option<&Address>, single_call: bo } let broadcast = Broadcast { - new_origin: new_origin.unwrap_or(ccx.ecx.env.tx.caller), + new_origin: new_origin.unwrap_or(ccx.ecx.tx.caller), original_caller: ccx.caller, - original_origin: ccx.ecx.env.tx.caller, + original_origin: ccx.ecx.tx.caller, depth, single_call, }; diff --git a/crates/cheatcodes/src/test.rs b/crates/cheatcodes/src/test.rs index 9a59430a9264c..bc36accccde12 100644 --- a/crates/cheatcodes/src/test.rs +++ b/crates/cheatcodes/src/test.rs @@ -78,7 +78,7 @@ impl Cheatcode for skip_1Call { if *skipTest { // Skip should not work if called deeper than at test level. // Since we're not returning the magic skip bytes, this will cause a test failure. - ensure!(ccx.ecx.journaled_state.depth() <= 1, "`skip` can only be used at test level"); + ensure!(ccx.ecx.journaled_state.depth <= 1, "`skip` can only be used at test level"); Err([MAGIC_SKIP, reason.as_bytes()].concat().into()) } else { Ok(Default::default()) diff --git a/crates/cheatcodes/src/test/assert.rs b/crates/cheatcodes/src/test/assert.rs index a61cc4b2a2ece..7bb433c88259f 100644 --- a/crates/cheatcodes/src/test/assert.rs +++ b/crates/cheatcodes/src/test/assert.rs @@ -6,6 +6,7 @@ use foundry_evm_core::{ constants::CHEATCODE_ADDRESS, }; use itertools::Itertools; +use revm::context::JournalTr; use std::fmt::{Debug, Display}; const EQ_REL_DELTA_RESOLUTION: U256 = U256::from_limbs([18, 0, 0, 0]); @@ -190,7 +191,11 @@ fn handle_assertion_result( Err(msg.into()) } else { executor.console_log(ccx, &msg); - ccx.ecx.sstore(CHEATCODE_ADDRESS, GLOBAL_FAIL_SLOT, U256::from(1))?; + ccx.ecx.journaled_state.sstore( + CHEATCODE_ADDRESS, + GLOBAL_FAIL_SLOT, + U256::from(1), + )?; Ok(Default::default()) } } diff --git a/crates/cheatcodes/src/test/assume.rs b/crates/cheatcodes/src/test/assume.rs index 74bd79e0964b6..6cdf3e621aece 100644 --- a/crates/cheatcodes/src/test/assume.rs +++ b/crates/cheatcodes/src/test/assume.rs @@ -9,7 +9,7 @@ use std::fmt::Debug; #[derive(Clone, Debug)] pub struct AssumeNoRevert { /// The call depth at which the cheatcode was added. - pub depth: u64, + pub depth: usize, /// Acceptable revert parameters for the next call, to be thrown out if they are encountered; /// reverts with parameters not specified here will count as normal reverts and not rejects /// towards the counter. @@ -56,7 +56,7 @@ impl Cheatcode for assumeCall { impl Cheatcode for assumeNoRevert_0Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { - assume_no_revert(ccx.state, ccx.ecx.journaled_state.depth(), vec![]) + assume_no_revert(ccx.state, ccx.ecx.journaled_state.depth, vec![]) } } @@ -65,7 +65,7 @@ impl Cheatcode for assumeNoRevert_1Call { let Self { potentialRevert } = self; assume_no_revert( ccx.state, - ccx.ecx.journaled_state.depth(), + ccx.ecx.journaled_state.depth, vec![AcceptableRevertParameters::from(potentialRevert)], ) } @@ -76,7 +76,7 @@ impl Cheatcode for assumeNoRevert_2Call { let Self { potentialReverts } = self; assume_no_revert( ccx.state, - ccx.ecx.journaled_state.depth(), + ccx.ecx.journaled_state.depth, potentialReverts.iter().map(AcceptableRevertParameters::from).collect(), ) } @@ -84,7 +84,7 @@ impl Cheatcode for assumeNoRevert_2Call { fn assume_no_revert( state: &mut Cheatcodes, - depth: u64, + depth: usize, parameters: Vec, ) -> Result { ensure!( diff --git a/crates/cheatcodes/src/test/expect.rs b/crates/cheatcodes/src/test/expect.rs index 9c3d79a3767bd..73748458c69c9 100644 --- a/crates/cheatcodes/src/test/expect.rs +++ b/crates/cheatcodes/src/test/expect.rs @@ -8,7 +8,10 @@ use alloy_primitives::{ map::{hash_map::Entry, AddressHashMap, HashMap}, Address, Bytes, LogData as RawLog, U256, }; -use revm::interpreter::{InstructionResult, Interpreter, InterpreterAction, InterpreterResult}; +use revm::{ + context::JournalTr, + interpreter::{InstructionResult, Interpreter, InterpreterAction, InterpreterResult}, +}; use super::revert_handlers::RevertParameters; /// Tracks the expected calls per address. @@ -66,7 +69,7 @@ pub struct ExpectedRevert { /// The expected data returned by the revert, None being any. pub reason: Option>, /// The depth at which the revert is expected. - pub depth: u64, + pub depth: usize, /// The type of expected revert. pub kind: ExpectedRevertKind, /// If true then only the first 4 bytes of expected data returned by the revert are checked. @@ -76,7 +79,7 @@ pub struct ExpectedRevert { /// Address that reverted the call. pub reverted_by: Option
, /// Max call depth reached during next call execution. - pub max_depth: u64, + pub max_depth: usize, /// Number of times this revert is expected. pub count: u64, /// Actual number of times this revert has been seen. @@ -86,7 +89,7 @@ pub struct ExpectedRevert { #[derive(Clone, Debug)] pub struct ExpectedEmit { /// The depth at which we expect this emit to have occurred - pub depth: u64, + pub depth: usize, /// The log we expect pub log: Option, /// The checks to perform: @@ -132,12 +135,20 @@ impl Display for CreateScheme { } } +impl From for CreateScheme { + fn from(scheme: revm::context_interface::CreateScheme) -> Self { + match scheme { + revm::context_interface::CreateScheme::Create => Self::Create, + revm::context_interface::CreateScheme::Create2 { .. } => Self::Create2, + } + } +} + impl CreateScheme { - pub fn eq(&self, create_scheme: revm::primitives::CreateScheme) -> bool { + pub fn eq(&self, create_scheme: Self) -> bool { matches!( (self, create_scheme), - (Self::Create, revm::primitives::CreateScheme::Create) | - (Self::Create2, revm::primitives::CreateScheme::Create2 { .. }) + (Self::Create, Self::Create) | (Self::Create2, Self::Create2 { .. }) ) } } @@ -623,14 +634,14 @@ impl Cheatcode for _expectCheatcodeRevert_2Call { impl Cheatcode for expectSafeMemoryCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { min, max } = *self; - expect_safe_memory(ccx.state, min, max, ccx.ecx.journaled_state.depth()) + expect_safe_memory(ccx.state, min, max, ccx.ecx.journaled_state.depth().try_into()?) } } impl Cheatcode for stopExpectSafeMemoryCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self {} = self; - ccx.state.allowed_mem_writes.remove(&ccx.ecx.journaled_state.depth()); + ccx.state.allowed_mem_writes.remove(&ccx.ecx.journaled_state.depth().try_into()?); Ok(Default::default()) } } @@ -638,7 +649,7 @@ impl Cheatcode for stopExpectSafeMemoryCall { impl Cheatcode for expectSafeMemoryCallCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { min, max } = *self; - expect_safe_memory(ccx.state, min, max, ccx.ecx.journaled_state.depth() + 1) + expect_safe_memory(ccx.state, min, max, (ccx.ecx.journaled_state.depth() + 1).try_into()?) } } @@ -742,7 +753,7 @@ fn expect_call( fn expect_emit( state: &mut Cheatcodes, - depth: u64, + depth: usize, checks: [bool; 5], address: Option
, anonymous: bool, @@ -812,11 +823,11 @@ pub(crate) fn handle_expect_emit( .expected_emits .insert(index_to_fill_or_check, (event_to_fill_or_check, count_map)); } else { - interpreter.instruction_result = InstructionResult::Revert; - interpreter.next_action = InterpreterAction::Return { + interpreter.control.instruction_result = InstructionResult::Revert; + interpreter.control.next_action = InterpreterAction::Return { result: InterpreterResult { output: Error::encode("use vm.expectEmitAnonymous to match anonymous events"), - gas: interpreter.gas, + gas: interpreter.control.gas, result: InstructionResult::Revert, }, }; @@ -956,7 +967,7 @@ fn expect_create( fn expect_revert( state: &mut Cheatcodes, reason: Option<&[u8]>, - depth: u64, + depth: usize, cheatcode: bool, partial_match: bool, reverter: Option
, diff --git a/crates/cheatcodes/src/utils.rs b/crates/cheatcodes/src/utils.rs index 4735ffaa41087..97b5c7ecd213a 100644 --- a/crates/cheatcodes/src/utils.rs +++ b/crates/cheatcodes/src/utils.rs @@ -8,6 +8,7 @@ use foundry_common::ens::namehash; use foundry_evm_core::constants::DEFAULT_CREATE2_DEPLOYER; use proptest::prelude::Strategy; use rand::{seq::SliceRandom, Rng, RngCore}; +use revm::context::JournalTr; /// Contains locations of traces ignored via cheatcodes. /// @@ -232,9 +233,9 @@ impl Cheatcode for copyStorageCall { "target address cannot have arbitrary storage" ); - if let Ok(from_account) = ccx.load_account(*from) { + if let Ok(from_account) = ccx.ecx.journaled_state.load_account(*from) { let from_storage = from_account.storage.clone(); - if let Ok(mut to_account) = ccx.load_account(*to) { + if let Ok(mut to_account) = ccx.ecx.journaled_state.load_account(*to) { to_account.storage = from_storage; if let Some(ref mut arbitrary_storage) = &mut ccx.state.arbitrary_storage { arbitrary_storage.mark_copy(from, to); diff --git a/crates/common/fmt/Cargo.toml b/crates/common/fmt/Cargo.toml index 2a56b3b10e010..cf4aa5a7ba765 100644 --- a/crates/common/fmt/Cargo.toml +++ b/crates/common/fmt/Cargo.toml @@ -25,7 +25,7 @@ alloy-serde.workspace = true serde.workspace = true serde_json.workspace = true chrono.workspace = true -revm-primitives.workspace = true +revm.workspace = true comfy-table.workspace = true yansi.workspace = true diff --git a/crates/common/fmt/src/eof.rs b/crates/common/fmt/src/eof.rs index 1527d42bb77bc..692d745ebdd29 100644 --- a/crates/common/fmt/src/eof.rs +++ b/crates/common/fmt/src/eof.rs @@ -1,5 +1,6 @@ +use alloy_primitives::hex; use comfy_table::{modifiers::UTF8_ROUND_CORNERS, ContentArrangement, Table}; -use revm_primitives::{ +use revm::bytecode::{ Eof, }; use std::fmt::{self, Write}; @@ -15,11 +16,12 @@ pub fn pretty_eof(eof: &Eof) -> Result { sum_code_sizes: _, sum_container_sizes: _, }, - body: - EofBody { types_section, code_section, container_section, data_section, is_data_filled: _ }, + body, raw: _, } = eof; + let EofBody { code_info, code_section, container_section, data_section, .. } = &body; + let mut result = String::new(); let mut table = Table::new(); @@ -42,13 +44,13 @@ pub fn pretty_eof(eof: &Eof) -> Result { table.apply_modifier(UTF8_ROUND_CORNERS); table.set_content_arrangement(ContentArrangement::Dynamic); table.set_header(vec!["", "Inputs", "Outputs", "Max stack height", "Code"]); - for (idx, (code, type_section)) in code_section.iter().zip(types_section).enumerate() { + for (idx, type_section) in code_info.iter().enumerate() { table.add_row(vec![ &idx.to_string(), &type_section.inputs.to_string(), &type_section.outputs.to_string(), &type_section.max_stack_size.to_string(), - &code.to_string(), + &hex::encode_prefixed(body.code(idx).unwrap_or_default()), ]); } diff --git a/crates/common/fmt/src/ui.rs b/crates/common/fmt/src/ui.rs index 16600324bcb0f..89e18e5620183 100644 --- a/crates/common/fmt/src/ui.rs +++ b/crates/common/fmt/src/ui.rs @@ -12,7 +12,7 @@ use alloy_rpc_types::{ AccessListItem, Block, BlockTransactions, Header, Log, Transaction, TransactionReceipt, }; use alloy_serde::{OtherFields, WithOtherFields}; -use revm_primitives::SignedAuthorization; +use revm::context_interface::transaction::SignedAuthorization; use serde::Deserialize; /// length of the name column for pretty formatting `{:>20}{value}` diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml index 816f06054734f..7f938e3911a20 100644 --- a/crates/config/Cargo.toml +++ b/crates/config/Cargo.toml @@ -19,7 +19,8 @@ foundry-compilers = { workspace = true, features = ["svm-solc"] } alloy-chains = { workspace = true, features = ["serde"] } alloy-primitives = { workspace = true, features = ["serde"] } -revm-primitives.workspace = true + +revm.workspace = true solar-parse.workspace = true diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 2abb5a04cb233..a0f0df4c8637f 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -9,7 +9,7 @@ extern crate tracing; use crate::cache::StorageCachingConfig; -use alloy_primitives::{address, Address, B256, U256}; +use alloy_primitives::{address, map::AddressHashMap, Address, FixedBytes, B256, U256}; use eyre::{ContextCompat, WrapErr}; use figment::{ providers::{Env, Format, Serialized, Toml}, @@ -39,7 +39,7 @@ use foundry_compilers::{ RestrictionsWithVersion, VyperLanguage, }; use regex::Regex; -use revm_primitives::{map::AddressHashMap, FixedBytes, SpecId}; +use revm::primitives::hardfork::SpecId; use semver::Version; use serde::{Deserialize, Serialize, Serializer}; use std::{ diff --git a/crates/config/src/utils.rs b/crates/config/src/utils.rs index 86b25d1043797..bcb20ab698afb 100644 --- a/crates/config/src/utils.rs +++ b/crates/config/src/utils.rs @@ -7,7 +7,7 @@ use foundry_compilers::artifacts::{ remappings::{Remapping, RemappingError}, EvmVersion, }; -use revm_primitives::SpecId; +use revm::primitives::hardfork::SpecId; use serde::{de::Error, Deserialize, Deserializer}; use std::{ io, diff --git a/crates/debugger/src/dump.rs b/crates/debugger/src/dump.rs index 83af7b0e777f7..2d50b4079ed4b 100644 --- a/crates/debugger/src/dump.rs +++ b/crates/debugger/src/dump.rs @@ -5,7 +5,7 @@ use foundry_compilers::{ artifacts::sourcemap::{Jump, SourceElement}, multi::MultiCompilerLanguage, }; -use foundry_evm_core::utils::PcIcMap; +use foundry_evm_core::ic::PcIcMap; use foundry_evm_traces::debug::{ArtifactData, ContractSources, SourceData}; use serde::Serialize; use std::{collections::HashMap, path::Path}; diff --git a/crates/debugger/src/op.rs b/crates/debugger/src/op.rs index bc8e96ccb3997..8e2edce964ae9 100644 --- a/crates/debugger/src/op.rs +++ b/crates/debugger/src/op.rs @@ -1,5 +1,5 @@ use alloy_primitives::Bytes; -use revm::interpreter::opcode; +use revm::bytecode::opcode; /// Named parameter of an EVM opcode. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] diff --git a/crates/debugger/src/tui/context.rs b/crates/debugger/src/tui/context.rs index 0c61a1fcd41c4..a2a4c987a78d6 100644 --- a/crates/debugger/src/tui/context.rs +++ b/crates/debugger/src/tui/context.rs @@ -4,7 +4,7 @@ use crate::{debugger::DebuggerContext, DebugNode, ExitReason}; use alloy_primitives::{hex, Address}; use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers, MouseEvent, MouseEventKind}; use foundry_evm_core::buffer::BufferKind; -use revm::interpreter::OpCode; +use revm::bytecode::opcode::OpCode; use revm_inspectors::tracing::types::{CallKind, CallTraceStep}; use std::ops::ControlFlow; diff --git a/crates/evm/core/Cargo.toml b/crates/evm/core/Cargo.toml index 5730e6fb3ab4a..45097ca47f1fa 100644 --- a/crates/evm/core/Cargo.toml +++ b/crates/evm/core/Cargo.toml @@ -20,6 +20,7 @@ foundry-config.workspace = true foundry-evm-abi.workspace = true alloy-dyn-abi = { workspace = true, features = ["arbitrary", "eip712"] } +alloy-evm.workspace = true alloy-genesis.workspace = true alloy-json-abi.workspace = true alloy-primitives = { workspace = true, features = [ @@ -43,11 +44,13 @@ revm = { workspace = true, features = [ "optional_block_gas_limit", "optional_no_base_fee", "arbitrary", - "optimism", "c-kzg", "blst", + "secp256r1", ] } revm-inspectors.workspace = true +op-revm.workspace = true +alloy-op-evm.workspace = true auto_impl.workspace = true eyre.workspace = true diff --git a/crates/evm/core/src/backend/cow.rs b/crates/evm/core/src/backend/cow.rs index 3ffb9fc84f3cd..4220150e6536b 100644 --- a/crates/evm/core/src/backend/cow.rs +++ b/crates/evm/core/src/backend/cow.rs @@ -3,23 +3,25 @@ use super::BackendError; use crate::{ backend::{ - diagnostic::RevertDiagnostic, Backend, DatabaseExt, LocalForkId, RevertStateSnapshotAction, + diagnostic::RevertDiagnostic, Backend, DatabaseExt, JournaledState, LocalForkId, + RevertStateSnapshotAction, }, fork::{CreateFork, ForkId}, - InspectorExt, + AsEnvMut, Env, EnvMut, InspectorExt, }; +use alloy_evm::Evm; use alloy_genesis::GenesisAccount; use alloy_primitives::{Address, B256, U256}; use alloy_rpc_types::TransactionRequest; use eyre::WrapErr; use foundry_fork_db::DatabaseError; use revm::{ - db::DatabaseRef, - primitives::{ - Account, AccountInfo, Bytecode, Env, EnvWithHandlerCfg, HashMap as Map, ResultAndState, - SpecId, - }, - Database, DatabaseCommit, JournaledState, + bytecode::Bytecode, + context_interface::result::ResultAndState, + database::DatabaseRef, + primitives::{hardfork::SpecId, HashMap as Map}, + state::{Account, AccountInfo}, + Database, DatabaseCommit, }; use std::{borrow::Cow, collections::BTreeMap}; @@ -54,7 +56,7 @@ pub struct CowBackend<'a> { impl<'a> CowBackend<'a> { /// Creates a new `CowBackend` with the given `Backend`. pub fn new_borrowed(backend: &'a Backend) -> Self { - Self { backend: Cow::Borrowed(backend), is_initialized: false, spec_id: SpecId::LATEST } + Self { backend: Cow::Borrowed(backend), is_initialized: false, spec_id: SpecId::default() } } /// Executes the configured transaction of the `env` without committing state changes @@ -64,18 +66,19 @@ impl<'a> CowBackend<'a> { #[instrument(name = "inspect", level = "debug", skip_all)] pub fn inspect( &mut self, - env: &mut EnvWithHandlerCfg, + env: &mut Env, inspector: &mut I, ) -> eyre::Result { // this is a new call to inspect with a new env, so even if we've cloned the backend // already, we reset the initialized state self.is_initialized = false; - self.spec_id = env.handler_cfg.spec_id; - let mut evm = crate::utils::new_evm_with_inspector(self, env.clone(), inspector); + self.spec_id = env.evm_env.cfg_env.spec; + + let mut evm = crate::evm::new_evm_with_inspector(self, env.to_owned(), inspector); - let res = evm.transact().wrap_err("EVM error")?; + let res = evm.transact(env.tx.clone()).wrap_err("EVM error")?; - env.env = evm.context.evm.inner.env; + *env = evm.as_env_mut().to_owned(); Ok(res) } @@ -90,10 +93,11 @@ impl<'a> CowBackend<'a> { /// Returns a mutable instance of the Backend. /// /// If this is the first time this is called, the backed is cloned and initialized. - fn backend_mut(&mut self, env: &Env) -> &mut Backend { + fn backend_mut(&mut self, env: &EnvMut<'_>) -> &mut Backend { if !self.is_initialized { let backend = self.backend.to_mut(); - let env = EnvWithHandlerCfg::new_with_spec_id(Box::new(env.clone()), self.spec_id); + let mut env = env.to_owned(); + env.evm_env.cfg_env.spec = self.spec_id; backend.initialize(&env); self.is_initialized = true; return backend @@ -111,7 +115,7 @@ impl<'a> CowBackend<'a> { } impl DatabaseExt for CowBackend<'_> { - fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &Env) -> U256 { + fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &mut EnvMut<'_>) -> U256 { self.backend_mut(env).snapshot_state(journaled_state, env) } @@ -119,7 +123,7 @@ impl DatabaseExt for CowBackend<'_> { &mut self, id: U256, journaled_state: &JournaledState, - current: &mut Env, + current: &mut EnvMut<'_>, action: RevertStateSnapshotAction, ) -> Option { self.backend_mut(current).revert_state(id, journaled_state, current, action) @@ -154,7 +158,7 @@ impl DatabaseExt for CowBackend<'_> { fn select_fork( &mut self, id: LocalForkId, - env: &mut Env, + env: &mut EnvMut<'_>, journaled_state: &mut JournaledState, ) -> eyre::Result<()> { self.backend_mut(env).select_fork(id, env, journaled_state) @@ -164,7 +168,7 @@ impl DatabaseExt for CowBackend<'_> { &mut self, id: Option, block_number: u64, - env: &mut Env, + env: &mut EnvMut<'_>, journaled_state: &mut JournaledState, ) -> eyre::Result<()> { self.backend_mut(env).roll_fork(id, block_number, env, journaled_state) @@ -174,7 +178,7 @@ impl DatabaseExt for CowBackend<'_> { &mut self, id: Option, transaction: B256, - env: &mut Env, + env: &mut EnvMut<'_>, journaled_state: &mut JournaledState, ) -> eyre::Result<()> { self.backend_mut(env).roll_fork_to_transaction(id, transaction, env, journaled_state) @@ -184,21 +188,32 @@ impl DatabaseExt for CowBackend<'_> { &mut self, id: Option, transaction: B256, - env: Env, + mut env: Env, journaled_state: &mut JournaledState, inspector: &mut dyn InspectorExt, ) -> eyre::Result<()> { - self.backend_mut(&env).transact(id, transaction, env, journaled_state, inspector) + self.backend_mut(&env.as_env_mut()).transact( + id, + transaction, + env, + journaled_state, + inspector, + ) } fn transact_from_tx( &mut self, transaction: &TransactionRequest, - env: Env, + mut env: Env, journaled_state: &mut JournaledState, inspector: &mut dyn InspectorExt, ) -> eyre::Result<()> { - self.backend_mut(&env).transact_from_tx(transaction, env, journaled_state, inspector) + self.backend_mut(&env.as_env_mut()).transact_from_tx( + transaction, + env, + journaled_state, + inspector, + ) } fn active_fork_id(&self) -> Option { @@ -230,7 +245,7 @@ impl DatabaseExt for CowBackend<'_> { allocs: &BTreeMap, journaled_state: &mut JournaledState, ) -> Result<(), BackendError> { - self.backend_mut(&Env::default()).load_allocs(allocs, journaled_state) + self.backend_mut(&Env::default().as_env_mut()).load_allocs(allocs, journaled_state) } fn clone_account( @@ -239,7 +254,11 @@ impl DatabaseExt for CowBackend<'_> { target: &Address, journaled_state: &mut JournaledState, ) -> Result<(), BackendError> { - self.backend_mut(&Env::default()).clone_account(source, target, journaled_state) + self.backend_mut(&Env::default().as_env_mut()).clone_account( + source, + target, + journaled_state, + ) } fn is_persistent(&self, acc: &Address) -> bool { diff --git a/crates/evm/core/src/backend/error.rs b/crates/evm/core/src/backend/error.rs index 1dabeafded152..42456cceadd16 100644 --- a/crates/evm/core/src/backend/error.rs +++ b/crates/evm/core/src/backend/error.rs @@ -1,6 +1,6 @@ use alloy_primitives::Address; pub use foundry_fork_db::{DatabaseError, DatabaseResult}; -use revm::primitives::EVMError; +use revm::context_interface::result::EVMError; use std::convert::Infallible; pub type BackendResult = Result; @@ -59,7 +59,6 @@ impl> From> for BackendError { EVMError::Database(err) => err.into(), EVMError::Custom(err) => Self::msg(err), EVMError::Header(err) => Self::msg(err.to_string()), - EVMError::Precompile(err) => Self::msg(err), EVMError::Transaction(err) => Self::msg(err.to_string()), } } diff --git a/crates/evm/core/src/backend/in_memory_db.rs b/crates/evm/core/src/backend/in_memory_db.rs index c1956f96eb54f..0ffa718fb3671 100644 --- a/crates/evm/core/src/backend/in_memory_db.rs +++ b/crates/evm/core/src/backend/in_memory_db.rs @@ -4,8 +4,10 @@ use crate::state_snapshot::StateSnapshots; use alloy_primitives::{Address, B256, U256}; use foundry_fork_db::DatabaseError; use revm::{ - db::{CacheDB, DatabaseRef, EmptyDB}, - primitives::{Account, AccountInfo, Bytecode, HashMap as Map}, + bytecode::Bytecode, + database::{CacheDB, DatabaseRef, EmptyDB}, + primitives::HashMap as Map, + state::{Account, AccountInfo}, Database, DatabaseCommit, }; diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index 24eab386ee495..49716cd38c84a 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -2,11 +2,13 @@ use crate::{ constants::{CALLER, CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, TEST_CONTRACT_ADDRESS}, + evm::new_evm_with_inspector, fork::{CreateFork, ForkId, MultiFork}, state_snapshot::StateSnapshots, - utils::{configure_tx_env, configure_tx_req_env, new_evm_with_inspector}, - InspectorExt, + utils::{configure_tx_env, configure_tx_req_env}, + AsEnvMut, Env, EnvMut, InspectorExt, }; +use alloy_evm::Evm; use alloy_genesis::GenesisAccount; use alloy_network::{AnyRpcBlock, AnyTxEnvelope, TransactionResponse}; use alloy_primitives::{keccak256, uint, Address, TxKind, B256, U256}; @@ -15,14 +17,15 @@ use eyre::Context; use foundry_common::{is_known_system_sender, SYSTEM_TRANSACTION_TYPE}; pub use foundry_fork_db::{cache::BlockchainDbMeta, BlockchainDb, SharedBackend}; use revm::{ - db::{CacheDB, DatabaseRef}, - inspectors::NoOpInspector, + bytecode::Bytecode, + context::JournalInner, + context_interface::{block::BlobExcessGasAndPrice, result::ResultAndState}, + database::{CacheDB, DatabaseRef}, + inspector::NoOpInspector, precompile::{PrecompileSpecId, Precompiles}, - primitives::{ - Account, AccountInfo, BlobExcessGasAndPrice, Bytecode, Env, EnvWithHandlerCfg, EvmState, - EvmStorageSlot, HashMap as Map, Log, ResultAndState, SpecId, KECCAK_EMPTY, - }, - Database, DatabaseCommit, JournaledState, + primitives::{hardfork::SpecId, HashMap as Map, Log, KECCAK_EMPTY}, + state::{Account, AccountInfo, EvmState, EvmStorageSlot}, + Database, DatabaseCommit, JournalEntry, }; use std::{ collections::{BTreeMap, HashMap, HashSet}, @@ -68,6 +71,8 @@ const DEFAULT_PERSISTENT_ACCOUNTS: [Address; 3] = pub const GLOBAL_FAIL_SLOT: U256 = uint!(0x6661696c65640000000000000000000000000000000000000000000000000000_U256); +pub type JournaledState = JournalInner; + /// An extension trait that allows us to easily extend the `revm::Inspector` capabilities #[auto_impl::auto_impl(&mut)] pub trait DatabaseExt: Database + DatabaseCommit { @@ -76,7 +81,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { /// A state snapshot is associated with a new unique id that's created for the snapshot. /// State snapshots can be reverted: [DatabaseExt::revert_state], however, depending on the /// [RevertStateSnapshotAction], it will keep the snapshot alive or delete it. - fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &Env) -> U256; + fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &mut EnvMut<'_>) -> U256; /// Reverts the snapshot if it exists /// @@ -94,7 +99,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { &mut self, id: U256, journaled_state: &JournaledState, - env: &mut Env, + env: &mut EnvMut<'_>, action: RevertStateSnapshotAction, ) -> Option; @@ -113,7 +118,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { fn create_select_fork( &mut self, fork: CreateFork, - env: &mut Env, + env: &mut EnvMut<'_>, journaled_state: &mut JournaledState, ) -> eyre::Result { let id = self.create_fork(fork)?; @@ -127,7 +132,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { fn create_select_fork_at_transaction( &mut self, fork: CreateFork, - env: &mut Env, + env: &mut EnvMut<'_>, journaled_state: &mut JournaledState, transaction: B256, ) -> eyre::Result { @@ -158,7 +163,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { fn select_fork( &mut self, id: LocalForkId, - env: &mut Env, + env: &mut EnvMut<'_>, journaled_state: &mut JournaledState, ) -> eyre::Result<()>; @@ -173,7 +178,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { &mut self, id: Option, block_number: u64, - env: &mut Env, + env: &mut EnvMut<'_>, journaled_state: &mut JournaledState, ) -> eyre::Result<()>; @@ -189,7 +194,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { &mut self, id: Option, transaction: B256, - env: &mut Env, + env: &mut EnvMut<'_>, journaled_state: &mut JournaledState, ) -> eyre::Result<()>; @@ -433,7 +438,7 @@ pub struct Backend { mem_db: FoundryEvmInMemoryDB, /// The journaled_state to use to initialize new forks with /// - /// The way [`revm::JournaledState`] works is, that it holds the "hot" accounts loaded from the + /// The way [`JournaledState`] works is, that it holds the "hot" accounts loaded from the /// underlying `Database` that feeds the Account and State data to the journaled_state so it /// can apply changes to the state while the EVM executes. /// @@ -738,11 +743,11 @@ impl Backend { /// Initializes settings we need to keep track of. /// /// We need to track these mainly to prevent issues when switching between different evms - pub(crate) fn initialize(&mut self, env: &EnvWithHandlerCfg) { + pub(crate) fn initialize(&mut self, env: &Env) { self.set_caller(env.tx.caller); - self.set_spec_id(env.handler_cfg.spec_id); + self.set_spec_id(env.evm_env.cfg_env.spec); - let test_contract = match env.tx.transact_to { + let test_contract = match env.tx.kind { TxKind::Call(to) => to, TxKind::Create => { let nonce = self @@ -755,11 +760,6 @@ impl Backend { self.set_test_contract(test_contract); } - /// Returns the `EnvWithHandlerCfg` with the current `spec_id` set. - fn env_with_handler_cfg(&self, env: Env) -> EnvWithHandlerCfg { - EnvWithHandlerCfg::new_with_spec_id(Box::new(env), self.inner.spec_id) - } - /// Executes the configured test call of the `env` without committing state changes. /// /// Note: in case there are any cheatcodes executed that modify the environment, this will @@ -767,15 +767,15 @@ impl Backend { #[instrument(name = "inspect", level = "debug", skip_all)] pub fn inspect( &mut self, - env: &mut EnvWithHandlerCfg, + env: &mut Env, inspector: &mut I, ) -> eyre::Result { self.initialize(env); - let mut evm = crate::utils::new_evm_with_inspector(self, env.clone(), inspector); + let mut evm = crate::evm::new_evm_with_inspector(self, env.to_owned(), inspector); - let res = evm.transact().wrap_err("EVM error")?; + let res = evm.transact(env.tx.clone()).wrap_err("EVM error")?; - env.env = evm.context.evm.inner.env; + *env = evm.as_env_mut().to_owned(); Ok(res) } @@ -869,7 +869,7 @@ impl Backend { pub fn replay_until( &mut self, id: LocalForkId, - env: Env, + mut env: Env, tx_hash: B256, journaled_state: &mut JournaledState, ) -> eyre::Result>> { @@ -878,9 +878,8 @@ impl Backend { let persistent_accounts = self.inner.persistent_accounts.clone(); let fork_id = self.ensure_fork_id(id)?.clone(); - let env = self.env_with_handler_cfg(env); let fork = self.inner.get_fork_by_id_mut(id)?; - let full_block = fork.db.db.get_full_block(env.block.number.to::())?; + let full_block = fork.db.db.get_full_block(env.evm_env.block_env.number)?; for tx in full_block.inner.transactions.txns() { // System transactions such as on L2s don't contain any pricing info so we skip them @@ -900,7 +899,7 @@ impl Backend { commit_transaction( &tx.inner, - env.clone(), + &mut env.as_env_mut(), journaled_state, fork, &fork_id, @@ -914,12 +913,12 @@ impl Backend { } impl DatabaseExt for Backend { - fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &Env) -> U256 { + fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &mut EnvMut<'_>) -> U256 { trace!("create snapshot"); let id = self.inner.state_snapshots.insert(BackendStateSnapshot::new( self.create_db_snapshot(), journaled_state.clone(), - env.clone(), + env.to_owned(), )); trace!(target: "backend", "Created new snapshot {}", id); id @@ -929,7 +928,7 @@ impl DatabaseExt for Backend { &mut self, id: U256, current_state: &JournaledState, - current: &mut Env, + current: &mut EnvMut<'_>, action: RevertStateSnapshotAction, ) -> Option { trace!(?id, "revert snapshot"); @@ -970,7 +969,7 @@ impl DatabaseExt for Backend { .map(|acc| acc.info.clone()) .unwrap_or_default(); - if !fork.db.accounts.contains_key(&caller) { + if !fork.db.cache.accounts.contains_key(&caller) { // update the caller account which is required by the evm fork.db.insert_account_info(caller, caller_account.clone()); } @@ -981,7 +980,7 @@ impl DatabaseExt for Backend { } } - update_current_env_with_fork_env(current, env); + update_current_env_with_fork_env(&mut current.as_env_mut(), env); trace!(target: "backend", "Reverted snapshot {}", id); Some(journaled_state) @@ -1027,7 +1026,7 @@ impl DatabaseExt for Backend { self.roll_fork_to_transaction( Some(id), transaction, - &mut env, + &mut env.as_env_mut(), &mut self.inner.new_journaled_state(), )?; Ok(id) @@ -1038,7 +1037,7 @@ impl DatabaseExt for Backend { fn select_fork( &mut self, id: LocalForkId, - env: &mut Env, + env: &mut EnvMut<'_>, active_journaled_state: &mut JournaledState, ) -> eyre::Result<()> { trace!(?id, "select fork"); @@ -1127,7 +1126,7 @@ impl DatabaseExt for Backend { .map(|acc| acc.info.clone()) .unwrap_or_default(); - if !fork.db.accounts.contains_key(&caller) { + if !fork.db.cache.accounts.contains_key(&caller) { // update the caller account which is required by the evm fork.db.insert_account_info(caller, caller_account.clone()); } @@ -1153,7 +1152,7 @@ impl DatabaseExt for Backend { &mut self, id: Option, block_number: u64, - env: &mut Env, + env: &mut EnvMut<'_>, journaled_state: &mut JournaledState, ) -> eyre::Result<()> { trace!(?id, ?block_number, "roll fork"); @@ -1203,7 +1202,7 @@ impl DatabaseExt for Backend { ); } } else { - let _ = active.journaled_state.load_account(*addr, &mut active.db); + let _ = active.journaled_state.load_account(&mut active.db, *addr); } } @@ -1217,7 +1216,7 @@ impl DatabaseExt for Backend { &mut self, id: Option, transaction: B256, - env: &mut Env, + env: &mut EnvMut<'_>, journaled_state: &mut JournaledState, ) -> eyre::Result<()> { trace!(?id, ?transaction, "roll fork to transaction"); @@ -1231,9 +1230,9 @@ impl DatabaseExt for Backend { update_env_block(env, &block); - // replay all transactions that came before - let env = env.clone(); + let env = env.to_owned(); + // replay all transactions that came before self.replay_until(id, env, transaction, journaled_state)?; Ok(()) @@ -1265,13 +1264,12 @@ impl DatabaseExt for Backend { // So we modify the env to match the transaction's block. let (_fork_block, block) = self.get_block_number_and_block_for_transaction(id, transaction)?; - update_env_block(&mut env, &block); + update_env_block(&mut env.as_env_mut(), &block); - let env = self.env_with_handler_cfg(env); let fork = self.inner.get_fork_by_id_mut(id)?; commit_transaction( &tx, - env, + &mut env.as_env_mut(), journaled_state, fork, &fork_id, @@ -1292,13 +1290,12 @@ impl DatabaseExt for Backend { self.commit(journaled_state.state.clone()); let res = { - configure_tx_req_env(&mut env, tx, None)?; - let env = self.env_with_handler_cfg(env); + configure_tx_req_env(&mut env.as_env_mut(), tx, None)?; let mut db = self.clone(); - let mut evm = new_evm_with_inspector(&mut db, env, inspector); - evm.context.evm.journaled_state.depth = journaled_state.depth + 1; - evm.transact()? + let mut evm = new_evm_with_inspector(&mut db, env.to_owned(), inspector); + evm.journaled_state.depth = journaled_state.depth + 1; + evm.transact(env.tx)? }; self.commit(res.state); @@ -1405,7 +1402,7 @@ impl DatabaseExt for Backend { ) -> Result<(), BackendError> { // Fetch the account from the journaled state. Will create a new account if it does // not already exist. - let mut state_acc = journaled_state.load_account(*target, self)?; + let mut state_acc = journaled_state.load_account(self, *target)?; // Set the account's bytecode and code hash, if the `bytecode` field is present. if let Some(bytecode) = source.code.as_ref() { @@ -1439,7 +1436,7 @@ impl DatabaseExt for Backend { state_acc.info.balance = source.balance; // Touch the account to ensure the loaded information persists if called in `setUp`. - journaled_state.touch(target); + journaled_state.touch(*target); Ok(()) } @@ -1474,9 +1471,9 @@ impl DatabaseExt for Backend { fn set_blockhash(&mut self, block_number: U256, block_hash: B256) { if let Some(db) = self.active_fork_db_mut() { - db.block_hashes.insert(block_number, block_hash); + db.cache.block_hashes.insert(block_number.saturating_to(), block_hash); } else { - self.mem_db.block_hashes.insert(block_number, block_hash); + self.mem_db.cache.block_hashes.insert(block_number.saturating_to(), block_hash); } } } @@ -1803,7 +1800,13 @@ impl BackendInner { /// Returns a new, empty, `JournaledState` with set precompiles pub fn new_journaled_state(&self) -> JournaledState { - JournaledState::new(self.spec_id, self.precompiles().addresses().copied().collect()) + let mut journal = { + let mut journal_inner = JournalInner::new(); + journal_inner.set_spec_id(self.spec_id); + journal_inner + }; + journal.precompiles.extend(self.precompiles().addresses().copied()); + journal } } @@ -1819,7 +1822,7 @@ impl Default for BackendInner { caller: None, next_fork_id: Default::default(), persistent_accounts: Default::default(), - spec_id: SpecId::LATEST, + spec_id: SpecId::default(), // grant the cheatcode,default test and caller address access to execute cheatcodes // itself cheatcode_access_accounts: HashSet::from([ @@ -1832,9 +1835,9 @@ impl Default for BackendInner { } /// This updates the currently used env with the fork's environment -pub(crate) fn update_current_env_with_fork_env(current: &mut Env, fork: Env) { - current.block = fork.block; - current.cfg = fork.cfg; +pub(crate) fn update_current_env_with_fork_env(current: &mut EnvMut<'_>, fork: Env) { + *current.block = fork.evm_env.block_env; + *current.cfg = fork.evm_env.cfg_env; current.tx.chain_id = fork.tx.chain_id; } @@ -1886,17 +1889,17 @@ fn merge_db_account_data( ) { trace!(?addr, "merging database data"); - let Some(acc) = active.accounts.get(&addr) else { return }; + let Some(acc) = active.cache.accounts.get(&addr) else { return }; // port contract cache over - if let Some(code) = active.contracts.get(&acc.info.code_hash) { + if let Some(code) = active.cache.contracts.get(&acc.info.code_hash) { trace!("merging contract cache"); - fork_db.contracts.insert(acc.info.code_hash, code.clone()); + fork_db.cache.contracts.insert(acc.info.code_hash, code.clone()); } // port account storage over use std::collections::hash_map::Entry; - match fork_db.accounts.entry(addr) { + match fork_db.cache.accounts.entry(addr) { Entry::Vacant(vacant) => { trace!("target account not present - inserting from active"); // if the fork_db doesn't have the target account @@ -1923,14 +1926,14 @@ fn is_contract_in_state(journaled_state: &JournaledState, acc: Address) -> bool } /// Updates the env's block with the block's data -fn update_env_block(env: &mut Env, block: &AnyRpcBlock) { - env.block.timestamp = U256::from(block.header.timestamp); - env.block.coinbase = block.header.beneficiary; +fn update_env_block(env: &mut EnvMut<'_>, block: &AnyRpcBlock) { + env.block.timestamp = block.header.timestamp; + env.block.beneficiary = block.header.beneficiary; env.block.difficulty = block.header.difficulty; env.block.prevrandao = Some(block.header.mix_hash.unwrap_or_default()); - env.block.basefee = U256::from(block.header.base_fee_per_gas.unwrap_or_default()); - env.block.gas_limit = U256::from(block.header.gas_limit); - env.block.number = U256::from(block.header.number); + env.block.basefee = block.header.base_fee_per_gas.unwrap_or_default(); + env.block.gas_limit = block.header.gas_limit; + env.block.number = block.header.number; if let Some(excess_blob_gas) = block.header.excess_blob_gas { env.block.blob_excess_gas_and_price = Some(BlobExcessGasAndPrice::new(excess_blob_gas, false)); @@ -1941,14 +1944,14 @@ fn update_env_block(env: &mut Env, block: &AnyRpcBlock) { /// state, with an inspector. fn commit_transaction( tx: &Transaction, - mut env: EnvWithHandlerCfg, + env: &mut EnvMut<'_>, journaled_state: &mut JournaledState, fork: &mut Fork, fork_id: &ForkId, persistent_accounts: &HashSet
, inspector: &mut dyn InspectorExt, ) -> eyre::Result<()> { - configure_tx_env(&mut env.env, tx); + configure_tx_env(env, tx); let now = Instant::now(); let res = { @@ -1957,10 +1960,10 @@ fn commit_transaction( let depth = journaled_state.depth; let mut db = Backend::new_with_fork(fork_id, fork, journaled_state)?; - let mut evm = crate::utils::new_evm_with_inspector(&mut db as _, env, inspector); + let mut evm = crate::evm::new_evm_with_inspector(&mut db as _, env.to_owned(), inspector); // Adjust inner EVM depth to ensure that inspectors receive accurate data. - evm.context.evm.inner.journaled_state.depth = depth + 1; - evm.transact().wrap_err("backend: failed committing transaction")? + evm.journaled_state.depth = depth + 1; + evm.transact(env.tx.clone()).wrap_err("backend: failed committing transaction")? }; trace!(elapsed = ?now.elapsed(), "transacted transaction"); @@ -2012,7 +2015,7 @@ mod tests { use foundry_common::provider::get_http_provider; use foundry_config::{Config, NamedChain}; use foundry_fork_db::cache::{BlockchainDb, BlockchainDbMeta}; - use revm::DatabaseRef; + use revm::database::DatabaseRef; const ENDPOINT: Option<&str> = option_env!("ETH_RPC_URL"); @@ -2053,8 +2056,7 @@ mod tests { } drop(backend); - let meta = - BlockchainDbMeta { cfg_env: env.cfg, block_env: env.block, hosts: Default::default() }; + let meta = BlockchainDbMeta { block_env: env.evm_env.block_env, hosts: Default::default() }; let db = BlockchainDb::new( meta, diff --git a/crates/evm/core/src/backend/snapshot.rs b/crates/evm/core/src/backend/snapshot.rs index 36c4657c2618c..d26d9a55e750d 100644 --- a/crates/evm/core/src/backend/snapshot.rs +++ b/crates/evm/core/src/backend/snapshot.rs @@ -1,8 +1,10 @@ -use alloy_primitives::{map::AddressHashMap, B256, U256}; -use revm::{ - primitives::{AccountInfo, Env, HashMap}, - JournaledState, +use super::JournaledState; +use crate::Env; +use alloy_primitives::{ + map::{AddressHashMap, HashMap}, + B256, U256, }; +use revm::state::AccountInfo; use serde::{Deserialize, Serialize}; /// A minimal abstraction of a state at a certain point in time diff --git a/crates/evm/core/src/buffer.rs b/crates/evm/core/src/buffer.rs index 1db7420d78736..5cce0a91ad97b 100644 --- a/crates/evm/core/src/buffer.rs +++ b/crates/evm/core/src/buffer.rs @@ -1,5 +1,5 @@ use alloy_primitives::U256; -use revm::interpreter::opcode; +use revm::bytecode::opcode; /// Used to keep track of which buffer is currently active to be drawn by the debugger. #[derive(Debug, PartialEq)] diff --git a/crates/evm/core/src/either_evm.rs b/crates/evm/core/src/either_evm.rs new file mode 100644 index 0000000000000..1ee289d88a162 --- /dev/null +++ b/crates/evm/core/src/either_evm.rs @@ -0,0 +1,239 @@ +use alloy_evm::{eth::EthEvmContext, Database, EthEvm, Evm, EvmEnv}; +use alloy_op_evm::OpEvm; +use alloy_primitives::{Address, Bytes}; +use op_revm::{OpContext, OpHaltReason, OpSpecId, OpTransaction, OpTransactionError}; +use revm::{ + context::{ + result::{EVMError, ExecutionResult, HaltReason, ResultAndState}, + BlockEnv, TxEnv, + }, + handler::PrecompileProvider, + interpreter::InterpreterResult, + primitives::hardfork::SpecId, + DatabaseCommit, Inspector, +}; + +/// Alias for result type returned by [`Evm::transact`] methods. +type EitherEvmResult = + Result, EVMError>; + +/// Alias for result type returned by [`Evm::transact_commit`] methods. +type EitherExecResult = + Result, EVMError>; + +/// [`EitherEvm`] delegates its calls to one of the two evm implementations; either [`EthEvm`] or +/// [`OpEvm`]. +/// +/// Calls are delegated to [`OpEvm`] only if optimism is enabled. +/// +/// The call delegation is handled via its own implementation of the [`Evm`] trait. +/// +/// The [`Evm::transact`] and other such calls work over the [`OpTransaction`] type. +/// +/// However, the [`Evm::HaltReason`] and [`Evm::Error`] leverage the optimism [`OpHaltReason`] and +/// [`OpTransactionError`] as these are supersets of the eth types. This makes it easier to map eth +/// types to op types and also prevents ignoring of any error that maybe thrown by [`OpEvm`]. +#[allow(clippy::large_enum_variant)] +pub enum EitherEvm +where + DB: Database, +{ + /// [`EthEvm`] implementation. + Eth(EthEvm), + /// [`OpEvm`] implementation. + Op(OpEvm), +} + +impl EitherEvm +where + DB: Database, + I: Inspector> + Inspector>, + P: PrecompileProvider, Output = InterpreterResult> + + PrecompileProvider, Output = InterpreterResult>, +{ + /// Converts the [`EthEvm::transact`] result to [`EitherEvmResult`]. + fn map_eth_result( + &self, + result: Result, EVMError>, + ) -> EitherEvmResult { + match result { + Ok(result) => { + // Map the halt reason + Ok(result.map_haltreason(OpHaltReason::Base)) + } + Err(e) => Err(self.map_eth_err(e)), + } + } + + /// Converts the [`EthEvm::transact_commit`] result to [`EitherExecResult`]. + fn map_exec_result( + &self, + result: Result>, + ) -> EitherExecResult { + match result { + Ok(result) => { + // Map the halt reason + Ok(result.map_haltreason(OpHaltReason::Base)) + } + Err(e) => Err(self.map_eth_err(e)), + } + } + + /// Maps [`EVMError`] to [`EVMError`]. + fn map_eth_err(&self, err: EVMError) -> EVMError { + match err { + EVMError::Transaction(invalid_tx) => { + EVMError::Transaction(OpTransactionError::Base(invalid_tx)) + } + EVMError::Database(e) => EVMError::Database(e), + EVMError::Header(e) => EVMError::Header(e), + EVMError::Custom(e) => EVMError::Custom(e), + } + } +} + +impl Evm for EitherEvm +where + DB: Database, + I: Inspector> + Inspector>, + P: PrecompileProvider, Output = InterpreterResult> + + PrecompileProvider, Output = InterpreterResult>, +{ + type DB = DB; + type Error = EVMError; + type HaltReason = OpHaltReason; + type Tx = OpTransaction; + type Spec = SpecId; + + fn block(&self) -> &BlockEnv { + match self { + Self::Eth(evm) => evm.block(), + Self::Op(evm) => evm.block(), + } + } + + fn db_mut(&mut self) -> &mut Self::DB { + match self { + Self::Eth(evm) => evm.db_mut(), + Self::Op(evm) => evm.db_mut(), + } + } + + fn into_db(self) -> Self::DB + where + Self: Sized, + { + match self { + Self::Eth(evm) => evm.into_db(), + Self::Op(evm) => evm.into_db(), + } + } + + fn finish(self) -> (Self::DB, EvmEnv) + where + Self: Sized, + { + match self { + Self::Eth(evm) => evm.finish(), + Self::Op(evm) => { + let (db, env) = evm.finish(); + (db, map_env(env)) + } + } + } + + fn enable_inspector(&mut self) { + match self { + Self::Eth(evm) => evm.enable_inspector(), + Self::Op(evm) => evm.enable_inspector(), + } + } + + fn disable_inspector(&mut self) { + match self { + Self::Eth(evm) => evm.disable_inspector(), + Self::Op(evm) => evm.disable_inspector(), + } + } + + fn set_inspector_enabled(&mut self, enabled: bool) { + match self { + Self::Eth(evm) => evm.set_inspector_enabled(enabled), + Self::Op(evm) => evm.set_inspector_enabled(enabled), + } + } + + fn into_env(self) -> EvmEnv + where + Self: Sized, + { + match self { + Self::Eth(evm) => evm.into_env(), + Self::Op(evm) => map_env(evm.into_env()), + } + } + + fn transact( + &mut self, + tx: impl alloy_evm::IntoTxEnv, + ) -> Result, Self::Error> { + match self { + Self::Eth(evm) => { + let eth = evm.transact(tx.into_tx_env().base); + self.map_eth_result(eth) + } + Self::Op(evm) => evm.transact(tx), + } + } + + fn transact_commit( + &mut self, + tx: impl alloy_evm::IntoTxEnv, + ) -> Result, Self::Error> + where + Self::DB: DatabaseCommit, + { + match self { + Self::Eth(evm) => { + let eth = evm.transact_commit(tx.into_tx_env().base); + self.map_exec_result(eth) + } + Self::Op(evm) => evm.transact_commit(tx), + } + } + + fn transact_raw( + &mut self, + tx: Self::Tx, + ) -> Result, Self::Error> { + match self { + Self::Eth(evm) => { + let res = evm.transact_raw(tx.base); + self.map_eth_result(res) + } + Self::Op(evm) => evm.transact_raw(tx), + } + } + + fn transact_system_call( + &mut self, + caller: Address, + contract: Address, + data: Bytes, + ) -> Result, Self::Error> { + match self { + Self::Eth(evm) => { + let eth = evm.transact_system_call(caller, contract, data); + self.map_eth_result(eth) + } + Self::Op(evm) => evm.transact_system_call(caller, contract, data), + } + } +} + +/// Maps [`EvmEnv`] to [`EvmEnv`]. +fn map_env(env: EvmEnv) -> EvmEnv { + let eth_spec_id = env.spec_id().into_eth_spec(); + let cfg = env.cfg_env.with_spec(eth_spec_id); + EvmEnv { cfg_env: cfg, block_env: env.block_env } +} diff --git a/crates/evm/core/src/env.rs b/crates/evm/core/src/env.rs new file mode 100644 index 0000000000000..a7708f132380d --- /dev/null +++ b/crates/evm/core/src/env.rs @@ -0,0 +1,103 @@ +pub use alloy_evm::EvmEnv; +use revm::{ + context::{BlockEnv, CfgEnv, JournalInner, JournalTr, TxEnv}, + primitives::hardfork::SpecId, + Context, Database, Journal, JournalEntry, +}; + +/// Helper container type for [`EvmEnv`] and [`TxEnv`]. +#[derive(Clone, Debug, Default)] +pub struct Env { + pub evm_env: EvmEnv, + pub tx: TxEnv, +} + +/// Helper container type for [`EvmEnv`] and [`TxEnv`]. +impl Env { + pub fn default_with_spec_id(spec_id: SpecId) -> Self { + let mut cfg = CfgEnv::default(); + cfg.spec = spec_id; + + Self::from(cfg, BlockEnv::default(), TxEnv::default()) + } + + pub fn from(cfg: CfgEnv, block: BlockEnv, tx: TxEnv) -> Self { + Self { evm_env: EvmEnv { cfg_env: cfg, block_env: block }, tx } + } + + pub fn new_with_spec_id(cfg: CfgEnv, block: BlockEnv, tx: TxEnv, spec_id: SpecId) -> Self { + let mut cfg = cfg; + cfg.spec = spec_id; + + Self::from(cfg, block, tx) + } +} + +/// Helper struct with mutable references to the block and cfg environments. +pub struct EnvMut<'a> { + pub block: &'a mut BlockEnv, + pub cfg: &'a mut CfgEnv, + pub tx: &'a mut TxEnv, +} + +impl EnvMut<'_> { + /// Returns a copy of the environment. + pub fn to_owned(&self) -> Env { + Env { + evm_env: EvmEnv { cfg_env: self.cfg.to_owned(), block_env: self.block.to_owned() }, + tx: self.tx.to_owned(), + } + } +} + +pub trait AsEnvMut { + fn as_env_mut(&mut self) -> EnvMut<'_>; +} + +impl AsEnvMut for EnvMut<'_> { + fn as_env_mut(&mut self) -> EnvMut<'_> { + EnvMut { block: self.block, cfg: self.cfg, tx: self.tx } + } +} + +impl AsEnvMut for Env { + fn as_env_mut(&mut self) -> EnvMut<'_> { + EnvMut { + block: &mut self.evm_env.block_env, + cfg: &mut self.evm_env.cfg_env, + tx: &mut self.tx, + } + } +} + +impl, C> AsEnvMut + for Context +{ + fn as_env_mut(&mut self) -> EnvMut<'_> { + EnvMut { block: &mut self.block, cfg: &mut self.cfg, tx: &mut self.tx } + } +} + +pub trait ContextExt { + type DB: Database; + + fn as_db_env_and_journal( + &mut self, + ) -> (&mut Self::DB, &mut JournalInner, EnvMut<'_>); +} + +impl ContextExt + for Context, C> +{ + type DB = DB; + + fn as_db_env_and_journal( + &mut self, + ) -> (&mut Self::DB, &mut JournalInner, EnvMut<'_>) { + ( + &mut self.journaled_state.database, + &mut self.journaled_state.inner, + EnvMut { block: &mut self.block, cfg: &mut self.cfg, tx: &mut self.tx }, + ) + } +} diff --git a/crates/evm/core/src/evm.rs b/crates/evm/core/src/evm.rs new file mode 100644 index 0000000000000..0f2e678b2f3ae --- /dev/null +++ b/crates/evm/core/src/evm.rs @@ -0,0 +1,371 @@ +use std::ops::{Deref, DerefMut}; + +use crate::{ + backend::DatabaseExt, constants::DEFAULT_CREATE2_DEPLOYER_CODEHASH, Env, InspectorExt, +}; +use alloy_consensus::constants::KECCAK_EMPTY; +use alloy_evm::{eth::EthEvmContext, Evm, EvmEnv}; +use alloy_primitives::{Address, Bytes, U256}; +use foundry_fork_db::DatabaseError; +use revm::{ + context::{ + result::{EVMError, HaltReason, ResultAndState}, + BlockEnv, CfgEnv, ContextTr, CreateScheme, Evm as RevmEvm, JournalTr, TxEnv, + }, + handler::{ + instructions::EthInstructions, EthFrame, EthPrecompiles, FrameInitOrResult, FrameResult, + Handler, ItemOrResult, MainnetHandler, PrecompileProvider, + }, + inspector::InspectorHandler, + interpreter::{ + interpreter::EthInterpreter, return_ok, CallInputs, CallOutcome, CallScheme, CallValue, + CreateInputs, CreateOutcome, FrameInput, Gas, InputsImpl, InstructionResult, + InterpreterResult, + }, + primitives::hardfork::SpecId, + Context, ExecuteEvm, Journal, +}; + +pub struct FoundryPrecompiles { + inner: EthPrecompiles, +} + +impl FoundryPrecompiles { + pub fn new() -> Self { + Self { inner: EthPrecompiles::default() } + } +} + +impl Default for FoundryPrecompiles { + fn default() -> Self { + Self::new() + } +} + +impl PrecompileProvider for FoundryPrecompiles { + type Output = InterpreterResult; + + /// Set the spec for the precompiles. + fn set_spec(&mut self, spec: <::Cfg as revm::context::Cfg>::Spec) -> bool { + PrecompileProvider::::set_spec(&mut self.inner, spec) + } + + /// Run the precompile. + fn run( + &mut self, + context: &mut CTX, + address: &Address, + inputs: &InputsImpl, + is_static: bool, + gas_limit: u64, + ) -> Result, String> { + self.inner.run(context, address, inputs, is_static, gas_limit) + } + + /// Get the warm addresses. + fn warm_addresses(&self) -> Box> { + self.inner.warm_addresses() + } + + /// Check if the address is a precompile. + fn contains(&self, address: &Address) -> bool { + self.inner.contains(address) + } +} + +pub fn new_evm_with_inspector<'i, 'db, I: InspectorExt + ?Sized>( + db: &'db mut dyn DatabaseExt, + env: Env, + inspector: &'i mut I, +) -> FoundryEvm<'db, &'i mut I> { + let ctx = EthEvmContext { + journaled_state: { + let mut journal = Journal::new(db); + journal.set_spec_id(env.evm_env.cfg_env.spec); + journal + }, + block: env.evm_env.block_env, + cfg: env.evm_env.cfg_env, + tx: env.tx, + chain: (), + error: Ok(()), + }; + + FoundryEvm { + inner: RevmEvm::new_with_inspector( + ctx, + inspector, + EthInstructions::default(), + FoundryPrecompiles::default(), + ), + } +} + +pub fn new_evm_with_existing_context<'a>( + ctx: EthEvmContext<&'a mut dyn DatabaseExt>, + inspector: &'a mut dyn InspectorExt, +) -> FoundryEvm<'a, &'a mut dyn InspectorExt> { + FoundryEvm { + inner: RevmEvm::new_with_inspector( + ctx, + inspector, + EthInstructions::default(), + FoundryPrecompiles::default(), + ), + } +} + +fn get_create2_factory_call_inputs( + salt: U256, + inputs: &CreateInputs, + deployer: Address, +) -> CallInputs { + let calldata = [&salt.to_be_bytes::<32>()[..], &inputs.init_code[..]].concat(); + CallInputs { + caller: inputs.caller, + bytecode_address: deployer, + target_address: deployer, + scheme: CallScheme::Call, + value: CallValue::Transfer(inputs.value), + input: calldata.into(), + gas_limit: inputs.gas_limit, + is_static: false, + return_memory_offset: 0..0, + is_eof: false, + } +} + +pub struct FoundryEvm<'db, I: InspectorExt> { + #[allow(clippy::type_complexity)] + pub inner: RevmEvm< + EthEvmContext<&'db mut dyn DatabaseExt>, + I, + EthInstructions>, + FoundryPrecompiles, + >, +} + +impl FoundryEvm<'_, I> { + pub fn run_execution( + &mut self, + frame: FrameInput, + ) -> Result> { + let mut handler = FoundryHandler::<_>::default(); + + // Create first frame action + let frame = handler.inspect_first_frame_init(&mut self.inner, frame)?; + let frame_result = match frame { + ItemOrResult::Item(frame) => handler.inspect_run_exec_loop(&mut self.inner, frame)?, + ItemOrResult::Result(result) => result, + }; + + Ok(frame_result) + } +} + +impl<'db, I: InspectorExt> Evm for FoundryEvm<'db, I> { + type DB = &'db mut dyn DatabaseExt; + type Error = EVMError; + type HaltReason = HaltReason; + type Spec = SpecId; + type Tx = TxEnv; + + fn block(&self) -> &BlockEnv { + &self.inner.block + } + + fn db_mut(&mut self) -> &mut Self::DB { + self.inner.db() + } + + fn set_inspector_enabled(&mut self, _enabled: bool) { + unimplemented!("FoundryEvm is always inspecting") + } + + fn transact_raw( + &mut self, + tx: Self::Tx, + ) -> Result, Self::Error> { + let mut handler = FoundryHandler::<_>::default(); + self.inner.set_tx(tx); + handler.inspect_run(&mut self.inner) + } + + fn transact_system_call( + &mut self, + _caller: Address, + _contract: Address, + _data: Bytes, + ) -> Result, Self::Error> { + unimplemented!() + } + + fn finish(self) -> (Self::DB, EvmEnv) + where + Self: Sized, + { + let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.data.ctx; + + (journaled_state.database, EvmEnv { block_env, cfg_env }) + } +} + +impl<'db, I: InspectorExt> Deref for FoundryEvm<'db, I> { + type Target = Context; + + fn deref(&self) -> &Self::Target { + &self.inner.data.ctx + } +} + +impl DerefMut for FoundryEvm<'_, I> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner.data.ctx + } +} + +pub struct FoundryHandler<'db, I: InspectorExt> { + #[allow(clippy::type_complexity)] + inner: MainnetHandler< + RevmEvm< + EthEvmContext<&'db mut dyn DatabaseExt>, + I, + EthInstructions>, + FoundryPrecompiles, + >, + EVMError, + EthFrame< + RevmEvm< + EthEvmContext<&'db mut dyn DatabaseExt>, + I, + EthInstructions>, + FoundryPrecompiles, + >, + EVMError, + EthInterpreter, + >, + >, + create2_overrides: Vec<(usize, CallInputs)>, +} + +impl Default for FoundryHandler<'_, I> { + fn default() -> Self { + Self { inner: MainnetHandler::default(), create2_overrides: Vec::new() } + } +} + +impl<'db, I: InspectorExt> Handler for FoundryHandler<'db, I> { + type Evm = RevmEvm< + EthEvmContext<&'db mut dyn DatabaseExt>, + I, + EthInstructions>, + FoundryPrecompiles, + >; + type Error = EVMError; + type Frame = EthFrame< + RevmEvm< + EthEvmContext<&'db mut dyn DatabaseExt>, + I, + EthInstructions>, + FoundryPrecompiles, + >, + EVMError, + EthInterpreter, + >; + type HaltReason = HaltReason; + + fn frame_return_result( + &mut self, + frame: &mut Self::Frame, + evm: &mut Self::Evm, + result: ::FrameResult, + ) -> Result<(), Self::Error> { + let result = if self + .create2_overrides + .last() + .is_some_and(|(depth, _)| *depth == evm.journal().depth) + { + let (_, call_inputs) = self.create2_overrides.pop().unwrap(); + let FrameResult::Call(mut result) = result else { + unreachable!("create2 override should be a call frame"); + }; + + // Decode address from output. + let address = match result.instruction_result() { + return_ok!() => Address::try_from(result.output().as_ref()) + .map_err(|_| { + result.result = InterpreterResult { + result: InstructionResult::Revert, + output: "invalid CREATE2 factory output".into(), + gas: Gas::new(call_inputs.gas_limit), + }; + }) + .ok(), + _ => None, + }; + + FrameResult::Create(CreateOutcome { result: result.result, address }) + } else { + result + }; + + self.inner.frame_return_result(frame, evm, result) + } +} + +impl InspectorHandler for FoundryHandler<'_, I> { + type IT = EthInterpreter; + + fn inspect_frame_call( + &mut self, + frame: &mut Self::Frame, + evm: &mut Self::Evm, + ) -> Result, Self::Error> { + let frame_or_result = self.inner.inspect_frame_call(frame, evm)?; + + let ItemOrResult::Item(FrameInput::Create(inputs)) = &frame_or_result else { + return Ok(frame_or_result) + }; + + let CreateScheme::Create2 { salt } = inputs.scheme else { return Ok(frame_or_result) }; + + if !evm.data.inspector.should_use_create2_factory(&mut evm.data.ctx, inputs) { + return Ok(frame_or_result) + } + + let gas_limit = inputs.gas_limit; + + // Get CREATE2 deployer. + let create2_deployer = evm.data.inspector.create2_deployer(); + // Generate call inputs for CREATE2 factory. + let call_inputs = get_create2_factory_call_inputs(salt, inputs, create2_deployer); + + // Push data about current override to the stack. + self.create2_overrides.push((evm.journal().depth(), call_inputs.clone())); + + // Sanity check that CREATE2 deployer exists. + let code_hash = evm.journal().load_account(create2_deployer)?.info.code_hash; + if code_hash == KECCAK_EMPTY { + return Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome { + result: InterpreterResult { + result: InstructionResult::Revert, + output: format!("missing CREATE2 deployer: {create2_deployer}").into(), + gas: Gas::new(gas_limit), + }, + memory_offset: 0..0, + }))) + } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH { + return Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome { + result: InterpreterResult { + result: InstructionResult::Revert, + output: "invalid CREATE2 deployer bytecode".into(), + gas: Gas::new(gas_limit), + }, + memory_offset: 0..0, + }))) + } + + // Return the created CALL frame instead + Ok(ItemOrResult::Item(FrameInput::Call(Box::new(call_inputs)))) + } +} diff --git a/crates/evm/core/src/fork/database.rs b/crates/evm/core/src/fork/database.rs index 53595e451fd2f..30549f028aace 100644 --- a/crates/evm/core/src/fork/database.rs +++ b/crates/evm/core/src/fork/database.rs @@ -9,8 +9,9 @@ use alloy_rpc_types::BlockId; use foundry_fork_db::{BlockchainDb, DatabaseError, SharedBackend}; use parking_lot::Mutex; use revm::{ - db::{CacheDB, DatabaseRef}, - primitives::{Account, AccountInfo, Bytecode}, + bytecode::Bytecode, + database::{CacheDB, DatabaseRef}, + state::{Account, AccountInfo}, Database, DatabaseCommit, }; use std::sync::Arc; @@ -209,7 +210,12 @@ pub struct ForkDbStateSnapshot { impl ForkDbStateSnapshot { fn get_storage(&self, address: Address, index: U256) -> Option { - self.local.accounts.get(&address).and_then(|account| account.storage.get(&index)).copied() + self.local + .cache + .accounts + .get(&address) + .and_then(|account| account.storage.get(&index)) + .copied() } } @@ -220,7 +226,7 @@ impl DatabaseRef for ForkDbStateSnapshot { type Error = DatabaseError; fn basic_ref(&self, address: Address) -> Result, Self::Error> { - match self.local.accounts.get(&address) { + match self.local.cache.accounts.get(&address) { Some(account) => Ok(Some(account.info.clone())), None => { let mut acc = self.state_snapshot.accounts.get(&address).cloned(); @@ -238,7 +244,7 @@ impl DatabaseRef for ForkDbStateSnapshot { } fn storage_ref(&self, address: Address, index: U256) -> Result { - match self.local.accounts.get(&address) { + match self.local.cache.accounts.get(&address) { Some(account) => match account.storage.get(&index) { Some(entry) => Ok(*entry), None => match self.get_storage(address, index) { @@ -274,11 +280,7 @@ mod tests { async fn fork_db_insert_basic_default() { let rpc = foundry_test_utils::rpc::next_http_rpc_endpoint(); let provider = get_http_provider(rpc.clone()); - let meta = BlockchainDbMeta { - cfg_env: Default::default(), - block_env: Default::default(), - hosts: BTreeSet::from([rpc]), - }; + let meta = BlockchainDbMeta { block_env: Default::default(), hosts: BTreeSet::from([rpc]) }; let db = BlockchainDb::new(meta, None); let backend = SharedBackend::spawn_backend(Arc::new(provider), db.clone(), None).await; diff --git a/crates/evm/core/src/fork/init.rs b/crates/evm/core/src/fork/init.rs index c84cd945c4ded..8b23ae5b8531a 100644 --- a/crates/evm/core/src/fork/init.rs +++ b/crates/evm/core/src/fork/init.rs @@ -1,11 +1,11 @@ -use crate::utils::apply_chain_and_block_specific_env_changes; +use crate::{utils::apply_chain_and_block_specific_env_changes, AsEnvMut, Env, EvmEnv}; use alloy_consensus::BlockHeader; -use alloy_primitives::{Address, U256}; +use alloy_primitives::Address; use alloy_provider::{network::BlockResponse, Network, Provider}; use alloy_rpc_types::BlockNumberOrTag; use eyre::WrapErr; use foundry_common::NON_ARCHIVE_NODE_WARNING; -use revm::primitives::{BlockEnv, CfgEnv, Env, TxEnv}; +use revm::context::{BlockEnv, CfgEnv, TxEnv}; /// Initializes a REVM block environment based on a forked /// ethereum provider. @@ -46,38 +46,51 @@ pub async fn environment>( eyre::bail!("failed to get block for block number: {block_number}") }; - let mut cfg = CfgEnv::default(); - cfg.chain_id = override_chain_id.unwrap_or(rpc_chain_id); - cfg.memory_limit = memory_limit; - cfg.limit_contract_code_size = Some(usize::MAX); - // EIP-3607 rejects transactions from senders with deployed code. - // If EIP-3607 is enabled it can cause issues during fuzz/invariant tests if the caller - // is a contract. So we disable the check by default. - cfg.disable_eip3607 = true; - cfg.disable_block_gas_limit = disable_block_gas_limit; + let cfg = configure_env( + override_chain_id.unwrap_or(rpc_chain_id), + memory_limit, + disable_block_gas_limit, + ); let mut env = Env { - cfg, - block: BlockEnv { - number: U256::from(block.header().number()), - timestamp: U256::from(block.header().timestamp()), - coinbase: block.header().beneficiary(), - difficulty: block.header().difficulty(), - prevrandao: block.header().mix_hash(), - basefee: U256::from(block.header().base_fee_per_gas().unwrap_or_default()), - gas_limit: U256::from(block.header().gas_limit()), - ..Default::default() + evm_env: EvmEnv { + cfg_env: cfg, + block_env: BlockEnv { + number: block.header().number(), + timestamp: block.header().timestamp(), + beneficiary: block.header().beneficiary(), + difficulty: block.header().difficulty(), + prevrandao: block.header().mix_hash(), + basefee: block.header().base_fee_per_gas().unwrap_or_default(), + gas_limit: block.header().gas_limit(), + ..Default::default() + }, }, tx: TxEnv { caller: origin, - gas_price: U256::from(gas_price.unwrap_or(fork_gas_price)), + gas_price: gas_price.unwrap_or(fork_gas_price), chain_id: Some(override_chain_id.unwrap_or(rpc_chain_id)), gas_limit: block.header().gas_limit() as u64, ..Default::default() }, }; - apply_chain_and_block_specific_env_changes::(&mut env, &block); + apply_chain_and_block_specific_env_changes::(env.as_env_mut(), &block); Ok((env, block)) } + +/// Configures the environment for the given chain id and memory limit. +pub fn configure_env(chain_id: u64, memory_limit: u64, disable_block_gas_limit: bool) -> CfgEnv { + let mut cfg = CfgEnv::default(); + cfg.chain_id = chain_id; + cfg.memory_limit = memory_limit; + cfg.limit_contract_code_size = Some(usize::MAX); + // EIP-3607 rejects transactions from senders with deployed code. + // If EIP-3607 is enabled it can cause issues during fuzz/invariant tests if the caller + // is a contract. So we disable the check by default. + cfg.disable_eip3607 = true; + cfg.disable_block_gas_limit = disable_block_gas_limit; + cfg.disable_nonce_check = true; + cfg +} diff --git a/crates/evm/core/src/fork/mod.rs b/crates/evm/core/src/fork/mod.rs index 9401c2d32ed58..3049f9f957a63 100644 --- a/crates/evm/core/src/fork/mod.rs +++ b/crates/evm/core/src/fork/mod.rs @@ -1,8 +1,8 @@ use super::opts::EvmOpts; -use revm::primitives::Env; +use crate::Env; mod init; -pub use init::environment; +pub use init::{configure_env, environment}; pub mod database; diff --git a/crates/evm/core/src/fork/multi.rs b/crates/evm/core/src/fork/multi.rs index 2470c315410a2..59a05d67be2f2 100644 --- a/crates/evm/core/src/fork/multi.rs +++ b/crates/evm/core/src/fork/multi.rs @@ -4,8 +4,9 @@ //! concurrently active pairs at once. use super::CreateFork; +use crate::Env; use alloy_consensus::BlockHeader; -use alloy_primitives::{map::HashMap, U256}; +use alloy_primitives::map::HashMap; use alloy_provider::network::BlockResponse; use foundry_common::provider::{ProviderBuilder, RetryProvider}; use foundry_config::Config; @@ -16,7 +17,6 @@ use futures::{ task::{Context, Poll}, Future, FutureExt, StreamExt, }; -use revm::primitives::Env; use std::{ fmt::{self, Write}, pin::Pin, @@ -150,7 +150,7 @@ impl MultiFork { } /// Updates block number and timestamp of given fork with new values. - pub fn update_block(&self, fork: ForkId, number: U256, timestamp: U256) -> eyre::Result<()> { + pub fn update_block(&self, fork: ForkId, number: u64, timestamp: u64) -> eyre::Result<()> { trace!(?fork, ?number, ?timestamp, "update fork block"); self.handler .clone() @@ -200,7 +200,7 @@ enum Request { /// Returns the environment of the fork. GetEnv(ForkId, GetEnvSender), /// Updates the block number and timestamp of the fork. - UpdateBlock(ForkId, U256, U256), + UpdateBlock(ForkId, u64, u64), /// Shutdowns the entire `MultiForkHandler`, see `ShutDownMultiFork` ShutDown(OneshotSender<()>), /// Returns the Fork Url for the `ForkId` if it exists. @@ -302,10 +302,10 @@ impl MultiForkHandler { /// Update fork block number and timestamp. Used to preserve values set by `roll` and `warp` /// cheatcodes when new fork selected. - fn update_block(&mut self, fork_id: ForkId, block_number: U256, block_timestamp: U256) { + fn update_block(&mut self, fork_id: ForkId, block_number: u64, block_timestamp: u64) { if let Some(fork) = self.forks.get_mut(&fork_id) { - fork.opts.env.block.number = block_number; - fork.opts.env.block.timestamp = block_timestamp; + fork.opts.env.evm_env.block_env.number = block_number; + fork.opts.env.evm_env.block_env.timestamp = block_timestamp; } } @@ -519,7 +519,7 @@ async fn create_fork(mut fork: CreateFork) -> eyre::Result<(ForkId, CreatedFork, // Initialise the fork environment. let (env, block) = fork.evm_opts.fork_evm_env(&fork.url).await?; fork.env = env; - let meta = BlockchainDbMeta::new(fork.env.clone(), fork.url.clone()); + let meta = BlockchainDbMeta::new(fork.env.evm_env.block_env.clone(), fork.url.clone()); // We need to use the block number from the block because the env's number can be different on // some L2s (e.g. Arbitrum). @@ -527,7 +527,7 @@ async fn create_fork(mut fork: CreateFork) -> eyre::Result<(ForkId, CreatedFork, // Determine the cache path if caching is enabled. let cache_path = if fork.enable_caching { - Config::foundry_block_cache_dir(meta.cfg_env.chain_id, number) + Config::foundry_block_cache_dir(fork.env.evm_env.cfg_env.chain_id, number) } else { None }; diff --git a/crates/evm/core/src/ic.rs b/crates/evm/core/src/ic.rs index d58193dbefd03..7fc64791ace06 100644 --- a/crates/evm/core/src/ic.rs +++ b/crates/evm/core/src/ic.rs @@ -1,10 +1,6 @@ use alloy_primitives::map::rustc_hash::FxHashMap; use eyre::Result; -use revm::interpreter::{ - opcode::{PUSH0, PUSH1, PUSH32}, - OpCode, -}; -use revm_inspectors::opcode::immediate_size; +use revm::bytecode::opcode::{OpCode, PUSH0, PUSH1, PUSH32}; use serde::Serialize; /// Maps from program counter to instruction counter. @@ -117,8 +113,7 @@ pub fn decode_instructions(code: &[u8]) -> Result> { while pc < code.len() { let op = OpCode::new(code[pc]); let next_pc = pc + 1; - let immediate_size = - op.map(|op| immediate_size(op, &code[next_pc..])).unwrap_or(0) as usize; + let immediate_size = op.map(|op| op.info().immediate_size()).unwrap_or(0) as usize; let is_normal_push = op.map(|op| op.is_push()).unwrap_or(false); if !is_normal_push && next_pc + immediate_size > code.len() { @@ -138,3 +133,51 @@ pub fn decode_instructions(code: &[u8]) -> Result> { Ok(steps) } + +#[cfg(test)] +pub mod tests { + use super::*; + + #[test] + fn decode_push2_and_stop() -> Result<()> { + // 0x61 0xAA 0xBB = PUSH2 0xAABB + // 0x00 = STOP + let code = vec![0x61, 0xAA, 0xBB, 0x00]; + let insns = decode_instructions(&code)?; + + // PUSH2 then STOP + assert_eq!(insns.len(), 2); + + // PUSH2 at pc = 0 + let i0 = &insns[0]; + assert_eq!(i0.pc, 0); + assert_eq!(i0.op, Some(OpCode::PUSH2)); + assert_eq!(i0.immediate.as_ref(), &[0xAA, 0xBB]); + + // STOP at pc = 3 + let i1 = &insns[1]; + assert_eq!(i1.pc, 3); + assert_eq!(i1.op, Some(OpCode::STOP)); + assert!(i1.immediate.is_empty()); + + Ok(()) + } + + #[test] + fn decode_arithmetic_ops() -> Result<()> { + // 0x01 = ADD, 0x02 = MUL, 0x03 = SUB, 0x04 = DIV + let code = vec![0x01, 0x02, 0x03, 0x04]; + let insns = decode_instructions(&code)?; + + assert_eq!(insns.len(), 4); + + let expected = [(0, OpCode::ADD), (1, OpCode::MUL), (2, OpCode::SUB), (3, OpCode::DIV)]; + for ((pc, want_op), insn) in expected.iter().zip(insns.iter()) { + assert_eq!(insn.pc, *pc); + assert_eq!(insn.op, Some(*want_op)); + assert!(insn.immediate.is_empty()); + } + + Ok(()) + } +} diff --git a/crates/evm/core/src/lib.rs b/crates/evm/core/src/lib.rs index cf678551e21d6..76d6be35dd6cb 100644 --- a/crates/evm/core/src/lib.rs +++ b/crates/evm/core/src/lib.rs @@ -6,10 +6,11 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] use crate::constants::DEFAULT_CREATE2_DEPLOYER; +use alloy_evm::eth::EthEvmContext; use alloy_primitives::Address; use auto_impl::auto_impl; use backend::DatabaseExt; -use revm::{inspectors::NoOpInspector, interpreter::CreateInputs, EvmContext, Inspector}; +use revm::{inspector::NoOpInspector, interpreter::CreateInputs, Inspector}; use revm_inspectors::access_list::AccessListInspector; #[macro_use] @@ -20,13 +21,16 @@ pub mod abi { pub use foundry_evm_abi::*; } -mod ic; - +pub mod env; +pub use env::*; pub mod backend; pub mod buffer; pub mod constants; pub mod decode; +pub mod either_evm; +pub mod evm; pub mod fork; +pub mod ic; pub mod opcodes; pub mod opts; pub mod precompiles; @@ -36,15 +40,15 @@ pub mod utils; /// An extension trait that allows us to add additional hooks to Inspector for later use in /// handlers. #[auto_impl(&mut, Box)] -pub trait InspectorExt: for<'a> Inspector<&'a mut dyn DatabaseExt> { +pub trait InspectorExt: for<'a> Inspector> { /// Determines whether the `DEFAULT_CREATE2_DEPLOYER` should be used for a CREATE2 frame. /// /// If this function returns true, we'll replace CREATE2 frame with a CALL frame to CREATE2 /// factory. fn should_use_create2_factory( &mut self, - _context: &mut EvmContext<&mut dyn DatabaseExt>, - _inputs: &mut CreateInputs, + _context: &mut EthEvmContext<&mut dyn DatabaseExt>, + _inputs: &CreateInputs, ) -> bool { false } diff --git a/crates/evm/core/src/opcodes.rs b/crates/evm/core/src/opcodes.rs index 3251036c78f7a..7fad7ca5f3a3e 100644 --- a/crates/evm/core/src/opcodes.rs +++ b/crates/evm/core/src/opcodes.rs @@ -1,6 +1,6 @@ //! Opcode utils -use revm::interpreter::OpCode; +use revm::bytecode::opcode::OpCode; /// Returns true if the opcode modifies memory. /// diff --git a/crates/evm/core/src/opts.rs b/crates/evm/core/src/opts.rs index d135cceb904f9..11a602aab868f 100644 --- a/crates/evm/core/src/opts.rs +++ b/crates/evm/core/src/opts.rs @@ -1,11 +1,15 @@ use super::fork::environment; -use crate::{constants::DEFAULT_CREATE2_DEPLOYER, fork::CreateFork}; +use crate::{ + constants::DEFAULT_CREATE2_DEPLOYER, + fork::{configure_env, CreateFork}, + EvmEnv, +}; use alloy_primitives::{Address, B256, U256}; use alloy_provider::{network::AnyRpcBlock, Provider}; use eyre::WrapErr; use foundry_common::{provider::ProviderBuilder, ALCHEMY_FREE_TIER_CUPS}; use foundry_config::{Chain, Config, GasLimit}; -use revm::primitives::{BlockEnv, CfgEnv, TxEnv}; +use revm::context::{BlockEnv, TxEnv}; use serde::{Deserialize, Serialize}; use std::fmt::Write; use url::Url; @@ -106,7 +110,7 @@ impl EvmOpts { /// /// If a `fork_url` is set, it gets configured with settings fetched from the endpoint (chain /// id, ) - pub async fn evm_env(&self) -> eyre::Result { + pub async fn evm_env(&self) -> eyre::Result { if let Some(ref fork_url) = self.fork_url { Ok(self.fork_evm_env(fork_url).await?.0) } else { @@ -116,10 +120,7 @@ impl EvmOpts { /// Returns the `revm::Env` that is configured with settings retrieved from the endpoint. /// And the block that was used to configure the environment. - pub async fn fork_evm_env( - &self, - fork_url: &str, - ) -> eyre::Result<(revm::primitives::Env, AnyRpcBlock)> { + pub async fn fork_evm_env(&self, fork_url: &str) -> eyre::Result<(crate::Env, AnyRpcBlock)> { let provider = ProviderBuilder::new(fork_url) .compute_units_per_second(self.get_compute_units_per_second()) .build()?; @@ -145,31 +146,29 @@ impl EvmOpts { } /// Returns the `revm::Env` configured with only local settings - pub fn local_evm_env(&self) -> revm::primitives::Env { - let mut cfg = CfgEnv::default(); - cfg.chain_id = self.env.chain_id.unwrap_or(foundry_common::DEV_CHAIN_ID); - cfg.limit_contract_code_size = self.env.code_size_limit.or(Some(usize::MAX)); - cfg.memory_limit = self.memory_limit; - // EIP-3607 rejects transactions from senders with deployed code. - // If EIP-3607 is enabled it can cause issues during fuzz/invariant tests if the - // caller is a contract. So we disable the check by default. - cfg.disable_eip3607 = true; - cfg.disable_block_gas_limit = self.disable_block_gas_limit; - - revm::primitives::Env { - block: BlockEnv { - number: U256::from(self.env.block_number), - coinbase: self.env.block_coinbase, - timestamp: U256::from(self.env.block_timestamp), - difficulty: U256::from(self.env.block_difficulty), - prevrandao: Some(self.env.block_prevrandao), - basefee: U256::from(self.env.block_base_fee_per_gas), - gas_limit: U256::from(self.gas_limit()), - ..Default::default() + pub fn local_evm_env(&self) -> crate::Env { + let cfg = configure_env( + self.env.chain_id.unwrap_or(foundry_common::DEV_CHAIN_ID), + self.memory_limit, + self.disable_block_gas_limit, + ); + + crate::Env { + evm_env: EvmEnv { + cfg_env: cfg, + block_env: BlockEnv { + number: self.env.block_number, + beneficiary: self.env.block_coinbase, + timestamp: self.env.block_timestamp, + difficulty: U256::from(self.env.block_difficulty), + prevrandao: Some(self.env.block_prevrandao), + basefee: self.env.block_base_fee_per_gas, + gas_limit: self.gas_limit(), + ..Default::default() + }, }, - cfg, tx: TxEnv { - gas_price: U256::from(self.env.gas_price.unwrap_or_default()), + gas_price: self.env.gas_price.unwrap_or_default().into(), gas_limit: self.gas_limit(), caller: self.sender, ..Default::default() @@ -190,9 +189,9 @@ impl EvmOpts { /// /// for `mainnet` and `--fork-block-number 14435000` on mac the corresponding storage cache will /// be at `~/.foundry/cache/mainnet/14435000/storage.json`. - pub fn get_fork(&self, config: &Config, env: revm::primitives::Env) -> Option { + pub fn get_fork(&self, config: &Config, env: crate::Env) -> Option { let url = self.fork_url.clone()?; - let enable_caching = config.enable_caching(&url, env.cfg.chain_id); + let enable_caching = config.enable_caching(&url, env.evm_env.cfg_env.chain_id); Some(CreateFork { url, enable_caching, env, evm_opts: self.clone() }) } diff --git a/crates/evm/core/src/utils.rs b/crates/evm/core/src/utils.rs index 7125535694d49..fd11ee91654a0 100644 --- a/crates/evm/core/src/utils.rs +++ b/crates/evm/core/src/utils.rs @@ -1,5 +1,3 @@ -pub use crate::ic::*; -use crate::{backend::DatabaseExt, constants::DEFAULT_CREATE2_DEPLOYER_CODEHASH, InspectorExt}; use alloy_consensus::BlockHeader; use alloy_json_abi::{Function, JsonAbi}; use alloy_network::{AnyTxEnvelope, TransactionResponse}; @@ -8,20 +6,10 @@ use alloy_provider::{network::BlockResponse, Network}; use alloy_rpc_types::{Transaction, TransactionRequest}; use foundry_common::is_impersonated_tx; use foundry_config::NamedChain; -use foundry_fork_db::DatabaseError; -use revm::{ - handler::register::EvmHandler, - interpreter::{ - return_ok, CallInputs, CallOutcome, CallScheme, CallValue, CreateInputs, CreateOutcome, - Gas, InstructionResult, InterpreterResult, - }, - precompile::secp256r1::P256VERIFY, - primitives::{CreateScheme, EVMError, HandlerCfg, SpecId, KECCAK_EMPTY}, - FrameOrResult, FrameResult, -}; -use std::{cell::RefCell, rc::Rc, sync::Arc}; +use revm::primitives::hardfork::SpecId; +pub use revm::state::EvmState as StateChangeset; -pub use revm::primitives::EvmState as StateChangeset; +use crate::EnvMut; /// Depending on the configured chain id and block number this should apply any specific changes /// @@ -30,10 +18,11 @@ pub use revm::primitives::EvmState as StateChangeset; /// /// Should be called with proper chain id (retrieved from provider if not provided). pub fn apply_chain_and_block_specific_env_changes( - env: &mut revm::primitives::Env, + env: EnvMut<'_>, block: &N::BlockResponse, ) { use NamedChain::*; + if let Ok(chain) = NamedChain::try_from(env.cfg.chain_id) { let block_number = block.header().number(); @@ -72,7 +61,7 @@ pub fn apply_chain_and_block_specific_env_changes( serde_json::from_value::(l1_block_number).ok() }) { - env.block.number = l1_block_number; + env.block.number = l1_block_number.to(); } } _ => {} @@ -98,7 +87,7 @@ pub fn get_function<'a>( /// Configures the env for the given RPC transaction. /// Accounts for an impersonated transaction by resetting the `env.tx.caller` field to `tx.from`. -pub fn configure_tx_env(env: &mut revm::primitives::Env, tx: &Transaction) { +pub fn configure_tx_env(env: &mut EnvMut<'_>, tx: &Transaction) { let impersonated_from = is_impersonated_tx(&tx.inner).then_some(tx.from()); if let AnyTxEnvelope::Ethereum(tx) = &tx.inner.inner() { configure_tx_req_env(env, &tx.clone().into(), impersonated_from).expect("cannot fail"); @@ -109,7 +98,7 @@ pub fn configure_tx_env(env: &mut revm::primitives::Env, tx: &Transaction, tx: &TransactionRequest, impersonated_from: Option
, ) -> eyre::Result<()> { @@ -133,32 +122,31 @@ pub fn configure_tx_req_env( } = *tx; // If no `to` field then set create kind: https://eips.ethereum.org/EIPS/eip-2470#deployment-transaction - env.tx.transact_to = to.unwrap_or(TxKind::Create); + env.tx.kind = to.unwrap_or(TxKind::Create); // If the transaction is impersonated, we need to set the caller to the from // address Ref: https://github.com/foundry-rs/foundry/issues/9541 env.tx.caller = impersonated_from.unwrap_or(from.ok_or_else(|| eyre::eyre!("missing `from` field"))?); env.tx.gas_limit = gas.ok_or_else(|| eyre::eyre!("missing `gas` field"))?; - env.tx.nonce = nonce; + env.tx.nonce = nonce.unwrap_or_default(); env.tx.value = value.unwrap_or_default(); env.tx.data = input.input().cloned().unwrap_or_default(); env.tx.chain_id = chain_id; // Type 1, EIP-2930 - env.tx.access_list = access_list.clone().unwrap_or_default().0.into_iter().collect(); + env.tx.access_list = access_list.clone().unwrap_or_default(); // Type 2, EIP-1559 - env.tx.gas_price = U256::from(gas_price.or(max_fee_per_gas).unwrap_or_default()); - env.tx.gas_priority_fee = max_priority_fee_per_gas.map(U256::from); + env.tx.gas_price = gas_price.or(max_fee_per_gas).unwrap_or_default(); + env.tx.gas_priority_fee = max_priority_fee_per_gas; // Type 3, EIP-4844 env.tx.blob_hashes = blob_versioned_hashes.clone().unwrap_or_default(); - env.tx.max_fee_per_blob_gas = max_fee_per_blob_gas.map(U256::from); + env.tx.max_fee_per_blob_gas = max_fee_per_blob_gas.unwrap_or_default(); // Type 4, EIP-7702 if let Some(authorization_list) = authorization_list { - env.tx.authorization_list = - Some(revm::primitives::AuthorizationList::Signed(authorization_list.clone())); + env.tx.authorization_list = authorization_list.clone(); } Ok(()) @@ -166,202 +154,6 @@ pub fn configure_tx_req_env( /// Get the gas used, accounting for refunds pub fn gas_used(spec: SpecId, spent: u64, refunded: u64) -> u64 { - let refund_quotient = if SpecId::enabled(spec, SpecId::LONDON) { 5 } else { 2 }; + let refund_quotient = if SpecId::is_enabled_in(spec, SpecId::LONDON) { 5 } else { 2 }; spent - (refunded).min(spent / refund_quotient) } - -fn get_create2_factory_call_inputs( - salt: U256, - inputs: CreateInputs, - deployer: Address, -) -> CallInputs { - let calldata = [&salt.to_be_bytes::<32>()[..], &inputs.init_code[..]].concat(); - CallInputs { - caller: inputs.caller, - bytecode_address: deployer, - target_address: deployer, - scheme: CallScheme::Call, - value: CallValue::Transfer(inputs.value), - input: calldata.into(), - gas_limit: inputs.gas_limit, - is_static: false, - return_memory_offset: 0..0, - is_eof: false, - } -} - -/// Used for routing certain CREATE2 invocations through CREATE2_DEPLOYER. -/// -/// Overrides create hook with CALL frame if [InspectorExt::should_use_create2_factory] returns -/// true. Keeps track of overridden frames and handles outcome in the overridden insert_call_outcome -/// hook by inserting decoded address directly into interpreter. -/// -/// Should be installed after [revm::inspector_handle_register] and before any other registers. -pub fn create2_handler_register( - handler: &mut EvmHandler<'_, I, &mut dyn DatabaseExt>, -) { - let create2_overrides = Rc::>>::new(RefCell::new(Vec::new())); - - let create2_overrides_inner = create2_overrides.clone(); - let old_handle = handler.execution.create.clone(); - handler.execution.create = - Arc::new(move |ctx, mut inputs| -> Result> { - let CreateScheme::Create2 { salt } = inputs.scheme else { - return old_handle(ctx, inputs); - }; - if !ctx.external.should_use_create2_factory(&mut ctx.evm, &mut inputs) { - return old_handle(ctx, inputs); - } - - let gas_limit = inputs.gas_limit; - - // Get CREATE2 deployer. - let create2_deployer = ctx.external.create2_deployer(); - // Generate call inputs for CREATE2 factory. - let mut call_inputs = get_create2_factory_call_inputs(salt, *inputs, create2_deployer); - - // Call inspector to change input or return outcome. - let outcome = ctx.external.call(&mut ctx.evm, &mut call_inputs); - - // Push data about current override to the stack. - create2_overrides_inner - .borrow_mut() - .push((ctx.evm.journaled_state.depth(), call_inputs.clone())); - - // Sanity check that CREATE2 deployer exists. - let code_hash = ctx.evm.load_account(create2_deployer)?.info.code_hash; - if code_hash == KECCAK_EMPTY { - return Ok(FrameOrResult::Result(FrameResult::Call(CallOutcome { - result: InterpreterResult { - result: InstructionResult::Revert, - output: format!("missing CREATE2 deployer: {create2_deployer}").into(), - gas: Gas::new(gas_limit), - }, - memory_offset: 0..0, - }))) - } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH { - return Ok(FrameOrResult::Result(FrameResult::Call(CallOutcome { - result: InterpreterResult { - result: InstructionResult::Revert, - output: "invalid CREATE2 deployer bytecode".into(), - gas: Gas::new(gas_limit), - }, - memory_offset: 0..0, - }))) - } - - // Handle potential inspector override. - if let Some(outcome) = outcome { - return Ok(FrameOrResult::Result(FrameResult::Call(outcome))); - } - - // Create CALL frame for CREATE2 factory invocation. - let mut frame_or_result = ctx.evm.make_call_frame(&call_inputs); - - if let Ok(FrameOrResult::Frame(frame)) = &mut frame_or_result { - ctx.external - .initialize_interp(&mut frame.frame_data_mut().interpreter, &mut ctx.evm) - } - frame_or_result - }); - - let create2_overrides_inner = create2_overrides; - let old_handle = handler.execution.insert_call_outcome.clone(); - handler.execution.insert_call_outcome = - Arc::new(move |ctx, frame, shared_memory, mut outcome| { - // If we are on the depth of the latest override, handle the outcome. - if create2_overrides_inner - .borrow() - .last() - .is_some_and(|(depth, _)| *depth == ctx.evm.journaled_state.depth()) - { - let (_, call_inputs) = create2_overrides_inner.borrow_mut().pop().unwrap(); - outcome = ctx.external.call_end(&mut ctx.evm, &call_inputs, outcome); - - // Decode address from output. - let address = match outcome.instruction_result() { - return_ok!() => Address::try_from(outcome.output().as_ref()) - .map_err(|_| { - outcome.result = InterpreterResult { - result: InstructionResult::Revert, - output: "invalid CREATE2 factory output".into(), - gas: Gas::new(call_inputs.gas_limit), - }; - }) - .ok(), - _ => None, - }; - frame - .frame_data_mut() - .interpreter - .insert_create_outcome(CreateOutcome { address, result: outcome.result }); - - Ok(()) - } else { - old_handle(ctx, frame, shared_memory, outcome) - } - }); -} - -/// Adds Odyssey P256 precompile to the list of loaded precompiles. -pub fn odyssey_handler_register(handler: &mut EvmHandler<'_, EXT, DB>) { - let prev = handler.pre_execution.load_precompiles.clone(); - handler.pre_execution.load_precompiles = Arc::new(move || { - let mut loaded_precompiles = prev(); - - loaded_precompiles.extend([P256VERIFY]); - - loaded_precompiles - }); -} - -/// Creates a new EVM with the given inspector. -pub fn new_evm_with_inspector<'evm, 'i, 'db, I: InspectorExt + ?Sized>( - db: &'db mut dyn DatabaseExt, - env: revm::primitives::EnvWithHandlerCfg, - inspector: &'i mut I, -) -> revm::Evm<'evm, &'i mut I, &'db mut dyn DatabaseExt> { - let revm::primitives::EnvWithHandlerCfg { env, handler_cfg } = env; - - // NOTE: We could use `revm::Evm::builder()` here, but on the current patch it has some - // performance issues. - /* - revm::Evm::builder() - .with_db(db) - .with_env(env) - .with_external_context(inspector) - .with_handler_cfg(handler_cfg) - .append_handler_register(revm::inspector_handle_register) - .append_handler_register(create2_handler_register) - .build() - */ - - let mut handler = revm::Handler::new(handler_cfg); - handler.append_handler_register_plain(revm::inspector_handle_register); - if inspector.is_odyssey() { - handler.append_handler_register_plain(odyssey_handler_register); - } - handler.append_handler_register_plain(create2_handler_register); - - let context = revm::Context::new(revm::EvmContext::new_with_env(db, env), inspector); - - revm::Evm::new(context, handler) -} - -pub fn new_evm_with_existing_context<'a>( - inner: revm::InnerEvmContext<&'a mut dyn DatabaseExt>, - inspector: &'a mut dyn InspectorExt, -) -> revm::Evm<'a, &'a mut dyn InspectorExt, &'a mut dyn DatabaseExt> { - let handler_cfg = HandlerCfg::new(inner.spec_id()); - - let mut handler = revm::Handler::new(handler_cfg); - handler.append_handler_register_plain(revm::inspector_handle_register); - if inspector.is_odyssey() { - handler.append_handler_register_plain(odyssey_handler_register); - } - handler.append_handler_register_plain(create2_handler_register); - - let context = - revm::Context::new(revm::EvmContext { inner, precompiles: Default::default() }, inspector); - revm::Evm::new(context, handler) -} diff --git a/crates/evm/coverage/src/anchors.rs b/crates/evm/coverage/src/anchors.rs index 3d46065518c1b..415ad744b30e8 100644 --- a/crates/evm/coverage/src/anchors.rs +++ b/crates/evm/coverage/src/anchors.rs @@ -3,8 +3,8 @@ use crate::analysis::SourceAnalysis; use alloy_primitives::map::rustc_hash::FxHashSet; use eyre::ensure; use foundry_compilers::artifacts::sourcemap::{SourceElement, SourceMap}; -use foundry_evm_core::utils::IcPcMap; -use revm::interpreter::opcode; +use foundry_evm_core::ic::IcPcMap; +use revm::bytecode::opcode; /// Attempts to find anchors for the given items using the given source map and bytecode. pub fn find_anchors( diff --git a/crates/evm/coverage/src/inspector.rs b/crates/evm/coverage/src/inspector.rs index 6a6c50b093c8f..dfed9589e55fc 100644 --- a/crates/evm/coverage/src/inspector.rs +++ b/crates/evm/coverage/src/inspector.rs @@ -1,6 +1,11 @@ use crate::{HitMap, HitMaps}; use alloy_primitives::B256; -use revm::{interpreter::Interpreter, Database, EvmContext, Inspector}; +use revm::{ + context::ContextTr, + inspector::JournalExt, + interpreter::{interpreter_types::Jumps, Interpreter}, + Inspector, +}; use std::ptr::NonNull; /// Inspector implementation for collecting coverage information. @@ -29,16 +34,19 @@ impl Default for CoverageCollector { } } -impl Inspector for CoverageCollector { - fn initialize_interp(&mut self, interpreter: &mut Interpreter, _context: &mut EvmContext) { +impl Inspector for CoverageCollector +where + CTX: ContextTr, +{ + fn initialize_interp(&mut self, interpreter: &mut Interpreter, _context: &mut CTX) { get_or_insert_contract_hash(interpreter); self.insert_map(interpreter); } #[inline] - fn step(&mut self, interpreter: &mut Interpreter, _context: &mut EvmContext) { + fn step(&mut self, interpreter: &mut Interpreter, _context: &mut CTX) { let map = self.get_or_insert_map(interpreter); - map.hit(interpreter.program_counter() as u32); + map.hit(interpreter.bytecode.pc() as u32); } } @@ -64,14 +72,14 @@ impl CoverageCollector { #[cold] #[inline(never)] - fn insert_map(&mut self, interpreter: &Interpreter) { - let Some(hash) = interpreter.contract.hash else { eof_panic() }; + fn insert_map(&mut self, interpreter: &mut Interpreter) { + let hash = interpreter.bytecode.hash().unwrap_or_else(|| eof_panic()); self.current_hash = hash; // Converts the mutable reference to a `NonNull` pointer. self.current_map = self .maps .entry(hash) - .or_insert_with(|| HitMap::new(interpreter.contract.bytecode.original_bytes())) + .or_insert_with(|| HitMap::new(interpreter.bytecode.original_bytes())) .into(); } } @@ -81,18 +89,11 @@ impl CoverageCollector { /// If the contract hash is zero (contract not yet created but it's going to be created in current /// tx) then the hash is calculated from the bytecode. #[inline] -fn get_or_insert_contract_hash(interpreter: &mut Interpreter) -> &B256 { - let Some(hash) = interpreter.contract.hash.as_mut() else { eof_panic() }; - if hash.is_zero() { - set_contract_hash(hash, &interpreter.contract.bytecode); +fn get_or_insert_contract_hash(interpreter: &mut Interpreter) -> B256 { + if interpreter.bytecode.hash().is_none_or(|h| h.is_zero()) { + interpreter.bytecode.regenerate_hash(); } - hash -} - -#[cold] -#[inline(never)] -fn set_contract_hash(hash: &mut B256, bytecode: &revm::primitives::Bytecode) { - *hash = bytecode.hash_slow(); + interpreter.bytecode.hash().unwrap_or_else(|| eof_panic()) } #[cold] diff --git a/crates/evm/evm/Cargo.toml b/crates/evm/evm/Cargo.toml index 053a534405f7e..06074e305b630 100644 --- a/crates/evm/evm/Cargo.toml +++ b/crates/evm/evm/Cargo.toml @@ -24,6 +24,7 @@ foundry-evm-fuzz.workspace = true foundry-evm-traces.workspace = true alloy-dyn-abi = { workspace = true, features = ["arbitrary", "eip712"] } +alloy-evm.workspace = true alloy-json-abi.workspace = true alloy-primitives = { workspace = true, features = [ "serde", diff --git a/crates/evm/evm/src/executors/builder.rs b/crates/evm/evm/src/executors/builder.rs index c371a6550b879..a60934046efe1 100644 --- a/crates/evm/evm/src/executors/builder.rs +++ b/crates/evm/evm/src/executors/builder.rs @@ -1,6 +1,6 @@ use crate::{executors::Executor, inspectors::InspectorStackBuilder}; -use foundry_evm_core::backend::Backend; -use revm::primitives::{Env, EnvWithHandlerCfg, SpecId}; +use foundry_evm_core::{backend::Backend, Env}; +use revm::primitives::hardfork::SpecId; /// The builder that allows to configure an evm [`Executor`] which a stack of optional /// [`revm::Inspector`]s, such as [`Cheatcodes`]. @@ -27,7 +27,7 @@ impl Default for ExecutorBuilder { Self { stack: InspectorStackBuilder::new(), gas_limit: None, - spec_id: SpecId::LATEST, + spec_id: SpecId::default(), legacy_assertions: false, } } @@ -76,13 +76,18 @@ impl ExecutorBuilder { pub fn build(self, env: Env, db: Backend) -> Executor { let Self { mut stack, gas_limit, spec_id, legacy_assertions } = self; if stack.block.is_none() { - stack.block = Some(env.block.clone()); + stack.block = Some(env.evm_env.block_env.clone()); } if stack.gas_price.is_none() { stack.gas_price = Some(env.tx.gas_price); } - let gas_limit = gas_limit.unwrap_or_else(|| env.block.gas_limit.saturating_to()); - let env = EnvWithHandlerCfg::new_with_spec_id(Box::new(env), spec_id); + let gas_limit = gas_limit.unwrap_or(env.evm_env.block_env.gas_limit); + let env = Env::new_with_spec_id( + env.evm_env.cfg_env.clone(), + env.evm_env.block_env.clone(), + env.tx, + spec_id, + ); Executor::new(db, env, stack.build(), gas_limit, legacy_assertions) } } diff --git a/crates/evm/evm/src/executors/invariant/mod.rs b/crates/evm/evm/src/executors/invariant/mod.rs index 11c38bf43f29b..bf49f6c62f2ea 100644 --- a/crates/evm/evm/src/executors/invariant/mod.rs +++ b/crates/evm/evm/src/executors/invariant/mod.rs @@ -2,7 +2,7 @@ use crate::{ executors::{Executor, RawCallResult}, inspectors::Fuzzer, }; -use alloy_primitives::{Address, Bytes, FixedBytes, Selector, U256}; +use alloy_primitives::{map::HashMap, Address, Bytes, FixedBytes, Selector, U256}; use alloy_sol_types::{sol, SolCall}; use eyre::{eyre, ContextCompat, Result}; use foundry_common::contracts::{ContractsByAddress, ContractsByArtifact}; @@ -30,7 +30,7 @@ use proptest::{ test_runner::{TestCaseError, TestRunner}, }; use result::{assert_after_invariant, assert_invariants, can_continue}; -use revm::primitives::HashMap; +use revm::state::Account; use shrink::shrink_sequence; use std::{ cell::RefCell, @@ -865,7 +865,7 @@ impl<'a> InvariantExecutor<'a> { /// randomly generated addresses. fn collect_data( invariant_test: &InvariantTest, - state_changeset: &mut HashMap, + state_changeset: &mut HashMap, tx: &BasicTxDetails, call_result: &RawCallResult, run_depth: u32, diff --git a/crates/evm/evm/src/executors/invariant/replay.rs b/crates/evm/evm/src/executors/invariant/replay.rs index 89d7aa242a035..ab11f3728ae99 100644 --- a/crates/evm/evm/src/executors/invariant/replay.rs +++ b/crates/evm/evm/src/executors/invariant/replay.rs @@ -4,7 +4,7 @@ use super::{ }; use crate::executors::Executor; use alloy_dyn_abi::JsonAbiExt; -use alloy_primitives::{map::HashMap, Log}; +use alloy_primitives::{map::HashMap, Log, U256}; use eyre::Result; use foundry_common::{ContractsByAddress, ContractsByArtifact}; use foundry_evm_coverage::HitMaps; @@ -16,7 +16,6 @@ use foundry_evm_traces::{load_contracts, TraceKind, TraceMode, Traces}; use indicatif::ProgressBar; use parking_lot::RwLock; use proptest::test_runner::TestError; -use revm::primitives::U256; use std::sync::Arc; /// Replays a call sequence for collecting logs and traces. diff --git a/crates/evm/evm/src/executors/mod.rs b/crates/evm/evm/src/executors/mod.rs index 5937912e17601..6ab4e3202967e 100644 --- a/crates/evm/evm/src/executors/mod.rs +++ b/crates/evm/evm/src/executors/mod.rs @@ -6,14 +6,17 @@ // `Executor` struct should be accessed using a trait defined in `foundry-evm-core` instead of // the concrete `Executor` type. -use crate::inspectors::{ - cheatcodes::BroadcastableTransactions, Cheatcodes, InspectorData, InspectorStack, +use crate::{ + inspectors::{ + cheatcodes::BroadcastableTransactions, Cheatcodes, InspectorData, InspectorStack, + }, + Env, }; use alloy_dyn_abi::{DynSolValue, FunctionExt, JsonAbiExt}; use alloy_json_abi::Function; use alloy_primitives::{ map::{AddressHashMap, HashMap}, - Address, Bytes, Log, U256, + Address, Bytes, Log, TxKind, U256, }; use alloy_sol_types::{sol, SolCall}; use foundry_evm_core::{ @@ -24,17 +27,20 @@ use foundry_evm_core::{ }, decode::{RevertDecoder, SkipReason}, utils::StateChangeset, - InspectorExt, + EvmEnv, InspectorExt, }; use foundry_evm_coverage::HitMaps; use foundry_evm_traces::{SparsedTraceArena, TraceMode}; use revm::{ - db::{DatabaseCommit, DatabaseRef}, - interpreter::{return_ok, InstructionResult}, - primitives::{ - AuthorizationList, BlockEnv, Bytecode, Env, EnvWithHandlerCfg, ExecutionResult, Output, - ResultAndState, SignedAuthorization, SpecId, TxEnv, TxKind, + bytecode::Bytecode, + context::{BlockEnv, TxEnv}, + context_interface::{ + result::{ExecutionResult, Output, ResultAndState}, + transaction::SignedAuthorization, }, + database::{DatabaseCommit, DatabaseRef}, + interpreter::{return_ok, InstructionResult}, + primitives::hardfork::SpecId, }; use std::{ borrow::Cow, @@ -83,7 +89,7 @@ pub struct Executor { // so the performance difference should be negligible. backend: Backend, /// The EVM environment. - env: EnvWithHandlerCfg, + env: Env, /// The Revm inspector stack. inspector: InspectorStack, /// The gas limit for calls and deployments. @@ -103,7 +109,7 @@ impl Executor { #[inline] pub fn new( mut backend: Backend, - env: EnvWithHandlerCfg, + env: Env, inspector: InspectorStack, gas_limit: u64, legacy_assertions: bool, @@ -112,7 +118,7 @@ impl Executor { // do not fail. backend.insert_account_info( CHEATCODE_ADDRESS, - revm::primitives::AccountInfo { + revm::state::AccountInfo { code: Some(Bytecode::new_raw(Bytes::from_static(&[0]))), // Also set the code hash manually so that it's not computed later. // The code hash value does not matter, as long as it's not zero or `KECCAK_EMPTY`. @@ -125,7 +131,12 @@ impl Executor { } fn clone_with_backend(&self, backend: Backend) -> Self { - let env = EnvWithHandlerCfg::new_with_spec_id(Box::new(self.env().clone()), self.spec_id()); + let env = Env::new_with_spec_id( + self.env.evm_env.cfg_env.clone(), + self.env.evm_env.block_env.clone(), + self.env.tx.clone(), + self.spec_id(), + ); Self::new(backend, env, self.inspector().clone(), self.gas_limit, self.legacy_assertions) } @@ -141,12 +152,12 @@ impl Executor { /// Returns a reference to the EVM environment. pub fn env(&self) -> &Env { - &self.env.env + &self.env } /// Returns a mutable reference to the EVM environment. pub fn env_mut(&mut self) -> &mut Env { - &mut self.env.env + &mut self.env } /// Returns a reference to the EVM inspector. @@ -161,12 +172,12 @@ impl Executor { /// Returns the EVM spec ID. pub fn spec_id(&self) -> SpecId { - self.env.spec_id() + self.env.evm_env.cfg_env.spec } /// Sets the EVM spec ID. pub fn set_spec_id(&mut self, spec_id: SpecId) { - self.env.handler_cfg.spec_id = spec_id; + self.env.evm_env.cfg_env.spec = spec_id; } /// Returns the gas limit for calls and deployments. @@ -238,6 +249,7 @@ impl Executor { let mut account = self.backend().basic_ref(address)?.unwrap_or_default(); account.nonce = nonce; self.backend_mut().insert_account_info(address, account); + self.env_mut().tx.nonce = nonce; Ok(()) } @@ -293,17 +305,17 @@ impl Executor { /// /// # Panics /// - /// Panics if `env.tx.transact_to` is not `TxKind::Create(_)`. + /// Panics if `env.tx.kind` is not `TxKind::Create(_)`. #[instrument(name = "deploy", level = "debug", skip_all)] pub fn deploy_with_env( &mut self, - env: EnvWithHandlerCfg, + env: Env, rd: Option<&RevertDecoder>, ) -> Result { assert!( - matches!(env.tx.transact_to, TxKind::Create), + matches!(env.tx.kind, TxKind::Create), "Expected create transaction, got {:?}", - env.tx.transact_to + env.tx.kind ); trace!(sender=%env.tx.caller, "deploying contract"); @@ -344,9 +356,9 @@ impl Executor { res = res.into_result(rd)?; // record any changes made to the block's environment during setup - self.env_mut().block = res.env.block.clone(); + self.env_mut().evm_env.block_env = res.env.evm_env.block_env.clone(); // and also the chainid, which can be set manually - self.env_mut().cfg.chain_id = res.env.cfg.chain_id; + self.env_mut().evm_env.cfg_env.chain_id = res.env.evm_env.cfg_env.chain_id; let success = self.is_raw_call_success(to, Cow::Borrowed(&res.state_changeset), &res, false); @@ -425,7 +437,8 @@ impl Executor { authorization_list: Vec, ) -> eyre::Result { let mut env = self.build_test_env(from, to.into(), calldata, value); - env.tx.authorization_list = Some(AuthorizationList::Signed(authorization_list)); + env.tx.authorization_list = authorization_list; + env.tx.tx_type = 4; self.call_with_env(env) } @@ -445,7 +458,7 @@ impl Executor { /// /// The state after the call is **not** persisted. #[instrument(name = "call", level = "debug", skip_all)] - pub fn call_with_env(&self, mut env: EnvWithHandlerCfg) -> eyre::Result { + pub fn call_with_env(&self, mut env: Env) -> eyre::Result { let mut inspector = self.inspector().clone(); let mut backend = CowBackend::new_borrowed(self.backend()); let result = backend.inspect(&mut env, &mut inspector)?; @@ -454,7 +467,7 @@ impl Executor { /// Execute the transaction configured in `env.tx`. #[instrument(name = "transact", level = "debug", skip_all)] - pub fn transact_with_env(&mut self, mut env: EnvWithHandlerCfg) -> eyre::Result { + pub fn transact_with_env(&mut self, mut env: Env) -> eyre::Result { let mut inspector = self.inspector().clone(); let backend = self.backend_mut(); let result = backend.inspect(&mut env, &mut inspector)?; @@ -631,37 +644,36 @@ impl Executor { /// /// If using a backend with cheatcodes, `tx.gas_price` and `block.number` will be overwritten by /// the cheatcode state in between calls. - fn build_test_env( - &self, - caller: Address, - transact_to: TxKind, - data: Bytes, - value: U256, - ) -> EnvWithHandlerCfg { - let env = Env { - cfg: self.env().cfg.clone(), - // We always set the gas price to 0 so we can execute the transaction regardless of - // network conditions - the actual gas price is kept in `self.block` and is applied by - // the cheatcode handler if it is enabled - block: BlockEnv { - basefee: U256::ZERO, - gas_limit: U256::from(self.gas_limit), - ..self.env().block.clone() + fn build_test_env(&self, caller: Address, kind: TxKind, data: Bytes, value: U256) -> Env { + Env { + evm_env: EvmEnv { + cfg_env: { + let mut cfg = self.env().evm_env.cfg_env.clone(); + cfg.spec = self.spec_id(); + cfg + }, + // We always set the gas price to 0 so we can execute the transaction regardless of + // network conditions - the actual gas price is kept in `self.block` and is applied + // by the cheatcode handler if it is enabled + block_env: BlockEnv { + basefee: 0, + gas_limit: self.gas_limit, + ..self.env().evm_env.block_env.clone() + }, }, tx: TxEnv { caller, - transact_to, + kind, data, value, // As above, we set the gas price to 0. - gas_price: U256::ZERO, + gas_price: 0, gas_priority_fee: None, gas_limit: self.gas_limit, + chain_id: Some(self.env().evm_env.cfg_env.chain_id), ..self.env().tx.clone() }, - }; - - EnvWithHandlerCfg::new_with_spec_id(Box::new(env), self.spec_id()) + } } pub fn call_sol_default(&self, to: Address, args: &C) -> C::Return @@ -797,7 +809,7 @@ pub struct RawCallResult { /// The changeset of the state. pub state_changeset: StateChangeset, /// The `revm::Env` after the call - pub env: EnvWithHandlerCfg, + pub env: Env, /// The cheatcode states after execution pub cheatcodes: Option, /// The raw output of the execution @@ -822,7 +834,7 @@ impl Default for RawCallResult { coverage: None, transactions: None, state_changeset: HashMap::default(), - env: EnvWithHandlerCfg::new_with_spec_id(Box::default(), SpecId::LATEST), + env: Env::default(), cheatcodes: Default::default(), out: None, chisel_state: None, @@ -920,7 +932,7 @@ impl std::ops::DerefMut for CallResult { /// Converts the data aggregated in the `inspector` and `call` to a `RawCallResult` fn convert_executed_result( - env: EnvWithHandlerCfg, + env: Env, inspector: InspectorStack, ResultAndState { result, state: state_changeset }: ResultAndState, has_state_snapshot_failure: bool, @@ -938,10 +950,11 @@ fn convert_executed_result( } }; let gas = revm::interpreter::gas::calculate_initial_tx_gas( - env.spec_id(), + env.evm_env.cfg_env.spec, &env.tx.data, - env.tx.transact_to.is_create(), - &env.tx.access_list, + env.tx.kind.is_create(), + env.tx.access_list.len().try_into()?, + 0, 0, ); diff --git a/crates/evm/evm/src/executors/trace.rs b/crates/evm/evm/src/executors/trace.rs index 026612c88c484..c58ee8ddd6e59 100644 --- a/crates/evm/evm/src/executors/trace.rs +++ b/crates/evm/evm/src/executors/trace.rs @@ -1,10 +1,13 @@ -use crate::executors::{Executor, ExecutorBuilder}; +use crate::{ + executors::{Executor, ExecutorBuilder}, + Env, +}; use alloy_primitives::Address; use foundry_compilers::artifacts::EvmVersion; use foundry_config::{utils::evm_spec_id, Chain, Config}; use foundry_evm_core::{backend::Backend, fork::CreateFork, opts::EvmOpts}; use foundry_evm_traces::TraceMode; -use revm::primitives::{Env, SpecId}; +use revm::primitives::hardfork::SpecId; use std::ops::{Deref, DerefMut}; /// A default executor with tracing enabled @@ -14,7 +17,7 @@ pub struct TracingExecutor { impl TracingExecutor { pub fn new( - env: revm::primitives::Env, + env: Env, fork: Option, version: Option, trace_mode: TraceMode, diff --git a/crates/evm/evm/src/inspectors/chisel_state.rs b/crates/evm/evm/src/inspectors/chisel_state.rs index 023389ed4dfff..33798e7b0c6a4 100644 --- a/crates/evm/evm/src/inspectors/chisel_state.rs +++ b/crates/evm/evm/src/inspectors/chisel_state.rs @@ -1,7 +1,12 @@ use alloy_primitives::U256; +use foundry_evm_core::backend::DatabaseError; use revm::{ - interpreter::{InstructionResult, Interpreter}, - Database, EvmContext, Inspector, + context::ContextTr, + inspector::JournalExt, + interpreter::{ + interpreter::EthInterpreter, interpreter_types::Jumps, InstructionResult, Interpreter, + }, + Database, Inspector, }; /// An inspector for Chisel @@ -21,16 +26,21 @@ impl ChiselState { } } -impl Inspector for ChiselState { +impl Inspector for ChiselState +where + D: Database, + CTX: ContextTr, + CTX::Journal: JournalExt, +{ #[cold] - fn step_end(&mut self, interp: &mut Interpreter, _context: &mut EvmContext) { + fn step_end(&mut self, interp: &mut Interpreter, _context: &mut CTX) { // If we are at the final pc of the REPL contract execution, set the state. // Subtraction can't overflow because `pc` is always at least 1 in `step_end`. - if self.final_pc == interp.program_counter() - 1 { + if self.final_pc == interp.bytecode.pc() - 1 { self.state = Some(( interp.stack.data().clone(), - interp.shared_memory.context_memory().to_vec(), - interp.instruction_result, + interp.memory.borrow().context_memory().to_vec(), + interp.control.instruction_result, )) } } diff --git a/crates/evm/evm/src/inspectors/custom_printer.rs b/crates/evm/evm/src/inspectors/custom_printer.rs new file mode 100644 index 0000000000000..a35958ee550d0 --- /dev/null +++ b/crates/evm/evm/src/inspectors/custom_printer.rs @@ -0,0 +1,114 @@ +//! Custom print inspector, it has step level information of execution. +//! It is a great tool if some debugging is needed. + +use foundry_common::sh_println; +use foundry_evm_core::backend::DatabaseError; +use revm::{ + bytecode::opcode::OpCode, + context::{ContextTr, JournalTr}, + inspector::{inspectors::GasInspector, JournalExt}, + interpreter::{ + interpreter::EthInterpreter, + interpreter_types::{Jumps, LoopControl, MemoryTr}, + CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter, + }, + primitives::{Address, U256}, + Database, Inspector, +}; + +/// Custom print [Inspector], it has step level information of execution. +/// +/// It is a great tool if some debugging is needed. +#[derive(Clone, Debug, Default)] +pub struct CustomPrintTracer { + gas_inspector: GasInspector, +} + +impl Inspector for CustomPrintTracer +where + D: Database, + CTX: ContextTr, + CTX::Journal: JournalExt, +{ + fn initialize_interp(&mut self, interp: &mut Interpreter, _context: &mut CTX) { + self.gas_inspector.initialize_interp(&interp.control.gas); + } + + // get opcode by calling `interp.contract.opcode(interp.program_counter())`. + // all other information can be obtained from interp. + fn step(&mut self, interp: &mut Interpreter, context: &mut CTX) { + let opcode = interp.bytecode.opcode(); + let name = OpCode::name_by_op(opcode); + + let gas_remaining = self.gas_inspector.gas_remaining(); + + let memory_size = interp.memory.size(); + + let _ = sh_println!( + "depth:{}, PC:{}, gas:{:#x}({}), OPCODE: {:?}({:?}) refund:{:#x}({}) Stack:{:?}, Data size:{}", + context.journal().depth(), + interp.bytecode.pc(), + gas_remaining, + gas_remaining, + name, + opcode, + interp.control.gas.refunded(), + interp.control.gas.refunded(), + interp.stack.data(), + memory_size, + ); + + self.gas_inspector.step(&interp.control.gas); + } + + fn step_end(&mut self, interp: &mut Interpreter, _context: &mut CTX) { + self.gas_inspector.step_end(interp.control.gas_mut()); + } + + fn call_end(&mut self, _context: &mut CTX, _inputs: &CallInputs, outcome: &mut CallOutcome) { + self.gas_inspector.call_end(outcome) + } + + fn create_end( + &mut self, + _context: &mut CTX, + _inputs: &CreateInputs, + outcome: &mut CreateOutcome, + ) { + self.gas_inspector.create_end(outcome) + } + + fn call(&mut self, _context: &mut CTX, inputs: &mut CallInputs) -> Option { + let _ = sh_println!( + "SM Address: {:?}, caller:{:?},target:{:?} is_static:{:?}, transfer:{:?}, input_size:{:?}", + inputs.bytecode_address, + inputs.caller, + inputs.target_address, + inputs.is_static, + inputs.value, + inputs.input.len(), + ); + None + } + + fn create(&mut self, _context: &mut CTX, inputs: &mut CreateInputs) -> Option { + let _ = sh_println!( + "CREATE CALL: caller:{:?}, scheme:{:?}, value:{:?}, init_code:{:?}, gas:{:?}", + inputs.caller, + inputs.scheme, + inputs.value, + inputs.init_code, + inputs.gas_limit + ); + None + } + + fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { + let _ = sh_println!( + "SELFDESTRUCT: contract: {:?}, refund target: {:?}, value {:?}", + contract, + target, + value + ); + } +} diff --git a/crates/evm/evm/src/inspectors/logs.rs b/crates/evm/evm/src/inspectors/logs.rs index 570fb47dbe238..d6aed69892b60 100644 --- a/crates/evm/evm/src/inspectors/logs.rs +++ b/crates/evm/evm/src/inspectors/logs.rs @@ -1,12 +1,17 @@ use alloy_primitives::Log; use alloy_sol_types::{SolEvent, SolInterface, SolValue}; use foundry_common::{fmt::ConsoleFmt, ErrorExt}; -use foundry_evm_core::{abi::console, constants::HARDHAT_CONSOLE_ADDRESS, InspectorExt}; +use foundry_evm_core::{ + abi::console, backend::DatabaseError, constants::HARDHAT_CONSOLE_ADDRESS, InspectorExt, +}; use revm::{ + context::ContextTr, + inspector::JournalExt, interpreter::{ - CallInputs, CallOutcome, Gas, InstructionResult, Interpreter, InterpreterResult, + interpreter::EthInterpreter, CallInputs, CallOutcome, Gas, InstructionResult, Interpreter, + InterpreterResult, }, - Database, EvmContext, Inspector, + Database, Inspector, }; /// An inspector that collects logs during execution. @@ -39,16 +44,17 @@ impl LogCollector { } } -impl Inspector for LogCollector { - fn log(&mut self, _interp: &mut Interpreter, _context: &mut EvmContext, log: &Log) { - self.logs.push(log.clone()); +impl Inspector for LogCollector +where + D: Database, + CTX: ContextTr, + CTX::Journal: JournalExt, +{ + fn log(&mut self, _interp: &mut Interpreter, _context: &mut CTX, log: Log) { + self.logs.push(log); } - fn call( - &mut self, - _context: &mut EvmContext, - inputs: &mut CallInputs, - ) -> Option { + fn call(&mut self, _context: &mut CTX, inputs: &mut CallInputs) -> Option { if inputs.target_address == HARDHAT_CONSOLE_ADDRESS { return self.do_hardhat_log(inputs); } diff --git a/crates/evm/evm/src/inspectors/mod.rs b/crates/evm/evm/src/inspectors/mod.rs index 914bf460e5e44..fcf6836e2b9d8 100644 --- a/crates/evm/evm/src/inspectors/mod.rs +++ b/crates/evm/evm/src/inspectors/mod.rs @@ -7,6 +7,9 @@ pub use foundry_evm_traces::{StackSnapshotType, TracingInspector, TracingInspect pub use revm_inspectors::access_list::AccessListInspector; +mod custom_printer; +pub use custom_printer::CustomPrintTracer; + mod chisel_state; pub use chisel_state::ChiselState; diff --git a/crates/evm/evm/src/inspectors/script.rs b/crates/evm/evm/src/inspectors/script.rs index 57fa7b209b162..205215f08db08 100644 --- a/crates/evm/evm/src/inspectors/script.rs +++ b/crates/evm/evm/src/inspectors/script.rs @@ -1,8 +1,15 @@ +use alloy_evm::Database; use alloy_primitives::Address; use foundry_common::sh_err; +use foundry_evm_core::backend::DatabaseError; use revm::{ - interpreter::{opcode::ADDRESS, InstructionResult, Interpreter}, - Database, EvmContext, Inspector, + bytecode::opcode::ADDRESS, + context::ContextTr, + inspector::JournalExt, + interpreter::{ + interpreter::EthInterpreter, interpreter_types::Jumps, InstructionResult, Interpreter, + }, + Inspector, }; /// An inspector that enforces certain rules during script execution. @@ -14,21 +21,26 @@ pub struct ScriptExecutionInspector { pub script_address: Address, } -impl Inspector for ScriptExecutionInspector { +impl Inspector for ScriptExecutionInspector +where + D: Database, + CTX: ContextTr, + CTX::Journal: JournalExt, +{ #[inline] - fn step(&mut self, interpreter: &mut Interpreter, _ecx: &mut EvmContext) { + fn step(&mut self, interpreter: &mut Interpreter, _ecx: &mut CTX) { // Check if both target and bytecode address are the same as script contract address // (allow calling external libraries when bytecode address is different). - if interpreter.current_opcode() == ADDRESS && - interpreter.contract.target_address == self.script_address && - interpreter.contract.bytecode_address.unwrap_or_default() == self.script_address + if interpreter.bytecode.opcode() == ADDRESS && + interpreter.input.target_address == self.script_address && + interpreter.input.bytecode_address == Some(self.script_address) { // Log the reason for revert let _ = sh_err!( "Usage of `address(this)` detected in script contract. Script contracts are ephemeral and their addresses should not be relied upon." ); // Set the instruction result to Revert to stop execution - interpreter.instruction_result = InstructionResult::Revert; + interpreter.control.instruction_result = InstructionResult::Revert; } // Note: We don't return anything here as step returns void. // The original check returned InstructionResult::Continue, but that's the default diff --git a/crates/evm/evm/src/inspectors/stack.rs b/crates/evm/evm/src/inspectors/stack.rs index 773730d6cc136..a4bf2930c7fec 100644 --- a/crates/evm/evm/src/inspectors/stack.rs +++ b/crates/evm/evm/src/inspectors/stack.rs @@ -1,23 +1,32 @@ use super::{ - Cheatcodes, CheatsConfig, ChiselState, CoverageCollector, Fuzzer, LogCollector, - ScriptExecutionInspector, TracingInspector, + Cheatcodes, CheatsConfig, ChiselState, CoverageCollector, CustomPrintTracer, Fuzzer, + LogCollector, ScriptExecutionInspector, TracingInspector, +}; +use alloy_evm::{eth::EthEvmContext, Evm}; +use alloy_primitives::{ + map::{AddressHashMap, HashMap}, + Address, Bytes, Log, TxKind, U256, }; -use alloy_primitives::{map::AddressHashMap, Address, Bytes, Log, TxKind, U256}; use foundry_cheatcodes::{CheatcodesExecutor, Wallets}; -use foundry_evm_core::{backend::DatabaseExt, InspectorExt}; +use foundry_evm_core::{ + backend::{DatabaseExt, JournaledState}, + evm::new_evm_with_inspector, + ContextExt, Env, InspectorExt, +}; use foundry_evm_coverage::HitMaps; use foundry_evm_traces::{SparsedTraceArena, TraceMode}; use revm::{ - inspectors::CustomPrintTracer, + context::{ + result::{ExecutionResult, Output}, + BlockEnv, + }, + context_interface::CreateScheme, interpreter::{ CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, EOFCreateInputs, EOFCreateKind, Gas, InstructionResult, Interpreter, InterpreterResult, }, - primitives::{ - Account, AccountStatus, BlockEnv, CreateScheme, Env, EnvWithHandlerCfg, ExecutionResult, - HashMap, Output, TransactTo, - }, - EvmContext, Inspector, JournaledState, + state::{Account, AccountStatus}, + Inspector, }; use std::{ ops::{Deref, DerefMut}, @@ -36,7 +45,7 @@ pub struct InspectorStackBuilder { /// /// Used in the cheatcode handler to overwrite the gas price separately from the gas price /// in the execution environment. - pub gas_price: Option, + pub gas_price: Option, /// The cheatcodes config. pub cheatcodes: Option>, /// The fuzzer inspector and its state, if it exists. @@ -79,7 +88,7 @@ impl InspectorStackBuilder { /// Set the gas price. #[inline] - pub fn gas_price(mut self, gas_price: U256) -> Self { + pub fn gas_price(mut self, gas_price: u128) -> Self { self.gas_price = Some(gas_price); self } @@ -232,7 +241,7 @@ macro_rules! call_inspectors { } )+ }; - (#[ret] [$($inspector:expr),+ $(,)?], |$id:ident $(,)?| $call:expr $(,)?) => { + (#[ret] [$($inspector:expr),+ $(,)?], |$id:ident $(,)?| $call:expr $(,)?) => {{ $( if let Some($id) = $inspector { if let Some(result) = ({ #[inline(always)] #[cold] || $call })() { @@ -240,7 +249,7 @@ macro_rules! call_inspectors { } } )+ - }; + }}; } /// The collected results of [`InspectorStack`]. @@ -355,7 +364,7 @@ impl InspectorStack { /// Set variables from an environment for the relevant inspectors. #[inline] pub fn set_env(&mut self, env: &Env) { - self.set_block(&env.block); + self.set_block(&env.evm_env.block_env); self.set_gas_price(env.tx.gas_price); } @@ -369,7 +378,7 @@ impl InspectorStack { /// Sets the gas price for the relevant inspectors. #[inline] - pub fn set_gas_price(&mut self, gas_price: U256) { + pub fn set_gas_price(&mut self, gas_price: u128) { if let Some(cheatcodes) = &mut self.cheatcodes { cheatcodes.gas_price = Some(gas_price); } @@ -496,128 +505,129 @@ impl InspectorStackRefMut<'_> { /// Should be called on the top-level call of inner context (depth == 0 && /// self.in_inner_context) Decreases sender nonce for CALLs to keep backwards compatibility /// Updates tx.origin to the value before entering inner context - fn adjust_evm_data_for_inner_context(&mut self, ecx: &mut EvmContext<&mut dyn DatabaseExt>) { + fn adjust_evm_data_for_inner_context(&mut self, ecx: &mut EthEvmContext<&mut dyn DatabaseExt>) { let inner_context_data = self.inner_context_data.as_ref().expect("should be called in inner context"); - ecx.env.tx.caller = inner_context_data.original_origin; + ecx.tx.caller = inner_context_data.original_origin; } fn do_call_end( &mut self, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, inputs: &CallInputs, - outcome: CallOutcome, + outcome: &mut CallOutcome, ) -> CallOutcome { let result = outcome.result.result; call_inspectors!( #[ret] [&mut self.fuzzer, &mut self.tracer, &mut self.cheatcodes, &mut self.printer], |inspector| { - let new_outcome = inspector.call_end(ecx, inputs, outcome.clone()); + let previous_outcome = outcome.clone(); + inspector.call_end(ecx, inputs, outcome); // If the inspector returns a different status or a revert with a non-empty message, // we assume it wants to tell us something - let different = new_outcome.result.result != result || - (new_outcome.result.result == InstructionResult::Revert && - new_outcome.output() != outcome.output()); - different.then_some(new_outcome) + let different = outcome.result.result != result || + (outcome.result.result == InstructionResult::Revert && + outcome.output() != previous_outcome.output()); + different.then_some(outcome.clone()) }, ); - outcome + outcome.clone() } fn do_create_end( &mut self, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, call: &CreateInputs, - outcome: CreateOutcome, + outcome: &mut CreateOutcome, ) -> CreateOutcome { let result = outcome.result.result; call_inspectors!( #[ret] [&mut self.tracer, &mut self.cheatcodes, &mut self.printer], |inspector| { - let new_outcome = inspector.create_end(ecx, call, outcome.clone()); + let previous_outcome = outcome.clone(); + inspector.create_end(ecx, call, outcome); // If the inspector returns a different status or a revert with a non-empty message, // we assume it wants to tell us something - let different = new_outcome.result.result != result || - (new_outcome.result.result == InstructionResult::Revert && - new_outcome.output() != outcome.output()); - different.then_some(new_outcome) + let different = outcome.result.result != result || + (outcome.result.result == InstructionResult::Revert && + outcome.output() != previous_outcome.output()); + different.then_some(outcome.clone()) }, ); - outcome + outcome.clone() } fn do_eofcreate_end( &mut self, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, call: &EOFCreateInputs, - outcome: CreateOutcome, + outcome: &mut CreateOutcome, ) -> CreateOutcome { let result = outcome.result.result; call_inspectors!( #[ret] [&mut self.tracer, &mut self.cheatcodes, &mut self.printer], |inspector| { - let new_outcome = inspector.eofcreate_end(ecx, call, outcome.clone()); + let previous_outcome = outcome.clone(); + inspector.eofcreate_end(ecx, call, outcome); // If the inspector returns a different status or a revert with a non-empty message, // we assume it wants to tell us something - let different = new_outcome.result.result != result || - (new_outcome.result.result == InstructionResult::Revert && - new_outcome.output() != outcome.output()); - different.then_some(new_outcome) + let different = outcome.result.result != result || + (outcome.result.result == InstructionResult::Revert && + outcome.output() != previous_outcome.output()); + different.then_some(outcome.clone()) }, ); - outcome + outcome.clone() } fn transact_inner( &mut self, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, - transact_to: TransactTo, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, + kind: TxKind, caller: Address, input: Bytes, gas_limit: u64, value: U256, ) -> (InterpreterResult, Option
) { - let ecx = &mut ecx.inner; + let cached_env = Env::from(ecx.cfg.clone(), ecx.block.clone(), ecx.tx.clone()); - let cached_env = ecx.env.clone(); - - ecx.env.block.basefee = U256::ZERO; - ecx.env.tx.caller = caller; - ecx.env.tx.transact_to = transact_to; - ecx.env.tx.data = input; - ecx.env.tx.value = value; + ecx.block.basefee = 0; + ecx.tx.caller = caller; + ecx.tx.kind = kind; + ecx.tx.data = input; + ecx.tx.value = value; // Add 21000 to the gas limit to account for the base cost of transaction. - ecx.env.tx.gas_limit = gas_limit + 21000; + ecx.tx.gas_limit = gas_limit + 21000; + // If we haven't disabled gas limit checks, ensure that transaction gas limit will not // exceed block gas limit. - if !ecx.env.cfg.disable_block_gas_limit { - ecx.env.tx.gas_limit = - std::cmp::min(ecx.env.tx.gas_limit, ecx.env.block.gas_limit.to()); + if !ecx.cfg.disable_block_gas_limit { + ecx.tx.gas_limit = std::cmp::min(ecx.tx.gas_limit, ecx.block.gas_limit); } - ecx.env.tx.gas_price = U256::ZERO; + ecx.tx.gas_price = 0; self.inner_context_data = Some(InnerContextData { original_origin: cached_env.tx.caller }); self.in_inner_context = true; - let env = EnvWithHandlerCfg::new_with_spec_id(ecx.env.clone(), ecx.spec_id()); let res = self.with_stack(|inspector| { - let mut evm = crate::utils::new_evm_with_inspector(&mut ecx.db, env, inspector); + let (db, journal, env) = ecx.as_db_env_and_journal(); + let mut evm = new_evm_with_inspector(db, env.to_owned(), inspector); - evm.context.evm.inner.journaled_state.state = { - let mut state = ecx.journaled_state.state.clone(); + evm.journaled_state.state = { + let mut state = journal.state.clone(); for (addr, acc_mut) in &mut state { // mark all accounts cold, besides preloaded addresses - if !ecx.journaled_state.warm_preloaded_addresses.contains(addr) { + if !journal.warm_preloaded_addresses.contains(addr) { acc_mut.mark_cold(); } @@ -632,21 +642,23 @@ impl InspectorStackRefMut<'_> { }; // set depth to 1 to make sure traces are collected correctly - evm.context.evm.inner.journaled_state.depth = 1; + evm.journaled_state.depth = 1; - let res = evm.transact(); + let res = evm.transact(env.tx.clone()); // need to reset the env in case it was modified via cheatcodes during execution - ecx.env = evm.context.evm.inner.env; + *env.cfg = evm.cfg.clone(); + *env.block = evm.block.clone(); + + *env.tx = cached_env.tx; + env.block.basefee = cached_env.evm_env.block_env.basefee; + res }); self.in_inner_context = false; self.inner_context_data = None; - ecx.env.tx = cached_env.tx; - ecx.env.block.basefee = cached_env.block.basefee; - let mut gas = Gas::new(gas_limit); let Ok(res) = res else { @@ -726,7 +738,7 @@ impl InspectorStackRefMut<'_> { } /// Invoked at the beginning of a new top-level (0 depth) frame. - fn top_level_frame_start(&mut self, ecx: &mut EvmContext<&mut dyn DatabaseExt>) { + fn top_level_frame_start(&mut self, ecx: &mut EthEvmContext<&mut dyn DatabaseExt>) { if self.enable_isolation { // If we're in isolation mode, we need to keep track of the state at the beginning of // the frame to be able to roll back on revert @@ -737,7 +749,7 @@ impl InspectorStackRefMut<'_> { /// Invoked at the end of root frame. fn top_level_frame_end( &mut self, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, result: InstructionResult, ) { if !result.is_revert() { @@ -759,11 +771,11 @@ impl InspectorStackRefMut<'_> { } } -impl Inspector<&mut dyn DatabaseExt> for InspectorStackRefMut<'_> { +impl Inspector> for InspectorStackRefMut<'_> { fn initialize_interp( &mut self, interpreter: &mut Interpreter, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, ) { call_inspectors!( [ @@ -777,7 +789,11 @@ impl Inspector<&mut dyn DatabaseExt> for InspectorStackRefMut<'_> { ); } - fn step(&mut self, interpreter: &mut Interpreter, ecx: &mut EvmContext<&mut dyn DatabaseExt>) { + fn step( + &mut self, + interpreter: &mut Interpreter, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, + ) { call_inspectors!( [ &mut self.fuzzer, @@ -794,7 +810,7 @@ impl Inspector<&mut dyn DatabaseExt> for InspectorStackRefMut<'_> { fn step_end( &mut self, interpreter: &mut Interpreter, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, ) { call_inspectors!( [&mut self.tracer, &mut self.cheatcodes, &mut self.chisel_state, &mut self.printer], @@ -805,18 +821,18 @@ impl Inspector<&mut dyn DatabaseExt> for InspectorStackRefMut<'_> { fn log( &mut self, interpreter: &mut Interpreter, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, - log: &Log, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, + log: Log, ) { call_inspectors!( [&mut self.tracer, &mut self.log_collector, &mut self.cheatcodes, &mut self.printer], - |inspector| inspector.log(interpreter, ecx, log), + |inspector| inspector.log(interpreter, ecx, log.clone()), ); } fn call( &mut self, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, call: &mut CallInputs, ) -> Option { if self.in_inner_context && ecx.journaled_state.depth == 1 { @@ -882,7 +898,7 @@ impl Inspector<&mut dyn DatabaseExt> for InspectorStackRefMut<'_> { // Mark accounts and storage cold before STATICCALLs CallScheme::StaticCall | CallScheme::ExtStaticCall => { let JournaledState { state, warm_preloaded_addresses, .. } = - &mut ecx.journaled_state; + &mut ecx.journaled_state.inner; for (addr, acc_mut) in state { // Do not mark accounts and storage cold accounts with arbitrary storage. if let Some(cheatcodes) = &self.cheatcodes { @@ -910,28 +926,26 @@ impl Inspector<&mut dyn DatabaseExt> for InspectorStackRefMut<'_> { fn call_end( &mut self, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, inputs: &CallInputs, - outcome: CallOutcome, - ) -> CallOutcome { + outcome: &mut CallOutcome, + ) { // We are processing inner context outputs in the outer context, so need to avoid processing // twice. if self.in_inner_context && ecx.journaled_state.depth == 1 { - return outcome; + return; } - let outcome = self.do_call_end(ecx, inputs, outcome); + self.do_call_end(ecx, inputs, outcome); if ecx.journaled_state.depth == 0 { self.top_level_frame_end(ecx, outcome.result.result); } - - outcome } fn create( &mut self, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, create: &mut CreateInputs, ) -> Option { if self.in_inner_context && ecx.journaled_state.depth == 1 { @@ -970,28 +984,26 @@ impl Inspector<&mut dyn DatabaseExt> for InspectorStackRefMut<'_> { fn create_end( &mut self, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, call: &CreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { + outcome: &mut CreateOutcome, + ) { // We are processing inner context outputs in the outer context, so need to avoid processing // twice. if self.in_inner_context && ecx.journaled_state.depth == 1 { - return outcome; + return; } - let outcome = self.do_create_end(ecx, call, outcome); + self.do_create_end(ecx, call, outcome); if ecx.journaled_state.depth == 0 { self.top_level_frame_end(ecx, outcome.result.result); } - - outcome } fn eofcreate( &mut self, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, create: &mut EOFCreateInputs, ) -> Option { if self.in_inner_context && ecx.journaled_state.depth == 1 { @@ -1035,28 +1047,28 @@ impl Inspector<&mut dyn DatabaseExt> for InspectorStackRefMut<'_> { fn eofcreate_end( &mut self, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, call: &EOFCreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { + outcome: &mut CreateOutcome, + ) { // We are processing inner context outputs in the outer context, so need to avoid processing // twice. if self.in_inner_context && ecx.journaled_state.depth == 1 { - return outcome; + return; } - let outcome = self.do_eofcreate_end(ecx, call, outcome); + self.do_eofcreate_end(ecx, call, outcome); if ecx.journaled_state.depth == 0 { self.top_level_frame_end(ecx, outcome.result.result); } - - outcome } fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { call_inspectors!([&mut self.tracer, &mut self.printer], |inspector| { - Inspector::<&mut dyn DatabaseExt>::selfdestruct(inspector, contract, target, value) + Inspector::>::selfdestruct( + inspector, contract, target, value, + ) }); } } @@ -1064,8 +1076,8 @@ impl Inspector<&mut dyn DatabaseExt> for InspectorStackRefMut<'_> { impl InspectorExt for InspectorStackRefMut<'_> { fn should_use_create2_factory( &mut self, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, - inputs: &mut CreateInputs, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, + inputs: &CreateInputs, ) -> bool { call_inspectors!( #[ret] @@ -1091,9 +1103,13 @@ impl InspectorExt for InspectorStackRefMut<'_> { } } -impl Inspector<&mut dyn DatabaseExt> for InspectorStack { +impl Inspector> for InspectorStack { #[inline] - fn step(&mut self, interpreter: &mut Interpreter, ecx: &mut EvmContext<&mut dyn DatabaseExt>) { + fn step( + &mut self, + interpreter: &mut Interpreter, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, + ) { self.as_mut().step(interpreter, ecx) } @@ -1101,14 +1117,14 @@ impl Inspector<&mut dyn DatabaseExt> for InspectorStack { fn step_end( &mut self, interpreter: &mut Interpreter, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, ) { self.as_mut().step_end(interpreter, ecx) } fn call( &mut self, - context: &mut EvmContext<&mut dyn DatabaseExt>, + context: &mut EthEvmContext<&mut dyn DatabaseExt>, inputs: &mut CallInputs, ) -> Option { self.as_mut().call(context, inputs) @@ -1116,16 +1132,16 @@ impl Inspector<&mut dyn DatabaseExt> for InspectorStack { fn call_end( &mut self, - context: &mut EvmContext<&mut dyn DatabaseExt>, + context: &mut EthEvmContext<&mut dyn DatabaseExt>, inputs: &CallInputs, - outcome: CallOutcome, - ) -> CallOutcome { + outcome: &mut CallOutcome, + ) { self.as_mut().call_end(context, inputs, outcome) } fn create( &mut self, - context: &mut EvmContext<&mut dyn DatabaseExt>, + context: &mut EthEvmContext<&mut dyn DatabaseExt>, create: &mut CreateInputs, ) -> Option { self.as_mut().create(context, create) @@ -1133,16 +1149,16 @@ impl Inspector<&mut dyn DatabaseExt> for InspectorStack { fn create_end( &mut self, - context: &mut EvmContext<&mut dyn DatabaseExt>, + context: &mut EthEvmContext<&mut dyn DatabaseExt>, call: &CreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { + outcome: &mut CreateOutcome, + ) { self.as_mut().create_end(context, call, outcome) } fn eofcreate( &mut self, - context: &mut EvmContext<&mut dyn DatabaseExt>, + context: &mut EthEvmContext<&mut dyn DatabaseExt>, create: &mut EOFCreateInputs, ) -> Option { self.as_mut().eofcreate(context, create) @@ -1150,17 +1166,17 @@ impl Inspector<&mut dyn DatabaseExt> for InspectorStack { fn eofcreate_end( &mut self, - context: &mut EvmContext<&mut dyn DatabaseExt>, + context: &mut EthEvmContext<&mut dyn DatabaseExt>, call: &EOFCreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { + outcome: &mut CreateOutcome, + ) { self.as_mut().eofcreate_end(context, call, outcome) } fn initialize_interp( &mut self, interpreter: &mut Interpreter, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, ) { self.as_mut().initialize_interp(interpreter, ecx) } @@ -1168,22 +1184,22 @@ impl Inspector<&mut dyn DatabaseExt> for InspectorStack { fn log( &mut self, interpreter: &mut Interpreter, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, - log: &Log, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, + log: Log, ) { self.as_mut().log(interpreter, ecx, log) } fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { - Inspector::<&mut dyn DatabaseExt>::selfdestruct(&mut self.as_mut(), contract, target, value) + self.as_mut().selfdestruct(contract, target, value); } } impl InspectorExt for InspectorStack { fn should_use_create2_factory( &mut self, - ecx: &mut EvmContext<&mut dyn DatabaseExt>, - inputs: &mut CreateInputs, + ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, + inputs: &CreateInputs, ) -> bool { self.as_mut().should_use_create2_factory(ecx, inputs) } diff --git a/crates/evm/evm/src/lib.rs b/crates/evm/evm/src/lib.rs index 15858c0f393aa..92d39026aa677 100644 --- a/crates/evm/evm/src/lib.rs +++ b/crates/evm/evm/src/lib.rs @@ -11,7 +11,9 @@ extern crate tracing; pub mod executors; pub mod inspectors; -pub use foundry_evm_core::{backend, constants, decode, fork, opts, utils, InspectorExt}; +pub use foundry_evm_core::{ + backend, constants, decode, fork, opts, utils, Env, EnvMut, EvmEnv, 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/evm/fuzz/src/inspector.rs b/crates/evm/fuzz/src/inspector.rs index 052d87dac2dd1..540e3aa86968f 100644 --- a/crates/evm/fuzz/src/inspector.rs +++ b/crates/evm/fuzz/src/inspector.rs @@ -1,7 +1,9 @@ use crate::{invariant::RandomCallGenerator, strategies::EvmFuzzState}; use revm::{ + context::{ContextTr, Transaction}, + inspector::JournalExt, interpreter::{CallInputs, CallOutcome, CallScheme, Interpreter}, - Database, EvmContext, Inspector, + Inspector, }; /// An inspector that can fuzz and collect data for that effect. @@ -15,9 +17,12 @@ pub struct Fuzzer { pub fuzz_state: EvmFuzzState, } -impl Inspector for Fuzzer { +impl Inspector for Fuzzer +where + CTX: ContextTr, +{ #[inline] - fn step(&mut self, interp: &mut Interpreter, _context: &mut EvmContext) { + fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) { // We only collect `stack` and `memory` data before and after calls. if self.collect { self.collect_data(interp); @@ -26,9 +31,9 @@ impl Inspector for Fuzzer { } #[inline] - fn call(&mut self, ecx: &mut EvmContext, inputs: &mut CallInputs) -> Option { + fn call(&mut self, ecx: &mut CTX, inputs: &mut CallInputs) -> Option { // We don't want to override the very first call made to the test contract. - if self.call_generator.is_some() && ecx.env.tx.caller != inputs.caller { + if self.call_generator.is_some() && ecx.tx().caller() != inputs.caller { self.override_call(inputs); } @@ -40,12 +45,7 @@ impl Inspector for Fuzzer { } #[inline] - fn call_end( - &mut self, - _context: &mut EvmContext, - _inputs: &CallInputs, - outcome: CallOutcome, - ) -> CallOutcome { + fn call_end(&mut self, _context: &mut CTX, _inputs: &CallInputs, _outcome: &mut CallOutcome) { if let Some(ref mut call_generator) = self.call_generator { call_generator.used = false; } @@ -53,15 +53,13 @@ impl Inspector for Fuzzer { // We only collect `stack` and `memory` data before and after calls. // this will be turned off on the next `step` self.collect = true; - - outcome } } impl Fuzzer { /// Collects `stack` and `memory` values into the fuzz dictionary. fn collect_data(&mut self, interpreter: &Interpreter) { - self.fuzz_state.collect_values(interpreter.stack().data().iter().copied().map(Into::into)); + self.fuzz_state.collect_values(interpreter.stack.data().iter().copied().map(Into::into)); // TODO: disabled for now since it's flooding the dictionary // for index in 0..interpreter.shared_memory.len() / 32 { diff --git a/crates/evm/fuzz/src/strategies/param.rs b/crates/evm/fuzz/src/strategies/param.rs index 43dcdae7b00f3..a8834bcef9942 100644 --- a/crates/evm/fuzz/src/strategies/param.rs +++ b/crates/evm/fuzz/src/strategies/param.rs @@ -235,7 +235,7 @@ mod tests { }; use foundry_common::abi::get_func; use foundry_config::FuzzDictionaryConfig; - use revm::db::{CacheDB, EmptyDB}; + use revm::database::{CacheDB, EmptyDB}; #[test] fn can_fuzz_array() { diff --git a/crates/evm/fuzz/src/strategies/state.rs b/crates/evm/fuzz/src/strategies/state.rs index c598ada0accab..26b66807a7666 100644 --- a/crates/evm/fuzz/src/strategies/state.rs +++ b/crates/evm/fuzz/src/strategies/state.rs @@ -10,9 +10,9 @@ use foundry_config::FuzzDictionaryConfig; use foundry_evm_core::utils::StateChangeset; use parking_lot::{lock_api::RwLockReadGuard, RawRwLock, RwLock}; use revm::{ - db::{CacheDB, DatabaseRef, DbAccount}, - interpreter::opcode, - primitives::AccountInfo, + bytecode::opcode, + database::{CacheDB, DatabaseRef, DbAccount}, + state::AccountInfo, }; use std::{collections::BTreeMap, fmt, sync::Arc}; @@ -39,7 +39,7 @@ impl EvmFuzzState { deployed_libs: &[Address], ) -> Self { // Sort accounts to ensure deterministic dictionary generation from the same setUp state. - let mut accs = db.accounts.iter().collect::>(); + let mut accs = db.cache.accounts.iter().collect::>(); accs.sort_by_key(|(address, _)| *address); // Create fuzz dictionary and insert values from db state. diff --git a/crates/evm/traces/src/debug/mod.rs b/crates/evm/traces/src/debug/mod.rs index 0e6521a7f5a8c..0e07124597aa3 100644 --- a/crates/evm/traces/src/debug/mod.rs +++ b/crates/evm/traces/src/debug/mod.rs @@ -7,7 +7,7 @@ use alloy_dyn_abi::{ use alloy_primitives::U256; use foundry_common::fmt::format_token; use foundry_compilers::artifacts::sourcemap::{Jump, SourceElement}; -use revm::interpreter::OpCode; +use revm::bytecode::opcode::OpCode; use revm_inspectors::tracing::types::{CallTraceStep, DecodedInternalCall, DecodedTraceStep}; pub use sources::{ArtifactData, ContractSources, SourceData}; diff --git a/crates/evm/traces/src/debug/sources.rs b/crates/evm/traces/src/debug/sources.rs index 5c8d15ef19e65..cfd7056e5a8b6 100644 --- a/crates/evm/traces/src/debug/sources.rs +++ b/crates/evm/traces/src/debug/sources.rs @@ -8,7 +8,7 @@ use foundry_compilers::{ multi::MultiCompilerLanguage, Artifact, Compiler, ProjectCompileOutput, }; -use foundry_evm_core::utils::PcIcMap; +use foundry_evm_core::ic::PcIcMap; use foundry_linking::Linker; use rayon::prelude::*; use solar_parse::{interface::Session, Parser}; diff --git a/crates/evm/traces/src/lib.rs b/crates/evm/traces/src/lib.rs index 2107644793463..ab024a2c1f530 100644 --- a/crates/evm/traces/src/lib.rs +++ b/crates/evm/traces/src/lib.rs @@ -15,7 +15,7 @@ use foundry_common::{ contracts::{ContractsByAddress, ContractsByArtifact}, shell, }; -use revm::interpreter::OpCode; +use revm::bytecode::opcode::OpCode; use revm_inspectors::tracing::{ types::{DecodedTraceStep, TraceMemberOrder}, OpcodeFilter, diff --git a/crates/forge/Cargo.toml b/crates/forge/Cargo.toml index c03a708a1f38f..54f2845479cd1 100644 --- a/crates/forge/Cargo.toml +++ b/crates/forge/Cargo.toml @@ -24,6 +24,7 @@ foundry-common.workspace = true foundry-compilers = { workspace = true, features = ["full"] } foundry-config.workspace = true foundry-evm.workspace = true +foundry-evm-core.workspace = true foundry-wallets.workspace = true foundry-linking.workspace = true forge-script-sequence.workspace = true @@ -57,6 +58,8 @@ alloy-serde.workspace = true alloy-signer.workspace = true alloy-transport.workspace = true +revm.workspace = true + clap = { version = "4", features = ["derive", "env", "unicode", "wrap_help"] } clap_complete = "4" clap_complete_fig = "4" diff --git a/crates/forge/src/cmd/coverage.rs b/crates/forge/src/cmd/coverage.rs index 2b656c0be493f..3b2e04eb88b26 100644 --- a/crates/forge/src/cmd/coverage.rs +++ b/crates/forge/src/cmd/coverage.rs @@ -6,7 +6,6 @@ use crate::{ BytecodeReporter, ContractId, CoverageReport, CoverageReporter, CoverageSummaryReporter, DebugReporter, ItemAnchor, LcovReporter, }, - utils::IcPcMap, MultiContractRunnerBuilder, }; use alloy_primitives::{map::HashMap, Address, Bytes, U256}; @@ -23,6 +22,7 @@ use foundry_compilers::{ }; use foundry_config::Config; use foundry_evm::opts::EvmOpts; +use foundry_evm_core::ic::IcPcMap; use rayon::prelude::*; use semver::{Version, VersionReq}; use std::{ diff --git a/crates/forge/src/multi_runner.rs b/crates/forge/src/multi_runner.rs index 03e889c8c5544..9cc608113b711 100644 --- a/crates/forge/src/multi_runner.rs +++ b/crates/forge/src/multi_runner.rs @@ -23,10 +23,11 @@ use foundry_evm::{ opts::EvmOpts, revm, traces::{InternalTraceMode, TraceMode}, + Env, }; use foundry_linking::{LinkOutput, Linker}; use rayon::prelude::*; -use revm::primitives::SpecId; +use revm::primitives::hardfork::SpecId; use std::{ borrow::Borrow, collections::BTreeMap, @@ -249,10 +250,11 @@ impl MultiContractRunner { debug!("start executing all tests in contract"); + let executor = self.tcfg.executor(self.known_contracts.clone(), artifact_id, db.clone()); let runner = ContractRunner::new( &identifier, contract, - self.tcfg.executor(self.known_contracts.clone(), artifact_id, db.clone()), + executor, progress, tokio_handle, span, @@ -279,7 +281,7 @@ pub struct TestRunnerConfig { /// EVM configuration. pub evm_opts: EvmOpts, /// EVM environment. - pub env: revm::primitives::Env, + pub env: Env, /// EVM version. pub spec_id: SpecId, /// The address which will be used to deploy the initial contracts and send all transactions. @@ -472,7 +474,7 @@ impl MultiContractRunnerBuilder { self, root: &Path, output: &ProjectCompileOutput, - env: revm::primitives::Env, + env: Env, evm_opts: EvmOpts, ) -> Result { let contracts = output diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index bec547b078394..3de6dde23ea8e 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -2944,7 +2944,7 @@ contract ContractTest { ... Failing tests: Encountered 1 failing test in test/Foo.t.sol:ContractTest -[FAIL: EVM error; transaction validation error: call gas cost exceeds the gas limit] setUp() ([GAS]) +[FAIL: EVM error; transaction validation error: call [GAS_COST] exceeds the [GAS_LIMIT]] setUp() ([GAS]) Encountered a total of 1 failing tests, 0 tests succeeded diff --git a/crates/forge/tests/it/config.rs b/crates/forge/tests/it/config.rs index 022303d51380f..b0f9d8da20a80 100644 --- a/crates/forge/tests/it/config.rs +++ b/crates/forge/tests/it/config.rs @@ -6,12 +6,12 @@ use forge::{ }; use foundry_evm::{ decode::decode_console_logs, - revm::primitives::SpecId, traces::{decode_trace_arena, render_trace_arena, CallTraceDecoderBuilder}, }; use foundry_test_utils::{init_tracing, Filter}; use futures::future::join_all; use itertools::Itertools; +use revm::primitives::hardfork::SpecId; use std::collections::BTreeMap; /// How to execute a test run. diff --git a/crates/forge/tests/it/spec.rs b/crates/forge/tests/it/spec.rs index 52e581c33c921..99a3a5e7a98b2 100644 --- a/crates/forge/tests/it/spec.rs +++ b/crates/forge/tests/it/spec.rs @@ -1,8 +1,8 @@ //! Integration tests for EVM specifications. use crate::{config::*, test_helpers::TEST_DATA_PARIS}; -use foundry_evm::revm::primitives::SpecId; use foundry_test_utils::Filter; +use revm::primitives::hardfork::SpecId; #[tokio::test(flavor = "multi_thread")] async fn test_shanghai_compat() { diff --git a/crates/forge/tests/it/test_helpers.rs b/crates/forge/tests/it/test_helpers.rs index c6ac80c114608..918eabf765a41 100644 --- a/crates/forge/tests/it/test_helpers.rs +++ b/crates/forge/tests/it/test_helpers.rs @@ -2,7 +2,7 @@ use alloy_chains::NamedChain; use alloy_primitives::U256; -use forge::{revm::primitives::SpecId, MultiContractRunner, MultiContractRunnerBuilder}; +use forge::{MultiContractRunner, MultiContractRunnerBuilder}; use foundry_cli::utils::install_crypto_provider; use foundry_compilers::{ artifacts::{EvmVersion, Libraries, Settings}, @@ -19,6 +19,7 @@ use foundry_test_utils::{ fd_lock, init_tracing, rpc::{next_http_archive_rpc_url, next_rpc_endpoint}, }; +use revm::primitives::hardfork::SpecId; use std::{ env, fmt, io::Write, diff --git a/crates/script/src/simulate.rs b/crates/script/src/simulate.rs index 7cd23ee74bace..372cb4b250381 100644 --- a/crates/script/src/simulate.rs +++ b/crates/script/src/simulate.rs @@ -11,7 +11,7 @@ use crate::{ }; use alloy_chains::NamedChain; use alloy_network::TransactionBuilder; -use alloy_primitives::{map::HashMap, utils::format_units, Address, Bytes, TxKind, U256}; +use alloy_primitives::{map::HashMap, utils::format_units, Address, Bytes, TxKind}; use dialoguer::Confirm; use eyre::{Context, Result}; use forge_script_sequence::{ScriptSequence, TransactionWithMetadata}; @@ -139,7 +139,7 @@ impl PreSimulationState { // Simulate mining the transaction if the user passes `--slow`. if self.args.slow { - runner.executor.env_mut().block.number += U256::from(1); + runner.executor.env_mut().evm_env.block_env.number += 1; } let is_noop_tx = if let Some(to) = to { diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index 42d7e4f6a855e..3179503f28f90 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -1008,6 +1008,8 @@ fn test_redactions() -> snapbox::Redactions { ("[SOLC_VERSION]", r"Solc( version)? \d+.\d+.\d+"), ("[ELAPSED]", r"(finished )?in \d+(\.\d+)?\w?s( \(.*?s CPU time\))?"), ("[GAS]", r"[Gg]as( used)?: \d+"), + ("[GAS_COST]", r"[Gg]as cost\s*\(\d+\)"), + ("[GAS_LIMIT]", r"[Gg]as limit\s*\(\d+\)"), ("[AVG_GAS]", r"μ: \d+, ~: \d+"), ("[FILE]", r"-->.*\.sol"), ("[FILE]", r"Location(.|\n)*\.rs(.|\n)*Backtrace"), diff --git a/crates/verify/Cargo.toml b/crates/verify/Cargo.toml index 8e2ec24f7d4d4..1d3afe7923ced 100644 --- a/crates/verify/Cargo.toml +++ b/crates/verify/Cargo.toml @@ -18,18 +18,19 @@ foundry-config.workspace = true foundry-cli.workspace = true foundry-common.workspace = true foundry-evm.workspace = true +foundry-evm-core.workspace = true serde_json.workspace = true alloy-json-abi.workspace = true alloy-primitives.workspace = true alloy-rpc-types.workspace = true alloy-dyn-abi.workspace = true -revm-primitives.workspace = true serde.workspace = true eyre.workspace = true alloy-provider.workspace = true tracing.workspace = true foundry-compilers = { workspace = true, features = ["full"] } foundry-block-explorers = { workspace = true, features = ["foundry-compilers"] } +revm.workspace = true clap = { version = "4", features = ["derive", "env", "unicode", "wrap_help"] } reqwest = { workspace = true, features = ["json"] } diff --git a/crates/verify/src/bytecode.rs b/crates/verify/src/bytecode.rs index 5c84dbc64d6a0..ee2e96188dab3 100644 --- a/crates/verify/src/bytecode.rs +++ b/crates/verify/src/bytecode.rs @@ -7,7 +7,7 @@ use crate::{ }, verify::VerifierArgs, }; -use alloy_primitives::{hex, Address, Bytes, U256}; +use alloy_primitives::{hex, Address, Bytes, TxKind, U256}; use alloy_provider::{ network::{AnyTxEnvelope, TransactionBuilder}, Provider, @@ -23,7 +23,8 @@ use foundry_common::shell; use foundry_compilers::{artifacts::EvmVersion, info::ContractInfo}; use foundry_config::{figment, impl_figment_convert, Config}; use foundry_evm::{constants::DEFAULT_CREATE2_DEPLOYER, utils::configure_tx_req_env}; -use revm_primitives::{AccountInfo, TxKind}; +use foundry_evm_core::AsEnvMut; +use revm::state::AccountInfo; use std::path::PathBuf; impl_figment_convert!(VerifyBytecodeArgs); @@ -242,7 +243,7 @@ impl VerifyBytecodeArgs { ) .await?; - env.block.number = U256::ZERO; // Genesis block + env.evm_env.block_env.number = 0; let genesis_block = provider.get_block(gen_blk_num.into()).full().await?; // Setup genesis tx and env. @@ -253,15 +254,13 @@ impl VerifyBytecodeArgs { .into_create(); if let Some(ref block) = genesis_block { - configure_env_block(&mut env, block); + configure_env_block(&mut env.as_env_mut(), block); gen_tx_req.max_fee_per_gas = block.header.base_fee_per_gas.map(|g| g as u128); gen_tx_req.gas = Some(block.header.gas_limit); gen_tx_req.gas_price = block.header.base_fee_per_gas.map(|g| g as u128); } - // configure_tx_rq_env(&mut env, &gen_tx); - - configure_tx_req_env(&mut env, &gen_tx_req, None) + configure_tx_req_env(&mut env.as_env_mut(), &gen_tx_req, None) .wrap_err("Failed to configure tx request env")?; // Seed deployer account with funds @@ -444,7 +443,7 @@ impl VerifyBytecodeArgs { evm_opts, ) .await?; - env.block.number = U256::from(simulation_block); + env.evm_env.block_env.number = simulation_block; let block = provider.get_block(simulation_block.into()).full().await?; // Workaround for the NonceTooHigh issue as we're not simulating prior txs of the same @@ -460,7 +459,7 @@ impl VerifyBytecodeArgs { transaction.set_nonce(prev_block_nonce); if let Some(ref block) = block { - configure_env_block(&mut env, block) + configure_env_block(&mut env.as_env_mut(), block) } // Replace the `input` with local creation code in the creation tx. @@ -478,7 +477,7 @@ impl VerifyBytecodeArgs { } // configure_req__env(&mut env, &transaction.inner); - configure_tx_req_env(&mut env, &transaction, None) + configure_tx_req_env(&mut env.as_env_mut(), &transaction, None) .wrap_err("Failed to configure tx request env")?; let fork_address = crate::utils::deploy_contract( diff --git a/crates/verify/src/utils.rs b/crates/verify/src/utils.rs index 81defa05d0f7b..03eef1ff789ae 100644 --- a/crates/verify/src/utils.rs +++ b/crates/verify/src/utils.rs @@ -1,6 +1,6 @@ use crate::{bytecode::VerifyBytecodeArgs, types::VerificationType}; use alloy_dyn_abi::DynSolValue; -use alloy_primitives::{Address, Bytes, U256}; +use alloy_primitives::{Address, Bytes, TxKind}; use alloy_provider::{network::AnyRpcBlock, Provider}; use alloy_rpc_types::BlockId; use clap::ValueEnum; @@ -17,14 +17,10 @@ use foundry_compilers::artifacts::{BytecodeHash, CompactContractBytecode, EvmVer use foundry_config::Config; use foundry_evm::{ constants::DEFAULT_CREATE2_DEPLOYER, executors::TracingExecutor, opts::EvmOpts, - traces::TraceMode, + traces::TraceMode, Env, EnvMut, }; use reqwest::Url; -use revm_primitives::{ - db::Database, - env::{EnvWithHandlerCfg, HandlerCfg}, - Bytecode, Env, SpecId, TxKind, -}; +use revm::{bytecode::Bytecode, database::Database, primitives::hardfork::SpecId}; use semver::Version; use serde::{Deserialize, Serialize}; use yansi::Paint; @@ -330,13 +326,13 @@ pub async fn get_tracing_executor( Ok((env, executor)) } -pub fn configure_env_block(env: &mut Env, block: &AnyRpcBlock) { - env.block.timestamp = U256::from(block.header.timestamp); - env.block.coinbase = block.header.beneficiary; +pub fn configure_env_block(env: &mut EnvMut<'_>, block: &AnyRpcBlock) { + env.block.timestamp = block.header.timestamp; + env.block.beneficiary = block.header.beneficiary; env.block.difficulty = block.header.difficulty; env.block.prevrandao = Some(block.header.mix_hash.unwrap_or_default()); - env.block.basefee = U256::from(block.header.base_fee_per_gas.unwrap_or_default()); - env.block.gas_limit = U256::from(block.header.gas_limit); + env.block.basefee = block.header.base_fee_per_gas.unwrap_or_default(); + env.block.gas_limit = block.header.gas_limit; } pub fn deploy_contract( @@ -345,14 +341,19 @@ pub fn deploy_contract( spec_id: SpecId, to: Option, ) -> Result { - let env_with_handler = EnvWithHandlerCfg::new(Box::new(env.clone()), HandlerCfg::new(spec_id)); + let env = Env::new_with_spec_id( + env.evm_env.cfg_env.clone(), + env.evm_env.block_env.clone(), + env.tx.clone(), + spec_id, + ); if to.is_some_and(|to| to.is_call()) { let TxKind::Call(to) = to.unwrap() else { unreachable!() }; if to != DEFAULT_CREATE2_DEPLOYER { eyre::bail!("Transaction `to` address is not the default create2 deployer i.e the tx is not a contract creation tx."); } - let result = executor.transact_with_env(env_with_handler)?; + let result = executor.transact_with_env(env)?; trace!(transact_result = ?result.exit_reason); if result.result.len() != 20 { @@ -363,7 +364,7 @@ pub fn deploy_contract( Ok(Address::from_slice(&result.result)) } else { - let deploy_result = executor.deploy_with_env(env_with_handler, None)?; + let deploy_result = executor.deploy_with_env(env, None)?; trace!(deploy_result = ?deploy_result.raw.exit_reason); Ok(deploy_result.address) } diff --git a/crates/verify/src/verify.rs b/crates/verify/src/verify.rs index 8fd9c98236a5d..804813c7a96e7 100644 --- a/crates/verify/src/verify.rs +++ b/crates/verify/src/verify.rs @@ -6,7 +6,7 @@ use crate::{ utils::is_host_only, RetryArgs, }; -use alloy_primitives::Address; +use alloy_primitives::{map::HashSet, Address}; use alloy_provider::Provider; use clap::{Parser, ValueHint}; use eyre::Result; @@ -20,7 +20,6 @@ use foundry_compilers::{artifacts::EvmVersion, compilers::solc::Solc, info::Cont use foundry_config::{figment, impl_figment_convert, impl_figment_convert_cast, Config, SolcReq}; use itertools::Itertools; use reqwest::Url; -use revm_primitives::HashSet; use semver::BuildMetadata; use std::path::PathBuf; diff --git a/deny.toml b/deny.toml index 16d88e50ba78f..be6615d08685f 100644 --- a/deny.toml +++ b/deny.toml @@ -40,22 +40,23 @@ confidence-threshold = 0.8 # See https://spdx.org/licenses/ for list of possible licenses # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. allow = [ - "MIT", - "Apache-2.0", + "0BSD", "Apache-2.0 WITH LLVM-exception", + "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", + "BSL-1.0", + "CC0-1.0", + "CDDL-1.0", + "CDLA-Permissive-2.0", "ISC", + "MIT", + "MPL-2.0", + "OpenSSL", "Unicode-3.0", "Unlicense", "WTFPL", - "BSL-1.0", - "0BSD", - "MPL-2.0", - "CDDL-1.0", "Zlib", - "OpenSSL", - "CDLA-Permissive-2.0", ] # Allow 1 or more licenses on a per-crate basis, so that particular licenses @@ -97,6 +98,7 @@ unknown-registry = "warn" unknown-git = "deny" allow-git = [ "https://github.com/alloy-rs/alloy", + "https://github.com/foundry-rs/foundry-fork-db", "https://github.com/paradigmxyz/revm-inspectors", "https://github.com/bluealloy/revm", ] diff --git a/testdata/default/cheats/Fee.t.sol b/testdata/default/cheats/Fee.t.sol index d258eaf13704e..120627c0004e9 100644 --- a/testdata/default/cheats/Fee.t.sol +++ b/testdata/default/cheats/Fee.t.sol @@ -12,7 +12,7 @@ contract FeeTest is DSTest { assertEq(block.basefee, 10, "fee failed"); } - function testFeeFuzzed(uint256 fee) public { + function testFeeFuzzed(uint64 fee) public { vm.fee(fee); assertEq(block.basefee, fee, "fee failed"); } diff --git a/testdata/default/cheats/GetBlockTimestamp.t.sol b/testdata/default/cheats/GetBlockTimestamp.t.sol index edeaa0de79841..816bc0d1ef89e 100644 --- a/testdata/default/cheats/GetBlockTimestamp.t.sol +++ b/testdata/default/cheats/GetBlockTimestamp.t.sol @@ -18,7 +18,7 @@ contract GetBlockTimestampTest is DSTest { assertEq(vm.getBlockTimestamp(), 10, "warp failed"); } - function testGetTimestampWithWarpFuzzed(uint128 jump) public { + function testGetTimestampWithWarpFuzzed(uint32 jump) public { uint256 pre = vm.getBlockTimestamp(); vm.warp(pre + jump); assertEq(vm.getBlockTimestamp(), pre + jump, "warp failed"); diff --git a/testdata/default/cheats/Roll.t.sol b/testdata/default/cheats/Roll.t.sol index 87f909cdd373f..0f26e3a431d7a 100644 --- a/testdata/default/cheats/Roll.t.sol +++ b/testdata/default/cheats/Roll.t.sol @@ -12,7 +12,7 @@ contract RollTest is DSTest { assertEq(block.number, 10, "roll failed"); } - function testRollFuzzed(uint128 jump) public { + function testRollFuzzed(uint32 jump) public { uint256 pre = block.number; vm.roll(block.number + jump); assertEq(block.number, pre + jump, "roll failed"); diff --git a/testdata/default/cheats/Warp.t.sol b/testdata/default/cheats/Warp.t.sol index 42f373c6172f7..7ba53f6e5eda4 100644 --- a/testdata/default/cheats/Warp.t.sol +++ b/testdata/default/cheats/Warp.t.sol @@ -12,7 +12,7 @@ contract WarpTest is DSTest { assertEq(block.timestamp, 10, "warp failed"); } - function testWarpFuzzed(uint128 jump) public { + function testWarpFuzzed(uint32 jump) public { uint256 pre = block.timestamp; vm.warp(block.timestamp + jump); assertEq(block.timestamp, pre + jump, "warp failed"); diff --git a/testdata/default/cheats/getBlockNumber.t.sol b/testdata/default/cheats/getBlockNumber.t.sol index ebf240dd811a1..18e2a163f3b86 100644 --- a/testdata/default/cheats/getBlockNumber.t.sol +++ b/testdata/default/cheats/getBlockNumber.t.sol @@ -17,7 +17,7 @@ contract GetBlockNumberTest is DSTest { assertEq(vm.getBlockNumber(), 10, "could not get correct block height after roll"); } - function testGetBlockNumberWithRollFuzzed(uint128 jump) public { + function testGetBlockNumberWithRollFuzzed(uint32 jump) public { uint256 pre = vm.getBlockNumber(); vm.roll(pre + jump); assertEq(vm.getBlockNumber(), pre + jump, "could not get correct block height after roll"); From caab7d03f23043338fb6616a60e900cd16e598dc Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Mon, 19 May 2025 10:00:15 -0400 Subject: [PATCH 104/244] bump(`revm`: step 2): bump `alloy` + `revm` + `alloy-evm` + other deps to latest (#10454) * restructure, move out of utils into evm, precompiles and future handlers * clean up * clean up * improve docs * scaffold handler * evaluate how to add handles * prefer EnvRef over EnvMut * address feedback of owned env * revert get_or_insert_map workaround * avoid changing types, leave mut where previously, avoid unnecessary mut * start layout out handler registry connected to evm * get create2 from frame inputs * start adding create2 handler * continue create2handler * wrap up create2 handler * clean up * continue fixing types * generalize precompiles * clean up * tag inline * fix imports * start fixing cheatcode types * use `env` on handler * clean up * temp revert * odyssey precompile was deprecated * refix cheatcode types * clean up * still facing issues with borrow-checker, double mut * open questions around passing around env * minor fix * for now work around mutability limitations by limited cloning, unclear performance impact or whether it will work with cheatcode macros * continue fixing types, still issues around cheatcodes, inspector * bump revm * bump deps * minor type fixes * bump foundry-fork-db to handle c-kzg build issue * bump rust version * utilize Host, ContextTr, JournalTr to avoid double mutable borrows * temp revert * temp revert * restore handler, improve types * refactor types * restore types * restore, clean up * continue fixing types * clean up * continue fixing types * revert journal env cloning, still issues around double borrows * fix core types per conversation, use EnvMut<'_> * fix types * more progress for foundry-evm * mutate outcome in place * temp revert exec_create * some progress with porting with_evm core loop * remove redundant types * context -> test_context in Cheatcodes config * construct new handler, wrapping evm context, imports Handler trait * temporarily comment out exec_create section to unblock * add replacement of EnvWithHandlerCfg * minor fixes * continue fixing types * continue fixing types * continue fixing types * continue fixing types * continue types * fix cached_env * remove possibly incorrect handling of CreateOutcome on methods like do_eofcreate_end as outcome is now mutated in place * add custom_printer from revm19, porting for compatibility * cast: fix types * verify: fix types * forge + script: fix types * anvil: start fixing types * anvil: continue porting types * anvil: continue porting types * anvil: continue porting types * anvil: continue porting types, small fix in foundry-evm * use AnvilEvm * stash optimism hardfork specifics for now * temp mute anvil use in forge * apply apparant fixes, test still failing * clean up * revert to replay * apply possible nonce 0/1 fixes, committed to proceed * disable nonce check in local_evm_env * undo is_odyssey remove * always spawn evm with handler * replay() -> inspect_replay() * modify macro, comment out anvil related cast tests for the time being * reapply state depth = 1 * something like this? * introduce outer block for early return * print debugging * clean up * fix merge * migrate: anvil to revm 21 (#10361) * downgrade op-revm to 2.0.0 to resolve dep conflict * op-revm 3.0 uses revm 22 * add `as_mut_dyn` to trait `MaybeFullDatabase` as we now require mut db_ref access ( * Revert "add `as_mut_dyn` to trait `MaybeFullDatabase` as we now require mut db_ref access (" This reverts commit 84d11f1742df768d773253de216a223a7d4683e6. * fix: Inspector should be generic over CTX not DB * fixes helpers: new_evm_with_inspector_* to use CTX generic * fix: pass TxEnv to evm.transact * fix: inspector inference in TransactionExecutor and build_access_list_with_state * workaround: dup LogCollector to use with AnvilEvmContext * coz FoundryEvmContext is not generic over DB, instead hardoded to dyn DatabaseExt * fix tests * fix traces test * fix: use default kzg settings in blob validation * reintroduce OptimismHardfork * fix: disable nonce check if nonce is None * fix!: load state tests by addressing breaking changes in state files * BlockEnv Breaking change: - most fields now use `u64` instead of `U64` / `U256` - coinbase renamed to beneficiary - best_block_number is `u64`, prev `U64` * fix: access_list test by using evm.inspect_with_tx * fix: replace evm.transact with evm.inspect_with_tx * fix: make impl Inspector for AnvilInspector generic over CTX * fix: clone inspector in TransactionExecutor to enable evm.inspect_commit * fix: remove cloned inspector from TransactionExecutor * feat(`anvil`): op support revm 21 (#10407) * enable OpHardforks in NodeConfig * feat: add is_optimism flag to foundry_evm::Env * feat(`anvil`): set is_optimism in Backend * feat(`anvil`): introducing EvmContext enum holding Eth and Op variants. * adds OpEnv to foundry_evm_core * feat: EitherEvm * impl Evm for EitherEvm * integrate EitherEvm into RPC and executor *Map OpHaltReason and OpTransactionError * rm old evm helpers * feat(`foundry_evm`): add deposit tx parts field to Env * fix(`anvil`): set deposit tx parts in tx executor and backend.inspect_tx * nit * docs EitherEvm * nit * refac: return TxEnv and Deposit parts separately * nits * nit * make anvil result aliases more generic * nit * intermediary(`revm bump`): re-enable Anvil tests, remove duplicate `LogCollector`, entire codebase builds (#10412) * temp refactor, still facing issue * clean up * clean up * temp cleanup, can later be refd * clean up, refactor stack.rs to apply ecx restore from cache to outside lamba * fix * clean up * clean up * avoid borrowing mutably for clarity * use EthEvmContext directly * FoundryEvmContext -> EthEvmContext * continue * fix tests * fix inspectors * codebase now builds entirely * fix clippy lints * remove duplicate LogCollector in Anvil * fmt * fix clippy * fix doctests * disable nonce checks on forks, enforce setting of tx.nonce on set_nonce * fix: use `transact` from alloy-evm (#10417) * Patch revm to fix interpreter panic * bump revm * fix eof test * fix bytecode hash * fix fixture * fix fixture * fix fixture * chore: mv EitherEvm to foundry_evm (#10445) mv EitherEvm to foundry_evm_core * remove unused JournalTr * restore formatting, avoid diff * remove leftover comment re: optimism support * fix displays_chained_error test * fix doc test * remove optimism todo leftover * avoid direct field assignment, prefer *current. * create2 handler register * fix patch * fix test_broadcast_raw_create2_deployer * bump alloy and related deps apply patches for block-explorers and compilers * fix: common * fix gas meter test * fix * fix: ConsoleFmt proc_macro * more fixes * fix: validate bool removal from abi_decode_* * fix: use take_slice instead of take_slice_unchecked in Decoder * fix more validate bool removal * correctly reset env.tx to cached env, cfg and block, ref https://github.com/foundry-rs/foundry/blob/a34f4c989b94f572497631ff5c85909d674c23a6/crates/evm/evm/src/inspectors/stack.rs#L640-L649 * address more alloy-core 1.0 breaking changes * fix anvil * exec_create * fix cast * bump gcloudsdk in wallets * fix(`cheatcodes`): rand workaround Use ChaChaRng as temporary measure since proptest is on rand 8 * revert test_GasMeter, assert exact gas used * fix arbitrum test * address deprecations * doc test fixes * fix clippy warnings * remove leftover comment * fix assert_can_detect_unlinked_target_with_libraries, ref: https://github.com/bluealloy/revm/commit/fc54dd087ba9a96291b1130bc8be73ade5d01ea5 * fix gas metering tests * restore unintended .wrap_err changes, ref: https://github.com/search?q=repo%3Afoundry-rs%2Ffoundry%20wrap_err(%22EVM%20error%22)&type=code * fix test_cheats_local_default * add CC0-1.0 license exception, has been previously approved in Reth: https://github.com/paradigmxyz/reth/blob/adb8bdc70758558d6122e87d78d73cc0f12d4dbb/deny.toml#L48 * usize depth * repin foundry-fork-db, this aligns the revm and alloy version back * fix clippy, after usize depth change * allow foundry-fork-db as git exception * revm 23 * fix: EitherEvm should work over OpTransaction * bump compilers and explorers * fix fmt * Env::from_with_spec_id -> Env::new_with_spec_id * bump clippy msrv to align with foundry.toml * chore: avoid leaking Anvil specific optimism fields into evm/core (#10466) * start sketching * maybe ? * some kind of conversion still required * continue porting * clean up types * pass op transaction in directly * fixes * restore setting of enveloped_tx * refactor anvil Env and reduce changes in tx processing * apply revm bump fixes, solar fixes * bump op-alloy-* * bump to msrv 1.86 for solar, use 0.15.* for alloy instead of pinning to 0.15.0, use alloy-evm patch for .use_ref() issue * fix: correctly set txtype when setting up TxEnv * start upgrading to revm 23 * bump PR to be revm 23+ compatible * fix: correctly set txtype when setting up TxEnv * fix: correctly set txtype when setting up TxEnv * clean up * fix merge conflict, apply fixes from upstream * bump to 0.7.2 * fix order * update block-explorers and compilers * fix clippy * fix failing abi test * empty * integrate BlobParams into anvil * fix tests * fix cast decode-event * fix tests * fix colored_traces * fix gas pausing * fix tests * fix test * update last commits from master to be u64 compatible * syn no longer implements PartialEq requiring us to use `matches!` * temp comment out journal push loop * fix clippy lint * revert clippy changes, make sure lint-foundry uses nightly clippy version * also assert that blob_count is less than the configured max_blob_count * fix: only upgrade tx_type to eip-2930 (type 1) if it is a legacy tx * optimistically remove previous workaround that was required for internal tracking, tests do not indicate it is longer required * nit * prefer using typed TransactionType over raw u8 * apply tx_type if set, upgrading from legacy to eip2930 if access_list is present and tx type is legacy * restore #[ret] macro that was removed unintendedly * replace redundant Env::new_with_spec_id(..) with default * allow passing is_optimism into Env constructor specific to Anvil * extract environment configuration into init.rs to make configuring the environment less error prone * remove redundant debug derive * restore #[cold] do hardhat log, previously preferred inline because of new context requirement for bytes but we refactor resolved this * avoid code duplication, add documented `apply_accesslist` * alloy 1.0 + fork-db 0.14 + op-alloy 0.16 + revm-insp 0.22 + block-explorers 0.17 * fix clippy * Update crates/evm/evm/src/inspectors/logs.rs Co-authored-by: Arsenii Kulikov * fix fmt * set env tx type by deriving tx type from other fields if no transaction_type has been set * use hardfork configured max_blob_count rather than hardcoded Dancun in assertion and error message * add temporary workaround for failing StdChains test because eth.llamarpc.com is down * bump(`revm`: step 3): reintroduce precompile injection (#10508) * sketching * sketch * sketch * restore test * add echo precompile test * pick a safe non precompile target outside of 0x00-0xff range * add op evm test * instead of activating all precompiles by default we activate selectively based on the spec defined * add note for us pinning to OpSpecId::BEDROCK here, we should make this configurable * bump deps to latest --------- Co-authored-by: zerosnacks Co-authored-by: Arsenii Kulikov Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Co-authored-by: grandizzy --- Cargo.lock | 1188 ++++++++++------- Cargo.toml | 104 +- clippy.toml | 2 +- crates/anvil/Cargo.toml | 1 + crates/anvil/core/src/eth/mod.rs | 1 - crates/anvil/core/src/eth/subscription.rs | 4 +- crates/anvil/core/src/eth/transaction/mod.rs | 19 +- crates/anvil/src/cmd.rs | 4 +- crates/anvil/src/config.rs | 2 +- crates/anvil/src/eth/api.rs | 2 +- crates/anvil/src/eth/backend/executor.rs | 60 +- crates/anvil/src/eth/backend/mem/mod.rs | 96 +- crates/anvil/src/eth/error.rs | 4 +- crates/anvil/src/eth/fees.rs | 4 +- crates/anvil/src/eth/otterscan/api.rs | 2 +- crates/anvil/src/eth/sign.rs | 2 +- crates/anvil/src/evm.rs | 344 +++-- crates/anvil/src/lib.rs | 3 +- crates/anvil/tests/it/anvil_api.rs | 21 +- crates/anvil/tests/it/api.rs | 22 +- crates/anvil/tests/it/eip4844.rs | 4 +- crates/anvil/tests/it/fork.rs | 20 +- crates/anvil/tests/it/otterscan.rs | 10 +- crates/anvil/tests/it/pubsub.rs | 4 +- crates/anvil/tests/it/state.rs | 4 +- crates/anvil/tests/it/transaction.rs | 52 +- crates/cast/Cargo.toml | 1 + crates/cast/src/args.rs | 13 +- crates/cast/src/cmd/create2.rs | 2 +- crates/cast/src/cmd/send.rs | 2 +- crates/cast/src/cmd/wallet/mod.rs | 4 +- crates/cast/src/cmd/wallet/vanity.rs | 2 +- crates/cast/src/lib.rs | 5 +- crates/cast/tests/cli/main.rs | 4 +- crates/cheatcodes/Cargo.toml | 1 + crates/cheatcodes/src/crypto.rs | 8 +- crates/cheatcodes/src/evm.rs | 4 +- crates/cheatcodes/src/evm/mapping.rs | 5 +- crates/cheatcodes/src/inspector.rs | 106 +- crates/cheatcodes/src/inspector/utils.rs | 1 + crates/cheatcodes/src/test/expect.rs | 1 + crates/cheatcodes/src/test/revert_handlers.rs | 4 +- crates/cheatcodes/src/utils.rs | 4 +- crates/common/fmt/src/eof.rs | 6 +- crates/common/src/abi.rs | 11 +- crates/common/src/constants.rs | 11 +- crates/common/src/contracts.rs | 2 +- crates/common/src/ens.rs | 19 +- crates/common/src/preprocessor/deps.rs | 11 +- crates/common/src/provider/mod.rs | 4 +- .../common/src/provider/runtime_transport.rs | 8 +- crates/evm/core/src/backend/mod.rs | 13 +- crates/evm/core/src/decode.rs | 10 +- crates/evm/core/src/either_evm.rs | 23 + crates/evm/core/src/evm.rs | 116 +- crates/evm/core/src/utils.rs | 28 +- crates/evm/evm/src/executors/fuzz/mod.rs | 2 +- crates/evm/evm/src/executors/invariant/mod.rs | 43 +- crates/evm/evm/src/executors/mod.rs | 8 +- crates/evm/evm/src/inspectors/chisel_state.rs | 2 +- crates/evm/evm/src/inspectors/logs.rs | 13 +- crates/evm/evm/src/inspectors/stack.rs | 10 +- crates/evm/fuzz/src/inspector.rs | 4 +- crates/evm/fuzz/src/lib.rs | 2 +- crates/evm/fuzz/src/strategies/int.rs | 2 +- crates/evm/fuzz/src/strategies/invariants.rs | 2 +- crates/evm/fuzz/src/strategies/state.rs | 4 +- crates/evm/fuzz/src/strategies/uint.rs | 2 +- crates/evm/traces/src/decoder/mod.rs | 16 +- crates/evm/traces/src/decoder/precompiles.rs | 30 +- crates/evm/traces/src/identifier/local.rs | 2 +- crates/forge/src/cmd/create.rs | 2 +- crates/forge/src/runner.rs | 12 +- crates/forge/tests/cli/cmd.rs | 2 +- crates/forge/tests/cli/test_cmd.rs | 2 - .../forge/tests/fixtures/colored_traces.svg | 14 +- crates/forge/tests/it/repros.rs | 2 +- crates/forge/tests/it/test_helpers.rs | 4 +- crates/macros/src/console_fmt.rs | 30 +- crates/script/src/execute.rs | 4 +- crates/script/src/transaction.rs | 4 +- crates/test-utils/src/rpc.rs | 2 +- crates/wallets/Cargo.toml | 2 +- crates/wallets/src/wallet_signer.rs | 16 +- testdata/default/cheats/Etch.t.sol | 2 +- 85 files changed, 1575 insertions(+), 1073 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d5d411c5c5da6..8d5e61e08da0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,15 +30,15 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.2.16", + "getrandom 0.3.3", "once_cell", "version_check", - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -58,11 +58,11 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-chains" -version = "0.1.69" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28e2652684758b0d9b389d248b209ed9fd9989ef489a550265fe4bb8454fe7eb" +checksum = "7734aecfc58a597dde036e4c5cace2ae43e2f8bf3d406b022a1ef34da178dd49" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "num_enum", "serde", "strum 0.27.1", @@ -70,14 +70,14 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27d301f5bcfd37e3aac727c360d8b50c33ddff9169ce0370198dedda36a9927d" +checksum = "785982a9b7b86d3fdf4ca43eb9a82447ccb7188ea78804ce64b6d6d82cc3e202" dependencies = [ - "alloy-eips", - "alloy-primitives", + "alloy-eips 1.0.3", + "alloy-primitives 1.1.0", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.0.3", "alloy-trie", "auto_impl", "c-kzg", @@ -86,6 +86,7 @@ dependencies = [ "k256", "once_cell", "rand 0.8.5", + "secp256k1", "serde", "serde_with", "thiserror 2.0.12", @@ -93,34 +94,34 @@ dependencies = [ [[package]] name = "alloy-consensus-any" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f4f97a85a45965e0e4f9f5b94bbafaa3e4ee6868bdbcf2e4a9acb4b358038fe" +checksum = "81d0d4b81bd538d023236b5301582c962aa2f2043d1b3a1373ea88fbee82a8e0" dependencies = [ "alloy-consensus", - "alloy-eips", - "alloy-primitives", + "alloy-eips 1.0.3", + "alloy-primitives 1.1.0", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.0.3", "serde", ] [[package]] name = "alloy-contract" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f39e8b96c9e25dde7222372332489075f7e750e4fd3e81c11eec0939b78b71b8" +checksum = "39564a2dcb9412294c70f6a797ccbf411586f4fe8ab01efb03bb3cabd0b42023" dependencies = [ "alloy-consensus", - "alloy-dyn-abi", - "alloy-json-abi", + "alloy-dyn-abi 1.1.0", + "alloy-json-abi 1.1.0", "alloy-network", "alloy-network-primitives", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-provider", "alloy-pubsub", "alloy-rpc-types-eth", - "alloy-sol-types", + "alloy-sol-types 1.1.0", "alloy-transport", "futures", "futures-util", @@ -133,10 +134,27 @@ version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb8e762aefd39a397ff485bc86df673465c4ad3ec8819cc60833a8a3ba5cdc87" dependencies = [ - "alloy-json-abi", - "alloy-primitives", - "alloy-sol-type-parser", - "alloy-sol-types", + "alloy-json-abi 0.8.25", + "alloy-primitives 0.8.25", + "alloy-sol-type-parser 0.8.25", + "alloy-sol-types 0.8.25", + "const-hex", + "itoa", + "serde", + "serde_json", + "winnow 0.7.10", +] + +[[package]] +name = "alloy-dyn-abi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f90b63261b7744642f6075ed17db6de118eecbe9516ea6c6ffd444b80180b75" +dependencies = [ + "alloy-json-abi 1.1.0", + "alloy-primitives 1.1.0", + "alloy-sol-type-parser 1.1.0", + "alloy-sol-types 1.1.0", "arbitrary", "const-hex", "derive_arbitrary", @@ -150,11 +168,11 @@ dependencies = [ [[package]] name = "alloy-eip2124" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "675264c957689f0fd75f5993a73123c2cc3b5c235a38f5b9037fe6c826bfb2c0" +checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-rlp", "crc", "serde", @@ -163,22 +181,22 @@ dependencies = [ [[package]] name = "alloy-eip2930" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" +checksum = "7b82752a889170df67bbb36d42ca63c531eb16274f0d7299ae2a680facba17bd" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-rlp", "serde", ] [[package]] name = "alloy-eip7702" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b15b13d38b366d01e818fe8e710d4d702ef7499eacd44926a06171dd9585d0c" +checksum = "804cefe429015b4244966c006d25bda5545fa9db5990e9c9079faf255052f50a" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-rlp", "k256", "serde", @@ -187,16 +205,36 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "0.13.0" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "609515c1955b33af3d78d26357540f68c5551a90ef58fd53def04f2aa074ec43" +dependencies = [ + "alloy-eip2124", + "alloy-eip2930", + "alloy-eip7702", + "alloy-primitives 1.1.0", + "alloy-rlp", + "alloy-serde 0.14.0", + "auto_impl", + "c-kzg", + "derive_more 2.0.1", + "either", + "serde", + "sha2 0.10.9", +] + +[[package]] +name = "alloy-eips" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10b11c382ca8075128d1ae6822b60921cf484c911d9a5831797a01218f98125f" +checksum = "7f29e7fda66a9d3315db883947a21b79f018cf6d873ee51660a93cb712696928" dependencies = [ "alloy-eip2124", "alloy-eip2930", "alloy-eip7702", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.0.3", "auto_impl", "c-kzg", "derive_more 2.0.1", @@ -207,15 +245,15 @@ dependencies = [ [[package]] name = "alloy-evm" -version = "0.3.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71b0b181c956dca015b4c08b36668736013787c9dc9e743fd39a23b8b130c14" +checksum = "de0210f2d5854895b376f7fbbf78f3e33eb4f0e59abc503502cc0ed8d295a837" dependencies = [ "alloy-consensus", - "alloy-eips", + "alloy-eips 1.0.3", "alloy-hardforks", - "alloy-primitives", - "alloy-sol-types", + "alloy-primitives 1.1.0", + "alloy-sol-types 1.1.0", "auto_impl", "derive_more 2.0.1", "op-alloy-consensus", @@ -226,26 +264,26 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd9e75c5dd40319ebbe807ebe9dfb10c24e4a70d9c7d638e62921d8dd093c8b" +checksum = "cfc71c06880f44758e8c748db17f3e4661240bfa06f665089097e8cdd0583ca4" dependencies = [ - "alloy-eips", - "alloy-primitives", - "alloy-serde", + "alloy-eips 1.0.3", + "alloy-primitives 1.1.0", + "alloy-serde 1.0.3", "alloy-trie", "serde", ] [[package]] name = "alloy-hardforks" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473ee2ab7f5262b36e8fbc1b5327d5c9d488ab247e31ac739b929dbe2444ae79" +checksum = "c7d3b2243e2adfaea41da41982f91ecab8083fa51b240d0427955d709f65b1b4" dependencies = [ "alloy-chains", "alloy-eip2124", - "alloy-primitives", + "alloy-primitives 1.1.0", "auto_impl", "dyn-clone", ] @@ -256,20 +294,32 @@ version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe6beff64ad0aa6ad1019a3db26fef565aefeb011736150ab73ed3366c3cfd1b" dependencies = [ - "alloy-primitives", - "alloy-sol-type-parser", + "alloy-primitives 0.8.25", + "alloy-sol-type-parser 0.8.25", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-json-abi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0068ae277f5ee3153a95eaea8ff10e188ed8ccde9b7f9926305415a2c0ab2442" +dependencies = [ + "alloy-primitives 1.1.0", + "alloy-sol-type-parser 1.1.0", "serde", "serde_json", ] [[package]] name = "alloy-json-rpc" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbcf26d02a72e23d5bc245425ea403c93ba17d254f20f9c23556a249c6c7e143" +checksum = "265ebe8c014bf3f1c7872a208e6fd3a157b93405ec826383492dbe31085197aa" dependencies = [ - "alloy-primitives", - "alloy-sol-types", + "alloy-primitives 1.1.0", + "alloy-sol-types 1.1.0", "serde", "serde_json", "thiserror 2.0.12", @@ -278,21 +328,21 @@ dependencies = [ [[package]] name = "alloy-network" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b44dd4429e190f727358571175ebf323db360a303bf4e1731213f510ced1c2e6" +checksum = "1a9d67becc5c6dd5c85e0f4a9cda0a1f4d5805749b8b4da906d96947ef801dd5" dependencies = [ "alloy-consensus", "alloy-consensus-any", - "alloy-eips", + "alloy-eips 1.0.3", "alloy-json-rpc", "alloy-network-primitives", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-rpc-types-any", "alloy-rpc-types-eth", - "alloy-serde", + "alloy-serde 1.0.3", "alloy-signer", - "alloy-sol-types", + "alloy-sol-types 1.1.0", "async-trait", "auto_impl", "derive_more 2.0.1", @@ -304,28 +354,28 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f736e1d1eb1b770dbd32919bdf46d4dcd4617f2eed07947dfb32649962baba" +checksum = "60301cdd4e0b9059ec53a5b34dc93c245947638b95634000f92c5f10acd17fbf" dependencies = [ "alloy-consensus", - "alloy-eips", - "alloy-primitives", - "alloy-serde", + "alloy-eips 1.0.3", + "alloy-primitives 1.1.0", + "alloy-serde 1.0.3", "serde", ] [[package]] name = "alloy-op-evm" -version = "0.3.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324cf0b3b08b4c3354460dee8208384a59245da8b0eaefe9e962d3942d919d58" +checksum = "5ee0165cc5f92d8866c0a21320ee6f089a7e1d0cebbf7008c37a6380a912ebe2" dependencies = [ "alloy-consensus", - "alloy-eips", + "alloy-eips 1.0.3", "alloy-evm", "alloy-op-hardforks", - "alloy-primitives", + "alloy-primitives 1.1.0", "auto_impl", "op-alloy-consensus", "op-revm", @@ -334,9 +384,9 @@ dependencies = [ [[package]] name = "alloy-op-hardforks" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "217a4efe17c43df77c1f261825350be0be1d907f56eb38a4b258936e33cfd1d8" +checksum = "04a45f2af91a348e5d22dbb3589d821d2e83d2e65b54c14c3f9e8e9c6903fc09" dependencies = [ "alloy-hardforks", "auto_impl", @@ -347,6 +397,33 @@ name = "alloy-primitives" version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c77490fe91a0ce933a1f219029521f20fc28c2c0ca95d53fa4da9c00b8d9d4e" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more 2.0.1", + "foldhash", + "hashbrown 0.15.3", + "indexmap 2.9.0", + "itoa", + "k256", + "keccak-asm", + "paste", + "proptest", + "rand 0.8.5", + "ruint", + "rustc-hash 2.1.1", + "serde", + "sha3", + "tiny-keccak", +] + +[[package]] +name = "alloy-primitives" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a12fe11d0b8118e551c29e1a67ccb6d01cc07ef08086df30f07487146de6fa1" dependencies = [ "alloy-rlp", "arbitrary", @@ -356,7 +433,7 @@ dependencies = [ "derive_arbitrary", "derive_more 2.0.1", "foldhash", - "getrandom 0.2.16", + "getrandom 0.3.3", "hashbrown 0.15.3", "indexmap 2.9.0", "itoa", @@ -365,7 +442,7 @@ dependencies = [ "paste", "proptest", "proptest-derive", - "rand 0.8.5", + "rand 0.9.1", "ruint", "rustc-hash 2.1.1", "serde", @@ -375,17 +452,17 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a557f9e3ec89437b06db3bfc97d20782b1f7cc55b5b602b6a82bf3f64d7efb0e" +checksum = "4af4bd045e414b3b52e929d31a9413bf072dd78cee9b962eb2d9fc5e500c3ccb" dependencies = [ "alloy-chains", "alloy-consensus", - "alloy-eips", + "alloy-eips 1.0.3", "alloy-json-rpc", "alloy-network", "alloy-network-primitives", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-pubsub", "alloy-rpc-client", "alloy-rpc-types-debug", @@ -393,7 +470,7 @@ dependencies = [ "alloy-rpc-types-trace", "alloy-rpc-types-txpool", "alloy-signer", - "alloy-sol-types", + "alloy-sol-types 1.1.0", "alloy-transport", "alloy-transport-http", "alloy-transport-ipc", @@ -420,12 +497,12 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0a261caff6c2ec6fe1d6eb77ba41159024c8387d05e4138804a387d403def55" +checksum = "cfbb328bc2538e10b17570eae25e5ecb2cdb97b729caa115617e124b05e9463e" dependencies = [ "alloy-json-rpc", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-transport", "bimap", "futures", @@ -436,6 +513,7 @@ dependencies = [ "tokio-stream", "tower 0.5.2", "tracing", + "wasmtimer", ] [[package]] @@ -462,12 +540,12 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec6dc89c4c3ef166f9fa436d1831f8142c16cf2e637647c936a6aaaabd8d898" +checksum = "6707200ade3dd821585ec208022a273889f328ee1e76014c9a81820ef6d3c48d" dependencies = [ "alloy-json-rpc", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-pubsub", "alloy-transport", "alloy-transport-http", @@ -490,64 +568,64 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3849f8131a18cc5d7f95f301d68a6af5aa2db28ad8522fb9db1f27b3794e8b68" +checksum = "a891e871830c1ef6e105a08f615fbb178b2edc4c75c203bf47c64dfa21acd849" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-rpc-types-anvil", "alloy-rpc-types-engine", "alloy-rpc-types-eth", "alloy-rpc-types-trace", "alloy-rpc-types-txpool", - "alloy-serde", + "alloy-serde 1.0.3", "serde", ] [[package]] name = "alloy-rpc-types-anvil" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19051fd5e8de7e1f95ec228c9303debd776dcc7caf8d1ece3191f711f5c06541" +checksum = "2f7e3f1efdb3ef6f2e0e09036099933f9d96ff1d3129be4b2e5394550a58b39d" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-rpc-types-eth", - "alloy-serde", + "alloy-serde 1.0.3", "serde", ] [[package]] name = "alloy-rpc-types-any" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd6d480e4e6e456f30eeeb3aef1512aaecb68df2a35d1f78865dbc4d20dc0fd" +checksum = "518c67d8465f885c7524f0fe2cc32861635e9409a6f2efc015e306ca8d73f377" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", - "alloy-serde", + "alloy-serde 1.0.3", ] [[package]] name = "alloy-rpc-types-debug" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "805eb9fa07f92f1225253e842b5454b4b3e258813445c1a1c9d8dd0fd90817c1" +checksum = "5cc83d5587cdfcfb3f9cfb83484c319ce1f5eec4da11c357153725785c17433c" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "serde", ] [[package]] name = "alloy-rpc-types-engine" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "689521777149dabe210ef122605fb00050e038f2e85b8c9897534739f1a904f8" +checksum = "85872461c13427e7715809871dfff8945df9309169e378a8737c8b0880a72b1b" dependencies = [ "alloy-consensus", - "alloy-eips", - "alloy-primitives", + "alloy-eips 1.0.3", + "alloy-primitives 1.1.0", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.0.3", "derive_more 2.0.1", "jsonwebtoken", "rand 0.8.5", @@ -557,18 +635,18 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8b6d55bdaa0c4a08650d4b32f174494cbade56adf6f2fcfa2a4f3490cb5511" +checksum = "117b370f315c7f6c856c51d840fef8728f9738ce46f5f48c2f6a901da454da81" dependencies = [ "alloy-consensus", "alloy-consensus-any", - "alloy-eips", + "alloy-eips 1.0.3", "alloy-network-primitives", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-rlp", - "alloy-serde", - "alloy-sol-types", + "alloy-serde 1.0.3", + "alloy-sol-types 1.1.0", "itertools 0.14.0", "serde", "serde_json", @@ -577,13 +655,13 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6019cd6a89230d765a621a7b1bc8af46a6a9cde2d2e540e6f9ce930e0fb7c6db" +checksum = "356253f9ad65afe964733c6c3677a70041424359bd6340ab5597ff37185c1a82" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-rpc-types-eth", - "alloy-serde", + "alloy-serde 1.0.3", "serde", "serde_json", "thiserror 2.0.12", @@ -591,36 +669,47 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee36e5404642696af511f09991f9f54a11b90e86e55efad868f8f56350eff5b0" +checksum = "d17e23d6d3e3fafaed4e4950c93172ee23ec665f54ca644dbdab418f90d24e46" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-rpc-types-eth", - "alloy-serde", + "alloy-serde 1.0.3", "serde", ] [[package]] name = "alloy-serde" -version = "0.13.0" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4dba6ff08916bc0a9cbba121ce21f67c0b554c39cf174bc7b9df6c651bd3c3b" +dependencies = [ + "alloy-primitives 1.1.0", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-serde" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1824791912f468a481dedc1db50feef3e85a078f6d743a62db2ee9c2ca674882" +checksum = "fcfe8652fc1500463a9193e90feb4628f243f5758e54abd41fa6310df80d3de9" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "serde", "serde_json", ] [[package]] name = "alloy-signer" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d087fe5aea96a93fbe71be8aaed5c57c3caac303c09e674bc5b1647990d648b" +checksum = "167a38442a3626ef0bf8295422f339b1392f56574c13017f2718bf5bdf878c6a" dependencies = [ - "alloy-dyn-abi", - "alloy-primitives", - "alloy-sol-types", + "alloy-dyn-abi 1.1.0", + "alloy-primitives 1.1.0", + "alloy-sol-types 1.1.0", "async-trait", "auto_impl", "either", @@ -631,13 +720,13 @@ dependencies = [ [[package]] name = "alloy-signer-aws" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6623e424e692388d0c42071ed997513d7a19d8b83e83732466c0c93aedd486bd" +checksum = "3b1e4c85d2dc9e94bd7829375193bc0406fc296a85120fb942ddf0299567c195" dependencies = [ "alloy-consensus", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-signer", "async-trait", "aws-sdk-kms", @@ -649,16 +738,16 @@ dependencies = [ [[package]] name = "alloy-signer-gcp" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53755624ad8fbd12be2dc2e9df31cbab38e4067fa3d4ba02814145535a221f98" +checksum = "c91bd57f930e0c2c56121dc34154f98d11d029170848a5901c6d5a47bc23e117" dependencies = [ "alloy-consensus", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-signer", "async-trait", - "gcloud-sdk", + "gcloud-sdk 0.27.1", "k256", "spki", "thiserror 2.0.12", @@ -667,16 +756,16 @@ dependencies = [ [[package]] name = "alloy-signer-ledger" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4224cd9c7b8107b1f7973361e81cf75e20a99835bcdc6ba7ac8ea50a6256e47" +checksum = "173704b2618f1ef66f6eebe5fca507ffb303455ff634a541331140db069e6de4" dependencies = [ "alloy-consensus", - "alloy-dyn-abi", + "alloy-dyn-abi 1.1.0", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-signer", - "alloy-sol-types", + "alloy-sol-types 1.1.0", "async-trait", "coins-ledger", "futures-util", @@ -687,13 +776,13 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2940353d2425bb75965cd5101075334e6271051e35610f903bf8099a52b0b1a9" +checksum = "92f04bf5386358318a17d189bb56bc1ef00320de4aa9ce939ae8cf76e3178ca0" dependencies = [ "alloy-consensus", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-signer", "async-trait", "coins-bip32", @@ -706,13 +795,13 @@ dependencies = [ [[package]] name = "alloy-signer-trezor" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bafd519704c7d9f2c449686e895a7681e5e7172bfef3f2d3ad8d0b4476d6f9d" +checksum = "5970e58fd000f26a5953d864a2c8b5a2672510436f5757830fa7cd93cc490cd8" dependencies = [ "alloy-consensus", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-signer", "async-trait", "semver 1.0.26", @@ -727,8 +816,22 @@ version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e10ae8e9a91d328ae954c22542415303919aabe976fe7a92eb06db1b68fd59f2" dependencies = [ - "alloy-sol-macro-expander", - "alloy-sol-macro-input", + "alloy-sol-macro-expander 0.8.25", + "alloy-sol-macro-input 0.8.25", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "alloy-sol-macro" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d3ef8e0d622453d969ba3cded54cf6800efdc85cb929fe22c5bdf8335666757" +dependencies = [ + "alloy-sol-macro-expander 1.1.0", + "alloy-sol-macro-input 1.1.0", "proc-macro-error2", "proc-macro2", "quote", @@ -741,8 +844,7 @@ version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83ad5da86c127751bc607c174d6c9fe9b85ef0889a9ca0c641735d77d4f98f26" dependencies = [ - "alloy-json-abi", - "alloy-sol-macro-input", + "alloy-sol-macro-input 0.8.25", "const-hex", "heck", "indexmap 2.9.0", @@ -750,7 +852,26 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.101", - "syn-solidity", + "syn-solidity 0.8.25", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0e84bd0693c69a8fbe3ec0008465e029c6293494df7cb07580bf4a33eff52e1" +dependencies = [ + "alloy-json-abi 1.1.0", + "alloy-sol-macro-input 1.1.0", + "const-hex", + "heck", + "indexmap 2.9.0", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.101", + "syn-solidity 1.1.0", "tiny-keccak", ] @@ -760,7 +881,23 @@ version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3d30f0d3f9ba3b7686f3ff1de9ee312647aac705604417a2f40c604f409a9e" dependencies = [ - "alloy-json-abi", + "const-hex", + "dunce", + "heck", + "macro-string", + "proc-macro2", + "quote", + "syn 2.0.101", + "syn-solidity 0.8.25", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3de663412dadf9b64f4f92f507f78deebcc92339d12cf15f88ded65d41c7935" +dependencies = [ + "alloy-json-abi 1.1.0", "const-hex", "dunce", "heck", @@ -769,7 +906,7 @@ dependencies = [ "quote", "serde_json", "syn 2.0.101", - "syn-solidity", + "syn-solidity 1.1.0", ] [[package]] @@ -782,26 +919,50 @@ dependencies = [ "winnow 0.7.10", ] +[[package]] +name = "alloy-sol-type-parser" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "251273c5aa1abb590852f795c938730fa641832fc8fa77b5478ed1bf11b6097e" +dependencies = [ + "serde", + "winnow 0.7.10", +] + [[package]] name = "alloy-sol-types" version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d43d5e60466a440230c07761aa67671d4719d46f43be8ea6e7ed334d8db4a9ab" dependencies = [ - "alloy-json-abi", - "alloy-primitives", - "alloy-sol-macro", + "alloy-json-abi 0.8.25", + "alloy-primitives 0.8.25", + "alloy-sol-macro 0.8.25", + "const-hex", + "serde", +] + +[[package]] +name = "alloy-sol-types" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5460a975434ae594fe2b91586253c1beb404353b78f0a55bf124abcd79557b15" +dependencies = [ + "alloy-json-abi 1.1.0", + "alloy-primitives 1.1.0", + "alloy-sol-macro 1.1.0", "const-hex", "serde", ] [[package]] name = "alloy-transport" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6818b4c82a474cc01ac9e88ccfcd9f9b7bc893b2f8aea7e890a28dcd55c0a7aa" +checksum = "c4f91badc9371554f9f5e1c4d0731c208fcfb14cfd1583af997425005a962689" dependencies = [ "alloy-json-rpc", + "alloy-primitives 1.1.0", "base64 0.22.1", "derive_more 2.0.1", "futures", @@ -819,9 +980,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cc3079a33483afa1b1365a3add3ea3e21c75b10f704870198ba7846627d10f2" +checksum = "1ca577cff7579e39d3b4312dcd68809bd1ca693445cfdcf53f4f466a9b6b3df3" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -834,9 +995,9 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c6f8e20aa6b748357bed157c14e561a176d0f6cffed7f99ee37758a7d16202" +checksum = "aed6f489a90092929a480cbe30d16a147fa89f859f8d9ef26f60555681503c8b" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -854,9 +1015,9 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "0.13.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef7a4301e8967c1998f193755fd9429e0ca81730e2e134e30c288c43dbf96f0" +checksum = "30aa80247a43d71bf683294907e74c634be7b4307d02530c856fac7fc4c2566a" dependencies = [ "alloy-pubsub", "alloy-transport", @@ -872,14 +1033,14 @@ dependencies = [ [[package]] name = "alloy-trie" -version = "0.7.9" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a94854e420f07e962f7807485856cde359ab99ab6413883e15235ad996e8b" +checksum = "983d99aa81f586cef9dae38443245e585840fcf0fc58b09aee0b1f27aed1d500" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-rlp", "arrayvec", - "derive_more 1.0.0", + "derive_more 2.0.1", "nybbles", "serde", "smallvec", @@ -1004,28 +1165,28 @@ dependencies = [ "alloy-chains", "alloy-consensus", "alloy-contract", - "alloy-dyn-abi", - "alloy-eips", + "alloy-dyn-abi 1.1.0", + "alloy-eips 1.0.3", "alloy-evm", "alloy-genesis", "alloy-network", "alloy-op-evm", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-provider", "alloy-pubsub", "alloy-rlp", "alloy-rpc-types", - "alloy-serde", + "alloy-serde 1.0.3", "alloy-signer", "alloy-signer-local", - "alloy-sol-types", + "alloy-sol-types 1.1.0", "alloy-transport", "alloy-trie", "anvil-core", "anvil-rpc", "anvil-server", "async-trait", - "axum", + "axum 0.7.9", "chrono", "clap", "clap_complete", @@ -1048,6 +1209,7 @@ dependencies = [ "op-revm", "parking_lot", "rand 0.8.5", + "rand 0.9.1", "revm", "revm-inspectors", "serde", @@ -1065,19 +1227,19 @@ name = "anvil-core" version = "1.2.0" dependencies = [ "alloy-consensus", - "alloy-dyn-abi", - "alloy-eips", + "alloy-dyn-abi 1.1.0", + "alloy-eips 1.0.3", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-rlp", "alloy-rpc-types", - "alloy-serde", + "alloy-serde 1.0.3", "bytes", "foundry-common", "foundry-evm", "op-alloy-consensus", "op-revm", - "rand 0.8.5", + "rand 0.9.1", "revm", "serde", "serde_json", @@ -1098,7 +1260,7 @@ version = "1.2.0" dependencies = [ "anvil-rpc", "async-trait", - "axum", + "axum 0.7.9", "bytes", "clap", "futures", @@ -1621,9 +1783,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b756939cb2f8dc900aa6dcd505e6e2428e9cae7ff7b028c49e3946efa70878" +checksum = "93fcc8f365936c834db5514fc45aee5b1202d677e6b40e48468aaaa8183ca8c7" dependencies = [ "aws-lc-sys", "zeroize", @@ -1631,9 +1793,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.28.2" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa9b6986f250236c27e5a204062434a773a13243d2ffc2955f37bdba4c5c6a1" +checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079" dependencies = [ "bindgen", "cc", @@ -1668,9 +1830,9 @@ dependencies = [ [[package]] name = "aws-sdk-kms" -version = "1.67.0" +version = "1.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b650cf9e1e153ab13acd3aa1f73b271dac14e019353ec0b0c176f24a21bad03" +checksum = "2fc85e33344e39319761a1bb4bb11ccd56f44bd763cb02539436c0d6cc6ea13d" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1691,9 +1853,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.66.0" +version = "1.67.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "858007b14d0f1ade2e0124473c2126b24d334dc9486ad12eb7c0ed14757be464" +checksum = "0d4863da26489d1e6da91d7e12b10c17e86c14f94c53f416bd10e0a9c34057ba" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1714,9 +1876,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.67.0" +version = "1.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b83abf3ae8bd10a014933cc2383964a12ca5a3ebbe1948ad26b1b808e7d0d1f2" +checksum = "95caa3998d7237789b57b95a8e031f60537adab21fa84c91e35bef9455c652e4" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1737,9 +1899,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.67.0" +version = "1.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74e8e9ac4a837859c8f1d747054172e1e55933f02ed34728b0b34dea0591ec84" +checksum = "4939f6f449a37308a78c5a910fd91265479bd2bb11d186f0b8fc114d89ec828d" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1814,9 +1976,9 @@ dependencies = [ [[package]] name = "aws-smithy-http-client" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aff1159006441d02e57204bf57a1b890ba68bedb6904ffd2873c1c4c11c546b" +checksum = "7e44697a9bded898dcd0b1cb997430d949b87f4f8940d91023ae9062bf218250" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -1957,7 +2119,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.4.5", "base64 0.22.1", "bytes", "futures-util", @@ -1967,7 +2129,7 @@ dependencies = [ "hyper", "hyper-util", "itoa", - "matchit", + "matchit 0.7.3", "memchr", "mime", "percent-encoding", @@ -1987,6 +2149,32 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" +dependencies = [ + "axum-core 0.5.2", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "itoa", + "matchit 0.8.4", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower 0.5.2", + "tower-layer", + "tower-service", +] + [[package]] name = "axum-core" version = "0.4.5" @@ -2008,6 +2196,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-core" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.75" @@ -2078,7 +2285,7 @@ dependencies = [ "bitflags 2.9.0", "cexpr", "clang-sys", - "itertools 0.11.0", + "itertools 0.12.1", "lazy_static", "lazycell", "log", @@ -2291,11 +2498,10 @@ dependencies = [ [[package]] name = "c-kzg" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7e3c397401eb76228c89561cf22f85f41c95aa799ee9d860de3ea1cbc728fc" +checksum = "7318cfa722931cb5fe0838b98d3ce5621e75f6a6408abc21721d80de9223f2e4" dependencies = [ - "arbitrary", "blst", "cc", "glob", @@ -2318,18 +2524,18 @@ dependencies = [ "alloy-chains", "alloy-consensus", "alloy-contract", - "alloy-dyn-abi", - "alloy-json-abi", + "alloy-dyn-abi 1.1.0", + "alloy-json-abi 1.1.0", "alloy-json-rpc", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-provider", "alloy-rlp", "alloy-rpc-types", - "alloy-serde", + "alloy-serde 1.0.3", "alloy-signer", "alloy-signer-local", - "alloy-sol-types", + "alloy-sol-types 1.1.0", "alloy-transport", "anvil", "aws-sdk-kms", @@ -2351,9 +2557,10 @@ dependencies = [ "foundry-test-utils", "foundry-wallets", "futures", - "gcloud-sdk", + "gcloud-sdk 0.26.4", "itertools 0.14.0", "rand 0.8.5", + "rand 0.9.1", "rayon", "regex", "revm", @@ -2378,9 +2585,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.21" +version = "1.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" +checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" dependencies = [ "jobserver", "libc", @@ -2412,9 +2619,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" name = "chisel" version = "1.2.0" dependencies = [ - "alloy-dyn-abi", - "alloy-json-abi", - "alloy-primitives", + "alloy-dyn-abi 1.1.0", + "alloy-json-abi 1.1.0", + "alloy-primitives 1.1.0", "clap", "dirs", "eyre", @@ -2505,9 +2712,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.37" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" +checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" dependencies = [ "clap_builder", "clap_derive", @@ -2525,9 +2732,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.37" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" +checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" dependencies = [ "anstream", "anstyle", @@ -2869,9 +3076,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] @@ -3003,11 +3210,11 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.6" +version = "3.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697b5419f348fd5ae2478e8018cb016c00a5881c7f46c717de98ffd135a5651c" +checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" dependencies = [ - "nix 0.29.0", + "nix 0.30.1", "windows-sys 0.59.0", ] @@ -3437,17 +3644,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "enumn" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "env_filter" version = "0.1.3" @@ -3505,9 +3701,9 @@ dependencies = [ [[package]] name = "error-code" -version = "3.3.1" +version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" [[package]] name = "eth-keystore" @@ -3559,8 +3755,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78329cbf3c326a3ce2694003976c019fe5f407682b1fdc76e89e463826ea511a" dependencies = [ "ahash", - "alloy-dyn-abi", - "alloy-primitives", + "alloy-dyn-abi 0.8.25", + "alloy-primitives 0.8.25", "indexmap 2.9.0", ] @@ -3715,18 +3911,18 @@ name = "forge" version = "1.2.0" dependencies = [ "alloy-chains", - "alloy-dyn-abi", - "alloy-json-abi", + "alloy-dyn-abi 1.1.0", + "alloy-json-abi 1.1.0", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-provider", "alloy-rpc-types", - "alloy-serde", + "alloy-serde 1.0.3", "alloy-signer", "alloy-signer-local", "alloy-transport", "anvil", - "axum", + "axum 0.7.9", "chrono", "clap", "clap_complete", @@ -3796,7 +3992,7 @@ dependencies = [ name = "forge-doc" version = "1.2.0" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "derive_more 2.0.1", "eyre", "forge-fmt", @@ -3819,7 +4015,7 @@ dependencies = [ name = "forge-fmt" version = "1.2.0" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "ariadne", "foundry-config", "foundry-solang-parser", @@ -3837,14 +4033,14 @@ version = "1.2.0" dependencies = [ "alloy-chains", "alloy-consensus", - "alloy-dyn-abi", - "alloy-eips", - "alloy-json-abi", + "alloy-dyn-abi 1.1.0", + "alloy-eips 1.0.3", + "alloy-json-abi 1.1.0", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-provider", "alloy-rpc-types", - "alloy-serde", + "alloy-serde 1.0.3", "alloy-signer", "clap", "dialoguer", @@ -3881,7 +4077,7 @@ name = "forge-script-sequence" version = "1.2.0" dependencies = [ "alloy-network", - "alloy-primitives", + "alloy-primitives 1.1.0", "eyre", "foundry-common", "foundry-compilers", @@ -3896,8 +4092,8 @@ dependencies = [ name = "forge-sol-macro-gen" version = "1.2.0" dependencies = [ - "alloy-sol-macro-expander", - "alloy-sol-macro-input", + "alloy-sol-macro-expander 1.1.0", + "alloy-sol-macro-input 1.1.0", "eyre", "foundry-common", "prettyplease", @@ -3911,9 +4107,9 @@ dependencies = [ name = "forge-verify" version = "1.2.0" dependencies = [ - "alloy-dyn-abi", - "alloy-json-abi", - "alloy-primitives", + "alloy-dyn-abi 1.1.0", + "alloy-json-abi 1.1.0", + "alloy-primitives 1.1.0", "alloy-provider", "alloy-rpc-types", "async-trait", @@ -3952,13 +4148,13 @@ dependencies = [ [[package]] name = "foundry-block-explorers" -version = "0.13.3" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8025385c52416bf14e5bb28d21eb5efe2490dd6fb001a49b87f1825a626b4909" +checksum = "6129df264d2bd245ade4ed21a92f605bfd592dca8fb8e6e1adde1b9bd4288681" dependencies = [ "alloy-chains", - "alloy-json-abi", - "alloy-primitives", + "alloy-json-abi 1.1.0", + "alloy-primitives 1.1.0", "foundry-compilers", "reqwest", "semver 1.0.26", @@ -3974,18 +4170,18 @@ version = "1.2.0" dependencies = [ "alloy-chains", "alloy-consensus", - "alloy-dyn-abi", + "alloy-dyn-abi 1.1.0", "alloy-evm", "alloy-genesis", - "alloy-json-abi", + "alloy-json-abi 1.1.0", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-provider", "alloy-rlp", "alloy-rpc-types", "alloy-signer", "alloy-signer-local", - "alloy-sol-types", + "alloy-sol-types 1.1.0", "base64 0.22.1", "dialoguer", "ecdsa", @@ -4005,7 +4201,8 @@ dependencies = [ "p256", "parking_lot", "proptest", - "rand 0.8.5", + "rand 0.9.1", + "rand_chacha 0.9.0", "revm", "revm-inspectors", "semver 1.0.26", @@ -4021,7 +4218,7 @@ dependencies = [ name = "foundry-cheatcodes-spec" version = "1.2.0" dependencies = [ - "alloy-sol-types", + "alloy-sol-types 1.1.0", "foundry-macros", "schemars", "serde", @@ -4033,10 +4230,10 @@ name = "foundry-cli" version = "1.2.0" dependencies = [ "alloy-chains", - "alloy-dyn-abi", - "alloy-eips", - "alloy-json-abi", - "alloy-primitives", + "alloy-dyn-abi 1.1.0", + "alloy-eips 1.0.3", + "alloy-json-abi 1.1.0", + "alloy-primitives 1.1.0", "alloy-provider", "alloy-rlp", "cfg-if", @@ -4077,18 +4274,18 @@ version = "1.2.0" dependencies = [ "alloy-consensus", "alloy-contract", - "alloy-dyn-abi", - "alloy-eips", - "alloy-json-abi", + "alloy-dyn-abi 1.1.0", + "alloy-eips 1.0.3", + "alloy-json-abi 1.1.0", "alloy-json-rpc", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-provider", "alloy-pubsub", "alloy-rpc-client", "alloy-rpc-types", - "alloy-serde", - "alloy-sol-types", + "alloy-serde 1.0.3", + "alloy-sol-types 1.1.0", "alloy-transport", "alloy-transport-http", "alloy-transport-ipc", @@ -4096,7 +4293,7 @@ dependencies = [ "anstream", "anstyle", "async-trait", - "axum", + "axum 0.7.9", "chrono", "ciborium", "clap", @@ -4133,11 +4330,11 @@ name = "foundry-common-fmt" version = "1.2.0" dependencies = [ "alloy-consensus", - "alloy-dyn-abi", + "alloy-dyn-abi 1.1.0", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-rpc-types", - "alloy-serde", + "alloy-serde 1.0.3", "chrono", "comfy-table", "foundry-macros", @@ -4150,12 +4347,12 @@ dependencies = [ [[package]] name = "foundry-compilers" -version = "0.14.1" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bb4155f53d4b05642a1398ad105dc04d44b368a7932b85f6ed012af48768b7" +checksum = "3d6154e503612a175a88ff342592f0a44664dda54a508d9443121b62b1701f91" dependencies = [ - "alloy-json-abi", - "alloy-primitives", + "alloy-json-abi 1.1.0", + "alloy-primitives 1.1.0", "auto_impl", "derive_more 1.0.0", "dirs", @@ -4187,9 +4384,9 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts" -version = "0.14.1" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8239fe85061cdb35b8041ef84918e657099fe26f41b016ab8d2560ae6413183" +checksum = "efca59ffe52914a8ff4ae4e8e97e9fa5d782031d2f5a2d1fb109fa6aac26653d" dependencies = [ "foundry-compilers-artifacts-solc", "foundry-compilers-artifacts-vyper", @@ -4197,12 +4394,12 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-solc" -version = "0.14.1" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d5c80fda7c4fde0d2964b329b22d09718838da0c940e5df418f2c1db14fd24" +checksum = "0a3ffc93f94d2c4ae0ff0f7a12cdeaa5fbb043ced0c558cabd05631e32ac508a" dependencies = [ - "alloy-json-abi", - "alloy-primitives", + "alloy-json-abi 1.1.0", + "alloy-primitives 1.1.0", "foundry-compilers-core", "futures-util", "path-slash", @@ -4220,12 +4417,12 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-vyper" -version = "0.14.1" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eaf3cad3dd7bd9eae02736e98f55aaf00ee31fbc0a367613436c2fb01c43914" +checksum = "5f077777aa33f933f9f01e90f9ed78e4a40ed60a6380798b528681ca9519a577" dependencies = [ - "alloy-json-abi", - "alloy-primitives", + "alloy-json-abi 1.1.0", + "alloy-primitives 1.1.0", "foundry-compilers-artifacts-solc", "foundry-compilers-core", "path-slash", @@ -4235,11 +4432,11 @@ dependencies = [ [[package]] name = "foundry-compilers-core" -version = "0.14.1" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac5a1aef4083544309765a1a10c310dffde8c9b8bcfda79b7c2bcfde32f3be3" +checksum = "8ff92d5831075077fe64391dcbbe4a1518bce0439f97ab6a940fa1b9c1f3eaa2" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "cfg-if", "dunce", "fs_extra", @@ -4261,7 +4458,7 @@ name = "foundry-config" version = "1.2.0" dependencies = [ "alloy-chains", - "alloy-primitives", + "alloy-primitives 1.1.0", "dirs", "dunce", "eyre", @@ -4297,7 +4494,7 @@ dependencies = [ name = "foundry-debugger" version = "1.2.0" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "crossterm", "eyre", "foundry-common", @@ -4315,11 +4512,11 @@ dependencies = [ name = "foundry-evm" version = "1.2.0" dependencies = [ - "alloy-dyn-abi", + "alloy-dyn-abi 1.1.0", "alloy-evm", - "alloy-json-abi", - "alloy-primitives", - "alloy-sol-types", + "alloy-json-abi 1.1.0", + "alloy-primitives 1.1.0", + "alloy-sol-types 1.1.0", "eyre", "foundry-cheatcodes", "foundry-common", @@ -4343,8 +4540,8 @@ dependencies = [ name = "foundry-evm-abi" version = "1.2.0" dependencies = [ - "alloy-primitives", - "alloy-sol-types", + "alloy-primitives 1.1.0", + "alloy-sol-types 1.1.0", "derive_more 2.0.1", "foundry-common-fmt", "foundry-macros", @@ -4356,16 +4553,16 @@ name = "foundry-evm-core" version = "1.2.0" dependencies = [ "alloy-consensus", - "alloy-dyn-abi", + "alloy-dyn-abi 1.1.0", "alloy-evm", "alloy-genesis", - "alloy-json-abi", + "alloy-json-abi 1.1.0", "alloy-network", "alloy-op-evm", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-provider", "alloy-rpc-types", - "alloy-sol-types", + "alloy-sol-types 1.1.0", "auto_impl", "eyre", "foundry-cheatcodes-spec", @@ -4392,7 +4589,7 @@ dependencies = [ name = "foundry-evm-coverage" version = "1.2.0" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "eyre", "foundry-common", "foundry-compilers", @@ -4407,9 +4604,9 @@ dependencies = [ name = "foundry-evm-fuzz" version = "1.2.0" dependencies = [ - "alloy-dyn-abi", - "alloy-json-abi", - "alloy-primitives", + "alloy-dyn-abi 1.1.0", + "alloy-json-abi 1.1.0", + "alloy-primitives 1.1.0", "eyre", "foundry-common", "foundry-compilers", @@ -4420,7 +4617,7 @@ dependencies = [ "itertools 0.14.0", "parking_lot", "proptest", - "rand 0.8.5", + "rand 0.9.1", "revm", "serde", "thiserror 2.0.12", @@ -4431,10 +4628,10 @@ dependencies = [ name = "foundry-evm-traces" version = "1.2.0" dependencies = [ - "alloy-dyn-abi", - "alloy-json-abi", - "alloy-primitives", - "alloy-sol-types", + "alloy-dyn-abi 1.1.0", + "alloy-json-abi 1.1.0", + "alloy-primitives 1.1.0", + "alloy-sol-types 1.1.0", "eyre", "foundry-block-explorers", "foundry-common", @@ -4457,11 +4654,12 @@ dependencies = [ [[package]] name = "foundry-fork-db" -version = "0.12.0" -source = "git+https://github.com/foundry-rs/foundry-fork-db?rev=811a61a#811a61a1312d6510447d5511f0e8714024813322" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c99831be91edd8a025fa60443b5404ad407708bc337d2e20440d498b5806fab8" dependencies = [ "alloy-consensus", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-provider", "alloy-rpc-types", "eyre", @@ -4480,7 +4678,7 @@ dependencies = [ name = "foundry-linking" version = "1.2.0" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "foundry-compilers", "semver 1.0.26", "thiserror 2.0.12", @@ -4514,7 +4712,7 @@ dependencies = [ name = "foundry-test-utils" version = "1.2.0" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-provider", "eyre", "fd-lock", @@ -4524,7 +4722,7 @@ dependencies = [ "foundry-config", "idna_adapter", "parking_lot", - "rand 0.8.5", + "rand 0.9.1", "regex", "serde_json", "snapbox", @@ -4539,16 +4737,16 @@ name = "foundry-wallets" version = "1.2.0" dependencies = [ "alloy-consensus", - "alloy-dyn-abi", + "alloy-dyn-abi 1.1.0", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-signer", "alloy-signer-aws", "alloy-signer-gcp", "alloy-signer-ledger", "alloy-signer-local", "alloy-signer-trezor", - "alloy-sol-types", + "alloy-sol-types 1.1.0", "async-trait", "aws-config", "aws-sdk-kms", @@ -4557,7 +4755,7 @@ dependencies = [ "eth-keystore", "eyre", "foundry-config", - "gcloud-sdk", + "gcloud-sdk 0.27.1", "rpassword", "serde", "thiserror 2.0.12", @@ -4727,7 +4925,35 @@ dependencies = [ "serde", "serde_json", "tokio", - "tonic", + "tonic 0.12.3", + "tower 0.5.2", + "tower-layer", + "tower-util", + "tracing", + "url", +] + +[[package]] +name = "gcloud-sdk" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44163d7c0d0bc470caa43766beda779e584034abd6b681319d8f9be2fc194eba" +dependencies = [ + "async-trait", + "bytes", + "chrono", + "futures", + "hyper", + "jsonwebtoken", + "once_cell", + "prost", + "prost-types", + "reqwest", + "secret-vault-value", + "serde", + "serde_json", + "tokio", + "tonic 0.13.1", "tower 0.5.2", "tower-layer", "tower-util", @@ -4774,9 +5000,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "js-sys", @@ -4945,9 +5171,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.17" +version = "0.10.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c091d2e887e02c3462f52252c5ea61150270c0f2657b642e8d0d6df56c16e642" +checksum = "567f65fec4ef10dfab97ae71f26a27fd4d7fe7b8e3f90c8a58551c41ff3fb65b" dependencies = [ "bstr", "gix-trace", @@ -5430,9 +5656,9 @@ dependencies = [ [[package]] name = "idna_mapping" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5422cc5bc64289a77dbb45e970b86b5e9a04cb500abc7240505aedc1bf40f38" +checksum = "11c13906586a4b339310541a274dd927aff6fcbb5b8e3af90634c4b31681c792" dependencies = [ "unicode-joining-type", ] @@ -5659,9 +5885,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] @@ -5737,7 +5963,7 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "libc", ] @@ -5902,12 +6128,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.53.0", ] [[package]] @@ -6047,6 +6273,12 @@ dependencies = [ "hashbrown 0.15.3", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "mac" version = "0.1.1" @@ -6113,6 +6345,12 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + [[package]] name = "mdbook" version = "0.4.49" @@ -6318,6 +6556,18 @@ dependencies = [ "libc", ] +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.9.0", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "nom" version = "7.1.3" @@ -6514,6 +6764,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.101", @@ -6576,15 +6827,15 @@ dependencies = [ [[package]] name = "op-alloy-consensus" -version = "0.12.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917f7a65b83e8f9cf06d5209161babf39f5e5768e226a08ad42c033386248a66" +checksum = "6f318b09e24148f07392c5e011bae047a0043851f9041145df5f3b01e4fedd1e" dependencies = [ "alloy-consensus", - "alloy-eips", - "alloy-primitives", + "alloy-eips 1.0.3", + "alloy-primitives 1.1.0", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.0.3", "derive_more 2.0.1", "serde", "thiserror 2.0.12", @@ -6592,26 +6843,27 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types" -version = "0.12.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c087949da266a53e4c24d841a68590126ecfd3631b2fe74dbcd6da45702983" +checksum = "15ede8322c10c21249de4fced204e2af4978972e715afee34b6fe684d73880cf" dependencies = [ "alloy-consensus", - "alloy-eips", + "alloy-eips 1.0.3", "alloy-network-primitives", - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-rpc-types-eth", - "alloy-serde", + "alloy-serde 1.0.3", "derive_more 2.0.1", "op-alloy-consensus", "serde", "serde_json", + "thiserror 2.0.12", ] [[package]] name = "op-revm" -version = "2.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +version = "4.0.2" +source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" dependencies = [ "auto_impl", "once_cell", @@ -7028,7 +7280,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.25", + "zerocopy", ] [[package]] @@ -7323,9 +7575,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.7" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" dependencies = [ "bytes", "cfg_aliases", @@ -7343,12 +7595,13 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.11" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbafbbdbb0f638fe3f35f3c56739f77a8a1d070cb25603226c83339b391472b" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" dependencies = [ "bytes", - "getrandom 0.3.2", + "getrandom 0.3.3", + "lru-slab", "rand 0.9.1", "ring", "rustc-hash 2.1.1", @@ -7426,6 +7679,7 @@ checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", + "serde", ] [[package]] @@ -7463,7 +7717,8 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", + "serde", ] [[package]] @@ -7647,8 +7902,8 @@ dependencies = [ [[package]] name = "revm" -version = "21.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +version = "23.1.0" +source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" dependencies = [ "revm-bytecode", "revm-context", @@ -7665,10 +7920,11 @@ dependencies = [ [[package]] name = "revm-bytecode" -version = "2.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +version = "4.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" dependencies = [ "bitvec", + "once_cell", "phf", "revm-primitives", "serde", @@ -7676,8 +7932,8 @@ dependencies = [ [[package]] name = "revm-context" -version = "2.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +version = "4.1.0" +source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" dependencies = [ "cfg-if", "derive-where", @@ -7691,12 +7947,13 @@ dependencies = [ [[package]] name = "revm-context-interface" -version = "2.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +version = "4.1.0" +source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" dependencies = [ "alloy-eip2930", "alloy-eip7702", "auto_impl", + "either", "revm-database-interface", "revm-primitives", "revm-state", @@ -7705,11 +7962,10 @@ dependencies = [ [[package]] name = "revm-database" -version = "2.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +version = "4.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" dependencies = [ - "alloy-eips", - "auto_impl", + "alloy-eips 0.14.0", "revm-bytecode", "revm-database-interface", "revm-primitives", @@ -7719,8 +7975,8 @@ dependencies = [ [[package]] name = "revm-database-interface" -version = "2.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +version = "4.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" dependencies = [ "auto_impl", "revm-primitives", @@ -7730,8 +7986,8 @@ dependencies = [ [[package]] name = "revm-handler" -version = "2.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +version = "4.1.0" +source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" dependencies = [ "auto_impl", "revm-bytecode", @@ -7747,8 +8003,8 @@ dependencies = [ [[package]] name = "revm-inspector" -version = "2.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +version = "4.1.0" +source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" dependencies = [ "auto_impl", "revm-context", @@ -7763,14 +8019,14 @@ dependencies = [ [[package]] name = "revm-inspectors" -version = "0.18.1" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a32ec21c38a85f83773e6b3cdb7060aae8ac9edb291118fbfd4da7f2a50e620" +checksum = "9f847f5e88a09ac84b36529fbe2fee80b3d8bbf91e9a7ae3ea856c4125d0d232" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "alloy-rpc-types-eth", "alloy-rpc-types-trace", - "alloy-sol-types", + "alloy-sol-types 1.1.0", "anstyle", "colorchoice", "revm", @@ -7781,8 +8037,8 @@ dependencies = [ [[package]] name = "revm-interpreter" -version = "17.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +version = "19.1.0" +source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" dependencies = [ "revm-bytecode", "revm-context-interface", @@ -7792,8 +8048,8 @@ dependencies = [ [[package]] name = "revm-precompile" -version = "18.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +version = "20.1.0" +source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" dependencies = [ "ark-bls12-381", "ark-bn254", @@ -7816,18 +8072,18 @@ dependencies = [ [[package]] name = "revm-primitives" -version = "17.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +version = "19.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" dependencies = [ - "alloy-primitives", - "enumn", + "alloy-primitives 1.1.0", + "num_enum", "serde", ] [[package]] name = "revm-state" -version = "2.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=2401c2c3#2401c2c37c515316817048b67f23bd10e77cd9d5" +version = "4.0.0" +source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" dependencies = [ "bitflags 2.9.0", "revm-bytecode", @@ -8072,9 +8328,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.2" +version = "0.103.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7149975849f1abb3832b246010ef62ccc80d3a76169517ada7188252b9cfb437" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" dependencies = [ "aws-lc-rs", "ring", @@ -8155,15 +8411,6 @@ dependencies = [ "regex", ] -[[package]] -name = "scc" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22b2d775fb28f245817589471dd49c5edf64237f4a19d10ce9a92ff4651a27f4" -dependencies = [ - "sdd", -] - [[package]] name = "schannel" version = "0.1.27" @@ -8221,12 +8468,6 @@ dependencies = [ "sha2 0.10.9", ] -[[package]] -name = "sdd" -version = "3.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "584e070911c7017da6cb2eb0788d09f43d789029b5877d3e5ecc8acf86ceee21" - [[package]] name = "sec1" version = "0.7.3" @@ -8251,6 +8492,7 @@ dependencies = [ "bitcoin_hashes", "rand 0.8.5", "secp256k1-sys", + "serde", ] [[package]] @@ -8550,9 +8792,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" dependencies = [ "libc", "signal-hook-registry", @@ -8694,13 +8936,12 @@ dependencies = [ [[package]] name = "solar-ast" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0a583a12e73099d1f54bfe7c8a30d7af5ff3591c61ee51cce91045ee5496d86" +checksum = "7960f42b73c63b78df9e223ea88ca87b7aaef91e3b5084b89d79ec31ad9fc8e3" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "bumpalo", - "derive_more 2.0.1", "either", "num-bigint", "num-rational", @@ -8714,18 +8955,18 @@ dependencies = [ [[package]] name = "solar-config" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12642e7e8490d6855a345b5b9d5e55630bd30f54450a909e28f1385b448baada" +checksum = "00ff62c74517305ddee6fdfa741bac8195826d2820586659341063c991fa4a9e" dependencies = [ "strum 0.27.1", ] [[package]] name = "solar-data-structures" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dae8902cc28af53e2ba97c450aff7c59d112a433f9ef98fae808e02e25e6dee6" +checksum = "c3c5934e613b60cfb0b2eadc035bac1fb57641026e4c2fb3683e9580391bd109" dependencies = [ "bumpalo", "index_vec", @@ -8738,9 +8979,9 @@ dependencies = [ [[package]] name = "solar-interface" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded5ec7a5cee351c7a428842d273470180cab259c46f52d502ec3ab5484d0c3a" +checksum = "a614174b9fa673b0a01cc8308d18578f32dd091359786368964bbd19e94e59f7" dependencies = [ "annotate-snippets", "anstream", @@ -8755,7 +8996,6 @@ dependencies = [ "match_cfg", "normalize-path", "rayon", - "scc", "scoped-tls", "solar-config", "solar-data-structures", @@ -8767,9 +9007,9 @@ dependencies = [ [[package]] name = "solar-macros" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2c9ff6e00eeeff12eac9d589f1f20413d3b71b9c0c292d1eefbd34787e0836" +checksum = "ccbdb5d9ecd4127af47279f99475f9fbff6ad3d03afc98ba78e1998bc07c0d46" dependencies = [ "proc-macro2", "quote", @@ -8778,11 +9018,11 @@ dependencies = [ [[package]] name = "solar-parse" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e1bc1d0253b0f7f2c7cd25ed7bc5d5e8cac43e717d002398250e0e66e43278b" +checksum = "7965e27a45ca85135ffd45839f9623131175fb43d2ad3526d32de0946f250f1b" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.0", "bitflags 2.9.0", "bumpalo", "itertools 0.14.0", @@ -8799,12 +9039,12 @@ dependencies = [ [[package]] name = "solar-sema" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded4b26fb85a0ae2f3277377236af0884c82f38965a2c51046a53016c8b5f332" +checksum = "c7e695824aaf984aa01493ebd5e7e83ddf84629d4a2667a0adf25cb6b65fa63e" dependencies = [ - "alloy-json-abi", - "alloy-primitives", + "alloy-json-abi 1.1.0", + "alloy-primitives 1.1.0", "bitflags 2.9.0", "bumpalo", "derive_more 2.0.1", @@ -8812,7 +9052,6 @@ dependencies = [ "once_map", "paste", "rayon", - "scc", "serde", "serde_json", "solar-ast", @@ -9138,6 +9377,18 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "syn-solidity" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0f0d4760f4c2a0823063b2c70e97aa2ad185f57be195172ccc0e23c4b787c4" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -9176,12 +9427,12 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.19.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.3.3", "once_cell", "rustix 1.0.7", "windows-sys 0.59.0", @@ -9546,7 +9797,7 @@ checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" dependencies = [ "async-stream", "async-trait", - "axum", + "axum 0.7.9", "base64 0.22.1", "bytes", "h2", @@ -9559,7 +9810,6 @@ dependencies = [ "percent-encoding", "pin-project 1.1.10", "prost", - "rustls-native-certs", "rustls-pemfile", "socket2", "tokio", @@ -9571,6 +9821,37 @@ dependencies = [ "tracing", ] +[[package]] +name = "tonic" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e581ba15a835f4d9ea06c55ab1bd4dce26fc53752c69a04aac00703bfb49ba9" +dependencies = [ + "async-trait", + "axum 0.8.4", + "base64 0.22.1", + "bytes", + "h2", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project 1.1.10", + "prost", + "rustls-native-certs", + "socket2", + "tokio", + "tokio-rustls", + "tokio-stream", + "tower 0.5.2", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "topological-sort" version = "0.2.2" @@ -9605,9 +9886,12 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", + "indexmap 2.9.0", "pin-project-lite", + "slab", "sync_wrapper", "tokio", + "tokio-util", "tower-layer", "tower-service", "tracing", @@ -9615,9 +9899,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" +checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" dependencies = [ "bitflags 2.9.0", "bytes", @@ -9921,9 +10205,9 @@ checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-joining-type" -version = "0.7.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22f8cb47ccb8bc750808755af3071da4a10dcd147b68fc874b7ae4b12543f6f5" +checksum = "d8d00a78170970967fdb83f9d49b92f959ab2bb829186b113e4f4604ad98e180" [[package]] name = "unicode-linebreak" @@ -10038,7 +10322,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "serde", ] @@ -10810,33 +11094,13 @@ dependencies = [ "is-terminal", ] -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive 0.7.35", -] - [[package]] name = "zerocopy" version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "zerocopy-derive 0.8.25", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", + "zerocopy-derive", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fcf9b8e7c9a45..f0c082a66b3ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ resolver = "2" version = "1.2.0" edition = "2021" # Remember to update clippy.toml as well -rust-version = "1.85" +rust-version = "1.86" authors = ["Foundry Contributors"] license = "MIT OR Apache-2.0" homepage = "https://github.com/foundry-rs/foundry" @@ -195,63 +195,65 @@ foundry-wallets = { path = "crates/wallets" } foundry-linking = { path = "crates/linking" } # solc & compilation utilities -foundry-block-explorers = { version = "0.13.3", default-features = false } -foundry-compilers = { version = "0.14.0", default-features = false } -foundry-fork-db = "0.12" +foundry-block-explorers = { version = "0.17.0", default-features = false } +foundry-compilers = { version = "0.16.1", default-features = false } +foundry-fork-db = "0.14" solang-parser = { version = "=0.3.7", package = "foundry-solang-parser" } -solar-parse = { version = "=0.1.2", default-features = false } -solar-sema = { version = "=0.1.2", default-features = false } - -## revm -revm = { version = "21.0.0", default-features = false } -revm-inspectors = { version = "0.18.1", features = ["serde"] } -op-revm = { version = "2.0.0", default-features = false } +solar-parse = { version = "=0.1.3", default-features = false } +solar-sema = { version = "=0.1.3", default-features = false } ## alloy -alloy-consensus = { version = "0.13.0", default-features = false } -alloy-contract = { version = "0.13.0", default-features = false } -alloy-eips = { version = "0.13.0", default-features = false } -alloy-genesis = { version = "0.13.0", default-features = false } -alloy-json-rpc = { version = "0.13.0", default-features = false } -alloy-network = { version = "0.13.0", default-features = false } -alloy-provider = { version = "0.13.0", default-features = false } -alloy-pubsub = { version = "0.13.0", default-features = false } -alloy-rpc-client = { version = "0.13.0", default-features = false } -alloy-rpc-types = { version = "0.13.0", default-features = true } -alloy-serde = { version = "0.13.0", default-features = false } -alloy-signer = { version = "0.13.0", default-features = false } -alloy-signer-aws = { version = "0.13.0", default-features = false } -alloy-signer-gcp = { version = "0.13.0", default-features = false } -alloy-signer-ledger = { version = "0.13.0", default-features = false } -alloy-signer-local = { version = "0.13.0", default-features = false } -alloy-signer-trezor = { version = "0.13.0", default-features = false } -alloy-transport = { version = "0.13.0", default-features = false } -alloy-transport-http = { version = "0.13.0", default-features = false } -alloy-transport-ipc = { version = "0.13.0", default-features = false } -alloy-transport-ws = { version = "0.13.0", default-features = false } +alloy-consensus = { version = "1.0.3", default-features = false } +alloy-contract = { version = "1.0.3", default-features = false } +alloy-eips = { version = "1.0.3", default-features = false } +alloy-genesis = { version = "1.0.3", default-features = false } +alloy-json-rpc = { version = "1.0.3", default-features = false } +alloy-network = { version = "1.0.3", default-features = false } +alloy-provider = { version = "1.0.3", default-features = false } +alloy-pubsub = { version = "1.0.3", default-features = false } +alloy-rpc-client = { version = "1.0.3", default-features = false } +alloy-rpc-types = { version = "1.0.3", default-features = true } +alloy-serde = { version = "1.0.3", default-features = false } +alloy-signer = { version = "1.0.3", default-features = false } +alloy-signer-aws = { version = "1.0.3", default-features = false } +alloy-signer-gcp = { version = "1.0.3", default-features = false } +alloy-signer-ledger = { version = "1.0.3", default-features = false } +alloy-signer-local = { version = "1.0.3", default-features = false } +alloy-signer-trezor = { version = "1.0.3", default-features = false } +alloy-transport = { version = "1.0.3", default-features = false } +alloy-transport-http = { version = "1.0.3", default-features = false } +alloy-transport-ipc = { version = "1.0.3", default-features = false } +alloy-transport-ws = { version = "1.0.3", default-features = false } ## alloy-core -alloy-dyn-abi = "0.8.22" -alloy-json-abi = "0.8.22" -alloy-primitives = { version = "0.8.22", features = [ +alloy-dyn-abi = "1.0" +alloy-json-abi = "1.0" +alloy-primitives = { version = "1.0", features = [ "getrandom", "rand", "map-fxhash", "map-foldhash", ] } -alloy-sol-macro-expander = "0.8.22" -alloy-sol-macro-input = "0.8.22" -alloy-sol-types = "0.8.22" +alloy-sol-macro-expander = "1.0" +alloy-sol-macro-input = "1.0" +alloy-sol-types = "1.0" -alloy-chains = "0.1" -alloy-evm = "0.3.2" -alloy-op-evm = "0.3.2" +alloy-chains = "0.2" alloy-rlp = "0.3" -alloy-trie = "0.7.0" +alloy-trie = "0.8.1" ## op-alloy -op-alloy-consensus = "0.12.0" -op-alloy-rpc-types = "0.12.0" +op-alloy-consensus = "0.16.0" +op-alloy-rpc-types = "0.16.0" + +## revm +revm = { version = "23.1.0", default-features = false } +revm-inspectors = { version = "0.22.3", features = ["serde"] } +op-revm = { version = "4.0.2", default-features = false } + +## alloy-evm +alloy-evm = "0.8.1" +alloy-op-evm = "0.8.1" ## cli anstream = "0.6" @@ -298,7 +300,9 @@ mesc = "0.3" num-format = "0.4" parking_lot = "0.12" proptest = "1" -rand = "0.8" +rand = "0.9" +rand_08 = { package = "rand", version = "0.8" } +rand_chacha = "0.9.0" rayon = "1" regex = { version = "1", default-features = false } reqwest = { version = "0.12", default-features = false, features = [ @@ -369,10 +373,14 @@ idna_adapter = "=1.1.0" # alloy-transport-ipc = { git = "https://github.com/alloy-rs/alloy", rev = "7fab7ee" } # alloy-transport-ws = { git = "https://github.com/alloy-rs/alloy", rev = "7fab7ee" } +## alloy-evm +# alloy-evm = { git = "https://github.com/alloy-rs/evm.git", rev = "95f6a8a" } +# alloy-op-evm = { git = "https://github.com/alloy-rs/evm.git", rev = "95f6a8a" } + ## revm -revm = { git = "https://github.com/bluealloy/revm.git", rev = "2401c2c3" } -op-revm = { git = "https://github.com/bluealloy/revm.git", rev = "2401c2c3" } +revm = { git = "https://github.com/bluealloy/revm.git", rev = "b5808253" } +op-revm = { git = "https://github.com/bluealloy/revm.git", rev = "b5808253" } # revm-inspectors = { git = "https://github.com/paradigmxyz/revm-inspectors.git", rev = "a625c04" } ## foundry -foundry-fork-db = { git = "https://github.com/foundry-rs/foundry-fork-db", rev = "811a61a" } +# foundry-fork-db = { git = "https://github.com/foundry-rs/foundry-fork-db", rev = "811a61a" } diff --git a/clippy.toml b/clippy.toml index 86b7412b14a56..f4a551607f2fe 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,4 +1,4 @@ -msrv = "1.85" +msrv = "1.86" # `bytes::Bytes` is included by default and `alloy_primitives::Bytes` is a wrapper around it, # so it is safe to ignore it as well. diff --git a/crates/anvil/Cargo.toml b/crates/anvil/Cargo.toml index c70d1eb82c592..0b68a0e8c93de 100644 --- a/crates/anvil/Cargo.toml +++ b/crates/anvil/Cargo.toml @@ -90,6 +90,7 @@ yansi.workspace = true tempfile.workspace = true itertools.workspace = true rand.workspace = true +rand_08.workspace = true eyre.workspace = true # cli diff --git a/crates/anvil/core/src/eth/mod.rs b/crates/anvil/core/src/eth/mod.rs index ccc866d090c8e..bca300cac6cd8 100644 --- a/crates/anvil/core/src/eth/mod.rs +++ b/crates/anvil/core/src/eth/mod.rs @@ -35,7 +35,6 @@ pub struct Params { /// Represents ethereum JSON-RPC API #[derive(Clone, Debug, serde::Deserialize)] #[serde(tag = "method", content = "params")] -#[expect(clippy::large_enum_variant)] pub enum EthRequest { #[serde(rename = "web3_clientVersion", with = "empty_params")] Web3ClientVersion(()), diff --git a/crates/anvil/core/src/eth/subscription.rs b/crates/anvil/core/src/eth/subscription.rs index 80aee56b1a001..d0cada75e830b 100644 --- a/crates/anvil/core/src/eth/subscription.rs +++ b/crates/anvil/core/src/eth/subscription.rs @@ -1,6 +1,6 @@ //! Subscription types use alloy_primitives::hex; -use rand::{distributions::Alphanumeric, thread_rng, Rng}; +use rand::{distr::Alphanumeric, rng, Rng}; use std::fmt; /// Unique subscription id @@ -48,7 +48,7 @@ impl HexIdProvider { /// Generates a random hex encoded Id pub fn gen(&self) -> String { let id: String = - (&mut thread_rng()).sample_iter(Alphanumeric).map(char::from).take(self.len).collect(); + (&mut rng()).sample_iter(Alphanumeric).map(char::from).take(self.len).collect(); let out = hex::encode(id); format!("0x{out}") } diff --git a/crates/anvil/core/src/eth/transaction/mod.rs b/crates/anvil/core/src/eth/transaction/mod.rs index 85bba5504d9a0..b9fa0192cd39e 100644 --- a/crates/anvil/core/src/eth/transaction/mod.rs +++ b/crates/anvil/core/src/eth/transaction/mod.rs @@ -11,9 +11,7 @@ use alloy_consensus::{ }; use alloy_eips::eip2718::{Decodable2718, Eip2718Error, Encodable2718}; use alloy_network::{AnyReceiptEnvelope, AnyRpcTransaction, AnyTransactionReceipt, AnyTxEnvelope}; -use alloy_primitives::{ - Address, Bloom, Bytes, Log, PrimitiveSignature, TxHash, TxKind, B256, U256, U64, -}; +use alloy_primitives::{Address, Bloom, Bytes, Log, Signature, TxHash, TxKind, B256, U256, U64}; use alloy_rlp::{length_of_length, Decodable, Encodable, Header}; use alloy_rpc_types::{ request::TransactionRequest, trace::otterscan::OtsReceipt, AccessList, ConversionError, @@ -531,7 +529,8 @@ impl PendingTransaction { authorization_list, input, } = tx.tx(); - OpTransaction::new(TxEnv { + + let mut tx = TxEnv { caller, kind: TxKind::Call(*to), data: input.clone(), @@ -542,10 +541,12 @@ impl PendingTransaction { gas_priority_fee: Some(*max_priority_fee_per_gas), gas_limit: *gas_limit, access_list: access_list.clone(), - authorization_list: authorization_list.clone(), tx_type: 4, ..Default::default() - }) + }; + tx.set_signed_authorization(authorization_list.clone()); + + OpTransaction::new(tx) } TypedTransaction::Deposit(tx) => { let chain_id = tx.chain_id(); @@ -962,14 +963,14 @@ impl TypedTransaction { } /// Returns the Signature of the transaction - pub fn signature(&self) -> PrimitiveSignature { + pub fn signature(&self) -> Signature { match self { Self::Legacy(tx) => *tx.signature(), Self::EIP2930(tx) => *tx.signature(), Self::EIP1559(tx) => *tx.signature(), Self::EIP4844(tx) => *tx.signature(), Self::EIP7702(tx) => *tx.signature(), - Self::Deposit(_) => PrimitiveSignature::from_scalars_and_parity( + Self::Deposit(_) => Signature::from_scalars_and_parity( B256::with_last_byte(1), B256::with_last_byte(1), false, @@ -1521,7 +1522,7 @@ mod tests { chain_id: Some(4), }; - let signature = PrimitiveSignature::from_str("0eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca182b").unwrap(); + let signature = Signature::from_str("0eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca182b").unwrap(); let tx = TypedTransaction::Legacy(Signed::new_unchecked( tx, diff --git a/crates/anvil/src/cmd.rs b/crates/anvil/src/cmd.rs index 2968b12739786..320c975548567 100644 --- a/crates/anvil/src/cmd.rs +++ b/crates/anvil/src/cmd.rs @@ -12,7 +12,7 @@ use core::fmt; use foundry_common::shell; use foundry_config::{Chain, Config, FigmentProviders}; use futures::FutureExt; -use rand::{rngs::StdRng, SeedableRng}; +use rand_08::{rngs::StdRng, SeedableRng}; use std::{ future::Future, net::IpAddr, @@ -292,7 +292,7 @@ impl NodeArgs { if let Some(ref mnemonic) = self.mnemonic { gen = gen.phrase(mnemonic); } else if let Some(count) = self.mnemonic_random { - let mut rng = rand::thread_rng(); + let mut rng = rand_08::thread_rng(); let mnemonic = match Mnemonic::::new_with_count(&mut rng, count) { Ok(mnemonic) => mnemonic.to_phrase(), Err(_) => DEFAULT_MNEMONIC.to_string(), diff --git a/crates/anvil/src/config.rs b/crates/anvil/src/config.rs index 097618ecf8afa..668edd7ee972a 100644 --- a/crates/anvil/src/config.rs +++ b/crates/anvil/src/config.rs @@ -43,7 +43,7 @@ use foundry_evm_core::AsEnvMut; use itertools::Itertools; use op_revm::OpTransaction; use parking_lot::RwLock; -use rand::thread_rng; +use rand_08::thread_rng; use revm::{ context::{BlockEnv, CfgEnv, TxEnv}, context_interface::block::BlobExcessGasAndPrice, diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 670ef2d091c08..85a6a2951a80a 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -41,7 +41,7 @@ use alloy_network::{ }; use alloy_primitives::{ map::{HashMap, HashSet}, - Address, Bytes, PrimitiveSignature as Signature, TxHash, TxKind, B256, B64, U256, U64, + Address, Bytes, Signature, TxHash, TxKind, B256, B64, U256, U64, }; use alloy_provider::utils::{ eip1559_default_estimator, EIP1559_FEE_ESTIMATION_PAST_BLOCKS, diff --git a/crates/anvil/src/eth/backend/executor.rs b/crates/anvil/src/eth/backend/executor.rs index 2a036489fb2ce..ccf689cf674aa 100644 --- a/crates/anvil/src/eth/backend/executor.rs +++ b/crates/anvil/src/eth/backend/executor.rs @@ -7,15 +7,15 @@ use crate::{ error::InvalidTransactionError, pool::transactions::PoolTransaction, }, - // inject_precompiles, + inject_precompiles, mem::inspector::AnvilInspector, PrecompileFactory, }; use alloy_consensus::{ constants::EMPTY_WITHDRAWALS, proofs::calculate_receipt_root, Receipt, ReceiptWithBloom, }; -use alloy_eips::eip7685::EMPTY_REQUESTS_HASH; -use alloy_evm::{eth::EthEvmContext, EthEvm, Evm}; +use alloy_eips::{eip7685::EMPTY_REQUESTS_HASH, eip7840::BlobParams}; +use alloy_evm::{eth::EthEvmContext, precompiles::PrecompilesMap, EthEvm, Evm}; use alloy_op_evm::OpEvm; use alloy_primitives::{Bloom, BloomInput, Log, B256}; use anvil_core::eth::{ @@ -25,14 +25,15 @@ use anvil_core::eth::{ }, }; use foundry_evm::{backend::DatabaseError, traces::CallTraceNode}; -use foundry_evm_core::{either_evm::EitherEvm, evm::FoundryPrecompiles}; -use op_revm::{L1BlockInfo, OpContext}; +use foundry_evm_core::either_evm::EitherEvm; +use op_revm::{precompiles::OpPrecompiles, L1BlockInfo, OpContext}; use revm::{ - context::{Block as RevmBlock, BlockEnv, CfgEnv, Evm as RevmEvm, JournalTr}, + context::{Block as RevmBlock, BlockEnv, CfgEnv, Evm as RevmEvm, JournalTr, LocalContext}, context_interface::result::{EVMError, ExecutionResult, Output}, database::WrapDatabaseRef, - handler::instructions::EthInstructions, + handler::{instructions::EthInstructions, EthPrecompiles}, interpreter::InstructionResult, + precompile::{PrecompileSpecId, Precompiles}, primitives::hardfork::SpecId, Database, DatabaseRef, Inspector, Journal, }; @@ -117,6 +118,7 @@ pub struct TransactionExecutor<'a, Db: ?Sized, V: TransactionValidator> { pub print_traces: bool, /// Precompiles to inject to the EVM. pub precompile_factory: Option>, + pub blob_params: BlobParams, } impl TransactionExecutor<'_, DB, V> { @@ -295,7 +297,7 @@ impl Iterator for &mut TransactionExec let max_blob_gas = self.blob_gas_used.saturating_add( transaction.pending_transaction.transaction.transaction.blob_gas().unwrap_or(0), ); - if max_blob_gas > alloy_eips::eip4844::MAX_DATA_GAS_PER_BLOCK { + if max_blob_gas > self.blob_params.max_blob_gas_per_block() { return Some(TransactionExecutionOutcome::BlobGasExhausted(transaction)) } @@ -324,9 +326,9 @@ impl Iterator for &mut TransactionExec let exec_result = { let mut evm = new_evm_with_inspector(&mut *self.db, &env, &mut inspector); - // if let Some(factory) = &self.precompile_factory { - // inject_precompiles(&mut evm, factory.precompiles()); - // } + if let Some(factory) = &self.precompile_factory { + inject_precompiles(&mut evm, factory.precompiles()); + } trace!(target: "backend", "[{:?}] executing", transaction.hash()); // transact and commit the transaction @@ -418,12 +420,15 @@ pub fn new_evm_with_inspector( db: DB, env: &Env, inspector: I, -) -> EitherEvm +) -> EitherEvm where DB: Database, I: Inspector> + Inspector>, { if env.is_optimism { + // TODO: we currently pin to `OpSpecId::BEDROCK` as it is primarily used in the context of + // testing deposit transactions. We should make this configurable in the future. + let op_cfg = env.evm_env.cfg_env.clone().with_spec(op_revm::OpSpecId::BEDROCK); let op_context = OpContext { journaled_state: { let mut journal = Journal::new(db); @@ -432,44 +437,53 @@ where journal }, block: env.evm_env.block_env.clone(), - cfg: env.evm_env.cfg_env.clone().with_spec(op_revm::OpSpecId::BEDROCK), + cfg: op_cfg.clone(), tx: env.tx.clone(), chain: L1BlockInfo::default(), + local: LocalContext::default(), error: Ok(()), }; - let evm = op_revm::OpEvm(RevmEvm::new_with_inspector( + let op_precompiles = OpPrecompiles::new_with_spec(op_cfg.spec).precompiles(); + let op_evm = op_revm::OpEvm(RevmEvm::new_with_inspector( op_context, inspector, EthInstructions::default(), - FoundryPrecompiles::default(), + PrecompilesMap::from_static(op_precompiles), )); - let op = OpEvm::new(evm, true); + let op = OpEvm::new(op_evm, true); EitherEvm::Op(op) } else { - let evm_context = EthEvmContext { + let spec = env.evm_env.cfg_env.spec; + let eth_context = EthEvmContext { journaled_state: { let mut journal = Journal::new(db); - journal.set_spec_id(env.evm_env.cfg_env.spec); + journal.set_spec_id(spec); journal }, block: env.evm_env.block_env.clone(), cfg: env.evm_env.cfg_env.clone(), tx: env.tx.base.clone(), chain: (), + local: LocalContext::default(), error: Ok(()), }; - let evm = RevmEvm::new_with_inspector( - evm_context, + let eth_precompiles = EthPrecompiles { + precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)), + spec, + } + .precompiles; + let eth_evm = RevmEvm::new_with_inspector( + eth_context, inspector, EthInstructions::default(), - FoundryPrecompiles::new(), + PrecompilesMap::from_static(eth_precompiles), ); - let eth = EthEvm::new(evm, true); + let eth = EthEvm::new(eth_evm, true); EitherEvm::Eth(eth) } @@ -480,7 +494,7 @@ pub fn new_evm_with_inspector_ref<'db, DB, I>( db: &'db DB, env: &Env, inspector: &'db mut I, -) -> EitherEvm, &'db mut I, FoundryPrecompiles> +) -> EitherEvm, &'db mut I, PrecompilesMap> where DB: DatabaseRef + 'db + ?Sized, I: Inspector>> diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 35cbe1b19d6d2..f728d53d2e58c 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -26,14 +26,12 @@ use crate::{ sign::build_typed_transaction, util::get_precompiles_for, }, - // inject_precompiles, + inject_precompiles, mem::{ inspector::AnvilInspector, storage::{BlockchainStorage, InMemoryBlockStates, MinedBlockOutcome}, }, - ForkChoice, - NodeConfig, - PrecompileFactory, + ForkChoice, NodeConfig, PrecompileFactory, }; use alloy_chains::NamedChain; use alloy_consensus::{ @@ -48,9 +46,9 @@ use alloy_eips::{ EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID, LEGACY_TX_TYPE_ID, }, - eip4844::MAX_BLOBS_PER_BLOCK, + eip7840::BlobParams, }; -use alloy_evm::{eth::EthEvmContext, Database, Evm}; +use alloy_evm::{eth::EthEvmContext, precompiles::PrecompilesMap, Database, Evm}; use alloy_network::{ AnyHeader, AnyRpcBlock, AnyRpcHeader, AnyRpcTransaction, AnyTxEnvelope, AnyTxType, EthereumWallet, UnknownTxEnvelope, UnknownTypedTransaction, @@ -101,7 +99,7 @@ use foundry_evm::{ inspectors::AccessListInspector, traces::TracingInspectorConfig, }; -use foundry_evm_core::{either_evm::EitherEvm, evm::FoundryPrecompiles}; +use foundry_evm_core::either_evm::EitherEvm; use futures::channel::mpsc::{unbounded, UnboundedSender}; use op_alloy_consensus::{TxDeposit, DEPOSIT_TX_TYPE_ID}; use op_revm::{ @@ -779,6 +777,15 @@ impl Backend { self.env.read().is_optimism } + /// Returns [`BlobParams`] corresponding to the current spec. + pub fn blob_params(&self) -> BlobParams { + if self.env.read().evm_env.cfg_env.spec >= SpecId::PRAGUE { + BlobParams::prague() + } else { + BlobParams::cancun() + } + } + /// Returns an error if EIP1559 is not active (pre Berlin) pub fn ensure_eip1559_active(&self) -> Result<(), BlockchainError> { if self.is_eip1559() { @@ -1091,7 +1098,7 @@ impl Backend { ) -> EitherEvm< WrapDatabaseRef<&'db dyn DatabaseRef>, &'db mut I, - FoundryPrecompiles, + PrecompilesMap, > where I: Inspector>>> @@ -1099,11 +1106,13 @@ impl Backend { WrapDatabaseRef<&'db dyn DatabaseRef>: Database, { - new_evm_with_inspector_ref(db, env, inspector) - // TODO(yash): inject precompiles - // if let Some(factory) = &self.precompile_factory { - // inject_precompiles(&mut evm, factory.precompiles()); - // } + let mut evm = new_evm_with_inspector_ref(db, env, inspector); + + if let Some(factory) = &self.precompile_factory { + inject_precompiles(&mut evm, factory.precompiles()); + } + + evm } /// executes the transactions without writing to the underlying database @@ -1189,6 +1198,7 @@ impl Backend { precompile_factory: self.precompile_factory.clone(), odyssey: self.odyssey, optimism: self.is_optimism(), + blob_params: self.blob_params(), }; // create a new pending block @@ -1273,6 +1283,7 @@ impl Backend { odyssey: self.odyssey, precompile_factory: self.precompile_factory.clone(), optimism: self.is_optimism(), + blob_params: self.blob_params(), }; let executed_tx = executor.execute(); @@ -1487,36 +1498,34 @@ impl Backend { let caller = from.unwrap_or_default(); let to = to.as_ref().and_then(TxKind::to); let blob_hashes = blob_versioned_hashes.unwrap_or_default(); - env.tx = OpTransaction { - base: TxEnv { - caller, - gas_limit, - gas_price, - gas_priority_fee: max_priority_fee_per_gas, - max_fee_per_blob_gas: max_fee_per_blob_gas - .or_else(|| { - if !blob_hashes.is_empty() { - env.evm_env.block_env.blob_gasprice() - } else { - Some(0) - } - }) - .unwrap_or_default(), - kind: match to { - Some(addr) => TxKind::Call(*addr), - None => TxKind::Create, - }, - tx_type, - value: value.unwrap_or_default(), - data: input.into_input().unwrap_or_default(), - chain_id: Some(chain_id.unwrap_or(self.env.read().evm_env.cfg_env.chain_id)), - access_list: access_list.unwrap_or_default(), - blob_hashes, - authorization_list: authorization_list.unwrap_or_default(), - ..Default::default() + let mut base = TxEnv { + caller, + gas_limit, + gas_price, + gas_priority_fee: max_priority_fee_per_gas, + max_fee_per_blob_gas: max_fee_per_blob_gas + .or_else(|| { + if !blob_hashes.is_empty() { + env.evm_env.block_env.blob_gasprice() + } else { + Some(0) + } + }) + .unwrap_or_default(), + kind: match to { + Some(addr) => TxKind::Call(*addr), + None => TxKind::Create, }, + tx_type, + value: value.unwrap_or_default(), + data: input.into_input().unwrap_or_default(), + chain_id: Some(chain_id.unwrap_or(self.env.read().evm_env.cfg_env.chain_id)), + access_list: access_list.unwrap_or_default(), + blob_hashes, ..Default::default() }; + base.set_signed_authorization(authorization_list.unwrap_or_default()); + env.tx = OpTransaction { base, ..Default::default() }; if let Some(nonce) = nonce { env.tx.base.nonce = nonce; @@ -1736,7 +1745,7 @@ impl Backend { .map(|tx| AnyTxEnvelope::from(tx.clone())) .collect(); let header = Header { - logs_bloom:logs_bloom(logs.iter()), + logs_bloom: logs_bloom(logs.iter()), transactions_root: calculate_transaction_root(&transactions_envelopes), receipts_root: calculate_receipt_root(&transactions_envelopes), parent_hash: Default::default(), @@ -3173,8 +3182,9 @@ impl TransactionValidator for Backend { } // Ensure the tx does not exceed the max blobs per block. - if blob_count > MAX_BLOBS_PER_BLOCK { - return Err(InvalidTransactionError::TooManyBlobs(blob_count, MAX_BLOBS_PER_BLOCK)) + let max_blob_count = self.blob_params().max_blob_count as usize; + if blob_count > max_blob_count { + return Err(InvalidTransactionError::TooManyBlobs(blob_count, max_blob_count)) } // Check for any blob validation errors if not impersonating. diff --git a/crates/anvil/src/eth/error.rs b/crates/anvil/src/eth/error.rs index f9343d520ecfa..8df6df7476c50 100644 --- a/crates/anvil/src/eth/error.rs +++ b/crates/anvil/src/eth/error.rs @@ -334,7 +334,9 @@ impl From for InvalidTransactionError { InvalidTransaction::Eip4844NotSupported | InvalidTransaction::Eip7702NotSupported | InvalidTransaction::EofCreateShouldHaveToAddress | - InvalidTransaction::EmptyAuthorizationList => Self::Revm(err), + InvalidTransaction::EmptyAuthorizationList | + InvalidTransaction::Eip7873NotSupported | + InvalidTransaction::Eip7873MissingTarget => Self::Revm(err), } } } diff --git a/crates/anvil/src/eth/fees.rs b/crates/anvil/src/eth/fees.rs index bb9272f5f41c4..acec3a29201ac 100644 --- a/crates/anvil/src/eth/fees.rs +++ b/crates/anvil/src/eth/fees.rs @@ -9,7 +9,7 @@ use std::{ use alloy_consensus::Header; use alloy_eips::{ - calc_next_block_base_fee, eip1559::BaseFeeParams, eip4844::MAX_DATA_GAS_PER_BLOCK, + calc_next_block_base_fee, eip1559::BaseFeeParams, eip7691::MAX_BLOBS_PER_BLOCK_ELECTRA, eip7840::BlobParams, }; use alloy_primitives::B256; @@ -266,7 +266,7 @@ impl FeeHistoryService { let blob_gas_used = block.header.blob_gas_used.map(|g| g as f64); item.gas_used_ratio = gas_used / block.header.gas_limit as f64; item.blob_gas_used_ratio = - blob_gas_used.map(|g| g / MAX_DATA_GAS_PER_BLOCK as f64).unwrap_or(0 as f64); + blob_gas_used.map(|g| g / MAX_BLOBS_PER_BLOCK_ELECTRA as f64).unwrap_or(0 as f64); // extract useful tx info (gas_used, effective_reward) let mut transactions: Vec<(_, _)> = receipts diff --git a/crates/anvil/src/eth/otterscan/api.rs b/crates/anvil/src/eth/otterscan/api.rs index 227a8e421a260..129329991c03b 100644 --- a/crates/anvil/src/eth/otterscan/api.rs +++ b/crates/anvil/src/eth/otterscan/api.rs @@ -73,7 +73,7 @@ pub fn batch_build_ots_traces(traces: Vec) -> Vec Vec<(Address, Precompiles)>; + fn precompiles(&self) -> Vec; } -// /// Appends a handler register to `evm` that injects the given `precompiles`. -// /// -// /// This will add an additional handler that extends the default precompiles with the given set -// of /// precompiles. -// pub fn inject_precompiles( -// evm: &mut revm::Evm<'_, I, DB>, -// precompiles: Precompiles, -// ) { -// evm.handler.append_handler_register_box(Box::new(move |handler| { -// let precompiles = precompiles.clone(); -// let prev = handler.pre_execution.load_precompiles.clone(); -// handler.pre_execution.load_precompiles = Arc::new(move || { -// let mut cx = prev(); -// cx.extend(precompiles.iter().cloned().map(|(a, b)| (a, b.into()))); -// cx -// }); -// })); -// } - -// #[cfg(test)] -// mod tests { -// use crate::{evm::inject_precompiles, PrecompileFactory}; -// use alloy_primitives::{address, Address, Bytes}; -// use revm::{ -// precompile::{PrecompileOutput, PrecompileResult, Precompiles}, -// primitives::hardfork::SpecId, -// }; - -// #[test] -// fn build_evm_with_extra_precompiles() { -// const PRECOMPILE_ADDR: Address = address!("0x0000000000000000000000000000000000000071"); - -// fn my_precompile(_bytes: &Bytes, _gas_limit: u64) -> PrecompileResult { -// Ok(PrecompileOutput { bytes: Bytes::new(), gas_used: 0 }) -// } - -// #[derive(Debug)] -// struct CustomPrecompileFactory; - -// impl PrecompileFactory for CustomPrecompileFactory { -// fn precompiles(&self) -> Vec<(Address, Precompile)> { -// vec![(PRECOMPILE_ADDR, Precompile::Standard(my_precompile))] -// } -// } - -// let db = revm::db::EmptyDB::default(); -// let env = Box::::default(); -// let spec = SpecId::default(); -// let handler_cfg = revm::primitives::HandlerCfg::new(spec); -// let inspector = revm::inspectors::NoOpInspector; -// let context = revm::Context::new(revm::EvmContext::new_with_env(db, env), inspector); -// let handler = revm::Handler::new(handler_cfg); -// let mut evm = revm::Evm::new(context, handler); -// assert!(!evm -// .handler -// .pre_execution() -// .load_precompiles() -// .addresses() -// .any(|&addr| addr == PRECOMPILE_ADDR)); - -// inject_precompiles(&mut evm, CustomPrecompileFactory.precompiles()); -// assert!(evm -// .handler -// .pre_execution() -// .load_precompiles() -// .addresses() -// .any(|&addr| addr == PRECOMPILE_ADDR)); - -// let result = evm.transact().unwrap(); -// assert!(result.result.is_success()); -// } -// } +/// Inject precompiles into the EVM dynamically. +pub fn inject_precompiles( + evm: &mut EitherEvm, + precompiles: Vec, +) where + DB: Database, + I: Inspector> + Inspector>, +{ + for p in precompiles { + evm.precompiles_mut() + .apply_precompile(p.address(), |_| Some(DynPrecompile::from(*p.precompile()))); + } +} + +#[cfg(test)] +mod tests { + use std::convert::Infallible; + + use alloy_evm::{eth::EthEvmContext, precompiles::PrecompilesMap, EthEvm, Evm, EvmEnv}; + use alloy_op_evm::OpEvm; + use alloy_primitives::{address, Address, Bytes, TxKind}; + use foundry_evm_core::either_evm::EitherEvm; + use itertools::Itertools; + use op_revm::{precompiles::OpPrecompiles, L1BlockInfo, OpContext, OpSpecId, OpTransaction}; + use revm::{ + context::{CfgEnv, Evm as RevmEvm, JournalTr, LocalContext, TxEnv}, + database::{EmptyDB, EmptyDBTyped}, + handler::{instructions::EthInstructions, EthPrecompiles}, + inspector::NoOpInspector, + interpreter::interpreter::EthInterpreter, + precompile::{ + PrecompileOutput, PrecompileResult, PrecompileSpecId, PrecompileWithAddress, + Precompiles, + }, + primitives::hardfork::SpecId, + Journal, + }; + + use crate::{inject_precompiles, PrecompileFactory}; + + // A precompile activated in the `Prague` spec. + const ETH_PRAGUE_PRECOMPILE: Address = address!("0x0000000000000000000000000000000000000011"); + + // A precompile activated in the `Fjord` spec. + const OP_FROJD_PRECOMPILE: Address = address!("0x0000000000000000000000000000000000000100"); + + // A custom precompile address and payload for testing. + const PRECOMPILE_ADDR: Address = address!("0x0000000000000000000000000000000000000071"); + const PAYLOAD: &[u8] = &[0xde, 0xad, 0xbe, 0xef]; + + #[derive(Debug)] + struct CustomPrecompileFactory; + + impl PrecompileFactory for CustomPrecompileFactory { + fn precompiles(&self) -> Vec { + vec![PrecompileWithAddress::from(( + PRECOMPILE_ADDR, + custom_echo_precompile as fn(&[u8], u64) -> PrecompileResult, + ))] + } + } + + /// Custom precompile that echoes the input data. + /// In this example it uses `0xdeadbeef` as the input data, returning it as output. + fn custom_echo_precompile(input: &[u8], _gas_limit: u64) -> PrecompileResult { + Ok(PrecompileOutput { bytes: Bytes::copy_from_slice(input), gas_used: 0 }) + } + + /// Creates a new EVM instance with the custom precompile factory. + fn create_eth_evm( + spec: SpecId, + ) -> (foundry_evm::Env, EitherEvm, NoOpInspector, PrecompilesMap>) + { + let eth_env = foundry_evm::Env { + evm_env: EvmEnv { block_env: Default::default(), cfg_env: CfgEnv::new_with_spec(spec) }, + tx: TxEnv { + kind: TxKind::Call(PRECOMPILE_ADDR), + data: PAYLOAD.into(), + ..Default::default() + }, + }; + + let eth_evm_context = EthEvmContext { + journaled_state: Journal::new(EmptyDB::default()), + block: eth_env.evm_env.block_env.clone(), + cfg: eth_env.evm_env.cfg_env.clone(), + tx: eth_env.tx.clone(), + chain: (), + local: LocalContext::default(), + error: Ok(()), + }; + + let eth_precompiles = EthPrecompiles { + precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)), + spec, + } + .precompiles; + let eth_evm = EitherEvm::Eth(EthEvm::new( + RevmEvm::new_with_inspector( + eth_evm_context, + NoOpInspector, + EthInstructions::>::default(), + PrecompilesMap::from_static(eth_precompiles), + ), + true, + )); + + (eth_env, eth_evm) + } + + /// Creates a new OP EVM instance with the custom precompile factory. + fn create_op_evm( + spec: SpecId, + op_spec: OpSpecId, + ) -> ( + crate::eth::backend::env::Env, + EitherEvm, NoOpInspector, PrecompilesMap>, + ) { + let op_env = crate::eth::backend::env::Env { + evm_env: EvmEnv { block_env: Default::default(), cfg_env: CfgEnv::new_with_spec(spec) }, + tx: OpTransaction:: { + base: TxEnv { + kind: TxKind::Call(PRECOMPILE_ADDR), + data: PAYLOAD.into(), + ..Default::default() + }, + ..Default::default() + }, + is_optimism: true, + }; + + let op_cfg = op_env.evm_env.cfg_env.clone().with_spec(op_spec); + let op_evm_context = OpContext { + journaled_state: { + let mut journal = Journal::new(EmptyDB::default()); + // Converting SpecId into OpSpecId + journal.set_spec_id(op_env.evm_env.cfg_env.spec); + journal + }, + block: op_env.evm_env.block_env.clone(), + cfg: op_cfg.clone(), + tx: op_env.tx.clone(), + chain: L1BlockInfo::default(), + local: LocalContext::default(), + error: Ok(()), + }; + + let op_precompiles = OpPrecompiles::new_with_spec(op_cfg.spec).precompiles(); + let op_evm = EitherEvm::Op(OpEvm::new( + op_revm::OpEvm(RevmEvm::new_with_inspector( + op_evm_context, + NoOpInspector, + EthInstructions::>::default(), + PrecompilesMap::from_static(op_precompiles), + )), + true, + )); + + (op_env, op_evm) + } + + #[test] + fn build_eth_evm_with_extra_precompiles_default_spec() { + let (env, mut evm) = create_eth_evm(SpecId::default()); + + // Check that the Prague precompile IS present when using the default spec. + assert!(evm.precompiles_mut().addresses().contains(Ð_PRAGUE_PRECOMPILE)); + + assert!(!evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + inject_precompiles(&mut evm, CustomPrecompileFactory.precompiles()); + + assert!(evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + let result = match &mut evm { + EitherEvm::Eth(eth_evm) => eth_evm.transact(env.tx).unwrap(), + _ => unreachable!(), + }; + + assert!(result.result.is_success()); + assert_eq!(result.result.output(), Some(&PAYLOAD.into())); + } + + #[test] + fn build_eth_evm_with_extra_precompiles_london_spec() { + let (env, mut evm) = create_eth_evm(SpecId::LONDON); + + // Check that the Prague precompile IS NOT present when using the London spec. + assert!(!evm.precompiles_mut().addresses().contains(Ð_PRAGUE_PRECOMPILE)); + + assert!(!evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + inject_precompiles(&mut evm, CustomPrecompileFactory.precompiles()); + + assert!(evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + let result = match &mut evm { + EitherEvm::Eth(eth_evm) => eth_evm.transact(env.tx).unwrap(), + _ => unreachable!(), + }; + + assert!(result.result.is_success()); + assert_eq!(result.result.output(), Some(&PAYLOAD.into())); + } + + #[test] + fn build_op_evm_with_extra_precompiles_default_spec() { + let (env, mut evm) = create_op_evm( + SpecId::default(), + // TODO: OpSpecId::ISTHMUS is not yet supported, fails with: `Missing operator fee + // scalar for isthmus L1 Block`. + OpSpecId::HOLOCENE, + ); + + // Check that the Fjord precompile IS present when using the default spec. + assert!(evm.precompiles_mut().addresses().contains(&OP_FROJD_PRECOMPILE)); + + // Check that the Prague precompile is NOT present when using the default spec. + assert!(!evm.precompiles_mut().addresses().contains(Ð_PRAGUE_PRECOMPILE)); + + assert!(!evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + inject_precompiles(&mut evm, CustomPrecompileFactory.precompiles()); + + assert!(evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + let result = match &mut evm { + EitherEvm::Op(op_evm) => op_evm.transact(env.tx).unwrap(), + _ => unreachable!(), + }; + + assert!(result.result.is_success()); + assert_eq!(result.result.output(), Some(&PAYLOAD.into())); + } + + #[test] + fn build_op_evm_with_extra_precompiles_bedrock_spec() { + let (env, mut evm) = create_op_evm(SpecId::default(), OpSpecId::BEDROCK); + + // Check that the Fjord precompile IS NOT present when using the `OpSpecId::BEDROCK` spec. + assert!(!evm.precompiles_mut().addresses().contains(&OP_FROJD_PRECOMPILE)); + + // Check that the Prague precompile IS NOT present when using the `OpSpecId::BEDROCK` spec. + assert!(!evm.precompiles_mut().addresses().contains(Ð_PRAGUE_PRECOMPILE)); + + assert!(!evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + inject_precompiles(&mut evm, CustomPrecompileFactory.precompiles()); + + assert!(evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + let result = match &mut evm { + EitherEvm::Op(op_evm) => op_evm.transact(env.tx).unwrap(), + _ => unreachable!(), + }; + + assert!(result.result.is_success()); + assert_eq!(result.result.output(), Some(&PAYLOAD.into())); + } +} diff --git a/crates/anvil/src/lib.rs b/crates/anvil/src/lib.rs index b48ad1197569a..77e072e0aa1f2 100644 --- a/crates/anvil/src/lib.rs +++ b/crates/anvil/src/lib.rs @@ -53,8 +53,7 @@ pub use hardfork::{EthereumHardfork, OptimismHardfork}; pub mod eth; /// Evm related abstractions mod evm; -// pub use evm::{inject_precompiles, PrecompileFactory}; -pub use evm::PrecompileFactory; +pub use evm::{inject_precompiles, PrecompileFactory}; /// support for polling filters pub mod filter; diff --git a/crates/anvil/tests/it/anvil_api.rs b/crates/anvil/tests/it/anvil_api.rs index 68d4550d6bbd6..ce337714587b9 100644 --- a/crates/anvil/tests/it/anvil_api.rs +++ b/crates/anvil/tests/it/anvil_api.rs @@ -180,7 +180,7 @@ async fn can_impersonate_contract() { let res = provider.send_transaction(tx.clone()).await; res.unwrap_err(); - let greeting = greeter_contract.greet().call().await.unwrap()._0; + let greeting = greeter_contract.greet().call().await.unwrap(); assert_eq!("Hello World!", greeting); api.anvil_impersonate_account(impersonate).await.unwrap(); @@ -195,7 +195,7 @@ async fn can_impersonate_contract() { let res = provider.send_transaction(tx).await; res.unwrap_err(); - let greeting = greeter_contract.greet().call().await.unwrap()._0; + let greeting = greeter_contract.greet().call().await.unwrap(); assert_eq!("Hello World!", greeting); } @@ -430,12 +430,11 @@ async fn test_can_set_storage_bsc_fork() { let busd_contract = BUSD::new(busd_addr, &provider); - let BUSD::balanceOfReturn { _0 } = busd_contract + let balance = busd_contract .balanceOf(address!("0x0000000000000000000000000000000000000000")) .call() .await .unwrap(); - let balance = _0; assert_eq!(balance, U256::from(12345u64)); } @@ -625,20 +624,16 @@ async fn test_fork_revert_call_latest_block_timestamp() { let multicall_contract = Multicall::new(address!("0xeefba1e63905ef1d7acba5a8513c70307c1ce441"), &provider); - let Multicall::getCurrentBlockTimestampReturn { timestamp } = - multicall_contract.getCurrentBlockTimestamp().call().await.unwrap(); + let timestamp = multicall_contract.getCurrentBlockTimestamp().call().await.unwrap(); assert_eq!(timestamp, U256::from(latest_block.header.timestamp)); - let Multicall::getCurrentBlockDifficultyReturn { difficulty } = - multicall_contract.getCurrentBlockDifficulty().call().await.unwrap(); + let difficulty = multicall_contract.getCurrentBlockDifficulty().call().await.unwrap(); assert_eq!(difficulty, U256::from(latest_block.header.difficulty)); - let Multicall::getCurrentBlockGasLimitReturn { gaslimit } = - multicall_contract.getCurrentBlockGasLimit().call().await.unwrap(); + let gaslimit = multicall_contract.getCurrentBlockGasLimit().call().await.unwrap(); assert_eq!(gaslimit, U256::from(latest_block.header.gas_limit)); - let Multicall::getCurrentBlockCoinbaseReturn { coinbase } = - multicall_contract.getCurrentBlockCoinbase().call().await.unwrap(); + let coinbase = multicall_contract.getCurrentBlockCoinbase().call().await.unwrap(); assert_eq!(coinbase, latest_block.header.beneficiary); } @@ -754,7 +749,7 @@ async fn test_reorg() { .await .unwrap(); api.anvil_reorg(ReorgOptions { depth: 3, tx_block_pairs: vec![] }).await.unwrap(); - let value = storage.getValue().call().await.unwrap()._0; + let value = storage.getValue().call().await.unwrap(); assert_eq!("initial value".to_string(), value); api.mine_one().await; diff --git a/crates/anvil/tests/it/api.rs b/crates/anvil/tests/it/api.rs index d1b9238813d14..ce807eed6aa88 100644 --- a/crates/anvil/tests/it/api.rs +++ b/crates/anvil/tests/it/api.rs @@ -243,7 +243,7 @@ async fn can_call_on_pending_block() { let block_number = BlockNumberOrTag::Number(anvil_block_number as u64); let block = api.block_by_number(block_number).await.unwrap().unwrap(); - let Multicall::getCurrentBlockTimestampReturn { timestamp: ret_timestamp, .. } = contract + let ret_timestamp = contract .getCurrentBlockTimestamp() .block(BlockId::number(anvil_block_number as u64)) .call() @@ -251,7 +251,7 @@ async fn can_call_on_pending_block() { .unwrap(); assert_eq!(block.header.timestamp, ret_timestamp.to::()); - let Multicall::getCurrentBlockGasLimitReturn { gaslimit: ret_gas_limit, .. } = contract + let ret_gas_limit = contract .getCurrentBlockGasLimit() .block(BlockId::number(anvil_block_number as u64)) .call() @@ -259,7 +259,7 @@ async fn can_call_on_pending_block() { .unwrap(); assert_eq!(block.header.gas_limit, ret_gas_limit.to::()); - let Multicall::getCurrentBlockCoinbaseReturn { coinbase: ret_coinbase, .. } = contract + let ret_coinbase = contract .getCurrentBlockCoinbase() .block(BlockId::number(anvil_block_number as u64)) .call() @@ -296,8 +296,7 @@ async fn can_call_with_undersized_max_fee_per_gas() { .from(wallet.address()) .call() .await - .unwrap() - ._0; + .unwrap(); assert_eq!(last_sender, Address::ZERO); } @@ -323,8 +322,7 @@ async fn can_call_with_state_override() { let balance = U256::from(42u64); let mut overrides = AddressHashMap::default(); overrides.insert(account, AccountOverride { balance: Some(balance), ..Default::default() }); - let result = - multicall_contract.getEthBalance(account).state(overrides).call().await.unwrap().balance; + let result = multicall_contract.getEthBalance(account).state(overrides).call().await.unwrap(); assert_eq!(result, balance); // Test the `state_diff` account override @@ -341,16 +339,16 @@ async fn can_call_with_state_override() { ); let last_sender = - simple_storage_contract.lastSender().state(HashMap::default()).call().await.unwrap()._0; + simple_storage_contract.lastSender().state(HashMap::default()).call().await.unwrap(); // No `sender` set without override assert_eq!(last_sender, Address::ZERO); let last_sender = - simple_storage_contract.lastSender().state(overrides.clone()).call().await.unwrap()._0; + simple_storage_contract.lastSender().state(overrides.clone()).call().await.unwrap(); // `sender` *is* set with override assert_eq!(last_sender, account); - let value = simple_storage_contract.getValue().state(overrides).call().await.unwrap()._0; + let value = simple_storage_contract.getValue().state(overrides).call().await.unwrap(); // `value` *is not* changed with state-diff assert_eq!(value, init_value); @@ -368,11 +366,11 @@ async fn can_call_with_state_override() { ); let last_sender = - simple_storage_contract.lastSender().state(overrides.clone()).call().await.unwrap()._0; + simple_storage_contract.lastSender().state(overrides.clone()).call().await.unwrap(); // `sender` *is* set with override assert_eq!(last_sender, account); - let value = simple_storage_contract.getValue().state(overrides).call().await.unwrap()._0; + let value = simple_storage_contract.getValue().state(overrides).call().await.unwrap(); // `value` *is* changed with state assert_eq!(value, ""); } diff --git a/crates/anvil/tests/it/eip4844.rs b/crates/anvil/tests/it/eip4844.rs index 09e58e37d51e0..633c8a01bdef0 100644 --- a/crates/anvil/tests/it/eip4844.rs +++ b/crates/anvil/tests/it/eip4844.rs @@ -1,7 +1,7 @@ use crate::utils::{http_provider, http_provider_with_signer}; use alloy_consensus::{SidecarBuilder, SimpleCoder, Transaction}; use alloy_eips::{ - eip4844::{BLOB_TX_MIN_BLOB_GASPRICE, DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK}, + eip4844::{BLOB_TX_MIN_BLOB_GASPRICE, DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK_DENCUN}, Typed2718, }; use alloy_network::{EthereumWallet, ReceiptResponse, TransactionBuilder, TransactionBuilder4844}; @@ -81,7 +81,7 @@ async fn can_send_multiple_blobs_in_one_tx() { let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap(); - assert_eq!(receipt.blob_gas_used, Some(MAX_DATA_GAS_PER_BLOCK)); + assert_eq!(receipt.blob_gas_used, Some(MAX_DATA_GAS_PER_BLOCK_DENCUN)); assert_eq!(receipt.blob_gas_price, Some(0x1)); // 1 wei } diff --git a/crates/anvil/tests/it/fork.rs b/crates/anvil/tests/it/fork.rs index a0bc8aa05cff1..595c44ce0d0c6 100644 --- a/crates/anvil/tests/it/fork.rs +++ b/crates/anvil/tests/it/fork.rs @@ -478,12 +478,12 @@ async fn can_deploy_greeter_on_fork() { let greeter_contract = Greeter::deploy(&provider, "Hello World!".to_string()).await.unwrap(); let greeting = greeter_contract.greet().call().await.unwrap(); - assert_eq!("Hello World!", greeting._0); + assert_eq!("Hello World!", greeting); let greeter_contract = Greeter::deploy(&provider, "Hello World!".to_string()).await.unwrap(); let greeting = greeter_contract.greet().call().await.unwrap(); - assert_eq!("Hello World!", greeting._0); + assert_eq!("Hello World!", greeting); } #[tokio::test(flavor = "multi_thread")] @@ -691,7 +691,7 @@ async fn test_fork_nft_set_approve_all() { let nouns = ERC721::new(nouns_addr, provider.clone()); let real_owner = nouns.ownerOf(token_id).call().await.unwrap(); - assert_eq!(real_owner._0, owner); + assert_eq!(real_owner, owner); let approval = nouns.setApprovalForAll(nouns_addr, true); let tx = TransactionRequest::default() .from(owner) @@ -704,13 +704,13 @@ async fn test_fork_nft_set_approve_all() { assert!(status); // transfer: impersonate real owner and transfer nft - api.anvil_impersonate_account(real_owner._0).await.unwrap(); + api.anvil_impersonate_account(real_owner).await.unwrap(); - api.anvil_set_balance(real_owner._0, U256::from(10000e18 as u64)).await.unwrap(); + api.anvil_set_balance(real_owner, U256::from(10000e18 as u64)).await.unwrap(); - let call = nouns.transferFrom(real_owner._0, signer, token_id); + let call = nouns.transferFrom(real_owner, signer, token_id); let tx = TransactionRequest::default() - .from(real_owner._0) + .from(real_owner) .to(nouns_addr) .with_input(call.calldata().to_owned()); let tx = WithOtherFields::new(tx); @@ -719,7 +719,7 @@ async fn test_fork_nft_set_approve_all() { assert!(status); let real_owner = nouns.ownerOf(token_id).call().await.unwrap(); - assert_eq!(real_owner._0, wallet.address()); + assert_eq!(real_owner, wallet.address()); } // @@ -1115,11 +1115,11 @@ async fn can_override_fork_chain_id() { Greeter::deploy(provider.clone(), "Hello World!".to_string()).await.unwrap(); let greeting = greeter_contract.greet().call().await.unwrap(); - assert_eq!("Hello World!", greeting._0); + assert_eq!("Hello World!", greeting); let greeter_contract = Greeter::deploy(provider.clone(), "Hello World!".to_string()).await.unwrap(); let greeting = greeter_contract.greet().call().await.unwrap(); - assert_eq!("Hello World!", greeting._0); + assert_eq!("Hello World!", greeting); let provider = handle.http_provider(); let chain_id = provider.get_chain_id().await.unwrap(); diff --git a/crates/anvil/tests/it/otterscan.rs b/crates/anvil/tests/it/otterscan.rs index eede93be15705..3809e3183e1a7 100644 --- a/crates/anvil/tests/it/otterscan.rs +++ b/crates/anvil/tests/it/otterscan.rs @@ -233,7 +233,7 @@ async fn test_call_ots_trace_transaction() { depth: 0, from: sender, to: contract_address, - value: U256::from(1337), + value: Some(U256::from(1337)), input: Contract::runCall::SELECTOR.into(), output: Bytes::new(), }, @@ -242,7 +242,7 @@ async fn test_call_ots_trace_transaction() { depth: 1, from: contract_address, to: contract_address, - value: U256::ZERO, + value: Some(U256::ZERO), input: Contract::do_staticcallCall::SELECTOR.into(), output: true.abi_encode().into(), }, @@ -251,7 +251,7 @@ async fn test_call_ots_trace_transaction() { depth: 1, from: contract_address, to: contract_address, - value: U256::ZERO, + value: Some(U256::ZERO), input: Contract::do_callCall::SELECTOR.into(), output: Bytes::new(), }, @@ -260,7 +260,7 @@ async fn test_call_ots_trace_transaction() { depth: 2, from: contract_address, to: sender, - value: U256::from(1337), + value: Some(U256::from(1337)), input: Bytes::new(), output: Bytes::new(), }, @@ -269,7 +269,7 @@ async fn test_call_ots_trace_transaction() { depth: 2, from: contract_address, to: contract_address, - value: U256::ZERO, + value: Some(U256::ZERO), input: Contract::do_delegatecallCall::SELECTOR.into(), output: Bytes::new(), }, diff --git a/crates/anvil/tests/it/pubsub.rs b/crates/anvil/tests/it/pubsub.rs index 44051401f2a78..04515d83aa02b 100644 --- a/crates/anvil/tests/it/pubsub.rs +++ b/crates/anvil/tests/it/pubsub.rs @@ -49,7 +49,7 @@ async fn test_sub_logs_legacy() { let contract = EmitLogs::new(contract_addr, provider.clone()); let val = contract.getValue().call().await.unwrap(); - assert_eq!(val._0, msg); + assert_eq!(val, msg); // subscribe to events from the contract let filter = Filter::new().address(contract.address().to_owned()); @@ -89,7 +89,7 @@ async fn test_sub_logs() { let contract = EmitLogs::new(contract_addr, provider.clone()); let val = contract.getValue().call().await.unwrap(); - assert_eq!(val._0, msg); + assert_eq!(val, msg); // subscribe to events from the contract let filter = Filter::new().address(contract.address().to_owned()); diff --git a/crates/anvil/tests/it/state.rs b/crates/anvil/tests/it/state.rs index 95bdddf57f566..fdb4c8b128679 100644 --- a/crates/anvil/tests/it/state.rs +++ b/crates/anvil/tests/it/state.rs @@ -149,12 +149,12 @@ async fn can_preserve_historical_states_between_dump_and_load() { let greeter = Greeter::new(*address, provider); let greeting_at_init = - greeter.greet().block(BlockId::number(deploy_blk_num)).call().await.unwrap()._0; + greeter.greet().block(BlockId::number(deploy_blk_num)).call().await.unwrap(); assert_eq!(greeting_at_init, "Hello"); let greeting_after_change = - greeter.greet().block(BlockId::number(change_greeting_blk_num)).call().await.unwrap()._0; + greeter.greet().block(BlockId::number(change_greeting_blk_num)).call().await.unwrap(); assert_eq!(greeting_after_change, "World!"); } diff --git a/crates/anvil/tests/it/transaction.rs b/crates/anvil/tests/it/transaction.rs index d01bfa02aa3af..43fd3498c5c9b 100644 --- a/crates/anvil/tests/it/transaction.rs +++ b/crates/anvil/tests/it/transaction.rs @@ -314,7 +314,7 @@ async fn can_deploy_greeter_http() { let greeting = alloy_greeter.greet().call().await.unwrap(); - assert_eq!("Hello World!", greeting._0); + assert_eq!("Hello World!", greeting); } #[tokio::test(flavor = "multi_thread")] @@ -351,7 +351,7 @@ async fn can_deploy_and_mine_manually() { let address = receipt.contract_address.unwrap(); let greeter_contract = Greeter::new(address, provider); let greeting = greeter_contract.greet().call().await.unwrap(); - assert_eq!("Hello World!", greeting._0); + assert_eq!("Hello World!", greeting); let set_greeting = greeter_contract.setGreeting("Another Message".to_string()); let tx = set_greeting.send().await.unwrap(); @@ -361,7 +361,7 @@ async fn can_deploy_and_mine_manually() { let _tx = tx.get_receipt().await.unwrap(); let greeting = greeter_contract.greet().call().await.unwrap(); - assert_eq!("Another Message", greeting._0); + assert_eq!("Another Message", greeting); } #[tokio::test(flavor = "multi_thread")] @@ -410,7 +410,7 @@ async fn can_call_greeter_historic() { let greeter_contract = Greeter::new(greeter_addr, provider.clone()); let greeting = greeter_contract.greet().call().await.unwrap(); - assert_eq!("Hello World!", greeting._0); + assert_eq!("Hello World!", greeting); let block_number = provider.get_block_number().await.unwrap(); @@ -424,7 +424,7 @@ async fn can_call_greeter_historic() { .unwrap(); let greeting = greeter_contract.greet().call().await.unwrap(); - assert_eq!("Another Message", greeting._0); + assert_eq!("Another Message", greeting); // min api.mine_one().await; @@ -432,7 +432,7 @@ async fn can_call_greeter_historic() { // returns previous state let greeting = greeter_contract.greet().block(BlockId::Number(block_number.into())).call().await.unwrap(); - assert_eq!("Hello World!", greeting._0); + assert_eq!("Hello World!", greeting); } #[tokio::test(flavor = "multi_thread")] @@ -452,7 +452,7 @@ async fn can_deploy_greeter_ws() { let greeter_contract = Greeter::new(greeter_addr, provider.clone()); let greeting = greeter_contract.greet().call().await.unwrap(); - assert_eq!("Hello World!", greeting._0); + assert_eq!("Hello World!", greeting); } #[tokio::test(flavor = "multi_thread")] @@ -479,41 +479,31 @@ async fn get_blocktimestamp_works() { let contract = Multicall::deploy(provider.clone()).await.unwrap(); - let timestamp = contract.getCurrentBlockTimestamp().call().await.unwrap().timestamp; + let timestamp = contract.getCurrentBlockTimestamp().call().await.unwrap(); assert!(timestamp > U256::from(1)); let latest_block = api.block_by_number(alloy_rpc_types::BlockNumberOrTag::Latest).await.unwrap().unwrap(); - let timestamp = contract.getCurrentBlockTimestamp().call().await.unwrap().timestamp; + let timestamp = contract.getCurrentBlockTimestamp().call().await.unwrap(); assert_eq!(timestamp.to::(), latest_block.header.timestamp); // repeat call same result - let timestamp = contract.getCurrentBlockTimestamp().call().await.unwrap().timestamp; + let timestamp = contract.getCurrentBlockTimestamp().call().await.unwrap(); assert_eq!(timestamp.to::(), latest_block.header.timestamp); // mock timestamp let next_timestamp = timestamp.to::() + 1337; api.evm_set_next_block_timestamp(next_timestamp).unwrap(); - let timestamp = contract - .getCurrentBlockTimestamp() - .block(BlockId::pending()) - .call() - .await - .unwrap() - .timestamp; + let timestamp = + contract.getCurrentBlockTimestamp().block(BlockId::pending()).call().await.unwrap(); assert_eq!(timestamp, U256::from(next_timestamp)); // repeat call same result - let timestamp = contract - .getCurrentBlockTimestamp() - .block(BlockId::pending()) - .call() - .await - .unwrap() - .timestamp; + let timestamp = + contract.getCurrentBlockTimestamp().block(BlockId::pending()).call().await.unwrap(); assert_eq!(timestamp, U256::from(next_timestamp)); } @@ -535,7 +525,7 @@ async fn call_past_state() { let deployed_block = provider.get_block_number().await.unwrap(); let value = contract.getValue().call().await.unwrap(); - assert_eq!(value._0, "initial value"); + assert_eq!(value, "initial value"); let gas_price = api.gas_price(); let set_tx = contract.setValue("hi".to_string()).gas_price(gas_price + 1); @@ -544,16 +534,16 @@ async fn call_past_state() { // assert new value let value = contract.getValue().call().await.unwrap(); - assert_eq!(value._0, "hi"); + assert_eq!(value, "hi"); // assert previous value let value = contract.getValue().block(BlockId::Number(deployed_block.into())).call().await.unwrap(); - assert_eq!(value._0, "initial value"); + assert_eq!(value, "initial value"); let hash = provider.get_block(BlockId::Number(1.into())).await.unwrap().unwrap().header.hash; let value = contract.getValue().block(BlockId::Hash(hash.into())).call().await.unwrap(); - assert_eq!(value._0, "initial value"); + assert_eq!(value, "initial value"); } #[tokio::test(flavor = "multi_thread")] @@ -723,7 +713,7 @@ async fn can_listen_full_pending_transaction() { api.anvil_set_auto_mine(false).await.unwrap(); let provider = alloy_provider::ProviderBuilder::new() - .on_ws(WsConnect::new(handle.ws_endpoint())) + .connect_ws(WsConnect::new(handle.ws_endpoint())) .await .unwrap(); @@ -1191,7 +1181,7 @@ async fn can_call_with_high_gas_limit() { let greeter_contract = Greeter::deploy(provider, "Hello World!".to_string()).await.unwrap(); let greeting = greeter_contract.greet().gas(60_000_000).call().await.unwrap(); - assert_eq!("Hello World!", greeting._0); + assert_eq!("Hello World!", greeting); } #[tokio::test(flavor = "multi_thread")] @@ -1230,7 +1220,7 @@ async fn test_reject_eip1559_pre_london() { let greeter_contract = Greeter::new(greeter_contract_addr, provider); let greeting = greeter_contract.greet().call().await.unwrap(); - assert_eq!("Hello World!", greeting._0); + assert_eq!("Hello World!", greeting); } // https://github.com/foundry-rs/foundry/issues/6931 diff --git a/crates/cast/Cargo.toml b/crates/cast/Cargo.toml index 23315bfa30f2b..1a9039d7508b6 100644 --- a/crates/cast/Cargo.toml +++ b/crates/cast/Cargo.toml @@ -58,6 +58,7 @@ eyre.workspace = true futures.workspace = true revm.workspace = true rand.workspace = true +rand_08.workspace = true rayon.workspace = true serde_json.workspace = true serde.workspace = true diff --git a/crates/cast/src/args.rs b/crates/cast/src/args.rs index 89b19eef406d8..36c8d4c89989d 100644 --- a/crates/cast/src/args.rs +++ b/crates/cast/src/args.rs @@ -215,20 +215,19 @@ pub async fn run_command(args: CastArgs) -> Result<()> { } CastSubcommand::DecodeEvent { sig, data } => { let decoded_event = if let Some(event_sig) = sig { - get_event(event_sig.as_str())?.decode_log_parts(None, &hex::decode(data)?, false)? + let event = get_event(event_sig.as_str())?; + event.decode_log_parts(core::iter::once(event.selector()), &hex::decode(data)?)? } else { let data = data.strip_prefix("0x").unwrap_or(data.as_str()); let selector = data.get(..64).unwrap_or_default(); + let selector = selector.parse()?; let identified_event = - SignaturesIdentifier::new(false)?.identify_event(selector.parse()?).await; + SignaturesIdentifier::new(false)?.identify_event(selector).await; if let Some(event) = identified_event { let _ = sh_println!("{}", event.signature()); let data = data.get(64..).unwrap_or_default(); - get_event(event.signature().as_str())?.decode_log_parts( - None, - &hex::decode(data)?, - false, - )? + get_event(event.signature().as_str())? + .decode_log_parts(core::iter::once(selector), &hex::decode(data)?)? } else { eyre::bail!("No matching event signature found for selector `{selector}`") } diff --git a/crates/cast/src/cmd/create2.rs b/crates/cast/src/cmd/create2.rs index 6cb21d1e80c77..3cab2caf0c8c9 100644 --- a/crates/cast/src/cmd/create2.rs +++ b/crates/cast/src/cmd/create2.rs @@ -184,7 +184,7 @@ impl Create2Args { if !no_random { let mut rng = match seed { Some(seed) => StdRng::from_seed(seed.0), - None => StdRng::from_entropy(), + None => StdRng::from_os_rng(), }; rng.fill_bytes(remaining); } diff --git a/crates/cast/src/cmd/send.rs b/crates/cast/src/cmd/send.rs index 7686e70a38a91..4109639db4aab 100644 --- a/crates/cast/src/cmd/send.rs +++ b/crates/cast/src/cmd/send.rs @@ -183,7 +183,7 @@ impl SendTxArgs { let wallet = EthereumWallet::from(signer); let provider = ProviderBuilder::<_, _, AnyNetwork>::default() .wallet(wallet) - .on_provider(&provider); + .connect_provider(&provider); cast_send(provider, tx, cast_async, confirmations, timeout).await } diff --git a/crates/cast/src/cmd/wallet/mod.rs b/crates/cast/src/cmd/wallet/mod.rs index 532de5eea0a37..49f421b2207fa 100644 --- a/crates/cast/src/cmd/wallet/mod.rs +++ b/crates/cast/src/cmd/wallet/mod.rs @@ -1,6 +1,6 @@ use alloy_chains::Chain; use alloy_dyn_abi::TypedData; -use alloy_primitives::{hex, Address, PrimitiveSignature as Signature, B256, U256}; +use alloy_primitives::{hex, Address, Signature, B256, U256}; use alloy_provider::Provider; use alloy_rpc_types::Authorization; use alloy_signer::{ @@ -17,7 +17,7 @@ use foundry_cli::{opts::RpcOpts, utils, utils::LoadConfig}; use foundry_common::{fs, sh_println, shell}; use foundry_config::Config; use foundry_wallets::{RawWalletOpts, WalletOpts, WalletSigner}; -use rand::thread_rng; +use rand_08::thread_rng; use serde_json::json; use std::path::Path; use yansi::Paint; diff --git a/crates/cast/src/cmd/wallet/vanity.rs b/crates/cast/src/cmd/wallet/vanity.rs index 2137feb42b31d..1c80e3165e858 100644 --- a/crates/cast/src/cmd/wallet/vanity.rs +++ b/crates/cast/src/cmd/wallet/vanity.rs @@ -221,7 +221,7 @@ pub fn wallet_generator() -> iter::Map, impl Fn(()) -> Generate /// Generates a random K-256 signing key and derives its Ethereum address. pub fn generate_wallet() -> GeneratedWallet { - let key = SigningKey::random(&mut rand::thread_rng()); + let key = SigningKey::random(&mut rand_08::thread_rng()); let address = secret_key_to_address(&key); (key, address) } diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 7ad227e0c8ab9..104c3e9ee44cc 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -159,7 +159,7 @@ impl> Cast

{ if let Some(func) = func { // decode args into tokens - decoded = match func.abi_decode_output(res.as_ref(), false) { + decoded = match func.abi_decode_output(res.as_ref()) { Ok(decoded) => decoded, Err(err) => { // ensure the address is a contract @@ -1099,8 +1099,7 @@ impl> Cast

{ .balanceOf(owner) .block(block.unwrap_or_default()) .call() - .await? - ._0) + .await?) } } diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 2d2dd5db9e4f3..a3de06e049659 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -55,7 +55,7 @@ Options: -j, --threads Number of threads to use. Specifying 0 defaults to the number of logical cores - [aliases: jobs] + [aliases: --jobs] -V, --version Print version @@ -2405,7 +2405,7 @@ forgetest_async!(cast_run_impersonated_tx, |_prj, cmd| { let http_endpoint = handle.http_endpoint(); - let provider = ProviderBuilder::new().on_http(http_endpoint.parse().unwrap()); + let provider = ProviderBuilder::new().connect_http(http_endpoint.parse().unwrap()); // send impersonated tx let tx = TransactionRequest::default() diff --git a/crates/cheatcodes/Cargo.toml b/crates/cheatcodes/Cargo.toml index c5a784c338dec..97eedfcc44200 100644 --- a/crates/cheatcodes/Cargo.toml +++ b/crates/cheatcodes/Cargo.toml @@ -53,6 +53,7 @@ memchr = "2.7" p256 = "0.13" ecdsa = "0.16" rand.workspace = true +rand_chacha.workspace = true revm.workspace = true revm-inspectors.workspace = true semver.workspace = true diff --git a/crates/cheatcodes/src/crypto.rs b/crates/cheatcodes/src/crypto.rs index 8ef7e96aeff3b..be6829ee3110b 100644 --- a/crates/cheatcodes/src/crypto.rs +++ b/crates/cheatcodes/src/crypto.rs @@ -217,7 +217,7 @@ fn create_wallet(private_key: &U256, label: Option<&str>, state: &mut Cheatcodes .abi_encode()) } -fn encode_full_sig(sig: alloy_primitives::PrimitiveSignature) -> Vec { +fn encode_full_sig(sig: alloy_primitives::Signature) -> Vec { // Retrieve v, r and s from signature. let v = U256::from(sig.v() as u64 + 27); let r = B256::from(sig.r()); @@ -225,7 +225,7 @@ fn encode_full_sig(sig: alloy_primitives::PrimitiveSignature) -> Vec { (v, r, s).abi_encode() } -fn encode_compact_sig(sig: alloy_primitives::PrimitiveSignature) -> Vec { +fn encode_compact_sig(sig: alloy_primitives::Signature) -> Vec { // Implement EIP-2098 compact signature. let r = B256::from(sig.r()); let mut vs = sig.s(); @@ -233,7 +233,7 @@ fn encode_compact_sig(sig: alloy_primitives::PrimitiveSignature) -> Vec { (r, vs).abi_encode() } -fn sign(private_key: &U256, digest: &B256) -> Result { +fn sign(private_key: &U256, digest: &B256) -> Result { // The `ecrecover` precompile does not use EIP-155. No chain ID is needed. let wallet = parse_wallet(private_key)?; let sig = wallet.sign_hash_sync(digest)?; @@ -245,7 +245,7 @@ fn sign_with_wallet( state: &mut Cheatcodes, signer: Option

, digest: &B256, -) -> Result { +) -> Result { if state.wallets().is_empty() { bail!("no wallets available"); } diff --git a/crates/cheatcodes/src/evm.rs b/crates/cheatcodes/src/evm.rs index 456c4337e4bff..573ba31f939e7 100644 --- a/crates/cheatcodes/src/evm.rs +++ b/crates/cheatcodes/src/evm.rs @@ -191,7 +191,7 @@ impl Cheatcode for loadCall { if ccx.state.has_arbitrary_storage(&target) { // If storage slot is untouched and load from a target with arbitrary storage, // then set random value for current slot. - let rand_value = ccx.state.rng().gen(); + let rand_value = ccx.state.rng().random(); ccx.state.arbitrary_storage.as_mut().unwrap().save( ccx.ecx, target, @@ -203,7 +203,7 @@ impl Cheatcode for loadCall { // If storage slot is untouched and load from a target that copies storage from // a source address with arbitrary storage, then copy existing arbitrary value. // If no arbitrary value generated yet, then the random one is saved and set. - let rand_value = ccx.state.rng().gen(); + let rand_value = ccx.state.rng().random(); val.data = ccx.state.arbitrary_storage.as_mut().unwrap().copy( ccx.ecx, target, diff --git a/crates/cheatcodes/src/evm/mapping.rs b/crates/cheatcodes/src/evm/mapping.rs index 569d0e0cb7724..29c12d6d3113c 100644 --- a/crates/cheatcodes/src/evm/mapping.rs +++ b/crates/cheatcodes/src/evm/mapping.rs @@ -7,10 +7,7 @@ use alloy_primitives::{ use alloy_sol_types::SolValue; use revm::{ bytecode::opcode, - interpreter::{ - interpreter_types::{Jumps, MemoryTr}, - Interpreter, - }, + interpreter::{interpreter_types::Jumps, Interpreter}, }; /// Recorded mapping slots. diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index e940300b43b25..1dc9025a3a4c4 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -46,11 +46,12 @@ use foundry_evm_traces::{TracingInspector, TracingInspectorConfig}; use foundry_wallets::multi_wallet::MultiWallet; use itertools::Itertools; use proptest::test_runner::{RngAlgorithm, TestRng, TestRunner}; -use rand::Rng; +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaChaRng; use revm::{ self, bytecode::{opcode as op, EOF_MAGIC_BYTES}, - context::{result::EVMError, BlockEnv, JournalTr}, + context::{result::EVMError, BlockEnv, JournalTr, LocalContext, TransactionType}, context_interface::{transaction::SignedAuthorization, CreateScheme}, handler::FrameResult, interpreter::{ @@ -95,10 +96,10 @@ pub trait CheatcodesExecutor { ccx: &mut CheatsCtxt, ) -> Result> { with_evm(self, ccx, |evm| { - evm.inner.data.ctx.journaled_state.depth += 1; + evm.inner.ctx.journaled_state.depth += 1; // Handle EOF bytecode - let frame = if evm.inner.data.ctx.cfg.spec.is_enabled_in(SpecId::OSAKA) && + let frame = if evm.inner.ctx.cfg.spec.is_enabled_in(SpecId::OSAKA) && inputs.scheme == CreateScheme::Create && inputs.init_code.starts_with(&EOF_MAGIC_BYTES) { @@ -117,7 +118,7 @@ pub trait CheatcodesExecutor { FrameResult::Create(create) | FrameResult::EOFCreate(create) => create, }; - evm.inner.data.ctx.journaled_state.depth -= 1; + evm.inner.ctx.journaled_state.depth -= 1; Ok(outcome) }) @@ -156,6 +157,7 @@ where inner: ccx.ecx.journaled_state.inner.clone(), database: &mut *ccx.ecx.journaled_state.database as &mut dyn DatabaseExt, }, + local: LocalContext::default(), chain: (), error, }; @@ -164,11 +166,11 @@ where let res = f(&mut evm)?; - ccx.ecx.journaled_state.inner = evm.inner.data.ctx.journaled_state.inner; - ccx.ecx.block = evm.inner.data.ctx.block; - ccx.ecx.tx = evm.inner.data.ctx.tx; - ccx.ecx.cfg = evm.inner.data.ctx.cfg; - ccx.ecx.error = evm.inner.data.ctx.error; + ccx.ecx.journaled_state.inner = evm.inner.ctx.journaled_state.inner; + ccx.ecx.block = evm.inner.ctx.block; + ccx.ecx.tx = evm.inner.ctx.tx; + ccx.ecx.cfg = evm.inner.ctx.cfg; + ccx.ecx.error = evm.inner.ctx.error; Ok(res) } @@ -499,6 +501,9 @@ pub struct Cheatcodes { /// strategies. test_runner: Option, + /// Temp Rng since proptest hasn't been updated to rand 0.9 + rng: Option, + /// Ignored traces. pub ignored_traces: IgnoredTraces, @@ -563,6 +568,7 @@ impl Cheatcodes { arbitrary_storage: Default::default(), deprecated: Default::default(), wallets: Default::default(), + rng: Default::default(), } } @@ -591,7 +597,7 @@ impl Cheatcodes { executor: &mut dyn CheatcodesExecutor, ) -> Result { // decode the cheatcode call - let decoded = Vm::VmCalls::abi_decode(&call.input, false).map_err(|e| { + let decoded = Vm::VmCalls::abi_decode(&call.input.bytes(ecx)).map_err(|e| { if let alloy_sol_types::Error::UnknownSelector { name: _, selector } = e { let msg = format!( "unknown cheatcode with selector {selector}; \ @@ -629,6 +635,21 @@ impl Cheatcodes { } } + /// Apply EIP-2930 access list. + /// + /// If the transaction type is [TransactionType::Legacy] we need to upgrade it to + /// [TransactionType::Eip2930] in order to use access lists. Other transaction types support + /// access lists themselves. + fn apply_accesslist(&mut self, ecx: Ecx) { + if let Some(access_list) = &self.access_list { + ecx.tx.access_list = access_list.clone(); + + if ecx.tx.tx_type == TransactionType::Legacy as u8 { + ecx.tx.tx_type = TransactionType::Eip2930 as u8; + } + } + } + /// Called when there was a revert. /// /// Cleanup any previously applied cheatcodes that altered the state in such a way that revm's @@ -709,10 +730,8 @@ impl Cheatcodes { } } - // Apply EIP-2930 access lists. - if let Some(access_list) = &self.access_list { - ecx.tx.access_list = access_list.clone() - } + // Apply EIP-2930 access list + self.apply_accesslist(ecx); // Apply our broadcast if let Some(broadcast) = &self.broadcast { @@ -992,7 +1011,7 @@ impl Cheatcodes { // The calldata is at most, as big as this call's input, and if calldata.len() <= call.input.len() && // Both calldata match, taking the length of the assumed smaller one (which will have at least the selector), and - *calldata == call.input[..calldata.len()] && + *calldata == call.input.bytes(ecx)[..calldata.len()] && // The value matches, if provided expected .value.is_none_or(|value| Some(value) == call.transfer_value()) && @@ -1008,19 +1027,25 @@ impl Cheatcodes { // Handle mocked calls if let Some(mocks) = self.mocked_calls.get_mut(&call.bytecode_address) { - let ctx = - MockCallDataContext { calldata: call.input.clone(), value: call.transfer_value() }; - - if let Some(return_data_queue) = match mocks.get_mut(&ctx) { - Some(queue) => Some(queue), - None => mocks - .iter_mut() - .find(|(mock, _)| { - call.input.get(..mock.calldata.len()) == Some(&mock.calldata[..]) && - mock.value.is_none_or(|value| Some(value) == call.transfer_value()) - }) - .map(|(_, v)| v), - } { + let ctx = MockCallDataContext { + calldata: call.input.bytes(ecx), + value: call.transfer_value(), + }; + + if let Some(return_data_queue) = + match mocks.get_mut(&ctx) { + Some(queue) => Some(queue), + None => mocks + .iter_mut() + .find(|(mock, _)| { + call.input.bytes(ecx).get(..mock.calldata.len()) == + Some(&mock.calldata[..]) && + mock.value + .is_none_or(|value| Some(value) == call.transfer_value()) + }) + .map(|(_, v)| v), + } + { if let Some(return_data) = if return_data_queue.len() == 1 { // If the mocked calls stack has a single element in it, don't empty it return_data_queue.front().map(|x| x.to_owned()) @@ -1077,10 +1102,8 @@ impl Cheatcodes { } } - // Apply EIP-2930 access lists. - if let Some(access_list) = &self.access_list { - ecx.tx.access_list = access_list.clone() - } + // Apply EIP-2930 access list + self.apply_accesslist(ecx); // Apply our broadcast if let Some(broadcast) = &self.broadcast { @@ -1113,6 +1136,8 @@ impl Cheatcodes { let is_fixed_gas_limit = check_if_fixed_gas_limit(&ecx, call.gas_limit); + let input = TransactionInput::new(call.input.bytes(ecx)); + let account = ecx.journaled_state.inner.state().get_mut(&broadcast.new_origin).unwrap(); @@ -1120,7 +1145,7 @@ impl Cheatcodes { from: Some(broadcast.new_origin), to: Some(TxKind::from(Some(call.target_address))), value: call.transfer_value(), - input: TransactionInput::new(call.input.clone()), + input, nonce: Some(account.info.nonce), chain_id: Some(ecx.cfg.chain_id), gas: if is_fixed_gas_limit { Some(call.gas_limit) } else { None }, @@ -1222,7 +1247,7 @@ impl Cheatcodes { oldBalance: old_balance, newBalance: U256::ZERO, // updated on call_end value: call.call_value(), - data: call.input.clone(), + data: call.input.bytes(ecx), reverted: false, deployedCode: Bytes::new(), storageAccesses: vec![], // updated on step @@ -1238,7 +1263,12 @@ impl Cheatcodes { } pub fn rng(&mut self) -> &mut impl Rng { - self.test_runner().rng() + // Prop test uses rand 8 whereas alloy-core has been bumped to rand 9 + // self.test_runner().rng() + self.rng.get_or_insert_with(|| match self.config.seed { + Some(seed) => ChaChaRng::from_seed(seed.to_be_bytes::<32>()), + None => ChaChaRng::from_os_rng(), + }) } pub fn test_runner(&mut self) -> &mut TestRunner { @@ -1924,7 +1954,7 @@ impl Cheatcodes { self.should_overwrite_arbitrary_storage(&target_address, key) { if self.has_arbitrary_storage(&target_address) { - let arbitrary_value = self.rng().gen(); + let arbitrary_value = self.rng().random(); self.arbitrary_storage.as_mut().unwrap().save( ecx, target_address, @@ -1932,7 +1962,7 @@ impl Cheatcodes { arbitrary_value, ); } else if self.is_arbitrary_storage_copy(&target_address) { - let arbitrary_value = self.rng().gen(); + let arbitrary_value = self.rng().random(); self.arbitrary_storage.as_mut().unwrap().copy( ecx, target_address, diff --git a/crates/cheatcodes/src/inspector/utils.rs b/crates/cheatcodes/src/inspector/utils.rs index bd71b2b18622f..c82f9023fafd4 100644 --- a/crates/cheatcodes/src/inspector/utils.rs +++ b/crates/cheatcodes/src/inspector/utils.rs @@ -39,6 +39,7 @@ impl CommonCreateInput for &mut CreateInputs { let kind = match scheme { CreateScheme::Create => "create", CreateScheme::Create2 { .. } => "create2", + CreateScheme::Custom { .. } => "custom", }; debug!(target: "cheatcodes", tx=?cheatcode.broadcastable_transactions.back().unwrap(), "broadcastable {kind}"); } diff --git a/crates/cheatcodes/src/test/expect.rs b/crates/cheatcodes/src/test/expect.rs index 73748458c69c9..1917331de54de 100644 --- a/crates/cheatcodes/src/test/expect.rs +++ b/crates/cheatcodes/src/test/expect.rs @@ -140,6 +140,7 @@ impl From for CreateScheme { match scheme { revm::context_interface::CreateScheme::Create => Self::Create, revm::context_interface::CreateScheme::Create2 { .. } => Self::Create2, + _ => unimplemented!("Unsupported create scheme"), } } } diff --git a/crates/cheatcodes/src/test/revert_handlers.rs b/crates/cheatcodes/src/test/revert_handlers.rs index 2dfd4b014fa6f..92026b9a86697 100644 --- a/crates/cheatcodes/src/test/revert_handlers.rs +++ b/crates/cheatcodes/src/test/revert_handlers.rs @@ -23,7 +23,7 @@ static DUMMY_CALL_OUTPUT: Bytes = Bytes::from_static(&[0u8; 8192]); const DUMMY_CREATE_ADDRESS: Address = address!("0x0000000000000000000000000000000000000001"); fn stringify(data: &[u8]) -> String { - if let Ok(s) = String::abi_decode(data, true) { + if let Ok(s) = String::abi_decode(data) { return s; } if data.is_ascii() { @@ -240,7 +240,7 @@ fn decode_revert(revert: Vec) -> Vec { revert.get(..4).map(|s| s.try_into().unwrap()), Some(Vm::CheatcodeError::SELECTOR | alloy_sol_types::Revert::SELECTOR) ) { - if let Ok(decoded) = Vec::::abi_decode(&revert[4..], false) { + if let Ok(decoded) = Vec::::abi_decode(&revert[4..]) { return decoded; } } diff --git a/crates/cheatcodes/src/utils.rs b/crates/cheatcodes/src/utils.rs index 97b5c7ecd213a..e8ddcec78aea6 100644 --- a/crates/cheatcodes/src/utils.rs +++ b/crates/cheatcodes/src/utils.rs @@ -116,7 +116,7 @@ impl Cheatcode for randomInt_1Call { impl Cheatcode for randomBoolCall { fn apply(&self, state: &mut Cheatcodes) -> Result { - let rand_bool: bool = state.rng().gen(); + let rand_bool: bool = state.rng().random(); Ok(rand_bool.abi_encode()) } } @@ -287,7 +287,7 @@ fn random_uint(state: &mut Cheatcodes, bits: Option, bounds: Option<(U256, ensure!(min <= max, "min must be less than or equal to max"); // Generate random between range min..=max let exclusive_modulo = max - min; - let mut random_number: U256 = state.rng().gen(); + let mut random_number: U256 = state.rng().random(); if exclusive_modulo != U256::MAX { let inclusive_modulo = exclusive_modulo + U256::from(1); random_number %= inclusive_modulo; diff --git a/crates/common/fmt/src/eof.rs b/crates/common/fmt/src/eof.rs index 692d745ebdd29..a9f47d8083b5e 100644 --- a/crates/common/fmt/src/eof.rs +++ b/crates/common/fmt/src/eof.rs @@ -1,8 +1,6 @@ use alloy_primitives::hex; use comfy_table::{modifiers::UTF8_ROUND_CORNERS, ContentArrangement, Table}; -use revm::bytecode::{ - Eof, -}; +use revm::bytecode::Eof; use std::fmt::{self, Write}; pub fn pretty_eof(eof: &Eof) -> Result { @@ -49,7 +47,7 @@ pub fn pretty_eof(eof: &Eof) -> Result { &idx.to_string(), &type_section.inputs.to_string(), &type_section.outputs.to_string(), - &type_section.max_stack_size.to_string(), + &type_section.max_stack_increase.to_string(), &hex::encode_prefixed(body.code(idx).unwrap_or_default()), ]); } diff --git a/crates/common/src/abi.rs b/crates/common/src/abi.rs index 28824925cacda..cdba532d842dd 100644 --- a/crates/common/src/abi.rs +++ b/crates/common/src/abi.rs @@ -63,11 +63,8 @@ pub fn abi_decode_calldata( calldata = &calldata[4..]; } - let res = if input { - func.abi_decode_input(calldata, false) - } else { - func.abi_decode_output(calldata, false) - }?; + let res = + if input { func.abi_decode_input(calldata) } else { func.abi_decode_output(calldata) }?; // in case the decoding worked but nothing was decoded if res.is_empty() { @@ -219,7 +216,7 @@ mod tests { assert_eq!(event.inputs.len(), 3); // Only the address fields get indexed since total_params > num_indexed_params - let parsed = event.decode_log(&log, false).unwrap(); + let parsed = event.decode_log(&log).unwrap(); assert_eq!(event.inputs.iter().filter(|param| param.indexed).count(), 2); assert_eq!(parsed.indexed[0], DynSolValue::Address(Address::from_word(param0))); @@ -244,7 +241,7 @@ mod tests { // All parameters get indexed since num_indexed_params == total_params assert_eq!(event.inputs.iter().filter(|param| param.indexed).count(), 3); - let parsed = event.decode_log(&log, false).unwrap(); + let parsed = event.decode_log(&log).unwrap(); assert_eq!(parsed.indexed[0], DynSolValue::Address(Address::from_word(param0))); assert_eq!(parsed.indexed[1], DynSolValue::Uint(U256::from_be_bytes([3; 32]), 256)); diff --git a/crates/common/src/constants.rs b/crates/common/src/constants.rs index ab94aad05a84e..b8fcdc7f6fd44 100644 --- a/crates/common/src/constants.rs +++ b/crates/common/src/constants.rs @@ -2,7 +2,7 @@ use alloy_consensus::Typed2718; use alloy_network::AnyTxEnvelope; -use alloy_primitives::{address, Address, PrimitiveSignature, B256}; +use alloy_primitives::{address, Address, Signature, B256}; use std::time::Duration; /// The dev chain-id, inherited from hardhat @@ -62,12 +62,9 @@ pub fn is_impersonated_tx(tx: &AnyTxEnvelope) -> bool { false } -pub fn is_impersonated_sig(sig: &PrimitiveSignature, ty: u8) -> bool { - let impersonated_sig = PrimitiveSignature::from_scalars_and_parity( - B256::with_last_byte(1), - B256::with_last_byte(1), - false, - ); +pub fn is_impersonated_sig(sig: &Signature, ty: u8) -> bool { + let impersonated_sig = + Signature::from_scalars_and_parity(B256::with_last_byte(1), B256::with_last_byte(1), false); if ty != SYSTEM_TRANSACTION_TYPE && sig == &impersonated_sig { return true; } diff --git a/crates/common/src/contracts.rs b/crates/common/src/contracts.rs index f0b30724edf2e..86556f7194402 100644 --- a/crates/common/src/contracts.rs +++ b/crates/common/src/contracts.rs @@ -149,7 +149,7 @@ impl ContractsByArtifact { // Try to decode ctor args with contract abi. if let Some(constructor) = contract.abi.constructor() { let constructor_args = &code[deployed_bytecode.len()..]; - if constructor.abi_decode_input(constructor_args, false).is_ok() { + if constructor.abi_decode_input(constructor_args).is_ok() { // If we can decode args with current abi then remove args from // code to compare. code = &code[..deployed_bytecode.len()] diff --git a/crates/common/src/ens.rs b/crates/common/src/ens.rs index 9d19ac258cd23..6a5d0630cbc27 100644 --- a/crates/common/src/ens.rs +++ b/crates/common/src/ens.rs @@ -116,21 +116,16 @@ pub trait ProviderEnsExt> { &self, node: B256, error_name: &str, - ) -> Result, EnsError>; + ) -> Result, EnsError>; /// Performs a forward lookup of an ENS name to an address. async fn resolve_name(&self, name: &str) -> Result { let node = namehash(name); let resolver = self.get_resolver(node, name).await?; - let addr = resolver - .addr(node) - .call() - .await - .map_err(EnsError::Resolve) - .inspect_err(|e| { + let addr = + resolver.addr(node).call().await.map_err(EnsError::Resolve).inspect_err(|e| { let _ = sh_eprintln!("{e:?}"); - })? - ._0; + })?; Ok(addr) } @@ -139,7 +134,7 @@ pub trait ProviderEnsExt> { let name = reverse_address(address); let node = namehash(&name); let resolver = self.get_resolver(node, &name).await?; - let name = resolver.name(node).call().await.map_err(EnsError::Lookup)?._0; + let name = resolver.name(node).call().await.map_err(EnsError::Lookup)?; Ok(name) } } @@ -154,9 +149,9 @@ where &self, node: B256, error_name: &str, - ) -> Result, EnsError> { + ) -> Result, EnsError> { let registry = EnsRegistry::new(ENS_ADDRESS, self); - let address = registry.resolver(node).call().await.map_err(EnsError::Resolver)?._0; + let address = registry.resolver(node).call().await.map_err(EnsError::Resolver)?; if address == Address::ZERO { return Err(EnsError::ResolverNotFound(error_name.to_string())); } diff --git a/crates/common/src/preprocessor/deps.rs b/crates/common/src/preprocessor/deps.rs index 5fd3fd6ee64b6..1348a1928e60e 100644 --- a/crates/common/src/preprocessor/deps.rs +++ b/crates/common/src/preprocessor/deps.rs @@ -219,14 +219,14 @@ impl<'hir> Visit<'hir> for BytecodeDependencyCollector<'hir> { fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) -> ControlFlow { if let StmtKind::Try(stmt_try) = stmt.kind { - if let ExprKind::Call(call_expr, call_args, named_args) = stmt_try.expr.kind { + if let ExprKind::Call(call_expr, call_args, named_args) = &stmt_try.expr.kind { if let Some(dependency) = handle_call_expr( self.src, self.source_map, &stmt_try.expr, call_expr, - &call_args, - &named_args, + call_args, + named_args, true, ) { self.collect_dependency(dependency); @@ -266,7 +266,7 @@ fn handle_call_expr( // `new Counter {value: 333} ( address(this))` // the offset will be used to replace `{value: 333} ( ` with `(` let call_args_offset = if named_args.is_some() && !call_args.is_empty() { - (call_args.span().lo() - ty_new.span.hi()).to_usize() + (call_args.span.lo() - ty_new.span.hi()).to_usize() } else { 0 }; @@ -378,9 +378,6 @@ pub(crate) fn remove_bytecode_dependencies( "_args: encodeArgs{id}(DeployHelper{id}.FoundryPpConstructorArgs", id = dep.referenced_contract.get() )); - if *call_args_offset > 0 { - update.push('('); - } updates.insert((dep.loc.start, dep.loc.end + call_args_offset, update)); updates.insert(( diff --git a/crates/common/src/provider/mod.rs b/crates/common/src/provider/mod.rs index 6c2d561ba0c1f..0603b91f97d2d 100644 --- a/crates/common/src/provider/mod.rs +++ b/crates/common/src/provider/mod.rs @@ -280,7 +280,7 @@ impl ProviderBuilder { } let provider = AlloyProviderBuilder::<_, _, AnyNetwork>::default() - .on_provider(RootProvider::new(client)); + .connect_provider(RootProvider::new(client)); Ok(provider) } @@ -323,7 +323,7 @@ impl ProviderBuilder { let provider = AlloyProviderBuilder::<_, _, AnyNetwork>::default() .with_recommended_fillers() .wallet(wallet) - .on_provider(RootProvider::new(client)); + .connect_provider(RootProvider::new(client)); Ok(provider) } diff --git a/crates/common/src/provider/runtime_transport.rs b/crates/common/src/provider/runtime_transport.rs index d5e98afa57766..f4c5e789dd137 100644 --- a/crates/common/src/provider/runtime_transport.rs +++ b/crates/common/src/provider/runtime_transport.rs @@ -198,11 +198,15 @@ impl RuntimeTransport { /// Connects to a WS transport. async fn connect_ws(&self) -> Result { let auth = self.jwt.as_ref().and_then(|jwt| build_auth(jwt.clone()).ok()); - let ws = WsConnect { url: self.url.to_string(), auth, config: None } + let mut ws = WsConnect::new(self.url.to_string()); + if let Some(auth) = auth { + ws = ws.with_auth(auth); + }; + let service = ws .into_service() .await .map_err(|e| RuntimeTransportError::TransportError(e, self.url.to_string()))?; - Ok(InnerTransport::Ws(ws)) + Ok(InnerTransport::Ws(service)) } /// Connects to an IPC transport. diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index 49716cd38c84a..69cfa8962b3ff 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -8,6 +8,7 @@ use crate::{ utils::{configure_tx_env, configure_tx_req_env}, AsEnvMut, Env, EnvMut, InspectorExt, }; +use alloy_consensus::Typed2718; use alloy_evm::Evm; use alloy_genesis::GenesisAccount; use alloy_network::{AnyRpcBlock, AnyTxEnvelope, TransactionResponse}; @@ -884,8 +885,8 @@ impl Backend { for tx in full_block.inner.transactions.txns() { // System transactions such as on L2s don't contain any pricing info so we skip them // otherwise this would cause reverts - if is_known_system_sender(tx.from()) || - tx.transaction_type() == Some(SYSTEM_TRANSACTION_TYPE) + if is_known_system_sender(tx.inner().inner.signer()) || + tx.ty() == SYSTEM_TRANSACTION_TYPE { trace!(tx=?tx.tx_hash(), "skipping system transaction"); continue; @@ -1268,7 +1269,7 @@ impl DatabaseExt for Backend { let fork = self.inner.get_fork_by_id_mut(id)?; commit_transaction( - &tx, + &tx.inner, &mut env.as_env_mut(), journaled_state, fork, @@ -1854,12 +1855,6 @@ pub(crate) fn merge_account_data( merge_journaled_state_data(addr, active_journaled_state, &mut target_fork.journaled_state); } - // need to mock empty journal entries in case the current checkpoint is higher than the existing - // journal entries - while active_journaled_state.journal.len() > target_fork.journaled_state.journal.len() { - target_fork.journaled_state.journal.push(Default::default()); - } - *active_journaled_state = target_fork.journaled_state.clone(); } diff --git a/crates/evm/core/src/decode.rs b/crates/evm/core/src/decode.rs index 7c8a03da3e300..c3dab88f49cd5 100644 --- a/crates/evm/core/src/decode.rs +++ b/crates/evm/core/src/decode.rs @@ -55,7 +55,7 @@ pub fn decode_console_logs(logs: &[Log]) -> Vec { /// This function returns [None] if it is not a DSTest log or the result of a Hardhat /// `console.log`. pub fn decode_console_log(log: &Log) -> Option { - console::ds::ConsoleEvents::decode_log(log, false).ok().map(|decoded| decoded.to_string()) + console::ds::ConsoleEvents::decode_log(log).ok().map(|decoded| decoded.to_string()) } /// Decodes revert data. @@ -151,7 +151,7 @@ impl RevertDecoder { } // Solidity's `Panic(uint256)` and `Vm`'s custom errors. - if let Ok(e) = alloy_sol_types::ContractError::::abi_decode(err, false) { + if let Ok(e) = alloy_sol_types::ContractError::::abi_decode(err) { return Some(e.to_string()); } @@ -163,7 +163,7 @@ impl RevertDecoder { for error in errors { // If we don't decode, don't return an error, try to decode as a string // later. - if let Ok(decoded) = error.abi_decode_input(data, false) { + if let Ok(decoded) = error.abi_decode_input(data) { return Some(format!( "{}({})", error.name, @@ -211,7 +211,7 @@ impl RevertDecoder { /// Helper function that decodes provided error as an ABI encoded or an ASCII string (if not empty). fn decode_as_non_empty_string(err: &[u8]) -> Option { // ABI-encoded `string`. - if let Ok(s) = String::abi_decode(err, true) { + if let Ok(s) = String::abi_decode(err) { if !s.is_empty() { return Some(s); } @@ -272,7 +272,7 @@ mod tests { "0xe17594de" "756688fe00000000000000000000000000000000000000000000000000000000" ); - assert_eq!(decoder.decode(data, None), "ValidationFailed(0x)"); + assert_eq!(decoder.decode(data, None), "custom error 0xe17594de: 756688fe00000000000000000000000000000000000000000000000000000000"); /* abi.encodeWithSelector(ValidationFailed.selector, abi.encodeWithSelector(InvalidNonce.selector)) diff --git a/crates/evm/core/src/either_evm.rs b/crates/evm/core/src/either_evm.rs index 1ee289d88a162..c04a9b1678a61 100644 --- a/crates/evm/core/src/either_evm.rs +++ b/crates/evm/core/src/either_evm.rs @@ -103,8 +103,17 @@ where type Error = EVMError; type HaltReason = OpHaltReason; type Tx = OpTransaction; + type Inspector = I; + type Precompiles = P; type Spec = SpecId; + fn chain_id(&self) -> u64 { + match self { + Self::Eth(evm) => evm.chain_id(), + Self::Op(evm) => evm.chain_id(), + } + } + fn block(&self) -> &BlockEnv { match self { Self::Eth(evm) => evm.block(), @@ -142,6 +151,20 @@ where } } + fn precompiles_mut(&mut self) -> &mut Self::Precompiles { + match self { + Self::Eth(evm) => evm.precompiles_mut(), + Self::Op(evm) => evm.precompiles_mut(), + } + } + + fn inspector_mut(&mut self) -> &mut Self::Inspector { + match self { + Self::Eth(evm) => evm.inspector_mut(), + Self::Op(evm) => evm.inspector_mut(), + } + } + fn enable_inspector(&mut self) { match self { Self::Eth(evm) => evm.enable_inspector(), diff --git a/crates/evm/core/src/evm.rs b/crates/evm/core/src/evm.rs index 0f2e678b2f3ae..b5938c109f040 100644 --- a/crates/evm/core/src/evm.rs +++ b/crates/evm/core/src/evm.rs @@ -4,75 +4,29 @@ use crate::{ backend::DatabaseExt, constants::DEFAULT_CREATE2_DEPLOYER_CODEHASH, Env, InspectorExt, }; use alloy_consensus::constants::KECCAK_EMPTY; -use alloy_evm::{eth::EthEvmContext, Evm, EvmEnv}; +use alloy_evm::{eth::EthEvmContext, precompiles::PrecompilesMap, Evm, EvmEnv}; use alloy_primitives::{Address, Bytes, U256}; use foundry_fork_db::DatabaseError; use revm::{ context::{ result::{EVMError, HaltReason, ResultAndState}, - BlockEnv, CfgEnv, ContextTr, CreateScheme, Evm as RevmEvm, JournalTr, TxEnv, + BlockEnv, CfgEnv, ContextTr, CreateScheme, Evm as RevmEvm, JournalTr, LocalContext, TxEnv, }, handler::{ instructions::EthInstructions, EthFrame, EthPrecompiles, FrameInitOrResult, FrameResult, - Handler, ItemOrResult, MainnetHandler, PrecompileProvider, + Handler, ItemOrResult, MainnetHandler, }, inspector::InspectorHandler, interpreter::{ - interpreter::EthInterpreter, return_ok, CallInputs, CallOutcome, CallScheme, CallValue, - CreateInputs, CreateOutcome, FrameInput, Gas, InputsImpl, InstructionResult, + interpreter::EthInterpreter, return_ok, CallInput, CallInputs, CallOutcome, CallScheme, + CallValue, CreateInputs, CreateOutcome, FrameInput, Gas, InstructionResult, InterpreterResult, }, + precompile::{PrecompileSpecId, Precompiles}, primitives::hardfork::SpecId, Context, ExecuteEvm, Journal, }; -pub struct FoundryPrecompiles { - inner: EthPrecompiles, -} - -impl FoundryPrecompiles { - pub fn new() -> Self { - Self { inner: EthPrecompiles::default() } - } -} - -impl Default for FoundryPrecompiles { - fn default() -> Self { - Self::new() - } -} - -impl PrecompileProvider for FoundryPrecompiles { - type Output = InterpreterResult; - - /// Set the spec for the precompiles. - fn set_spec(&mut self, spec: <::Cfg as revm::context::Cfg>::Spec) -> bool { - PrecompileProvider::::set_spec(&mut self.inner, spec) - } - - /// Run the precompile. - fn run( - &mut self, - context: &mut CTX, - address: &Address, - inputs: &InputsImpl, - is_static: bool, - gas_limit: u64, - ) -> Result, String> { - self.inner.run(context, address, inputs, is_static, gas_limit) - } - - /// Get the warm addresses. - fn warm_addresses(&self) -> Box> { - self.inner.warm_addresses() - } - - /// Check if the address is a precompile. - fn contains(&self, address: &Address) -> bool { - self.inner.contains(address) - } -} - pub fn new_evm_with_inspector<'i, 'db, I: InspectorExt + ?Sized>( db: &'db mut dyn DatabaseExt, env: Env, @@ -88,15 +42,22 @@ pub fn new_evm_with_inspector<'i, 'db, I: InspectorExt + ?Sized>( cfg: env.evm_env.cfg_env, tx: env.tx, chain: (), + local: LocalContext::default(), error: Ok(()), }; + let spec = ctx.cfg.spec; + let precompiles = EthPrecompiles { + precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)), + spec, + } + .precompiles; FoundryEvm { inner: RevmEvm::new_with_inspector( ctx, inspector, EthInstructions::default(), - FoundryPrecompiles::default(), + PrecompilesMap::from_static(precompiles), ), } } @@ -105,12 +66,19 @@ pub fn new_evm_with_existing_context<'a>( ctx: EthEvmContext<&'a mut dyn DatabaseExt>, inspector: &'a mut dyn InspectorExt, ) -> FoundryEvm<'a, &'a mut dyn InspectorExt> { + let spec = ctx.cfg.spec; + let precompiles = EthPrecompiles { + precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)), + spec, + } + .precompiles; + FoundryEvm { inner: RevmEvm::new_with_inspector( ctx, inspector, EthInstructions::default(), - FoundryPrecompiles::default(), + PrecompilesMap::from_static(precompiles), ), } } @@ -127,7 +95,7 @@ fn get_create2_factory_call_inputs( target_address: deployer, scheme: CallScheme::Call, value: CallValue::Transfer(inputs.value), - input: calldata.into(), + input: CallInput::Bytes(calldata.into()), gas_limit: inputs.gas_limit, is_static: false, return_memory_offset: 0..0, @@ -141,7 +109,7 @@ pub struct FoundryEvm<'db, I: InspectorExt> { EthEvmContext<&'db mut dyn DatabaseExt>, I, EthInstructions>, - FoundryPrecompiles, + PrecompilesMap, >, } @@ -164,12 +132,18 @@ impl FoundryEvm<'_, I> { } impl<'db, I: InspectorExt> Evm for FoundryEvm<'db, I> { + type Precompiles = PrecompilesMap; + type Inspector = I; type DB = &'db mut dyn DatabaseExt; type Error = EVMError; type HaltReason = HaltReason; type Spec = SpecId; type Tx = TxEnv; + fn chain_id(&self) -> u64 { + self.inner.ctx.cfg.chain_id + } + fn block(&self) -> &BlockEnv { &self.inner.block } @@ -178,6 +152,14 @@ impl<'db, I: InspectorExt> Evm for FoundryEvm<'db, I> { self.inner.db() } + fn precompiles_mut(&mut self) -> &mut Self::Precompiles { + &mut self.inner.precompiles + } + + fn inspector_mut(&mut self) -> &mut Self::Inspector { + unimplemented!("Inspector is not mutable") + } + fn set_inspector_enabled(&mut self, _enabled: bool) { unimplemented!("FoundryEvm is always inspecting") } @@ -204,7 +186,7 @@ impl<'db, I: InspectorExt> Evm for FoundryEvm<'db, I> { where Self: Sized, { - let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.data.ctx; + let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.ctx; (journaled_state.database, EvmEnv { block_env, cfg_env }) } @@ -214,13 +196,13 @@ impl<'db, I: InspectorExt> Deref for FoundryEvm<'db, I> { type Target = Context; fn deref(&self) -> &Self::Target { - &self.inner.data.ctx + &self.inner.ctx } } impl DerefMut for FoundryEvm<'_, I> { fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner.data.ctx + &mut self.inner.ctx } } @@ -231,7 +213,7 @@ pub struct FoundryHandler<'db, I: InspectorExt> { EthEvmContext<&'db mut dyn DatabaseExt>, I, EthInstructions>, - FoundryPrecompiles, + PrecompilesMap, >, EVMError, EthFrame< @@ -239,7 +221,7 @@ pub struct FoundryHandler<'db, I: InspectorExt> { EthEvmContext<&'db mut dyn DatabaseExt>, I, EthInstructions>, - FoundryPrecompiles, + PrecompilesMap, >, EVMError, EthInterpreter, @@ -259,7 +241,7 @@ impl<'db, I: InspectorExt> Handler for FoundryHandler<'db, I> { EthEvmContext<&'db mut dyn DatabaseExt>, I, EthInstructions>, - FoundryPrecompiles, + PrecompilesMap, >; type Error = EVMError; type Frame = EthFrame< @@ -267,7 +249,7 @@ impl<'db, I: InspectorExt> Handler for FoundryHandler<'db, I> { EthEvmContext<&'db mut dyn DatabaseExt>, I, EthInstructions>, - FoundryPrecompiles, + PrecompilesMap, >, EVMError, EthInterpreter, @@ -329,14 +311,14 @@ impl InspectorHandler for FoundryHandler<'_, I> { let CreateScheme::Create2 { salt } = inputs.scheme else { return Ok(frame_or_result) }; - if !evm.data.inspector.should_use_create2_factory(&mut evm.data.ctx, inputs) { + if !evm.inspector.should_use_create2_factory(&mut evm.ctx, inputs) { return Ok(frame_or_result) } let gas_limit = inputs.gas_limit; // Get CREATE2 deployer. - let create2_deployer = evm.data.inspector.create2_deployer(); + let create2_deployer = evm.inspector.create2_deployer(); // Generate call inputs for CREATE2 factory. let call_inputs = get_create2_factory_call_inputs(salt, inputs, create2_deployer); @@ -349,7 +331,9 @@ impl InspectorHandler for FoundryHandler<'_, I> { return Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome { result: InterpreterResult { result: InstructionResult::Revert, - output: format!("missing CREATE2 deployer: {create2_deployer}").into(), + output: Bytes::copy_from_slice( + format!("missing CREATE2 deployer: {create2_deployer}").as_bytes(), + ), gas: Gas::new(gas_limit), }, memory_offset: 0..0, diff --git a/crates/evm/core/src/utils.rs b/crates/evm/core/src/utils.rs index fd11ee91654a0..d12ce4d1191de 100644 --- a/crates/evm/core/src/utils.rs +++ b/crates/evm/core/src/utils.rs @@ -1,6 +1,12 @@ use alloy_consensus::BlockHeader; use alloy_json_abi::{Function, JsonAbi}; -use alloy_network::{AnyTxEnvelope, TransactionResponse}; +use alloy_network::{ + eip2718::{ + EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID, + LEGACY_TX_TYPE_ID, + }, + AnyTxEnvelope, TransactionResponse, +}; use alloy_primitives::{Address, Selector, TxKind, B256, U256}; use alloy_provider::{network::BlockResponse, Network}; use alloy_rpc_types::{Transaction, TransactionRequest}; @@ -116,11 +122,27 @@ pub fn configure_tx_req_env( chain_id, ref blob_versioned_hashes, ref access_list, - transaction_type: _, + transaction_type, ref authorization_list, sidecar: _, } = *tx; + // If no transaction type is provided, we need to infer it from the other fields. + let tx_type = transaction_type.unwrap_or_else(|| { + if authorization_list.is_some() { + EIP7702_TX_TYPE_ID + } else if blob_versioned_hashes.is_some() { + EIP4844_TX_TYPE_ID + } else if max_fee_per_gas.is_some() || max_priority_fee_per_gas.is_some() { + EIP1559_TX_TYPE_ID + } else if access_list.is_some() { + EIP2930_TX_TYPE_ID + } else { + LEGACY_TX_TYPE_ID + } + }); + env.tx.tx_type = tx_type; + // If no `to` field then set create kind: https://eips.ethereum.org/EIPS/eip-2470#deployment-transaction env.tx.kind = to.unwrap_or(TxKind::Create); // If the transaction is impersonated, we need to set the caller to the from @@ -146,7 +168,7 @@ pub fn configure_tx_req_env( // Type 4, EIP-7702 if let Some(authorization_list) = authorization_list { - env.tx.authorization_list = authorization_list.clone(); + env.tx.set_signed_authorization(authorization_list.clone()); } Ok(()) diff --git a/crates/evm/evm/src/executors/fuzz/mod.rs b/crates/evm/evm/src/executors/fuzz/mod.rs index 3e132c733b1a5..a64b072193587 100644 --- a/crates/evm/evm/src/executors/fuzz/mod.rs +++ b/crates/evm/evm/src/executors/fuzz/mod.rs @@ -207,7 +207,7 @@ impl FuzzedExecutor { } else { result.reason = (!reason.is_empty()).then_some(reason); let args = if let Some(data) = calldata.get(4..) { - func.abi_decode_input(data, false).unwrap_or_default() + func.abi_decode_input(data).unwrap_or_default() } else { vec![] }; diff --git a/crates/evm/evm/src/executors/invariant/mod.rs b/crates/evm/evm/src/executors/invariant/mod.rs index bf49f6c62f2ea..4e2914ae79e04 100644 --- a/crates/evm/evm/src/executors/invariant/mod.rs +++ b/crates/evm/evm/src/executors/invariant/mod.rs @@ -598,27 +598,27 @@ impl<'a> InvariantExecutor<'a> { /// /// targetArtifactSelectors > excludeArtifacts > targetArtifacts pub fn select_contract_artifacts(&mut self, invariant_address: Address) -> Result<()> { - let result = self + let targeted_artifact_selectors = self .executor .call_sol_default(invariant_address, &IInvariantTest::targetArtifactSelectorsCall {}); // Insert them into the executor `targeted_abi`. for IInvariantTest::FuzzArtifactSelector { artifact, selectors } in - result.targetedArtifactSelectors + targeted_artifact_selectors { let identifier = self.validate_selected_contract(artifact, &selectors)?; self.artifact_filters.targeted.entry(identifier).or_default().extend(selectors); } - let selected = self + let targeted_artifacts = self .executor .call_sol_default(invariant_address, &IInvariantTest::targetArtifactsCall {}); - let excluded = self + let excluded_artifacts = self .executor .call_sol_default(invariant_address, &IInvariantTest::excludeArtifactsCall {}); // Insert `excludeArtifacts` into the executor `excluded_abi`. - for contract in excluded.excludedArtifacts { + for contract in excluded_artifacts { let identifier = self.validate_selected_contract(contract, &[])?; if !self.artifact_filters.excluded.contains(&identifier) { @@ -648,7 +648,7 @@ impl<'a> InvariantExecutor<'a> { // Insert `targetArtifacts` into the executor `targeted_abi`, if they have not been seen // before. - for contract in selected.targetedArtifacts { + for contract in targeted_artifacts { let identifier = self.validate_selected_contract(contract, &[])?; if !self.artifact_filters.targeted.contains_key(&identifier) && @@ -690,14 +690,10 @@ impl<'a> InvariantExecutor<'a> { &self, to: Address, ) -> Result<(SenderFilters, FuzzRunIdentifiedContracts)> { - let targeted_senders = self - .executor - .call_sol_default(to, &IInvariantTest::targetSendersCall {}) - .targetedSenders; - let mut excluded_senders = self - .executor - .call_sol_default(to, &IInvariantTest::excludeSendersCall {}) - .excludedSenders; + let targeted_senders = + self.executor.call_sol_default(to, &IInvariantTest::targetSendersCall {}); + let mut excluded_senders = + self.executor.call_sol_default(to, &IInvariantTest::excludeSendersCall {}); // Extend with default excluded addresses - https://github.com/foundry-rs/foundry/issues/4163 excluded_senders.extend([ CHEATCODE_ADDRESS, @@ -708,14 +704,8 @@ impl<'a> InvariantExecutor<'a> { excluded_senders.extend(PRECOMPILES); let sender_filters = SenderFilters::new(targeted_senders, excluded_senders); - let selected = self - .executor - .call_sol_default(to, &IInvariantTest::targetContractsCall {}) - .targetedContracts; - let excluded = self - .executor - .call_sol_default(to, &IInvariantTest::excludeContractsCall {}) - .excludedContracts; + let selected = self.executor.call_sol_default(to, &IInvariantTest::targetContractsCall {}); + let excluded = self.executor.call_sol_default(to, &IInvariantTest::excludeContractsCall {}); let contracts = self .setup_contracts @@ -762,8 +752,7 @@ impl<'a> InvariantExecutor<'a> { ) -> Result<()> { let interfaces = self .executor - .call_sol_default(invariant_address, &IInvariantTest::targetInterfacesCall {}) - .targetedInterfaces; + .call_sol_default(invariant_address, &IInvariantTest::targetInterfacesCall {}); // Since `targetInterfaces` returns a tuple array there is no guarantee // that the addresses are unique this map is used to merge functions of @@ -815,14 +804,14 @@ impl<'a> InvariantExecutor<'a> { // Collect contract functions marked as target for fuzzing campaign. let selectors = self.executor.call_sol_default(address, &IInvariantTest::targetSelectorsCall {}); - for IInvariantTest::FuzzSelector { addr, selectors } in selectors.targetedSelectors { + for IInvariantTest::FuzzSelector { addr, selectors } in selectors { self.add_address_with_functions(addr, &selectors, false, targeted_contracts)?; } // Collect contract functions excluded from fuzzing campaign. - let selectors = + let excluded_selectors = self.executor.call_sol_default(address, &IInvariantTest::excludeSelectorsCall {}); - for IInvariantTest::FuzzSelector { addr, selectors } in selectors.excludedSelectors { + for IInvariantTest::FuzzSelector { addr, selectors } in excluded_selectors { self.add_address_with_functions(addr, &selectors, true, targeted_contracts)?; } diff --git a/crates/evm/evm/src/executors/mod.rs b/crates/evm/evm/src/executors/mod.rs index 6ab4e3202967e..bfd57a4a0ccee 100644 --- a/crates/evm/evm/src/executors/mod.rs +++ b/crates/evm/evm/src/executors/mod.rs @@ -396,7 +396,7 @@ impl Executor { let calldata = Bytes::from(args.abi_encode()); let mut raw = self.call_raw(from, to, calldata, value)?; raw = raw.into_result(rd)?; - Ok(CallResult { decoded_result: C::abi_decode_returns(&raw.result, false)?, raw }) + Ok(CallResult { decoded_result: C::abi_decode_returns(&raw.result)?, raw }) } /// Performs a call to an account on the current state of the VM. @@ -437,7 +437,7 @@ impl Executor { authorization_list: Vec, ) -> eyre::Result { let mut env = self.build_test_env(from, to.into(), calldata, value); - env.tx.authorization_list = authorization_list; + env.tx.set_signed_authorization(authorization_list); env.tx.tx_type = 4; self.call_with_env(env) } @@ -628,7 +628,7 @@ impl Executor { let executor = self.clone_with_backend(backend); let call = executor.call_sol(CALLER, address, &ITest::failedCall {}, U256::ZERO, None); match call { - Ok(CallResult { raw: _, decoded_result: ITest::failedReturn { failed } }) => { + Ok(CallResult { raw: _, decoded_result: failed }) => { trace!(failed, "DSTest::failed()"); !failed } @@ -890,7 +890,7 @@ impl RawCallResult { rd: Option<&RevertDecoder>, ) -> Result { self = self.into_result(rd)?; - let mut result = func.abi_decode_output(&self.result, false)?; + let mut result = func.abi_decode_output(&self.result)?; let decoded_result = if result.len() == 1 { result.pop().unwrap() } else { diff --git a/crates/evm/evm/src/inspectors/chisel_state.rs b/crates/evm/evm/src/inspectors/chisel_state.rs index 33798e7b0c6a4..67ff8255a261e 100644 --- a/crates/evm/evm/src/inspectors/chisel_state.rs +++ b/crates/evm/evm/src/inspectors/chisel_state.rs @@ -39,7 +39,7 @@ where if self.final_pc == interp.bytecode.pc() - 1 { self.state = Some(( interp.stack.data().clone(), - interp.memory.borrow().context_memory().to_vec(), + interp.memory.context_memory().to_vec(), interp.control.instruction_result, )) } diff --git a/crates/evm/evm/src/inspectors/logs.rs b/crates/evm/evm/src/inspectors/logs.rs index d6aed69892b60..32af7bdbce6c8 100644 --- a/crates/evm/evm/src/inspectors/logs.rs +++ b/crates/evm/evm/src/inspectors/logs.rs @@ -25,8 +25,11 @@ pub struct LogCollector { impl LogCollector { #[cold] - fn do_hardhat_log(&mut self, inputs: &CallInputs) -> Option { - if let Err(err) = self.hardhat_log(&inputs.input) { + fn do_hardhat_log(&mut self, context: &mut CTX, inputs: &CallInputs) -> Option + where + CTX: ContextTr, Journal: JournalExt>, + { + if let Err(err) = self.hardhat_log(&inputs.input.bytes(context)) { let result = InstructionResult::Revert; let output = err.abi_encode_revert(); return Some(CallOutcome { @@ -38,7 +41,7 @@ impl LogCollector { } fn hardhat_log(&mut self, data: &[u8]) -> alloy_sol_types::Result<()> { - let decoded = console::hh::ConsoleCalls::abi_decode(data, false)?; + let decoded = console::hh::ConsoleCalls::abi_decode(data)?; self.logs.push(hh_to_ds(&decoded)); Ok(()) } @@ -54,9 +57,9 @@ where self.logs.push(log); } - fn call(&mut self, _context: &mut CTX, inputs: &mut CallInputs) -> Option { + fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option { if inputs.target_address == HARDHAT_CONSOLE_ADDRESS { - return self.do_hardhat_log(inputs); + return self.do_hardhat_log(context, inputs); } None } diff --git a/crates/evm/evm/src/inspectors/stack.rs b/crates/evm/evm/src/inspectors/stack.rs index a4bf2930c7fec..de08972d2efa5 100644 --- a/crates/evm/evm/src/inspectors/stack.rs +++ b/crates/evm/evm/src/inspectors/stack.rs @@ -863,10 +863,9 @@ impl Inspector> for InspectorStackRefMut<'_> if let Some(mocks) = cheatcodes.mocked_functions.get(&call.target_address) { // Check if any mock function set for call data or if catch-all mock function set // for selector. - if let Some(target) = mocks - .get(&call.input) - .or_else(|| call.input.get(..4).and_then(|selector| mocks.get(selector))) - { + if let Some(target) = mocks.get(&call.input.bytes(ecx)).or_else(|| { + call.input.bytes(ecx).get(..4).and_then(|selector| mocks.get(selector)) + }) { call.bytecode_address = *target; } } @@ -882,11 +881,12 @@ impl Inspector> for InspectorStackRefMut<'_> match call.scheme { // Isolate CALLs CallScheme::Call | CallScheme::ExtCall => { + let input = call.input.bytes(ecx); let (result, _) = self.transact_inner( ecx, TxKind::Call(call.target_address), call.caller, - call.input.clone(), + input, call.gas_limit, call.value.get(), ); diff --git a/crates/evm/fuzz/src/inspector.rs b/crates/evm/fuzz/src/inspector.rs index 540e3aa86968f..279f0878382ac 100644 --- a/crates/evm/fuzz/src/inspector.rs +++ b/crates/evm/fuzz/src/inspector.rs @@ -2,7 +2,7 @@ use crate::{invariant::RandomCallGenerator, strategies::EvmFuzzState}; use revm::{ context::{ContextTr, Transaction}, inspector::JournalExt, - interpreter::{CallInputs, CallOutcome, CallScheme, Interpreter}, + interpreter::{CallInput, CallInputs, CallOutcome, CallScheme, Interpreter}, Inspector, }; @@ -80,7 +80,7 @@ impl Fuzzer { { // There's only a 30% chance that an override happens. if let Some(tx) = call_generator.next(call.caller, call.target_address) { - *call.input = tx.call_details.calldata.0; + call.input = CallInput::Bytes(tx.call_details.calldata.0.into()); call.caller = tx.sender; call.target_address = tx.call_details.target; diff --git a/crates/evm/fuzz/src/lib.rs b/crates/evm/fuzz/src/lib.rs index 3486dac0b5172..bce67dfe320fa 100644 --- a/crates/evm/fuzz/src/lib.rs +++ b/crates/evm/fuzz/src/lib.rs @@ -79,7 +79,7 @@ impl BaseCounterExample { if let Some((name, abi)) = &contracts.get(&addr) { if let Some(func) = abi.functions().find(|f| f.selector() == bytes[..4]) { // skip the function selector when decoding - if let Ok(args) = func.abi_decode_input(&bytes[4..], false) { + if let Ok(args) = func.abi_decode_input(&bytes[4..]) { return Self { sender: Some(sender), addr: Some(addr), diff --git a/crates/evm/fuzz/src/strategies/int.rs b/crates/evm/fuzz/src/strategies/int.rs index 3732de0617325..53d63ce03f923 100644 --- a/crates/evm/fuzz/src/strategies/int.rs +++ b/crates/evm/fuzz/src/strategies/int.rs @@ -1,10 +1,10 @@ use alloy_dyn_abi::{DynSolType, DynSolValue}; use alloy_primitives::{Sign, I256, U256}; use proptest::{ + prelude::Rng, strategy::{NewTree, Strategy, ValueTree}, test_runner::TestRunner, }; -use rand::Rng; /// Value tree for signed ints (up to int256). pub struct IntValueTree { diff --git a/crates/evm/fuzz/src/strategies/invariants.rs b/crates/evm/fuzz/src/strategies/invariants.rs index 37c0b157c3cc2..3222529099d28 100644 --- a/crates/evm/fuzz/src/strategies/invariants.rs +++ b/crates/evm/fuzz/src/strategies/invariants.rs @@ -34,7 +34,7 @@ pub fn override_call_strat( // Choose a random contract if target selected by lazy strategy is not in fuzz run // identified contracts. This can happen when contract is created in `setUp` call // but is not included in targetContracts. - contracts.values().choose(&mut rand::thread_rng()).unwrap() + contracts.values().choose(&mut rand::rng()).unwrap() }); let fuzzed_functions: Vec<_> = contract.abi_fuzzed_functions().cloned().collect(); any::().prop_map(move |index| index.get(&fuzzed_functions).clone()) diff --git a/crates/evm/fuzz/src/strategies/state.rs b/crates/evm/fuzz/src/strategies/state.rs index 26b66807a7666..80c0c029865d2 100644 --- a/crates/evm/fuzz/src/strategies/state.rs +++ b/crates/evm/fuzz/src/strategies/state.rs @@ -179,7 +179,7 @@ impl FuzzDictionary { if let Some(function) = function { if !function.outputs.is_empty() { // Decode result and collect samples to be used in subsequent fuzz runs. - if let Ok(decoded_result) = function.abi_decode_output(result, false) { + if let Ok(decoded_result) = function.abi_decode_output(result) { self.insert_sample_values(decoded_result, run_depth); } } @@ -195,7 +195,7 @@ impl FuzzDictionary { // Try to decode log with events from contract abi. if let Some(abi) = abi { for event in abi.events() { - if let Ok(decoded_event) = event.decode_log(log, false) { + if let Ok(decoded_event) = event.decode_log(log) { samples.extend(decoded_event.indexed); samples.extend(decoded_event.body); log_decoded = true; diff --git a/crates/evm/fuzz/src/strategies/uint.rs b/crates/evm/fuzz/src/strategies/uint.rs index af133efa00826..4a9dfe955020c 100644 --- a/crates/evm/fuzz/src/strategies/uint.rs +++ b/crates/evm/fuzz/src/strategies/uint.rs @@ -1,10 +1,10 @@ use alloy_dyn_abi::{DynSolType, DynSolValue}; use alloy_primitives::U256; use proptest::{ + prelude::Rng, strategy::{NewTree, Strategy, ValueTree}, test_runner::TestRunner, }; -use rand::Rng; /// Value tree for unsigned ints (up to uint256). pub struct UintValueTree { diff --git a/crates/evm/traces/src/decoder/mod.rs b/crates/evm/traces/src/decoder/mod.rs index 2e22ca7cdc358..483ebc0b90785 100644 --- a/crates/evm/traces/src/decoder/mod.rs +++ b/crates/evm/traces/src/decoder/mod.rs @@ -409,7 +409,7 @@ impl CallTraceDecoder { } if args.is_none() { - if let Ok(v) = func.abi_decode_input(&trace.data[SELECTOR_LEN..], false) { + if let Ok(v) = func.abi_decode_input(&trace.data[SELECTOR_LEN..]) { args = Some(v.iter().map(|value| self.format_value(value)).collect()); } } @@ -445,7 +445,7 @@ impl CallTraceDecoder { } } "sign" | "signP256" => { - let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..], false).ok()?; + let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..]).ok()?; // Redact private key and replace in trace // sign(uint256,bytes32) / signP256(uint256,bytes32) / sign(Wallet,bytes32) @@ -458,7 +458,7 @@ impl CallTraceDecoder { Some(decoded.iter().map(format_token).collect()) } "signDelegation" | "signAndAttachDelegation" => { - let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..], false).ok()?; + let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..]).ok()?; // Redact private key and replace in trace for // signAndAttachDelegation(address implementation, uint256 privateKey) // signDelegation(address implementation, uint256 privateKey) @@ -495,7 +495,7 @@ impl CallTraceDecoder { if self.verbosity >= 5 { None } else { - let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..], false).ok()?; + let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..]).ok()?; let token = if func.name.as_str() == "parseJson" || // `keyExists` is being deprecated in favor of `keyExistsJson`. It will be removed in future versions. func.name.as_str() == "keyExists" || @@ -513,7 +513,7 @@ impl CallTraceDecoder { if self.verbosity >= 5 { None } else { - let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..], false).ok()?; + let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..]).ok()?; let token = if func.name.as_str() == "parseToml" || func.name.as_str() == "keyExistsToml" { @@ -528,7 +528,7 @@ impl CallTraceDecoder { "createFork" | "createSelectFork" | "rpc" => { - let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..], false).ok()?; + let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..]).ok()?; // Redact RPC URL except if referenced by an alias if !decoded.is_empty() && func.inputs[0].ty == "string" { @@ -561,7 +561,7 @@ impl CallTraceDecoder { } if let Some(values) = - funcs.iter().find_map(|func| func.abi_decode_output(&trace.output, false).ok()) + funcs.iter().find_map(|func| func.abi_decode_output(&trace.output).ok()) { // Functions coming from an external database do not have any outputs specified, // and will lead to returning an empty list of values. @@ -628,7 +628,7 @@ impl CallTraceDecoder { } }; for event in events { - if let Ok(decoded) = event.decode_log(log, false) { + if let Ok(decoded) = event.decode_log(log) { let params = reconstruct_params(event, &decoded); return DecodedCallLog { name: Some(event.name.clone()), diff --git a/crates/evm/traces/src/decoder/precompiles.rs b/crates/evm/traces/src/decoder/precompiles.rs index 508bf1e1c4320..245c70e10ec57 100644 --- a/crates/evm/traces/src/decoder/precompiles.rs +++ b/crates/evm/traces/src/decoder/precompiles.rs @@ -106,13 +106,13 @@ pub(super) fn decode(trace: &CallTrace, _chain_id: u64) -> Option alloy_sol_types::Result> { - let mut decoder = abi::Decoder::new(data, false); + let mut decoder = abi::Decoder::new(data); let b_size = decoder.take_offset()?; let e_size = decoder.take_offset()?; let m_size = decoder.take_offset()?; - let b = decoder.take_slice_unchecked(b_size)?; - let e = decoder.take_slice_unchecked(e_size)?; - let m = decoder.take_slice_unchecked(m_size)?; + let b = decoder.take_slice(b_size)?; + let e = decoder.take_slice(e_size)?; + let m = decoder.take_slice(m_size)?; Ok(vec![ b_size.to_string(), e_size.to_string(), @@ -124,7 +124,7 @@ fn decode_modexp(data: &[u8]) -> alloy_sol_types::Result> { } fn decode_ecpairing(data: &[u8]) -> alloy_sol_types::Result> { - let mut decoder = abi::Decoder::new(data, false); + let mut decoder = abi::Decoder::new(data); let mut values = Vec::new(); // input must be either empty or a multiple of 6 32-byte values let mut tmp = <[&B256; 6]>::default(); @@ -138,14 +138,14 @@ fn decode_ecpairing(data: &[u8]) -> alloy_sol_types::Result> { } fn decode_blake2f<'a>(data: &'a [u8]) -> alloy_sol_types::Result> { - let mut decoder = abi::Decoder::new(data, false); - let rounds = u32::from_be_bytes(decoder.take_slice_unchecked(4)?.try_into().unwrap()); + let mut decoder = abi::Decoder::new(data); + let rounds = u32::from_be_bytes(decoder.take_slice(4)?.try_into().unwrap()); let u64_le_list = |x: &'a [u8]| x.chunks_exact(8).map(|x| u64::from_le_bytes(x.try_into().unwrap())); - let h = u64_le_list(decoder.take_slice_unchecked(64)?); - let m = u64_le_list(decoder.take_slice_unchecked(128)?); - let t = u64_le_list(decoder.take_slice_unchecked(16)?); - let f = decoder.take_slice_unchecked(1)?[0]; + let h = u64_le_list(decoder.take_slice(64)?); + let m = u64_le_list(decoder.take_slice(128)?); + let t = u64_le_list(decoder.take_slice(16)?); + let f = decoder.take_slice(1)?[0]; Ok(vec![ rounds.to_string(), iter_to_string(h), @@ -156,12 +156,12 @@ fn decode_blake2f<'a>(data: &'a [u8]) -> alloy_sol_types::Result> { } fn decode_kzg(data: &[u8]) -> alloy_sol_types::Result> { - let mut decoder = abi::Decoder::new(data, false); + let mut decoder = abi::Decoder::new(data); let versioned_hash = decoder.take_word()?; let z = decoder.take_word()?; let y = decoder.take_word()?; - let commitment = decoder.take_slice_unchecked(48)?; - let proof = decoder.take_slice_unchecked(48)?; + let commitment = decoder.take_slice(48)?; + let proof = decoder.take_slice(48)?; Ok(vec![ versioned_hash.to_string(), z.to_string(), @@ -173,7 +173,7 @@ fn decode_kzg(data: &[u8]) -> alloy_sol_types::Result> { fn abi_decode_call(data: &[u8]) -> alloy_sol_types::Result<(&'static str, T)> { // raw because there are no selectors here - Ok((T::SIGNATURE, T::abi_decode_raw(data, false)?)) + Ok((T::SIGNATURE, T::abi_decode_raw(data)?)) } fn iter_to_string, T: std::fmt::Display>(iter: I) -> String { diff --git a/crates/evm/traces/src/identifier/local.rs b/crates/evm/traces/src/identifier/local.rs index dcd4c31bcaf9f..f0bb8cd9d7d76 100644 --- a/crates/evm/traces/src/identifier/local.rs +++ b/crates/evm/traces/src/identifier/local.rs @@ -59,7 +59,7 @@ impl<'a> LocalTraceIdentifier<'a> { // Try to decode ctor args with contract abi. if let Some(constructor) = contract.abi.constructor() { let constructor_args = ¤t_bytecode[bytecode.len()..]; - if constructor.abi_decode_input(constructor_args, false).is_ok() { + if constructor.abi_decode_input(constructor_args).is_ok() { // If we can decode args with current abi then remove args from // code to compare. current_bytecode = ¤t_bytecode[..bytecode.len()] diff --git a/crates/forge/src/cmd/create.rs b/crates/forge/src/cmd/create.rs index 5cffad23b9141..6768b43829836 100644 --- a/crates/forge/src/cmd/create.rs +++ b/crates/forge/src/cmd/create.rs @@ -184,7 +184,7 @@ impl CreateArgs { let deployer = signer.address(); let provider = ProviderBuilder::<_, _, AnyNetwork>::default() .wallet(EthereumWallet::new(signer)) - .on_provider(provider); + .connect_provider(provider); self.deploy( abi, bin, diff --git a/crates/forge/src/runner.rs b/crates/forge/src/runner.rs index eb8f87221bfed..3e2f65fde7f8e 100644 --- a/crates/forge/src/runner.rs +++ b/crates/forge/src/runner.rs @@ -826,14 +826,10 @@ impl<'a> FunctionRunner<'a> { if self.cr.contract.abi.functions().filter(|func| func.name.is_before_test_setup()).count() == 1 { - for calldata in self - .executor - .call_sol_default( - address, - &ITest::beforeTestSetupCall { testSelector: func.selector() }, - ) - .beforeTestCalldata - { + for calldata in self.executor.call_sol_default( + address, + &ITest::beforeTestSetupCall { testSelector: func.selector() }, + ) { // Apply before test configured calldata. match self.executor.to_mut().transact_raw( self.tcfg.sender, diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 611fc39056351..3f76a179a0994 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -36,7 +36,7 @@ Options: -j, --threads Number of threads to use. Specifying 0 defaults to the number of logical cores - [aliases: jobs] + [aliases: --jobs] -V, --version Print version diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index 3de6dde23ea8e..6a75e4478bf3d 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -2916,8 +2916,6 @@ Traces: │ └─ ← [Return] 1 ├─ [0] VM::assertEq(1, 1) [staticcall] │ └─ ← [Return] - ├─ storage changes: - │ @ 0: 0 → 1 └─ ← [Stop] Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] diff --git a/crates/forge/tests/fixtures/colored_traces.svg b/crates/forge/tests/fixtures/colored_traces.svg index 4b2be87d03df7..e4181676bcc86 100644 --- a/crates/forge/tests/fixtures/colored_traces.svg +++ b/crates/forge/tests/fixtures/colored_traces.svg @@ -1,4 +1,4 @@ - +

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// # Ok(()) /// # } @@ -219,7 +219,7 @@ impl> Cast

{ /// ); /// /// # async fn foo() -> eyre::Result<()> { - /// let provider = ProviderBuilder::<_,_, AnyNetwork>::default().on_builtin("http://localhost:8545").await?;; + /// let provider = ProviderBuilder::<_,_, AnyNetwork>::default().connect("http://localhost:8545").await?;; /// let to = Address::from_str("0xB3C95ff08316fb2F2e3E52Ee82F8e7b605Aa1304")?; /// let greeting = greetingCall { i: U256::from(5) }.abi_encode(); /// let bytes = Bytes::from_iter(greeting.iter()); @@ -280,7 +280,7 @@ impl> Cast

{ /// ); /// /// # async fn foo() -> eyre::Result<()> { - /// let provider = ProviderBuilder::<_,_, AnyNetwork>::default().on_builtin("http://localhost:8545").await?;; + /// let provider = ProviderBuilder::<_,_, AnyNetwork>::default().connect("http://localhost:8545").await?;; /// let from = Address::from_str("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")?; /// let to = Address::from_str("0xB3C95ff08316fb2F2e3E52Ee82F8e7b605Aa1304")?; /// let greeting = greetCall { greeting: "hello".to_string() }.abi_encode(); @@ -315,7 +315,7 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let res = cast.publish("0x1234".to_string()).await?; /// println!("{:?}", res); @@ -344,7 +344,7 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let block = cast.block(5, true, None).await?; /// println!("{}", block); @@ -500,7 +500,7 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let addr = Address::from_str("0x7eD52863829AB99354F3a0503A622e82AcD5F7d3")?; /// let nonce = cast.nonce(addr, None).await?; @@ -522,7 +522,7 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let addr = Address::from_str("0x7eD52863829AB99354F3a0503A622e82AcD5F7d3")?; /// let slots = vec![FixedBytes::from_str("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")?]; @@ -555,7 +555,7 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let addr = Address::from_str("0x7eD52863829AB99354F3a0503A622e82AcD5F7d3")?; /// let slots = vec![FixedBytes::from_str("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")?]; @@ -588,7 +588,7 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let addr = Address::from_str("0x7eD52863829AB99354F3a0503A622e82AcD5F7d3")?; /// let implementation = cast.implementation(addr, false, None).await?; @@ -637,7 +637,7 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let addr = Address::from_str("0x7eD52863829AB99354F3a0503A622e82AcD5F7d3")?; /// let admin = cast.admin(addr, None).await?; @@ -667,7 +667,7 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let addr = Address::from_str("7eD52863829AB99354F3a0503A622e82AcD5F7d3")?; /// let computed_address = cast.compute_address(addr, None).await?; @@ -690,7 +690,7 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let addr = Address::from_str("0x00000000219ab540356cbb839cbe05303d7705fa")?; /// let code = cast.code(addr, None, false).await?; @@ -726,7 +726,7 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let addr = Address::from_str("0x00000000219ab540356cbb839cbe05303d7705fa")?; /// let codesize = cast.codesize(addr, None).await?; @@ -809,7 +809,7 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let tx_hash = "0xf8d1713ea15a81482958fb7ddf884baee8d3bcc478c5f2f604e008dc788ee4fc"; /// let receipt = cast.receipt(tx_hash.to_string(), None, 1, None, false).await?; @@ -870,7 +870,7 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let result = cast /// .rpc("eth_getBalance", &["0xc94770007dda54cF92009BFF0dE90c06F603a09f", "latest"]) @@ -902,7 +902,7 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let addr = Address::from_str("0x00000000006c3852cbEf3e08E8dF289169EdE581")?; /// let slot = B256::ZERO; @@ -964,7 +964,7 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// /// let block_number = cast.convert_block_number(Some(BlockId::number(5))).await?; @@ -1012,7 +1012,7 @@ impl> Cast

{ /// /// # async fn foo() -> eyre::Result<()> { /// let provider = - /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("wss://localhost:8545").await?; + /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("wss://localhost:8545").await?; /// let cast = Cast::new(provider); /// /// let filter = From 3e1c72b97cdffdced87d49c7fecf625e4035a559 Mon Sep 17 00:00:00 2001 From: Soubhik Singha Mahapatra <160333583+Soubhik-10@users.noreply.github.com> Date: Sat, 24 May 2025 19:21:51 +0530 Subject: [PATCH 141/244] feat: added rpc method to deal ERC20 tokens (#10495) * wip * wip * wip * wip * call + storage * type fix * wip * wip * smol fix * cleanup * cleanup * cleanup * cleanup * chore: pedantic touchups --------- Co-authored-by: Matthias Seitz --- crates/anvil/core/src/eth/mod.rs | 9 ++++ crates/anvil/src/eth/api.rs | 76 +++++++++++++++++++++++++++++++- crates/anvil/tests/it/fork.rs | 25 +++++++++++ 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/crates/anvil/core/src/eth/mod.rs b/crates/anvil/core/src/eth/mod.rs index a4d05ed29562f..052a2e7e5f535 100644 --- a/crates/anvil/core/src/eth/mod.rs +++ b/crates/anvil/core/src/eth/mod.rs @@ -363,6 +363,15 @@ pub enum EthRequest { #[serde(rename = "anvil_setBalance", alias = "hardhat_setBalance")] SetBalance(Address, #[serde(deserialize_with = "deserialize_number")] U256), + /// Modifies the ERC20 balance of an account. + #[serde( + rename = "anvil_dealERC20", + alias = "hardhat_dealERC20", + alias = "anvil_setERC20Balance", + alias = "tenderly_setErc20Balance" + )] + DealERC20(Address, Address, #[serde(deserialize_with = "deserialize_number")] U256), + /// Sets the code of a contract #[serde(rename = "anvil_setCode", alias = "hardhat_setCode")] SetCode(Address, Bytes), diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 5f19e05ae3fd6..243ae88440e8d 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -56,7 +56,7 @@ use alloy_rpc_types::{ }, request::TransactionRequest, simulate::{SimulatePayload, SimulatedBlock}, - state::EvmOverrides, + state::{AccountOverride, EvmOverrides, StateOverridesBuilder}, trace::{ filter::TraceFilter, geth::{GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace}, @@ -67,6 +67,7 @@ use alloy_rpc_types::{ EIP1186AccountProofResponse, FeeHistory, Filter, FilteredParams, Index, Log, Work, }; use alloy_serde::WithOtherFields; +use alloy_sol_types::{sol, SolCall, SolValue}; use alloy_transport::TransportErrorKind; use anvil_core::{ eth::{ @@ -355,6 +356,9 @@ impl EthApi { EthRequest::SetBalance(addr, val) => { self.anvil_set_balance(addr, val).await.to_rpc_result() } + EthRequest::DealERC20(addr, token_addr, val) => { + self.anvil_deal_erc20(addr, token_addr, val).await.to_rpc_result() + } EthRequest::SetCode(addr, code) => { self.anvil_set_code(addr, code).await.to_rpc_result() } @@ -1852,6 +1856,76 @@ impl EthApi { Ok(()) } + /// Deals ERC20 tokens to a address + /// + /// Handler for RPC call: `anvil_dealERC20` + pub async fn anvil_deal_erc20( + &self, + address: Address, + token_address: Address, + balance: U256, + ) -> Result<()> { + node_info!("anvil_dealERC20"); + + sol! { + #[sol(rpc)] + contract IERC20 { + function balanceOf(address target) external view returns (uint256); + } + } + + let calldata = IERC20::balanceOfCall { target: address }.abi_encode(); + let tx = TransactionRequest::default().with_to(token_address).with_input(calldata.clone()); + + // first collect all the slots that are used by the balanceOf call + let access_list_result = + self.create_access_list(WithOtherFields::new(tx.clone()), None).await?; + let access_list = access_list_result.access_list; + + // now we can iterate over all the accessed slots and try to find the one that contains the + // balance by overriding the slot and checking the `balanceOfCall` of + for item in access_list.0 { + if item.address != token_address { + continue; + }; + for slot in &item.storage_keys { + let account_override = AccountOverride::default() + .with_state_diff(std::iter::once((*slot, B256::from(balance.to_be_bytes())))); + + let state_override = StateOverridesBuilder::default() + .append(token_address, account_override) + .build(); + + let evm_override = EvmOverrides::state(Some(state_override)); + + let Ok(result) = + self.call(WithOtherFields::new(tx.clone()), None, evm_override).await + else { + // overriding this slot failed + continue; + }; + + let Ok(result_balance) = U256::abi_decode(&result) else { + // response returned something other than a U256 + continue; + }; + + if result_balance == balance { + self.anvil_set_storage_at( + token_address, + U256::from_be_bytes(slot.0), + B256::from(balance.to_be_bytes()), + ) + .await?; + return Ok(()); + } + } + } + + // unable to set the balance + Err(BlockchainError::Message("Unable to set ERC20 balance, no slot found".to_string())) + } + /// Sets the code of a contract. /// /// Handler for RPC call: `anvil_setCode` diff --git a/crates/anvil/tests/it/fork.rs b/crates/anvil/tests/it/fork.rs index 651ae5ec231ca..54bae673a6bd0 100644 --- a/crates/anvil/tests/it/fork.rs +++ b/crates/anvil/tests/it/fork.rs @@ -1465,6 +1465,31 @@ async fn test_reset_dev_account_nonce() { assert!(receipt.status()); } +#[tokio::test(flavor = "multi_thread")] +async fn test_set_erc20_balance() { + let config: NodeConfig = fork_config(); + let address = config.genesis_accounts[0].address(); + let (api, handle) = spawn(config).await; + + let provider = handle.http_provider(); + + alloy_sol_types::sol! { + #[sol(rpc)] + contract ERC20 { + function balanceOf(address owner) public view returns (uint256); + } + } + let dai = address!("0x6B175474E89094C44Da98b954EedeAC495271d0F"); + let erc20 = ERC20::new(dai, provider); + let value = U256::from(500); + + api.anvil_deal_erc20(address, dai, value).await.unwrap(); + + let new_balance = erc20.balanceOf(address).call().await.unwrap(); + + assert_eq!(new_balance, value); +} + #[tokio::test(flavor = "multi_thread")] async fn test_reset_updates_cache_path_when_rpc_url_not_provided() { let config: NodeConfig = fork_config(); From f86a66ea206d5e3405dce7cdfffc7c843a8b43cf Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Sat, 24 May 2025 16:01:32 +0200 Subject: [PATCH 142/244] fix: check for auth when deriving legacy (#10619) * fix: check for auth when deriving legacy * fmt --- crates/cast/src/tx.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/cast/src/tx.rs b/crates/cast/src/tx.rs index 651b11a64e30c..829d8e571ca80 100644 --- a/crates/cast/src/tx.rs +++ b/crates/cast/src/tx.rs @@ -138,6 +138,7 @@ pub struct InputState { pub struct CastTxBuilder { provider: P, tx: WithOtherFields, + /// Whether the transaction should be sent as a legacy transaction. legacy: bool, blob: bool, auth: Option, @@ -157,7 +158,8 @@ impl> CastTxBuilder { let chain = utils::get_chain(config.chain, &provider).await?; let etherscan_api_version = config.get_etherscan_api_version(Some(chain)); let etherscan_api_key = config.get_etherscan_api_key(Some(chain)); - let legacy = tx_opts.legacy || chain.is_legacy(); + // mark it as legacy if requested or the chain is legacy and no 7702 is provided. + let legacy = tx_opts.legacy || (chain.is_legacy() && tx_opts.auth.is_none()); if let Some(gas_limit) = tx_opts.gas_limit { tx.set_gas_limit(gas_limit.to()); From 7fba3dd72419698d044bf582045563a5157c39f7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 25 May 2025 12:21:18 +0200 Subject: [PATCH 143/244] chore(deps): weekly `cargo update` (#10625) Updating git repository `https://github.com/bluealloy/revm.git` Locking 73 packages to latest compatible versions Updating alloy-consensus v1.0.5 -> v1.0.7 Updating alloy-consensus-any v1.0.4 -> v1.0.7 Updating alloy-contract v1.0.5 -> v1.0.7 Updating alloy-dyn-abi v1.1.0 -> v1.1.2 Updating alloy-eips v1.0.5 -> v1.0.7 Updating alloy-ens v1.0.6 -> v1.0.7 Unchanged alloy-evm v0.9.1 (available: v0.10.0) Updating alloy-genesis v1.0.5 -> v1.0.7 Updating alloy-hardforks v0.2.2 -> v0.2.3 Updating alloy-json-abi v1.1.0 -> v1.1.2 Updating alloy-json-rpc v1.0.5 -> v1.0.7 Updating alloy-network v1.0.5 -> v1.0.7 Updating alloy-network-primitives v1.0.4 -> v1.0.7 Unchanged alloy-op-evm v0.9.1 (available: v0.10.0) Updating alloy-op-hardforks v0.2.2 -> v0.2.3 Updating alloy-primitives v1.1.0 -> v1.1.2 Updating alloy-provider v1.0.5 -> v1.0.7 Updating alloy-pubsub v1.0.5 -> v1.0.7 Updating alloy-rpc-client v1.0.5 -> v1.0.7 Updating alloy-rpc-types v1.0.5 -> v1.0.7 Updating alloy-rpc-types-anvil v1.0.4 -> v1.0.7 Updating alloy-rpc-types-any v1.0.4 -> v1.0.7 Updating alloy-rpc-types-debug v1.0.4 -> v1.0.7 Updating alloy-rpc-types-engine v1.0.4 -> v1.0.7 Updating alloy-rpc-types-eth v1.0.4 -> v1.0.7 Updating alloy-rpc-types-trace v1.0.4 -> v1.0.7 Updating alloy-rpc-types-txpool v1.0.4 -> v1.0.7 Updating alloy-serde v1.0.5 -> v1.0.7 Updating alloy-signer v1.0.5 -> v1.0.7 Updating alloy-signer-aws v1.0.5 -> v1.0.7 Updating alloy-signer-gcp v1.0.5 -> v1.0.7 Updating alloy-signer-ledger v1.0.5 -> v1.0.7 Updating alloy-signer-local v1.0.5 -> v1.0.7 Updating alloy-signer-trezor v1.0.5 -> v1.0.7 Updating alloy-sol-macro v1.1.0 -> v1.1.2 Updating alloy-sol-macro-expander v1.1.0 -> v1.1.2 Updating alloy-sol-macro-input v1.1.0 -> v1.1.2 Updating alloy-sol-type-parser v1.1.0 -> v1.1.2 Updating alloy-sol-types v1.1.0 -> v1.1.2 Updating alloy-transport v1.0.5 -> v1.0.7 Updating alloy-transport-http v1.0.5 -> v1.0.7 Updating alloy-transport-ipc v1.0.5 -> v1.0.7 Updating alloy-transport-ws v1.0.5 -> v1.0.7 Updating anstyle-wincon v3.0.7 -> v3.0.8 Updating aws-sdk-kms v1.69.0 -> v1.71.0 Updating aws-sdk-sso v1.68.0 -> v1.70.0 Updating aws-sdk-ssooidc v1.69.0 -> v1.71.0 Updating aws-sdk-sts v1.69.0 -> v1.71.0 Updating cc v1.2.23 -> v1.2.24 Updating clap-verbosity-flag v3.0.2 -> v3.0.3 Unchanged crossterm v0.28.1 (available: v0.29.0) Updating foundry-compilers v0.16.1 -> v0.16.2 Updating foundry-compilers-artifacts v0.16.1 -> v0.16.2 Updating foundry-compilers-artifacts-solc v0.16.1 -> v0.16.2 Updating foundry-compilers-artifacts-vyper v0.16.1 -> v0.16.2 Updating foundry-compilers-core v0.16.1 -> v0.16.2 Unchanged foundry-fork-db v0.14.0 (available: v0.15.0) Updating hyper-rustls v0.27.5 -> v0.27.6 Updating hyper-util v0.1.11 -> v0.1.12 Unchanged idna_adapter v1.1.0 (available: v1.2.1) Updating jiff v0.2.13 -> v0.2.14 Updating jiff-static v0.2.13 -> v0.2.14 Updating lalrpop v0.22.1 -> v0.22.2 Updating lalrpop-util v0.22.1 -> v0.22.2 Unchanged matchit v0.8.4 (available: v0.8.6) Updating mdbook v0.4.49 -> v0.4.50 Updating mio v1.0.3 -> v1.0.4 Adding once_cell_polyfill v1.70.1 Unchanged op-alloy-consensus v0.16.0 (available: v0.17.1) Unchanged op-alloy-rpc-types v0.16.0 (available: v0.17.1) Adding opener v0.8.1 Unchanged opener v0.7.2 (available: v0.8.1) Updating parity-scale-codec v3.7.4 -> v3.7.5 Updating parity-scale-codec-derive v3.7.4 -> v3.7.5 Unchanged protobuf v3.3.0 (available: v3.7.2) Unchanged protobuf-support v3.3.0 (available: v3.7.2) Unchanged rand v0.8.5 (available: v0.9.1) Unchanged revm-inspectors v0.22.3 (available: v0.23.0) Updating ruint v1.14.0 -> v1.15.0 Updating rustversion v1.0.20 -> v1.0.21 Updating syn-solidity v1.1.0 -> v1.1.2 Updating tokio v1.45.0 -> v1.45.1 Unchanged ui_test v0.29.2 (available: v0.30.0) Updating uuid v1.16.0 -> v1.17.0 Unchanged vergen v8.3.2 (available: v9.0.6) Updating windows-core v0.61.1 -> v0.61.2 Updating windows-result v0.3.3 -> v0.3.4 Updating windows-strings v0.4.1 -> v0.4.2 Unchanged zip-extract v0.2.1 (available: v0.2.3) note: to see how you depend on a package, run `cargo tree --invert --package @` Co-authored-by: mattsse <19890894+mattsse@users.noreply.github.com> --- Cargo.lock | 405 +++++++++++++++++++++++++++-------------------------- 1 file changed, 210 insertions(+), 195 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea0b862ec1302..e972d3906b5dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,14 +70,14 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9835a7b6216cb8118323581e58a18b1a5014fce55ce718635aaea7fa07bd700" +checksum = "7329eb72d95576dfb8813175bcf671198fb24266b0b3e520052a513e30c284df" dependencies = [ - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "alloy-trie", "auto_impl", "c-kzg", @@ -94,23 +94,23 @@ dependencies = [ [[package]] name = "alloy-consensus-any" -version = "1.0.4" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aec7fdaa4f0e4e1ca7e9271ca7887fdd467ca3b9e101582dc6c2bbd1645eae1c" +checksum = "f31b286aeef04a32720c10defd21c3aa6c626154ac442b55f6d472caeb1c6741" dependencies = [ "alloy-consensus", - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "serde", ] [[package]] name = "alloy-contract" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e810f27a4162190b50cdf4dabedee3ad9028772bd7e370fdfc0f63b8bc116d3" +checksum = "e1658352ca9425d7b5bbb3ae364bc276ab18d4afae06f5faf00377b6964fdf68" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -130,16 +130,15 @@ dependencies = [ [[package]] name = "alloy-dyn-abi" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f90b63261b7744642f6075ed17db6de118eecbe9516ea6c6ffd444b80180b75" +checksum = "18cc14d832bc3331ca22a1c7819de1ede99f58f61a7d123952af7dde8de124a6" dependencies = [ "alloy-json-abi", "alloy-primitives", "alloy-sol-type-parser", "alloy-sol-types", "arbitrary", - "const-hex", "derive_arbitrary", "derive_more 2.0.1", "itoa", @@ -208,16 +207,16 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fc566136b705991072f8f79762525e14f0ca39c38d45b034944770cb6c6b67" +checksum = "4fa190bfa5340aee544ac831114876fa73bc8da487095b49a5ea153a6a4656ea" dependencies = [ "alloy-eip2124", "alloy-eip2930", "alloy-eip7702", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "auto_impl", "c-kzg", "derive_more 2.0.1", @@ -228,9 +227,9 @@ dependencies = [ [[package]] name = "alloy-ens" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e75be61b140796044420ad1d5b31b415150c46e0a6e59c155d6f0e10e307b9ac" +checksum = "1ecbc80925fcfa5fa20ad45392535a98f586ee96ad75f8e801ca7e4d9176e0c4" dependencies = [ "alloy-contract", "alloy-primitives", @@ -247,7 +246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8c5b34c78c42525917b236e4135b1951ca183ede4004b594db0effee8bed169" dependencies = [ "alloy-consensus", - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-hardforks", "alloy-primitives", "alloy-sol-types", @@ -261,22 +260,22 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "765c0124a3174f136171df8498e4700266774c9de1008a0b987766cf215d08f6" +checksum = "2b81b2dfd278d58af8bfde8753fa4685407ba8fbad8bc88a2bb0e065eed48478" dependencies = [ - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-primitives", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "alloy-trie", "serde", ] [[package]] name = "alloy-hardforks" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b40cc82a2283e3ce6317bc1f0134ea50d20e8c1965393045ee952fb28a65ddbd" +checksum = "1d6b8067561eb8f884b215ace4c962313c5467e47bde6b457c8c51e268fb5d99" dependencies = [ "alloy-chains", "alloy-eip2124", @@ -287,9 +286,9 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0068ae277f5ee3153a95eaea8ff10e188ed8ccde9b7f9926305415a2c0ab2442" +checksum = "3ccaa79753d7bf15f06399ea76922afbfaf8d18bebed9e8fc452984b4a90dcc9" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -299,9 +298,9 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1590f44abdfe98686827a4e083b711ad17f843bf6ed8a50b78d3242f12a00ada" +checksum = "89ab2dba5dca01ad4281b4d4726a18e2012a20e3950bfc2a90c5376840555366" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -313,19 +312,19 @@ dependencies = [ [[package]] name = "alloy-network" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049a9022caa0c0a2dcd2bc2ea23fa098508f4a81d5dda774d753570a41e6acdb" +checksum = "f0ed07e76fbc72790a911ea100cdfbe85b1f12a097c91b948042e854959d140e" dependencies = [ "alloy-consensus", "alloy-consensus-any", - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-json-rpc", "alloy-network-primitives", "alloy-primitives", "alloy-rpc-types-any", "alloy-rpc-types-eth", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "alloy-signer", "alloy-sol-types", "async-trait", @@ -339,14 +338,14 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "1.0.4" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5630ce8552579d1393383b27fe4bfe7c700fb7480189a82fc054da24521947aa" +checksum = "f05aa52713c376f797b3c7077708585f22a5c3053a7b1b2b355ea98edeb2052d" dependencies = [ "alloy-consensus", - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-primitives", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "serde", ] @@ -357,7 +356,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4fda8b1920a38a5adc607d6ff7be1e8991e16ffcf97bb12765644b87331c598" dependencies = [ "alloy-consensus", - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-evm", "alloy-op-hardforks", "alloy-primitives", @@ -369,9 +368,9 @@ dependencies = [ [[package]] name = "alloy-op-hardforks" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a79617217008626a24fb52b02d532bf4554ac9b184a2d22bd6c5df628c151601" +checksum = "08043c9284e597f9b5cf741cc6d906fdb26c195a01d88423c84c00ffda835713" dependencies = [ "alloy-hardforks", "auto_impl", @@ -379,9 +378,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a12fe11d0b8118e551c29e1a67ccb6d01cc07ef08086df30f07487146de6fa1" +checksum = "18c35fc4b03ace65001676358ffbbaefe2a2b27ee50fe777c345082c7c888be8" dependencies = [ "alloy-rlp", "arbitrary", @@ -410,13 +409,13 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "959aedfc417737e2a59961c95e92c59726386748d85ef516a0d0687b440d3184" +checksum = "05a3f7a59c276c6e410267e77a166f9297dbe74e4605f1abf625e29d85c53144" dependencies = [ "alloy-chains", "alloy-consensus", - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-json-rpc", "alloy-network", "alloy-network-primitives", @@ -455,9 +454,9 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf694cd1494284e73e23b62568bb5df6777f99eaec6c0a4705ac5a5c61707208" +checksum = "fc3cbf02fdedbec7aadc7a77080b6b143752fa792c7fd49b86fd854257688bd4" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -498,9 +497,9 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20436220214938c4fe223244f00fbd618dda80572b8ffe7839d382a6c54f1c" +checksum = "d5f185483536cbcbf55971077140e03548dad4f3a4ddb35044bcdc01b8f02ce1" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -526,9 +525,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2981f41486264b2e254bc51b2691bbef9ed87d0545d11f31cb26af3109cc4" +checksum = "347dfd77ba4d74886dba9e2872ff64fb246001b08868d27baec94e7248503e08" dependencies = [ "alloy-primitives", "alloy-rpc-types-anvil", @@ -536,38 +535,38 @@ dependencies = [ "alloy-rpc-types-eth", "alloy-rpc-types-trace", "alloy-rpc-types-txpool", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "serde", ] [[package]] name = "alloy-rpc-types-anvil" -version = "1.0.4" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ebe3dcbc6c85678f29c205b2fcf6b110b32287bf6b72bbee37ed9011404e926" +checksum = "51e15bd6456742d6dcadacf3cd238a90a8a7aa9f00bc7cc641ae272f5d3f5d4f" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "serde", ] [[package]] name = "alloy-rpc-types-any" -version = "1.0.4" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c583654aab419fe9e553ba86ab503e1cda0b855509ac95210c4ca6df84724255" +checksum = "67971a228100ac65bd86e90439028853435f21796330ef08f00a70a918a84126" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", ] [[package]] name = "alloy-rpc-types-debug" -version = "1.0.4" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7913c67b874db23446a4cdd020da1bbc828513bd83536ccabfca403b71cdeaf9" +checksum = "fe8bc37b23e788c0f8081a7eec34fd439cfa8d4f137f6e987803fb2a733866ca" dependencies = [ "alloy-primitives", "serde", @@ -575,15 +574,15 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "1.0.4" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b70151dc3282ce4bbde31b80a7f0f1e53b9dec9b187f528394e8f0a0411975" +checksum = "2bcf49fe91b3d621440dcc5bb067afaeba5ca4b07f59e42fb7af42944146a8c0" dependencies = [ "alloy-consensus", - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "derive_more 2.0.1", "jsonwebtoken", "rand 0.8.5", @@ -593,17 +592,17 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "1.0.4" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4496ab5f898c88e9153b88fcb6738e2d58b2ba6d7d85c3144ee83c990316a3" +checksum = "89d9b4293dfd4721781d33ee40de060376932d4a55d421cf6618ad66ff97cc52" dependencies = [ "alloy-consensus", "alloy-consensus-any", - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-network-primitives", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "alloy-sol-types", "itertools 0.14.0", "serde", @@ -613,13 +612,13 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "1.0.4" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf555fe777cf7d11b8ebe837aca0b0ceb74f1ed9937f938b8c9fbd1460994cf" +checksum = "7f68f020452c0d570b4eee22d4ffda9e4eda68ebcf67e1199d6dff48097f442b" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "serde", "serde_json", "thiserror 2.0.12", @@ -627,13 +626,13 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "1.0.4" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c69ea401ce851b52c9b07d838173cd3c23c11a552a5e5ddde3ffd834647a46" +checksum = "62a82f15f296c2c83c55519d21ca07801fb58b118878b0f4777250968e49f4fe" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "serde", ] @@ -650,9 +649,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c34ffc38f543bfdceed8c1fa5253fa5131455bb3654976be4cc3a4ae6d61f4" +checksum = "3b7d927aa39ca51545ae4c9cf4bdb2cbc1f6b46ab4b54afc3ed9255f93eedbce" dependencies = [ "alloy-primitives", "serde", @@ -661,9 +660,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59245704a5dbd20b93913f4a20aa41b45c4c134f82e119bb54de4b627e003955" +checksum = "c63771b50008d2b079187e9e74a08235ab16ecaf4609b4eb895e2890a3bcd465" dependencies = [ "alloy-dyn-abi", "alloy-primitives", @@ -678,9 +677,9 @@ dependencies = [ [[package]] name = "alloy-signer-aws" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a24ea892abc29582dce6df5a1266ddf620fe93a04eb0265a3072c68c8b0ea10" +checksum = "27a8f3d6f2e11b5a4f73ab34f3b2b526684e6b26e2a2ebf2264c1dae45030451" dependencies = [ "alloy-consensus", "alloy-network", @@ -696,9 +695,9 @@ dependencies = [ [[package]] name = "alloy-signer-gcp" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f07be333cf6b3f06475d86b5fe39e5f94285714fffaf961173ff87448180f346" +checksum = "af53c8eb7b94b8a9b915b64a0fc56b4c1fde247d8aeb421504f25d673a4d360a" dependencies = [ "alloy-consensus", "alloy-network", @@ -714,9 +713,9 @@ dependencies = [ [[package]] name = "alloy-signer-ledger" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04ad29d22519ce6fcf85edb8fb0d335216e8522c4458cdd92792f06c2173f9f2" +checksum = "d86a43041a6f1c5b63659860311ab14ea765bf9cef3293322988d896a0b8c88c" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -734,9 +733,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae78644ab0945e95efa2dc0cfac8f53aa1226fe85c294a0d8ad82c5cc9f09a2" +checksum = "db906294ee7876bd332cd760f460d30de183554434e07fc19d7d54e16a7aeaf0" dependencies = [ "alloy-consensus", "alloy-network", @@ -753,9 +752,9 @@ dependencies = [ [[package]] name = "alloy-signer-trezor" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52a384f096c65ec6f9c541dd8a0d1217f38ff7aa0d2565254d03d9a51c23b5c6" +checksum = "2277b489b01e6178fc5404c978bdc82b211c9c50de4b1e0efb75ecea3eb2bf54" dependencies = [ "alloy-consensus", "alloy-network", @@ -770,9 +769,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3ef8e0d622453d969ba3cded54cf6800efdc85cb929fe22c5bdf8335666757" +checksum = "8612e0658964d616344f199ab251a49d48113992d81b92dab93ed855faa66383" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -784,9 +783,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0e84bd0693c69a8fbe3ec0008465e029c6293494df7cb07580bf4a33eff52e1" +checksum = "7a384edac7283bc4c010a355fb648082860c04b826bb7a814c45263c8f304c74" dependencies = [ "alloy-json-abi", "alloy-sol-macro-input", @@ -803,9 +802,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3de663412dadf9b64f4f92f507f78deebcc92339d12cf15f88ded65d41c7935" +checksum = "0dd588c2d516da7deb421b8c166dc60b7ae31bca5beea29ab6621fcfa53d6ca5" dependencies = [ "alloy-json-abi", "const-hex", @@ -821,9 +820,9 @@ dependencies = [ [[package]] name = "alloy-sol-type-parser" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "251273c5aa1abb590852f795c938730fa641832fc8fa77b5478ed1bf11b6097e" +checksum = "e86ddeb70792c7ceaad23e57d52250107ebbb86733e52f4a25d8dc1abc931837" dependencies = [ "serde", "winnow", @@ -831,22 +830,21 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5460a975434ae594fe2b91586253c1beb404353b78f0a55bf124abcd79557b15" +checksum = "584cb97bfc5746cb9dcc4def77da11694b5d6d7339be91b7480a6a68dc129387" dependencies = [ "alloy-json-abi", "alloy-primitives", "alloy-sol-macro", - "const-hex", "serde", ] [[package]] name = "alloy-transport" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56afd0561a291e84de9d5616fa3def4c4925a09117ea3b08d4d5d207c4f7083" +checksum = "ca9b645fe4f4e6582cfbb4a8d20cedcf5aa23548e92eacbdacac6278b425e023" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -867,9 +865,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90770711e649bb3df0a8a666ae7b80d1d77eff5462eaf6bb4d3eaf134f6e636e" +checksum = "ee18869ecabe658ff6316e7db7c25d958c7d10f0a1723c2f7447d4f402920b66" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -882,9 +880,9 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "983693379572a06e2bc1050116d975395604b357e1f2ac4420dd385d9ee18c11" +checksum = "ff95f0b3a3bd2b80a53a52f7649ea6ef3e7e91ff4bd439871199ec68b1b69038" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -902,9 +900,9 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90569cc2e13f5cdf53f42d5b3347cf4a89fccbcf9978cf08b165b4a1c6447672" +checksum = "f7c838e7562d16110fba3590a20c7765281c1a302cf567e1806d0c3ce1352b58" dependencies = [ "alloy-pubsub", "alloy-transport", @@ -1036,12 +1034,12 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa" dependencies = [ "anstyle", - "once_cell", + "once_cell_polyfill", "windows-sys 0.59.0", ] @@ -1053,7 +1051,7 @@ dependencies = [ "alloy-consensus", "alloy-contract", "alloy-dyn-abi", - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-evm", "alloy-genesis", "alloy-network", @@ -1063,7 +1061,7 @@ dependencies = [ "alloy-pubsub", "alloy-rlp", "alloy-rpc-types", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "alloy-signer", "alloy-signer-local", "alloy-sol-types", @@ -1115,12 +1113,12 @@ version = "1.2.1" dependencies = [ "alloy-consensus", "alloy-dyn-abi", - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-network", "alloy-primitives", "alloy-rlp", "alloy-rpc-types", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "bytes", "foundry-common", "foundry-evm", @@ -1701,14 +1699,14 @@ dependencies = [ "percent-encoding", "pin-project-lite", "tracing", - "uuid 1.16.0", + "uuid 1.17.0", ] [[package]] name = "aws-sdk-kms" -version = "1.69.0" +version = "1.71.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64c93b24f98760979113386e444886fc812632d4d84910b802d69a2bdbb5349" +checksum = "5de993b5250e1aa051f4091ab772ce164de8c078ee9793fdee033b20f7d371ad" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1728,9 +1726,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.68.0" +version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5f01ea61fed99b5fe4877abff6c56943342a56ff145e9e0c7e2494419008be" +checksum = "83447efb7179d8e2ad2afb15ceb9c113debbc2ecdf109150e338e2e28b86190b" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1750,9 +1748,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.69.0" +version = "1.71.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27454e4c55aaa4ef65647e3a1cf095cb834ca6d54e959e2909f1fef96ad87860" +checksum = "c5f9bfbbda5e2b9fe330de098f14558ee8b38346408efe9f2e9cee82dc1636a4" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1772,9 +1770,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.69.0" +version = "1.71.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffd6ef5d00c94215960fabcdf2d9fe7c090eed8be482d66d47b92d4aba1dd4aa" +checksum = "e17b984a66491ec08b4f4097af8911251db79296b3e4a763060b45805746264f" dependencies = [ "aws-credential-types", "aws-runtime", @@ -2391,7 +2389,7 @@ dependencies = [ "alloy-provider", "alloy-rlp", "alloy-rpc-types", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "alloy-signer", "alloy-signer-local", "alloy-sol-types", @@ -2446,9 +2444,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.23" +version = "1.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766" +checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7" dependencies = [ "jobserver", "libc", @@ -2583,9 +2581,9 @@ dependencies = [ [[package]] name = "clap-verbosity-flag" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2678fade3b77aa3a8ff3aae87e9c008d3fb00473a41c71fbf74e91c8c7b37e84" +checksum = "eeab6a5cdfc795a05538422012f20a5496f050223c91be4e5420bfd13c641fb1" dependencies = [ "clap", "log", @@ -3816,7 +3814,7 @@ dependencies = [ "alloy-primitives", "alloy-provider", "alloy-rpc-types", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "alloy-signer", "alloy-signer-local", "alloy-transport", @@ -3856,7 +3854,7 @@ dependencies = [ "inferno", "itertools 0.14.0", "mockall", - "opener", + "opener 0.7.2", "parking_lot", "paste", "path-slash", @@ -3949,13 +3947,13 @@ dependencies = [ "alloy-chains", "alloy-consensus", "alloy-dyn-abi", - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-json-abi", "alloy-network", "alloy-primitives", "alloy-provider", "alloy-rpc-types", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "alloy-signer", "clap", "dialoguer", @@ -4147,7 +4145,7 @@ version = "1.2.1" dependencies = [ "alloy-chains", "alloy-dyn-abi", - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-ens", "alloy-json-abi", "alloy-primitives", @@ -4193,7 +4191,7 @@ version = "1.2.1" dependencies = [ "alloy-consensus", "alloy-dyn-abi", - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-json-abi", "alloy-json-rpc", "alloy-network", @@ -4202,7 +4200,7 @@ dependencies = [ "alloy-pubsub", "alloy-rpc-client", "alloy-rpc-types", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "alloy-sol-types", "alloy-transport", "alloy-transport-http", @@ -4251,7 +4249,7 @@ dependencies = [ "alloy-network", "alloy-primitives", "alloy-rpc-types", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "chrono", "foundry-macros", "revm", @@ -4263,9 +4261,9 @@ dependencies = [ [[package]] name = "foundry-compilers" -version = "0.16.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6154e503612a175a88ff342592f0a44664dda54a508d9443121b62b1701f91" +checksum = "a43ecf9100de8d31242b7a7cf965196e3d8fb424a931a975a7882897726f4c46" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4300,9 +4298,9 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts" -version = "0.16.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efca59ffe52914a8ff4ae4e8e97e9fa5d782031d2f5a2d1fb109fa6aac26653d" +checksum = "d07ebb99f087075b97b68837de385f6cba07ca32314852a6507ce0dac5d66cd8" dependencies = [ "foundry-compilers-artifacts-solc", "foundry-compilers-artifacts-vyper", @@ -4310,9 +4308,9 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-solc" -version = "0.16.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a3ffc93f94d2c4ae0ff0f7a12cdeaa5fbb043ced0c558cabd05631e32ac508a" +checksum = "49ddf6d61defb08103e351dc16df637c42d69407bae0f8789f2662a6161e73f5" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4333,9 +4331,9 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-vyper" -version = "0.16.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f077777aa33f933f9f01e90f9ed78e4a40ed60a6380798b528681ca9519a577" +checksum = "65a777326b8e0bba45345043ed80ceab5e84f3e474ba2ac19673b31076f3c6b4" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4348,9 +4346,9 @@ dependencies = [ [[package]] name = "foundry-compilers-core" -version = "0.16.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff92d5831075077fe64391dcbbe4a1518bce0439f97ab6a940fa1b9c1f3eaa2" +checksum = "be02912b222eb5bd8a4e8a249a488af3e2fb4fc08e0f17a3bc402406a91295b5" dependencies = [ "alloy-primitives", "cfg-if", @@ -5198,11 +5196,10 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.5" +version = "0.27.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d" dependencies = [ - "futures-util", "http 1.3.1", "hyper", "hyper-util", @@ -5212,7 +5209,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 0.26.11", + "webpki-roots 1.0.0", ] [[package]] @@ -5230,9 +5227,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" +checksum = "cf9f1e950e0d9d1d3c47184416723cf29c0d1f93bd8cccf37e4beb6b44f31710" dependencies = [ "bytes", "futures-channel", @@ -5545,9 +5542,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806" +checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -5560,9 +5557,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48" +checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" dependencies = [ "proc-macro2", "quote", @@ -5686,9 +5683,9 @@ dependencies = [ [[package]] name = "lalrpop" -version = "0.22.1" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7047a26de42016abf8f181b46b398aef0b77ad46711df41847f6ed869a2a1d5b" +checksum = "ba4ebbd48ce411c1d10fb35185f5a51a7bfa3d8b24b4e330d30c9e3a34129501" dependencies = [ "ascii-canvas", "bit-set", @@ -5707,9 +5704,9 @@ dependencies = [ [[package]] name = "lalrpop-util" -version = "0.22.1" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d05b3fe34b8bd562c338db725dfa9beb9451a48f65f129ccb9538b48d2c93b" +checksum = "b5baa5e9ff84f1aefd264e6869907646538a52147a755d494517a8007fb48733" dependencies = [ "regex-automata 0.4.9", "rustversion", @@ -6011,9 +6008,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "mdbook" -version = "0.4.49" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1daacee059634081dee4250d2814763a365b92dfe14bfdef964bc27835209d4" +checksum = "f72bc08f096e1fb15cfc382babe218317c2897d2040f967c4db40d156ca28e21" dependencies = [ "ammonia", "anyhow", @@ -6026,8 +6023,7 @@ dependencies = [ "hex", "log", "memchr", - "once_cell", - "opener", + "opener 0.8.1", "pulldown-cmark", "regex", "serde", @@ -6129,14 +6125,14 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -6177,7 +6173,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee3224f0e8be7c2a1ebc77ef9c3eecb90f55c6594399ee825de964526b3c9056" dependencies = [ - "uuid 1.16.0", + "uuid 1.17.0", ] [[package]] @@ -6471,6 +6467,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + [[package]] name = "once_map" version = "0.4.21" @@ -6490,12 +6492,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f318b09e24148f07392c5e011bae047a0043851f9041145df5f3b01e4fedd1e" dependencies = [ "alloy-consensus", - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-network", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-eth", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "derive_more 2.0.1", "serde", "thiserror 2.0.12", @@ -6514,11 +6516,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15ede8322c10c21249de4fced204e2af4978972e715afee34b6fe684d73880cf" dependencies = [ "alloy-consensus", - "alloy-eips 1.0.5", + "alloy-eips 1.0.7", "alloy-network-primitives", "alloy-primitives", "alloy-rpc-types-eth", - "alloy-serde 1.0.5", + "alloy-serde 1.0.7", "derive_more 2.0.1", "op-alloy-consensus", "serde", @@ -6555,6 +6557,17 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "opener" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de96cad6ee771be7f68df884d3767460b4684012308d8342ed5623fe62b2628c" +dependencies = [ + "bstr", + "normpath", + "windows-sys 0.59.0", +] + [[package]] name = "openssl-probe" version = "0.1.6" @@ -6614,9 +6627,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.7.4" +version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9fde3d0718baf5bc92f577d652001da0f8d54cd03a7974e118d04fc888dc23d" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" dependencies = [ "arrayvec", "bitvec", @@ -6630,9 +6643,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.7.4" +version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581c837bb6b9541ce7faa9377c20616e4fb7650f6b0f68bc93c827ee504fb7b3" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -7222,7 +7235,7 @@ dependencies = [ "quick-xml 0.37.5", "strip-ansi-escapes", "thiserror 2.0.12", - "uuid 1.16.0", + "uuid 1.17.0", ] [[package]] @@ -7836,9 +7849,9 @@ dependencies = [ [[package]] name = "ruint" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78a46eb779843b2c4f21fac5773e25d6d5b7c8f0922876c91541790d2ca27eef" +checksum = "11256b5fe8c68f56ac6f39ef0720e592f33d2367a4782740d9c9142e889c7fb4" dependencies = [ "alloy-rlp", "arbitrary", @@ -8022,9 +8035,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "rusty-fork" @@ -8788,7 +8801,7 @@ dependencies = [ "thiserror 2.0.12", "tokio", "toml_edit", - "uuid 1.16.0", + "uuid 1.17.0", "zip", "zip-extract", ] @@ -9055,9 +9068,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0f0d4760f4c2a0823063b2c70e97aa2ad185f57be195172ccc0e23c4b787c4" +checksum = "1b5d879005cc1b5ba4e18665be9e9501d9da3a9b95f625497c4cb7ee082b532e" dependencies = [ "paste", "proc-macro2", @@ -9312,9 +9325,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.45.0" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", @@ -9933,12 +9946,14 @@ dependencies = [ [[package]] name = "uuid" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ "getrandom 0.3.3", + "js-sys", "serde", + "wasm-bindgen", ] [[package]] @@ -10353,15 +10368,15 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.61.1" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46ec44dc15085cea82cf9c78f85a9114c463a369786585ad2882d1ff0b0acf40" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", "windows-link", "windows-result", - "windows-strings 0.4.1", + "windows-strings 0.4.2", ] [[package]] @@ -10426,9 +10441,9 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b895b5356fc36103d0f64dd1e94dfa7ac5633f1c9dd6e80fe9ec4adef69e09d" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link", ] @@ -10444,9 +10459,9 @@ dependencies = [ [[package]] name = "windows-strings" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a7ab927b2637c19b3dbe0965e75d8f2d30bdd697a1516191cad2ec4df8fb28a" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] From 3c0b3df8f8ef8800a10912ce5a9dcd9eb7e971ff Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Sun, 25 May 2025 12:45:28 +0200 Subject: [PATCH 144/244] chore: make clippy happy (#10628) --- crates/anvil/core/src/eth/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/anvil/core/src/eth/mod.rs b/crates/anvil/core/src/eth/mod.rs index 052a2e7e5f535..df07f62ee730c 100644 --- a/crates/anvil/core/src/eth/mod.rs +++ b/crates/anvil/core/src/eth/mod.rs @@ -35,6 +35,7 @@ pub struct Params { /// Represents ethereum JSON-RPC API #[derive(Clone, Debug, serde::Deserialize)] #[serde(tag = "method", content = "params")] +#[allow(clippy::large_enum_variant)] pub enum EthRequest { #[serde(rename = "web3_clientVersion", with = "empty_params")] Web3ClientVersion(()), From 48a4af4a6846a309e1716885d96fa69c0f7e8ac1 Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Mon, 26 May 2025 12:46:14 +0200 Subject: [PATCH 145/244] chore(deps): bump revm to 24.0.0 (#10601) --- Cargo.lock | 208 +++++++++---------- Cargo.toml | 68 +++--- crates/anvil/core/src/eth/transaction/mod.rs | 4 +- crates/anvil/src/eth/backend/mem/mod.rs | 4 +- crates/anvil/tests/it/optimism.rs | 2 +- crates/cheatcodes/src/inspector.rs | 9 +- crates/debugger/src/tui/draw.rs | 1 - 7 files changed, 139 insertions(+), 157 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e972d3906b5dc..a8c4a15e7bc6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,9 +58,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-chains" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5848366a4f08dca1caca0a6151294a4799fe2e59ba25df100491d92e0b921b1c" +checksum = "517e5acbd38b6d4c59da380e8bbadc6d365bf001903ce46cf5521c53c647e07b" dependencies = [ "alloy-primitives", "num_enum", @@ -74,10 +74,10 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7329eb72d95576dfb8813175bcf671198fb24266b0b3e520052a513e30c284df" dependencies = [ - "alloy-eips 1.0.7", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.0.7", + "alloy-serde", "alloy-trie", "auto_impl", "c-kzg", @@ -99,10 +99,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31b286aeef04a32720c10defd21c3aa6c626154ac442b55f6d472caeb1c6741" dependencies = [ "alloy-consensus", - "alloy-eips 1.0.7", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.0.7", + "alloy-serde", "serde", ] @@ -185,26 +185,6 @@ dependencies = [ "thiserror 2.0.12", ] -[[package]] -name = "alloy-eips" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609515c1955b33af3d78d26357540f68c5551a90ef58fd53def04f2aa074ec43" -dependencies = [ - "alloy-eip2124", - "alloy-eip2930", - "alloy-eip7702", - "alloy-primitives", - "alloy-rlp", - "alloy-serde 0.14.0", - "auto_impl", - "c-kzg", - "derive_more 2.0.1", - "either", - "serde", - "sha2 0.10.9", -] - [[package]] name = "alloy-eips" version = "1.0.7" @@ -216,7 +196,7 @@ dependencies = [ "alloy-eip7702", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.0.7", + "alloy-serde", "auto_impl", "c-kzg", "derive_more 2.0.1", @@ -241,12 +221,12 @@ dependencies = [ [[package]] name = "alloy-evm" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8c5b34c78c42525917b236e4135b1951ca183ede4004b594db0effee8bed169" +checksum = "394b09cf3a32773eedf11828987f9c72dfa74545040be0422e3f5f09a2a3fab9" dependencies = [ "alloy-consensus", - "alloy-eips 1.0.7", + "alloy-eips", "alloy-hardforks", "alloy-primitives", "alloy-sol-types", @@ -264,9 +244,9 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b81b2dfd278d58af8bfde8753fa4685407ba8fbad8bc88a2bb0e065eed48478" dependencies = [ - "alloy-eips 1.0.7", + "alloy-eips", "alloy-primitives", - "alloy-serde 1.0.7", + "alloy-serde", "alloy-trie", "serde", ] @@ -318,13 +298,13 @@ checksum = "f0ed07e76fbc72790a911ea100cdfbe85b1f12a097c91b948042e854959d140e" dependencies = [ "alloy-consensus", "alloy-consensus-any", - "alloy-eips 1.0.7", + "alloy-eips", "alloy-json-rpc", "alloy-network-primitives", "alloy-primitives", "alloy-rpc-types-any", "alloy-rpc-types-eth", - "alloy-serde 1.0.7", + "alloy-serde", "alloy-signer", "alloy-sol-types", "async-trait", @@ -343,20 +323,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f05aa52713c376f797b3c7077708585f22a5c3053a7b1b2b355ea98edeb2052d" dependencies = [ "alloy-consensus", - "alloy-eips 1.0.7", + "alloy-eips", "alloy-primitives", - "alloy-serde 1.0.7", + "alloy-serde", "serde", ] [[package]] name = "alloy-op-evm" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4fda8b1920a38a5adc607d6ff7be1e8991e16ffcf97bb12765644b87331c598" +checksum = "9f32538cc243ec5d4603da9845cc2f5254c6a3a78e82475beb1a2a1de6c0d36c" dependencies = [ "alloy-consensus", - "alloy-eips 1.0.7", + "alloy-eips", "alloy-evm", "alloy-op-hardforks", "alloy-primitives", @@ -415,7 +395,7 @@ checksum = "05a3f7a59c276c6e410267e77a166f9297dbe74e4605f1abf625e29d85c53144" dependencies = [ "alloy-chains", "alloy-consensus", - "alloy-eips 1.0.7", + "alloy-eips", "alloy-json-rpc", "alloy-network", "alloy-network-primitives", @@ -535,7 +515,7 @@ dependencies = [ "alloy-rpc-types-eth", "alloy-rpc-types-trace", "alloy-rpc-types-txpool", - "alloy-serde 1.0.7", + "alloy-serde", "serde", ] @@ -547,7 +527,7 @@ checksum = "51e15bd6456742d6dcadacf3cd238a90a8a7aa9f00bc7cc641ae272f5d3f5d4f" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", - "alloy-serde 1.0.7", + "alloy-serde", "serde", ] @@ -559,7 +539,7 @@ checksum = "67971a228100ac65bd86e90439028853435f21796330ef08f00a70a918a84126" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", - "alloy-serde 1.0.7", + "alloy-serde", ] [[package]] @@ -579,10 +559,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bcf49fe91b3d621440dcc5bb067afaeba5ca4b07f59e42fb7af42944146a8c0" dependencies = [ "alloy-consensus", - "alloy-eips 1.0.7", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.0.7", + "alloy-serde", "derive_more 2.0.1", "jsonwebtoken", "rand 0.8.5", @@ -598,11 +578,11 @@ checksum = "89d9b4293dfd4721781d33ee40de060376932d4a55d421cf6618ad66ff97cc52" dependencies = [ "alloy-consensus", "alloy-consensus-any", - "alloy-eips 1.0.7", + "alloy-eips", "alloy-network-primitives", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.0.7", + "alloy-serde", "alloy-sol-types", "itertools 0.14.0", "serde", @@ -618,7 +598,7 @@ checksum = "7f68f020452c0d570b4eee22d4ffda9e4eda68ebcf67e1199d6dff48097f442b" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", - "alloy-serde 1.0.7", + "alloy-serde", "serde", "serde_json", "thiserror 2.0.12", @@ -632,21 +612,10 @@ checksum = "62a82f15f296c2c83c55519d21ca07801fb58b118878b0f4777250968e49f4fe" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", - "alloy-serde 1.0.7", + "alloy-serde", "serde", ] -[[package]] -name = "alloy-serde" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4dba6ff08916bc0a9cbba121ce21f67c0b554c39cf174bc7b9df6c651bd3c3b" -dependencies = [ - "alloy-primitives", - "serde", - "serde_json", -] - [[package]] name = "alloy-serde" version = "1.0.7" @@ -1051,7 +1020,7 @@ dependencies = [ "alloy-consensus", "alloy-contract", "alloy-dyn-abi", - "alloy-eips 1.0.7", + "alloy-eips", "alloy-evm", "alloy-genesis", "alloy-network", @@ -1061,7 +1030,7 @@ dependencies = [ "alloy-pubsub", "alloy-rlp", "alloy-rpc-types", - "alloy-serde 1.0.7", + "alloy-serde", "alloy-signer", "alloy-signer-local", "alloy-sol-types", @@ -1113,12 +1082,12 @@ version = "1.2.1" dependencies = [ "alloy-consensus", "alloy-dyn-abi", - "alloy-eips 1.0.7", + "alloy-eips", "alloy-network", "alloy-primitives", "alloy-rlp", "alloy-rpc-types", - "alloy-serde 1.0.7", + "alloy-serde", "bytes", "foundry-common", "foundry-evm", @@ -2389,7 +2358,7 @@ dependencies = [ "alloy-provider", "alloy-rlp", "alloy-rpc-types", - "alloy-serde 1.0.7", + "alloy-serde", "alloy-signer", "alloy-signer-local", "alloy-sol-types", @@ -3814,7 +3783,7 @@ dependencies = [ "alloy-primitives", "alloy-provider", "alloy-rpc-types", - "alloy-serde 1.0.7", + "alloy-serde", "alloy-signer", "alloy-signer-local", "alloy-transport", @@ -3947,13 +3916,13 @@ dependencies = [ "alloy-chains", "alloy-consensus", "alloy-dyn-abi", - "alloy-eips 1.0.7", + "alloy-eips", "alloy-json-abi", "alloy-network", "alloy-primitives", "alloy-provider", "alloy-rpc-types", - "alloy-serde 1.0.7", + "alloy-serde", "alloy-signer", "clap", "dialoguer", @@ -4145,7 +4114,7 @@ version = "1.2.1" dependencies = [ "alloy-chains", "alloy-dyn-abi", - "alloy-eips 1.0.7", + "alloy-eips", "alloy-ens", "alloy-json-abi", "alloy-primitives", @@ -4191,7 +4160,7 @@ version = "1.2.1" dependencies = [ "alloy-consensus", "alloy-dyn-abi", - "alloy-eips 1.0.7", + "alloy-eips", "alloy-json-abi", "alloy-json-rpc", "alloy-network", @@ -4200,7 +4169,7 @@ dependencies = [ "alloy-pubsub", "alloy-rpc-client", "alloy-rpc-types", - "alloy-serde 1.0.7", + "alloy-serde", "alloy-sol-types", "alloy-transport", "alloy-transport-http", @@ -4249,7 +4218,7 @@ dependencies = [ "alloy-network", "alloy-primitives", "alloy-rpc-types", - "alloy-serde 1.0.7", + "alloy-serde", "chrono", "foundry-macros", "revm", @@ -4570,9 +4539,9 @@ dependencies = [ [[package]] name = "foundry-fork-db" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c99831be91edd8a025fa60443b5404ad407708bc337d2e20440d498b5806fab8" +checksum = "b02fb598e4a8ae7b7af7c256081a419b071eacf5e03537806b339b3151409403" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -6169,9 +6138,9 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "newtype-uuid" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee3224f0e8be7c2a1ebc77ef9c3eecb90f55c6594399ee825de964526b3c9056" +checksum = "a8ba303c7a8f8fdee1fe1513cfd918f50f1c69bf65c91b39217bfc2b2af5c081" dependencies = [ "uuid 1.17.0", ] @@ -6487,17 +6456,17 @@ dependencies = [ [[package]] name = "op-alloy-consensus" -version = "0.16.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f318b09e24148f07392c5e011bae047a0043851f9041145df5f3b01e4fedd1e" +checksum = "bb35d16e5420e43e400a235783e3d18b6ba564917139b668b48e9ac42cb3d35a" dependencies = [ "alloy-consensus", - "alloy-eips 1.0.7", + "alloy-eips", "alloy-network", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-eth", - "alloy-serde 1.0.7", + "alloy-serde", "derive_more 2.0.1", "serde", "thiserror 2.0.12", @@ -6511,16 +6480,16 @@ checksum = "4ef71f23a8caf6f2a2d5cafbdc44956d44e6014dcb9aa58abf7e4e6481c6ec34" [[package]] name = "op-alloy-rpc-types" -version = "0.16.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15ede8322c10c21249de4fced204e2af4978972e715afee34b6fe684d73880cf" +checksum = "7534a0ec6b8409edc511acbe77abe7805aa63129b98e9a915bb4eb8555eaa6ff" dependencies = [ "alloy-consensus", - "alloy-eips 1.0.7", + "alloy-eips", "alloy-network-primitives", "alloy-primitives", "alloy-rpc-types-eth", - "alloy-serde 1.0.7", + "alloy-serde", "derive_more 2.0.1", "op-alloy-consensus", "serde", @@ -6530,8 +6499,9 @@ dependencies = [ [[package]] name = "op-revm" -version = "4.0.2" -source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47296d449fbe2d5cc74ab6e1213dee88cae3e2fd238343bec605c3c687bbcfab" dependencies = [ "auto_impl", "once_cell", @@ -7585,8 +7555,9 @@ dependencies = [ [[package]] name = "revm" -version = "23.1.0" -source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d3ae9d1b08303eb5150dcf820a29e14235cf3f24f6c09024458a4dcbffe6695" dependencies = [ "revm-bytecode", "revm-context", @@ -7603,8 +7574,9 @@ dependencies = [ [[package]] name = "revm-bytecode" -version = "4.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91f9b90b3bab18942252de2d970ee8559794c49ca7452b2cc1774456040f8fb" dependencies = [ "bitvec", "once_cell", @@ -7615,8 +7587,9 @@ dependencies = [ [[package]] name = "revm-context" -version = "4.1.0" -source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b181214eb2bbb76ee9d6195acba19857d991d2cdb9a65b7cb6939c30250a3966" dependencies = [ "cfg-if", "derive-where", @@ -7630,8 +7603,9 @@ dependencies = [ [[package]] name = "revm-context-interface" -version = "4.1.0" -source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b844f48a411e62c7dde0f757bf5cce49c85b86d6fc1d3b2722c07f2bec4c3ce" dependencies = [ "alloy-eip2930", "alloy-eip7702", @@ -7645,10 +7619,11 @@ dependencies = [ [[package]] name = "revm-database" -version = "4.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad3fbe34f6bb00a9c3155723b3718b9cb9f17066ba38f9eb101b678cd3626775" dependencies = [ - "alloy-eips 0.14.0", + "alloy-eips", "revm-bytecode", "revm-database-interface", "revm-primitives", @@ -7658,8 +7633,9 @@ dependencies = [ [[package]] name = "revm-database-interface" -version = "4.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b8acd36784a6d95d5b9e1b7be3ce014f1e759abb59df1fa08396b30f71adc2a" dependencies = [ "auto_impl", "revm-primitives", @@ -7669,8 +7645,9 @@ dependencies = [ [[package]] name = "revm-handler" -version = "4.1.0" -source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a9204e3ac1a8edb850cc441a6a1d0f2251c0089e5fffdaba11566429e6c64e" dependencies = [ "auto_impl", "revm-bytecode", @@ -7686,8 +7663,9 @@ dependencies = [ [[package]] name = "revm-inspector" -version = "4.1.0" -source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae4881eeae6ff35417c8569bc7cc03b6c0969869ee2c9b3945a39b4f9fa58bc5" dependencies = [ "auto_impl", "revm-context", @@ -7702,9 +7680,9 @@ dependencies = [ [[package]] name = "revm-inspectors" -version = "0.22.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f847f5e88a09ac84b36529fbe2fee80b3d8bbf91e9a7ae3ea856c4125d0d232" +checksum = "4b50ef375dbacefecfdacf8f02afc31df98acc5d8859a6f2b24d121ff2a740a8" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -7720,8 +7698,9 @@ dependencies = [ [[package]] name = "revm-interpreter" -version = "19.1.0" -source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" +version = "20.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5ee65e57375c6639b0f50555e92a4f1b2434349dd32f52e2176f5c711171697" dependencies = [ "revm-bytecode", "revm-context-interface", @@ -7731,8 +7710,9 @@ dependencies = [ [[package]] name = "revm-precompile" -version = "20.1.0" -source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" +version = "21.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9311e735123d8d53a02af2aa81877bba185be7c141be7f931bb3d2f3af449c" dependencies = [ "ark-bls12-381", "ark-bn254", @@ -7755,8 +7735,9 @@ dependencies = [ [[package]] name = "revm-primitives" -version = "19.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" +version = "19.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18ea2ea0134568ee1e14281ce52f60e2710d42be316888d464c53e37ff184fd8" dependencies = [ "alloy-primitives", "num_enum", @@ -7765,8 +7746,9 @@ dependencies = [ [[package]] name = "revm-state" -version = "4.0.0" -source = "git+https://github.com/bluealloy/revm.git?rev=b5808253#b580825320708f0c47d3734ceab03d90c0b11ba1" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0040c61c30319254b34507383ba33d85f92949933adf6525a2cede05d165e1fa" dependencies = [ "bitflags 2.9.1", "revm-bytecode", diff --git a/Cargo.toml b/Cargo.toml index 76f51d5337151..8686f046c2c14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -200,7 +200,7 @@ foundry-linking = { path = "crates/linking" } # solc & compilation utilities foundry-block-explorers = { version = "0.17.0", default-features = false } foundry-compilers = { version = "0.16.1", default-features = false } -foundry-fork-db = "0.14" +foundry-fork-db = "0.15" solang-parser = { version = "=0.3.8", package = "foundry-solang-parser" } solar-ast = { version = "=0.1.3", default-features = false } solar-parse = { version = "=0.1.3", default-features = false } @@ -208,28 +208,28 @@ solar-interface = { version = "=0.1.3", default-features = false } solar-sema = { version = "=0.1.3", default-features = false } ## alloy -alloy-consensus = { version = "1.0.5", default-features = false } -alloy-contract = { version = "1.0.5", default-features = false } -alloy-eips = { version = "1.0.5", default-features = false } -alloy-ens = { version = "1.0.5", default-features = false } -alloy-genesis = { version = "1.0.5", default-features = false } -alloy-json-rpc = { version = "1.0.5", default-features = false } -alloy-network = { version = "1.0.5", default-features = false } -alloy-provider = { version = "1.0.5", default-features = false } -alloy-pubsub = { version = "1.0.5", default-features = false } -alloy-rpc-client = { version = "1.0.5", default-features = false } -alloy-rpc-types = { version = "1.0.5", default-features = true } -alloy-serde = { version = "1.0.5", default-features = false } -alloy-signer = { version = "1.0.5", default-features = false } -alloy-signer-aws = { version = "1.0.5", default-features = false } -alloy-signer-gcp = { version = "1.0.5", default-features = false } -alloy-signer-ledger = { version = "1.0.5", default-features = false } -alloy-signer-local = { version = "1.0.5", default-features = false } -alloy-signer-trezor = { version = "1.0.5", default-features = false } -alloy-transport = { version = "1.0.5", default-features = false } -alloy-transport-http = { version = "1.0.5", default-features = false } -alloy-transport-ipc = { version = "1.0.5", default-features = false } -alloy-transport-ws = { version = "1.0.5", default-features = false } +alloy-consensus = { version = "1.0.7", default-features = false } +alloy-contract = { version = "1.0.7", default-features = false } +alloy-eips = { version = "1.0.7", default-features = false } +alloy-ens = { version = "1.0.7", default-features = false } +alloy-genesis = { version = "1.0.7", default-features = false } +alloy-json-rpc = { version = "1.0.7", default-features = false } +alloy-network = { version = "1.0.7", default-features = false } +alloy-provider = { version = "1.0.7", default-features = false } +alloy-pubsub = { version = "1.0.7", default-features = false } +alloy-rpc-client = { version = "1.0.7", default-features = false } +alloy-rpc-types = { version = "1.0.7", default-features = true } +alloy-serde = { version = "1.0.7", default-features = false } +alloy-signer = { version = "1.0.7", default-features = false } +alloy-signer-aws = { version = "1.0.7", default-features = false } +alloy-signer-gcp = { version = "1.0.7", default-features = false } +alloy-signer-ledger = { version = "1.0.7", default-features = false } +alloy-signer-local = { version = "1.0.7", default-features = false } +alloy-signer-trezor = { version = "1.0.7", default-features = false } +alloy-transport = { version = "1.0.7", default-features = false } +alloy-transport-http = { version = "1.0.7", default-features = false } +alloy-transport-ipc = { version = "1.0.7", default-features = false } +alloy-transport-ws = { version = "1.0.7", default-features = false } ## alloy-core alloy-dyn-abi = "1.0" @@ -249,18 +249,18 @@ alloy-rlp = "0.3" alloy-trie = "0.8.1" ## op-alloy -op-alloy-consensus = "0.16.0" -op-alloy-rpc-types = "0.16.0" +op-alloy-consensus = "0.17.1" +op-alloy-rpc-types = "0.17.1" op-alloy-flz = "0.13.0" ## revm -revm = { version = "23.1.0", default-features = false } -revm-inspectors = { version = "0.22.3", features = ["serde"] } -op-revm = { version = "4.0.2", default-features = false } +revm = { version = "24.0.0", default-features = false } +revm-inspectors = { version = "0.23.0", features = ["serde"] } +op-revm = { version = "5.0.0", default-features = false } ## alloy-evm -alloy-evm = "0.9.1" -alloy-op-evm = "0.9.1" +alloy-evm = "0.10.0" +alloy-op-evm = "0.10.0" ## cli anstream = "0.6" @@ -390,12 +390,12 @@ zip-extract = "=0.2.1" # alloy-transport-ws = { git = "https://github.com/alloy-rs/alloy", rev = "7fab7ee" } ## alloy-evm -# alloy-evm = { git = "https://github.com/alloy-rs/evm.git", rev = "95f6a8a" } -# alloy-op-evm = { git = "https://github.com/alloy-rs/evm.git", rev = "95f6a8a" } +# alloy-evm = { git = "https://github.com/alloy-rs/evm.git", rev = "8076e12" } +# alloy-op-evm = { git = "https://github.com/alloy-rs/evm.git", rev = "8076e12" } ## revm -revm = { git = "https://github.com/bluealloy/revm.git", rev = "b5808253" } -op-revm = { git = "https://github.com/bluealloy/revm.git", rev = "b5808253" } +# revm = { git = "https://github.com/bluealloy/revm.git", rev = "b5808253" } +# op-revm = { git = "https://github.com/bluealloy/revm.git", rev = "b5808253" } # revm-inspectors = { git = "https://github.com/paradigmxyz/revm-inspectors.git", rev = "a625c04" } ## foundry diff --git a/crates/anvil/core/src/eth/transaction/mod.rs b/crates/anvil/core/src/eth/transaction/mod.rs index f6122b2893207..ae6a7262565ca 100644 --- a/crates/anvil/core/src/eth/transaction/mod.rs +++ b/crates/anvil/core/src/eth/transaction/mod.rs @@ -60,7 +60,7 @@ pub fn transaction_request_to_typed( from: from.unwrap_or_default(), source_hash: other.get_deserialized::("sourceHash")?.ok()?, to: to.unwrap_or_default(), - mint: Some(mint), + mint, value: value.unwrap_or_default(), gas_limit: gas.unwrap_or_default(), is_system_transaction: other.get_deserialized::("isSystemTx")?.ok()?, @@ -574,7 +574,7 @@ impl PendingTransaction { let deposit = DepositTransactionParts { source_hash: *source_hash, - mint: *mint, + mint: Some(*mint), is_system_transaction: *is_system_transaction, }; diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index a7b02ff39c059..321ed41ea3925 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -3178,8 +3178,8 @@ impl TransactionValidator for Backend { // 1. no gas cost check required since already have prepaid gas from L1 // 2. increment account balance by deposited amount before checking for sufficient // funds `tx.value <= existing account value + deposited value` - if value > account.balance + U256::from(deposit_tx.mint.unwrap_or_default()) { - warn!(target: "backend", "[{:?}] insufficient balance={}, required={} account={:?}", tx.hash(), account.balance + U256::from(deposit_tx.mint.unwrap_or_default()), value, *pending.sender()); + if value > account.balance + U256::from(deposit_tx.mint) { + warn!(target: "backend", "[{:?}] insufficient balance={}, required={} account={:?}", tx.hash(), account.balance + U256::from(deposit_tx.mint), value, *pending.sender()); return Err(InvalidTransactionError::InsufficientFunds); } } diff --git a/crates/anvil/tests/it/optimism.rs b/crates/anvil/tests/it/optimism.rs index e8bfe4d6560a5..f871cca724a97 100644 --- a/crates/anvil/tests/it/optimism.rs +++ b/crates/anvil/tests/it/optimism.rs @@ -200,7 +200,7 @@ async fn test_deposit_tx_checks_sufficient_funds_after_applying_deposited_value( source_hash: b256!("0x0000000000000000000000000000000000000000000000000000000000000000"), from: sender, to: TxKind::Call(recipient), - mint: Some(send_value), + mint: send_value, value: U256::from(send_value), gas_limit: 21_000, is_system_transaction: false, diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index 9677806893d3f..4d9b5cd5ef5ed 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -54,7 +54,7 @@ use revm::{ context_interface::{transaction::SignedAuthorization, CreateScheme}, handler::FrameResult, interpreter::{ - interpreter_types::{Jumps, LoopControl, MemoryTr}, + interpreter_types::{Jumps, MemoryTr}, CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, FrameInput, Gas, Host, InstructionResult, Interpreter, InterpreterAction, InterpreterResult, }, @@ -1845,9 +1845,10 @@ impl Cheatcodes { if let Some(paused_gas) = self.gas_metering.paused_frames.last() { // Keep gas constant if paused. // Make sure we record the memory changes so that memory expansion is not paused. - let memory = interpreter.control.gas.memory; + let memory = *interpreter.control.gas.memory(); interpreter.control.gas = *paused_gas; - interpreter.control.gas.memory = memory; + interpreter.control.gas.memory_mut().words_num = memory.words_num; + interpreter.control.gas.memory_mut().expansion_cost = memory.expansion_cost; } else { // Record frame paused gas. self.gas_metering.paused_frames.push(interpreter.control.gas); @@ -1889,7 +1890,7 @@ impl Cheatcodes { #[cold] fn meter_gas_reset(&mut self, interpreter: &mut Interpreter) { - interpreter.control.gas = Gas::new(interpreter.control.gas().limit()); + interpreter.control.gas = Gas::new(interpreter.control.gas.limit()); self.gas_metering.reset = false; } diff --git a/crates/debugger/src/tui/draw.rs b/crates/debugger/src/tui/draw.rs index a918bc89ea733..580d6f958ac44 100644 --- a/crates/debugger/src/tui/draw.rs +++ b/crates/debugger/src/tui/draw.rs @@ -199,7 +199,6 @@ impl TUIContext<'_> { CallKind::CallCode => "Contract callcode", CallKind::DelegateCall => "Contract delegatecall", CallKind::AuthCall => "Contract authcall", - CallKind::EOFCreate => "EOF contract creation", }; let title = format!( "{} {} ", From b1f876772a1ab2104c82b2fa2c231d117a179100 Mon Sep 17 00:00:00 2001 From: pistomat Date: Mon, 26 May 2025 16:26:49 +0200 Subject: [PATCH 146/244] feat: implement add_balance endpoint (#10636) --- crates/anvil/core/src/eth/mod.rs | 14 +++++++++++++- crates/anvil/src/eth/api.rs | 13 +++++++++++++ crates/anvil/tests/it/fork.rs | 16 ++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/crates/anvil/core/src/eth/mod.rs b/crates/anvil/core/src/eth/mod.rs index df07f62ee730c..ac7db74892003 100644 --- a/crates/anvil/core/src/eth/mod.rs +++ b/crates/anvil/core/src/eth/mod.rs @@ -361,9 +361,21 @@ pub enum EthRequest { SetRpcUrl(String), /// Modifies the balance of an account. - #[serde(rename = "anvil_setBalance", alias = "hardhat_setBalance")] + #[serde( + rename = "anvil_setBalance", + alias = "hardhat_setBalance", + alias = "tenderly_setBalance" + )] SetBalance(Address, #[serde(deserialize_with = "deserialize_number")] U256), + /// Increases the balance of an account. + #[serde( + rename = "anvil_addBalance", + alias = "hardhat_addBalance", + alias = "tenderly_addBalance" + )] + AddBalance(Address, #[serde(deserialize_with = "deserialize_number")] U256), + /// Modifies the ERC20 balance of an account. #[serde( rename = "anvil_dealERC20", diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 243ae88440e8d..ec6fbeb4227a1 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -356,6 +356,9 @@ impl EthApi { EthRequest::SetBalance(addr, val) => { self.anvil_set_balance(addr, val).await.to_rpc_result() } + EthRequest::AddBalance(addr, val) => { + self.anvil_add_balance(addr, val).await.to_rpc_result() + } EthRequest::DealERC20(addr, token_addr, val) => { self.anvil_deal_erc20(addr, token_addr, val).await.to_rpc_result() } @@ -1856,6 +1859,16 @@ impl EthApi { Ok(()) } + /// Increases the balance of an account. + /// + /// Handler for RPC call: `anvil_addBalance` + pub async fn anvil_add_balance(&self, address: Address, balance: U256) -> Result<()> { + node_info!("anvil_addBalance"); + let current_balance = self.backend.get_balance(address, None).await?; + self.backend.set_balance(address, current_balance + balance).await?; + Ok(()) + } + /// Deals ERC20 tokens to a address /// /// Handler for RPC call: `anvil_dealERC20` diff --git a/crates/anvil/tests/it/fork.rs b/crates/anvil/tests/it/fork.rs index 54bae673a6bd0..e4e1cda1a31d3 100644 --- a/crates/anvil/tests/it/fork.rs +++ b/crates/anvil/tests/it/fork.rs @@ -1490,6 +1490,22 @@ async fn test_set_erc20_balance() { assert_eq!(new_balance, value); } +#[tokio::test(flavor = "multi_thread")] +async fn test_add_balance() { + let config: NodeConfig = fork_config(); + let address = config.genesis_accounts[0].address(); + let (api, _handle) = spawn(config).await; + + let start_balance = U256::from(100_000_u64); + api.anvil_set_balance(address, start_balance).await.unwrap(); + + let balance_increase = U256::from(50_000_u64); + api.anvil_add_balance(address, balance_increase).await.unwrap(); + + let new_balance = api.balance(address, None).await.unwrap(); + assert_eq!(new_balance, start_balance + balance_increase); +} + #[tokio::test(flavor = "multi_thread")] async fn test_reset_updates_cache_path_when_rpc_url_not_provided() { let config: NodeConfig = fork_config(); From 5e20961edeeab3c9c39dabe739ab7fba9a410fd2 Mon Sep 17 00:00:00 2001 From: zark <77061323+zarkk01@users.noreply.github.com> Date: Mon, 26 May 2025 23:21:59 +0300 Subject: [PATCH 147/244] fix(bindings): ensure forge bind generates snake_case file names (#10622) * fix(bindings): ensure forge bind generates snake_case file names * refactor: use heck crate for snake_case conversion --------- Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- Cargo.lock | 1 + crates/sol-macro-gen/Cargo.toml | 2 ++ crates/sol-macro-gen/src/sol_macro_gen.rs | 8 +++++--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a8c4a15e7bc6d..c05a8b99f5d05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3978,6 +3978,7 @@ dependencies = [ "alloy-sol-macro-input", "eyre", "foundry-common", + "heck", "prettyplease", "proc-macro2", "quote", diff --git a/crates/sol-macro-gen/Cargo.toml b/crates/sol-macro-gen/Cargo.toml index 79b47880f33f9..b983dd6a762b8 100644 --- a/crates/sol-macro-gen/Cargo.toml +++ b/crates/sol-macro-gen/Cargo.toml @@ -26,3 +26,5 @@ prettyplease.workspace = true serde_json.workspace = true eyre.workspace = true + +heck.workspace = true diff --git a/crates/sol-macro-gen/src/sol_macro_gen.rs b/crates/sol-macro-gen/src/sol_macro_gen.rs index 657dd4cbb8458..1e40d51169695 100644 --- a/crates/sol-macro-gen/src/sol_macro_gen.rs +++ b/crates/sol-macro-gen/src/sol_macro_gen.rs @@ -21,6 +21,8 @@ use std::{ str::FromStr, }; +use heck::ToSnakeCase; + pub struct SolMacroGen { pub path: PathBuf, pub name: String, @@ -209,7 +211,7 @@ edition = "2021" for instance in &self.instances { let contents = instance.expansion.as_ref().unwrap(); - let name = instance.name.to_lowercase(); + let name = instance.name.to_snake_case(); let path = src.join(format!("{name}.rs")); let file = syn::parse2(contents.clone()) .wrap_err_with(|| parse_error(&format!("{}:{}", path.display(), name)))?; @@ -266,7 +268,7 @@ edition = "2021" .to_string(); for instance in &self.instances { - let name = instance.name.to_lowercase(); + let name = instance.name.to_snake_case(); if !single_file { // Module write_mod_name(&mut mod_contents, &name)?; @@ -328,7 +330,7 @@ edition = "2021" )?; if !single_file { for instance in &self.instances { - let name = instance.name.to_lowercase(); + let name = instance.name.to_snake_case(); let path = if is_mod { crate_path.join(format!("{name}.rs")) } else { From b5d99b62ab10680985d3637ae1be38d619fde31d Mon Sep 17 00:00:00 2001 From: 0xrusowsky <90208954+0xrusowsky@users.noreply.github.com> Date: Mon, 26 May 2025 16:04:58 -0500 Subject: [PATCH 148/244] chore: standardize lint help + validate docs existance (#10639) --- crates/forge/tests/cli/lint.rs | 53 +++++++++++++++++++ crates/lint/src/linter.rs | 13 ++--- crates/lint/src/sol/gas/keccak.rs | 3 +- crates/lint/src/sol/high/incorrect_shift.rs | 3 +- crates/lint/src/sol/info/mixed_case.rs | 3 +- crates/lint/src/sol/info/pascal_case.rs | 3 +- .../lint/src/sol/info/screaming_snake_case.rs | 3 +- crates/lint/src/sol/macros.rs | 10 ++-- crates/lint/src/sol/med/div_mul.rs | 3 +- crates/lint/src/sol/mod.rs | 4 +- .../lint/testdata/DivideBeforeMultiply.stderr | 6 +++ crates/lint/testdata/IncorrectShift.stderr | 5 ++ crates/lint/testdata/Keccak256.stderr | 2 + crates/lint/testdata/MixedCase.stderr | 18 ++++--- .../lint/testdata/ScreamingSnakeCase.stderr | 12 +++-- crates/lint/testdata/StructPascalCase.stderr | 12 ++--- 16 files changed, 110 insertions(+), 43 deletions(-) diff --git a/crates/forge/tests/cli/lint.rs b/crates/forge/tests/cli/lint.rs index 94599eb059b17..2223d1cf11fce 100644 --- a/crates/forge/tests/cli/lint.rs +++ b/crates/forge/tests/cli/lint.rs @@ -1,3 +1,4 @@ +use forge_lint::{linter::Lint, sol::med::REGISTERED_LINTS}; use foundry_config::{LintSeverity, LinterConfig}; const CONTRACT: &str = r#" @@ -53,6 +54,7 @@ warning[divide-before-multiply]: multiplication should occur before division to 16 | (1 / 2) * 3; | ----------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply "#]]); @@ -75,6 +77,7 @@ note[mixed-case-variable]: mutable variables should use mixedCase 6 | uint256 VARIABLE_MIXED_CASE_INFO; | ------------------------ | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable "#]]); @@ -109,6 +112,7 @@ note[mixed-case-variable]: mutable variables should use mixedCase 6 | uint256 VARIABLE_MIXED_CASE_INFO; | ------------------------ | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable "#]]); @@ -134,6 +138,7 @@ warning[divide-before-multiply]: multiplication should occur before division to 16 | (1 / 2) * 3; | ----------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply "#]]); @@ -160,8 +165,56 @@ warning[incorrect-shift]: the order of args in a shift operation is incorrect 13 | result = 8 >> localValue; | --------------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#incorrect-shift "# ]]); }); + +#[tokio::test] +async fn ensure_lint_rule_docs() { + const FOUNDRY_BOOK_LINT_PAGE_URL: &str = + "https://book.getfoundry.sh/reference/forge/forge-lint"; + + // Fetch the content of the lint reference + let content = match reqwest::get(FOUNDRY_BOOK_LINT_PAGE_URL).await { + Ok(resp) => { + if !resp.status().is_success() { + panic!( + "Failed to fetch Foundry Book lint page ({FOUNDRY_BOOK_LINT_PAGE_URL}). Status: {status}", + status = resp.status() + ); + } + match resp.text().await { + Ok(text) => text, + Err(e) => { + panic!("Failed to read response text: {e}"); + } + } + } + Err(e) => { + panic!("Failed to fetch Foundry Book lint page ({FOUNDRY_BOOK_LINT_PAGE_URL}): {e}",); + } + }; + + // Ensure no missing lints + let mut missing_lints = Vec::new(); + for lint in REGISTERED_LINTS { + let selector = format!("#{}", lint.id()); + if !content.contains(&selector) { + missing_lints.push(lint.id()); + } + } + + if !missing_lints.is_empty() { + let mut msg = String::from( + "Foundry Book lint validation failed. The following lints must be added to the docs:\n", + ); + for lint in missing_lints { + msg.push_str(&format!(" - {lint}\n")); + } + msg.push_str("Please open a PR: https://github.com/foundry-rs/book"); + panic!("{msg}"); + } +} diff --git a/crates/lint/src/linter.rs b/crates/lint/src/linter.rs index 6c188ff86497f..2c11e0222a286 100644 --- a/crates/lint/src/linter.rs +++ b/crates/lint/src/linter.rs @@ -31,9 +31,7 @@ pub trait Lint { fn id(&self) -> &'static str; fn severity(&self) -> Severity; fn description(&self) -> &'static str; - fn help(&self) -> Option<&'static str> { - None - } + fn help(&self) -> &'static str; } pub struct LintContext<'s> { @@ -48,19 +46,14 @@ impl<'s> LintContext<'s> { // Helper method to emit diagnostics easily from passes pub fn emit(&self, lint: &'static L, span: Span) { - let (desc, help) = match (self.desc, lint.help()) { - (true, Some(help)) => (lint.description(), help), - (true, None) => (lint.description(), ""), - (false, _) => ("", ""), - }; - + let desc = if self.desc { lint.description() } else { "" }; let diag: DiagBuilder<'_, ()> = self .sess .dcx .diag(lint.severity().into(), desc) .code(DiagId::new_str(lint.id())) .span(MultiSpan::from_span(span)) - .help(help); + .help(lint.help()); diag.emit(); } diff --git a/crates/lint/src/sol/gas/keccak.rs b/crates/lint/src/sol/gas/keccak.rs index f4031554b90ec..7316f4c4239b7 100644 --- a/crates/lint/src/sol/gas/keccak.rs +++ b/crates/lint/src/sol/gas/keccak.rs @@ -11,8 +11,7 @@ declare_forge_lint!( ASM_KECCAK256, Severity::Gas, "asm-keccak256", - "hash using inline assembly to save gas", - "" + "hash using inline assembly to save gas" ); impl<'ast> EarlyLintPass<'ast> for AsmKeccak256 { diff --git a/crates/lint/src/sol/high/incorrect_shift.rs b/crates/lint/src/sol/high/incorrect_shift.rs index 6d038d86382cd..8d2326c5cc9f9 100644 --- a/crates/lint/src/sol/high/incorrect_shift.rs +++ b/crates/lint/src/sol/high/incorrect_shift.rs @@ -10,8 +10,7 @@ declare_forge_lint!( INCORRECT_SHIFT, Severity::High, "incorrect-shift", - "the order of args in a shift operation is incorrect", - "" + "the order of args in a shift operation is incorrect" ); impl<'ast> EarlyLintPass<'ast> for IncorrectShift { diff --git a/crates/lint/src/sol/info/mixed_case.rs b/crates/lint/src/sol/info/mixed_case.rs index 035c21ef592c1..5e839e9f313cf 100644 --- a/crates/lint/src/sol/info/mixed_case.rs +++ b/crates/lint/src/sol/info/mixed_case.rs @@ -10,8 +10,7 @@ declare_forge_lint!( MIXED_CASE_FUNCTION, Severity::Info, "mixed-case-function", - "function names should use mixedCase", - "https://docs.soliditylang.org/en/latest/style-guide.html#function-names" + "function names should use mixedCase" ); impl<'ast> EarlyLintPass<'ast> for MixedCaseFunction { diff --git a/crates/lint/src/sol/info/pascal_case.rs b/crates/lint/src/sol/info/pascal_case.rs index 435debd66ac3c..60cafbc8365a3 100644 --- a/crates/lint/src/sol/info/pascal_case.rs +++ b/crates/lint/src/sol/info/pascal_case.rs @@ -10,8 +10,7 @@ declare_forge_lint!( PASCAL_CASE_STRUCT, Severity::Info, "pascal-case-struct", - "structs should use PascalCase", - "https://docs.soliditylang.org/en/latest/style-guide.html#struct-names" + "structs should use PascalCase" ); impl<'ast> EarlyLintPass<'ast> for PascalCaseStruct { diff --git a/crates/lint/src/sol/info/screaming_snake_case.rs b/crates/lint/src/sol/info/screaming_snake_case.rs index 528638181b126..ccc978029b8a4 100644 --- a/crates/lint/src/sol/info/screaming_snake_case.rs +++ b/crates/lint/src/sol/info/screaming_snake_case.rs @@ -10,8 +10,7 @@ declare_forge_lint!( SCREAMING_SNAKE_CASE_CONSTANT, Severity::Info, "screaming-snake-case-const", - "constants should use SCREAMING_SNAKE_CASE", - "https://docs.soliditylang.org/en/latest/style-guide.html#constants" + "constants should use SCREAMING_SNAKE_CASE" ); declare_forge_lint!( diff --git a/crates/lint/src/sol/macros.rs b/crates/lint/src/sol/macros.rs index 093b96a7e4a70..357f742aa297c 100644 --- a/crates/lint/src/sol/macros.rs +++ b/crates/lint/src/sol/macros.rs @@ -7,16 +7,20 @@ /// - `$severity`: The `Severity` of the lint (e.g. `High`, `Med`, `Low`, `Info`, `Gas`). /// - `$str_id`: A unique identifier used to reference a specific lint during configuration. /// - `$desc`: A short description of the lint. -/// - `$help` (optional): Link to additional information about the lint or best practices. +/// +/// # Note +/// Each lint must have a `help` section in the foundry book. This help field is auto-generated by +/// the macro. Because of that, to ensure that new lint rules have their corresponding docs in the +/// book, the existence of the lint rule's help section is validated with a unit test. #[macro_export] macro_rules! declare_forge_lint { - ($id:ident, $severity:expr, $str_id:expr, $desc:expr, $help:expr) => { + ($id:ident, $severity:expr, $str_id:expr, $desc:expr) => { // Declare the static `Lint` metadata pub static $id: SolLint = SolLint { id: $str_id, severity: $severity, description: $desc, - help: if $help.is_empty() { None } else { Some($help) }, + help: concat!("https://book.getfoundry.sh/reference/forge/forge-lint#", $str_id), }; }; diff --git a/crates/lint/src/sol/med/div_mul.rs b/crates/lint/src/sol/med/div_mul.rs index b513468be6b83..b154971e55434 100644 --- a/crates/lint/src/sol/med/div_mul.rs +++ b/crates/lint/src/sol/med/div_mul.rs @@ -10,8 +10,7 @@ declare_forge_lint!( DIVIDE_BEFORE_MULTIPLY, Severity::Med, "divide-before-multiply", - "multiplication should occur before division to avoid loss of precision", - "" + "multiplication should occur before division to avoid loss of precision" ); impl<'ast> EarlyLintPass<'ast> for DivideBeforeMultiply { diff --git a/crates/lint/src/sol/mod.rs b/crates/lint/src/sol/mod.rs index 6bb2ffabef39a..463777d5b194a 100644 --- a/crates/lint/src/sol/mod.rs +++ b/crates/lint/src/sol/mod.rs @@ -159,7 +159,7 @@ pub enum SolLintError { pub struct SolLint { id: &'static str, description: &'static str, - help: Option<&'static str>, + help: &'static str, severity: Severity, } @@ -173,7 +173,7 @@ impl Lint for SolLint { fn description(&self) -> &'static str { self.description } - fn help(&self) -> Option<&'static str> { + fn help(&self) -> &'static str { self.help } } diff --git a/crates/lint/testdata/DivideBeforeMultiply.stderr b/crates/lint/testdata/DivideBeforeMultiply.stderr index 08d8ebe25d1c9..1c98f4b13d194 100644 --- a/crates/lint/testdata/DivideBeforeMultiply.stderr +++ b/crates/lint/testdata/DivideBeforeMultiply.stderr @@ -4,6 +4,7 @@ warning[divide-before-multiply]: multiplication should occur before division to 3 | (1 / 2) * 3; | ----------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply warning[divide-before-multiply]: multiplication should occur before division to avoid loss of precision --> ROOT/testdata/DivideBeforeMultiply.sol:LL:CC @@ -11,6 +12,7 @@ warning[divide-before-multiply]: multiplication should occur before division to 5 | ((1 / 2) * 3) * 4; | ----------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply warning[divide-before-multiply]: multiplication should occur before division to avoid loss of precision --> ROOT/testdata/DivideBeforeMultiply.sol:LL:CC @@ -18,6 +20,7 @@ warning[divide-before-multiply]: multiplication should occur before division to 6 | ((1 * 2) / 3) * 4; | ----------------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply warning[divide-before-multiply]: multiplication should occur before division to avoid loss of precision --> ROOT/testdata/DivideBeforeMultiply.sol:LL:CC @@ -25,6 +28,7 @@ warning[divide-before-multiply]: multiplication should occur before division to 7 | (1 / 2 / 3) * 4; | --------------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply warning[divide-before-multiply]: multiplication should occur before division to avoid loss of precision --> ROOT/testdata/DivideBeforeMultiply.sol:LL:CC @@ -32,6 +36,7 @@ warning[divide-before-multiply]: multiplication should occur before division to 8 | (1 / (2 + 3)) * 4; | ----------------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply warning[divide-before-multiply]: multiplication should occur before division to avoid loss of precision --> ROOT/testdata/DivideBeforeMultiply.sol:LL:CC @@ -39,4 +44,5 @@ warning[divide-before-multiply]: multiplication should occur before division to 15 | 1 / ((2 / 3) * 3); | ----------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply diff --git a/crates/lint/testdata/IncorrectShift.stderr b/crates/lint/testdata/IncorrectShift.stderr index 16fbda627cd9b..46276262da4bd 100644 --- a/crates/lint/testdata/IncorrectShift.stderr +++ b/crates/lint/testdata/IncorrectShift.stderr @@ -4,6 +4,7 @@ warning[incorrect-shift]: the order of args in a shift operation is incorrect 21 | result = 2 << stateValue; | --------------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#incorrect-shift warning[incorrect-shift]: the order of args in a shift operation is incorrect --> ROOT/testdata/IncorrectShift.sol:LL:CC @@ -11,6 +12,7 @@ warning[incorrect-shift]: the order of args in a shift operation is incorrect 22 | result = 8 >> localValue; | --------------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#incorrect-shift warning[incorrect-shift]: the order of args in a shift operation is incorrect --> ROOT/testdata/IncorrectShift.sol:LL:CC @@ -18,6 +20,7 @@ warning[incorrect-shift]: the order of args in a shift operation is incorrect 23 | result = 16 << (stateValue + 1); | ---------------------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#incorrect-shift warning[incorrect-shift]: the order of args in a shift operation is incorrect --> ROOT/testdata/IncorrectShift.sol:LL:CC @@ -25,6 +28,7 @@ warning[incorrect-shift]: the order of args in a shift operation is incorrect 24 | result = 32 >> getAmount(); | ----------------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#incorrect-shift warning[incorrect-shift]: the order of args in a shift operation is incorrect --> ROOT/testdata/IncorrectShift.sol:LL:CC @@ -32,4 +36,5 @@ warning[incorrect-shift]: the order of args in a shift operation is incorrect 25 | ... result = 1 << (localValue > 10 ? localShiftAmount : stateShiftAmount); | ------------------------------------------------------------ | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#incorrect-shift diff --git a/crates/lint/testdata/Keccak256.stderr b/crates/lint/testdata/Keccak256.stderr index e589bec00eb77..8011afa89a112 100644 --- a/crates/lint/testdata/Keccak256.stderr +++ b/crates/lint/testdata/Keccak256.stderr @@ -4,6 +4,7 @@ note[asm-keccak256]: hash using inline assembly to save gas 3 | keccak256(abi.encodePacked(a, b)); | --------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 note[asm-keccak256]: hash using inline assembly to save gas --> ROOT/testdata/Keccak256.sol:LL:CC @@ -11,4 +12,5 @@ note[asm-keccak256]: hash using inline assembly to save gas 7 | keccak256(abi.encodePacked(a, b)); | --------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 diff --git a/crates/lint/testdata/MixedCase.stderr b/crates/lint/testdata/MixedCase.stderr index 1245d53caf5cc..0976dced8716c 100644 --- a/crates/lint/testdata/MixedCase.stderr +++ b/crates/lint/testdata/MixedCase.stderr @@ -4,6 +4,7 @@ note[mixed-case-variable]: mutable variables should use mixedCase 9 | uint256 Variablemixedcase; | ----------------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable note[mixed-case-variable]: mutable variables should use mixedCase --> ROOT/testdata/MixedCase.sol:LL:CC @@ -11,6 +12,7 @@ note[mixed-case-variable]: mutable variables should use mixedCase 10 | uint256 VARIABLE_MIXED_CASE; | ------------------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable note[mixed-case-variable]: mutable variables should use mixedCase --> ROOT/testdata/MixedCase.sol:LL:CC @@ -18,6 +20,7 @@ note[mixed-case-variable]: mutable variables should use mixedCase 11 | uint256 VariableMixedCase; | ----------------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable note[mixed-case-variable]: mutable variables should use mixedCase --> ROOT/testdata/MixedCase.sol:LL:CC @@ -25,6 +28,7 @@ note[mixed-case-variable]: mutable variables should use mixedCase 17 | uint256 testVAL; | ------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable note[mixed-case-variable]: mutable variables should use mixedCase --> ROOT/testdata/MixedCase.sol:LL:CC @@ -32,6 +36,7 @@ note[mixed-case-variable]: mutable variables should use mixedCase 18 | uint256 TestVal; | ------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable note[mixed-case-variable]: mutable variables should use mixedCase --> ROOT/testdata/MixedCase.sol:LL:CC @@ -39,6 +44,7 @@ note[mixed-case-variable]: mutable variables should use mixedCase 19 | uint256 TESTVAL; | ------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable note[mixed-case-function]: function names should use mixedCase --> ROOT/testdata/MixedCase.sol:LL:CC @@ -46,7 +52,7 @@ note[mixed-case-function]: function names should use mixedCase 26 | function Functionmixedcase() public {} | ----------------- | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#function-names + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function note[mixed-case-function]: function names should use mixedCase --> ROOT/testdata/MixedCase.sol:LL:CC @@ -54,7 +60,7 @@ note[mixed-case-function]: function names should use mixedCase 27 | function FUNCTION_MIXED_CASE() public {} | ------------------- | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#function-names + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function note[mixed-case-function]: function names should use mixedCase --> ROOT/testdata/MixedCase.sol:LL:CC @@ -62,7 +68,7 @@ note[mixed-case-function]: function names should use mixedCase 28 | function FunctionMixedCase() public {} | ----------------- | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#function-names + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function note[mixed-case-function]: function names should use mixedCase --> ROOT/testdata/MixedCase.sol:LL:CC @@ -70,7 +76,7 @@ note[mixed-case-function]: function names should use mixedCase 29 | function function_mixed_case() public {} | ------------------- | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#function-names + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function note[mixed-case-function]: function names should use mixedCase --> ROOT/testdata/MixedCase.sol:LL:CC @@ -78,7 +84,7 @@ note[mixed-case-function]: function names should use mixedCase 53 | function invariantBalance_MixedCase_Enabled() public {} | ---------------------------------- | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#function-names + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function note[mixed-case-function]: function names should use mixedCase --> ROOT/testdata/MixedCase.sol:LL:CC @@ -86,5 +92,5 @@ note[mixed-case-function]: function names should use mixedCase 54 | function invariantbalance_mixedcase_enabled() public {} | ---------------------------------- | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#function-names + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function diff --git a/crates/lint/testdata/ScreamingSnakeCase.stderr b/crates/lint/testdata/ScreamingSnakeCase.stderr index 96c2cb34405b3..b511f09d254f3 100644 --- a/crates/lint/testdata/ScreamingSnakeCase.stderr +++ b/crates/lint/testdata/ScreamingSnakeCase.stderr @@ -4,7 +4,7 @@ note[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE 9 | uint256 constant screamingSnakeCase = 0; | ------------------ | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#constants + = help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-const note[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE --> ROOT/testdata/ScreamingSnakeCase.sol:LL:CC @@ -12,7 +12,7 @@ note[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE 10 | uint256 constant screaming_snake_case = 0; | -------------------- | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#constants + = help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-const note[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE --> ROOT/testdata/ScreamingSnakeCase.sol:LL:CC @@ -20,7 +20,7 @@ note[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE 11 | uint256 constant ScreamingSnakeCase = 0; | ------------------ | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#constants + = help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-const note[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE --> ROOT/testdata/ScreamingSnakeCase.sol:LL:CC @@ -28,7 +28,7 @@ note[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE 12 | uint256 constant SCREAMING_snake_case = 0; | -------------------- | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#constants + = help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-const note[screaming-snake-case-immutable]: immutables should use SCREAMING_SNAKE_CASE --> ROOT/testdata/ScreamingSnakeCase.sol:LL:CC @@ -36,6 +36,7 @@ note[screaming-snake-case-immutable]: immutables should use SCREAMING_SNAKE_CASE 19 | uint256 immutable screamingSnakeCase0 = 0; | ------------------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-immutable note[screaming-snake-case-immutable]: immutables should use SCREAMING_SNAKE_CASE --> ROOT/testdata/ScreamingSnakeCase.sol:LL:CC @@ -43,6 +44,7 @@ note[screaming-snake-case-immutable]: immutables should use SCREAMING_SNAKE_CASE 20 | uint256 immutable screaming_snake_case0 = 0; | --------------------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-immutable note[screaming-snake-case-immutable]: immutables should use SCREAMING_SNAKE_CASE --> ROOT/testdata/ScreamingSnakeCase.sol:LL:CC @@ -50,6 +52,7 @@ note[screaming-snake-case-immutable]: immutables should use SCREAMING_SNAKE_CASE 21 | uint256 immutable ScreamingSnakeCase0 = 0; | ------------------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-immutable note[screaming-snake-case-immutable]: immutables should use SCREAMING_SNAKE_CASE --> ROOT/testdata/ScreamingSnakeCase.sol:LL:CC @@ -57,4 +60,5 @@ note[screaming-snake-case-immutable]: immutables should use SCREAMING_SNAKE_CASE 22 | uint256 immutable SCREAMING_snake_case_0 = 0; | ---------------------- | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-immutable diff --git a/crates/lint/testdata/StructPascalCase.stderr b/crates/lint/testdata/StructPascalCase.stderr index 2ef869c7ccc21..7858c18cbf33d 100644 --- a/crates/lint/testdata/StructPascalCase.stderr +++ b/crates/lint/testdata/StructPascalCase.stderr @@ -4,7 +4,7 @@ note[pascal-case-struct]: structs should use PascalCase 13 | struct _PascalCase { | ----------- | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#struct-names + = help: https://book.getfoundry.sh/reference/forge/forge-lint#pascal-case-struct note[pascal-case-struct]: structs should use PascalCase --> ROOT/testdata/StructPascalCase.sol:LL:CC @@ -12,7 +12,7 @@ note[pascal-case-struct]: structs should use PascalCase 17 | struct pascalCase { | ---------- | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#struct-names + = help: https://book.getfoundry.sh/reference/forge/forge-lint#pascal-case-struct note[pascal-case-struct]: structs should use PascalCase --> ROOT/testdata/StructPascalCase.sol:LL:CC @@ -20,7 +20,7 @@ note[pascal-case-struct]: structs should use PascalCase 21 | struct pascalcase { | ---------- | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#struct-names + = help: https://book.getfoundry.sh/reference/forge/forge-lint#pascal-case-struct note[pascal-case-struct]: structs should use PascalCase --> ROOT/testdata/StructPascalCase.sol:LL:CC @@ -28,7 +28,7 @@ note[pascal-case-struct]: structs should use PascalCase 25 | struct pascal_case { | ----------- | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#struct-names + = help: https://book.getfoundry.sh/reference/forge/forge-lint#pascal-case-struct note[pascal-case-struct]: structs should use PascalCase --> ROOT/testdata/StructPascalCase.sol:LL:CC @@ -36,7 +36,7 @@ note[pascal-case-struct]: structs should use PascalCase 29 | struct PASCAL_CASE { | ----------- | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#struct-names + = help: https://book.getfoundry.sh/reference/forge/forge-lint#pascal-case-struct note[pascal-case-struct]: structs should use PascalCase --> ROOT/testdata/StructPascalCase.sol:LL:CC @@ -44,5 +44,5 @@ note[pascal-case-struct]: structs should use PascalCase 33 | struct PASCALCASE { | ---------- | - = help: https://docs.soliditylang.org/en/latest/style-guide.html#struct-names + = help: https://book.getfoundry.sh/reference/forge/forge-lint#pascal-case-struct From 496598b3717354780de294898da83c19143010b5 Mon Sep 17 00:00:00 2001 From: Mablr <59505383+mablr@users.noreply.github.com> Date: Tue, 27 May 2025 00:33:22 +0200 Subject: [PATCH 149/244] feat(cast mktx): add support for "--ethsign" option (#10641) - Sign transactions using "eth_signTransaction" on local node with unlocked accounts. - Same TX building logic as in "cast send --unlocked". - Added a test case to validate the new functionality. --- crates/cast/src/cmd/mktx.rs | 22 +++++++++++++++++++--- crates/cast/tests/cli/main.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/crates/cast/src/cmd/mktx.rs b/crates/cast/src/cmd/mktx.rs index af06d556c23ff..ebfb5afeadd47 100644 --- a/crates/cast/src/cmd/mktx.rs +++ b/crates/cast/src/cmd/mktx.rs @@ -2,6 +2,7 @@ use crate::tx::{self, CastTxBuilder}; use alloy_ens::NameOrAddress; use alloy_network::{eip2718::Encodable2718, EthereumWallet, TransactionBuilder}; use alloy_primitives::hex; +use alloy_provider::Provider; use alloy_signer::Signer; use clap::Parser; use eyre::{OptionExt, Result}; @@ -50,6 +51,10 @@ pub struct MakeTxArgs { /// Relaxes the wallet requirement. #[arg(long, requires = "from")] raw_unsigned: bool, + + /// Call `eth_signTransaction` using the `--from` argument or $ETH_FROM as sender + #[arg(long, requires = "from", conflicts_with = "raw_unsigned")] + ethsign: bool, } #[derive(Debug, Parser)] @@ -70,7 +75,7 @@ pub enum MakeTxSubcommands { impl MakeTxArgs { pub async fn run(self) -> Result<()> { - let Self { to, mut sig, mut args, command, tx, path, eth, raw_unsigned } = self; + let Self { to, mut sig, mut args, command, tx, path, eth, raw_unsigned, ethsign } = self; let blob_data = if let Some(path) = path { Some(std::fs::read(path)?) } else { None }; @@ -91,7 +96,7 @@ impl MakeTxArgs { let provider = get_provider(&config)?; - let tx_builder = CastTxBuilder::new(provider, tx, &config) + let tx_builder = CastTxBuilder::new(&provider, tx, &config) .await? .with_to(to) .await? @@ -108,7 +113,18 @@ impl MakeTxArgs { return Ok(()); } - // Retrieve the signer, and bail if it can't be constructed. + if ethsign { + // Use "eth_signTransaction" to sign the transaction only works if the node/RPC has + // unlocked accounts. + let (tx, _) = tx_builder.build(config.sender).await?; + let signed_tx = provider.sign_transaction(tx).await?; + + sh_println!("{signed_tx}")?; + return Ok(()); + } + + // Default to using the local signer. + // Get the signer from the wallet, and fail if it can't be constructed. let signer = eth.wallet.signer().await?; let from = signer.address(); diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 4735a8ce1abbc..1a0c0bf958cf8 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -1296,6 +1296,37 @@ casttest!(mktx_raw_unsigned, |_prj, cmd| { ]]); }); +casttest!(mktx_ethsign, async |_prj, cmd| { + let (_api, handle) = anvil::spawn(NodeConfig::test()).await; + let rpc = handle.http_endpoint(); + cmd.args([ + "mktx", + "--from", + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "--chain", + "31337", + "--nonce", + "0", + "--gas-limit", + "21000", + "--gas-price", + "10000000000", + "--priority-gas-price", + "1000000000", + "0x0000000000000000000000000000000000000001", + "--ethsign", + "--rpc-url", + rpc.as_str(), + ]) + .assert_success() + .stdout_eq(str![[ + r#" +0x02f86d827a6980843b9aca008502540be4008252089400000000000000000000000000000000000000018080c001a0b8eeb1ded87b085859c510c5692bed231e3ee8b068ccf71142bbf28da0e95987a07813b676a248ae8055f28495021d78dee6695479d339a6ad9d260d9eaf20674c + +"# + ]]); +}); + // tests that the raw encoded transaction is returned casttest!(tx_raw, |_prj, cmd| { let rpc = next_http_rpc_endpoint(); From 3e45ccb8a29cfa678a12a57c38af43251f416799 Mon Sep 17 00:00:00 2001 From: Mablr <59505383+mablr@users.noreply.github.com> Date: Tue, 27 May 2025 16:28:39 +0200 Subject: [PATCH 150/244] chore(wallets): improve error message for signer instantiation failure (#10646) chore(wallets): improve error message on signer instantiation failure --- crates/wallets/src/wallet.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/wallets/src/wallet.rs b/crates/wallets/src/wallet.rs index 29ce54438586d..8e3a4dafb332a 100644 --- a/crates/wallets/src/wallet.rs +++ b/crates/wallets/src/wallet.rs @@ -128,12 +128,14 @@ impl WalletOpts { eyre::bail!( "\ Error accessing local wallet. Did you set a private key, mnemonic or keystore? -Run `cast send --help` or `forge create --help` and use the corresponding CLI +Run the command with --help flag for more information or use the corresponding CLI flag to set your key via: --private-key, --mnemonic-path, --aws, --gcp, --interactive, --trezor or --ledger. -Alternatively, if you're using a local node with unlocked accounts, -use the --unlocked flag and either set the `ETH_FROM` environment variable to the address -of the unlocked account you want to use, or provide the --from flag with the address directly." +Alternatively, when using the `cast send` or `cast mktx` commands with a local node +or RPC that has unlocked accounts, the --unlocked or --ethsign flags can be used, +respectively. The sender address can be specified by setting the `ETH_FROM` environment +variable to the desired unlocked account address, or by providing the address directly +using the --from flag." ) }; From 65650a6fca64dbd17c093c106b1c61b1982f5469 Mon Sep 17 00:00:00 2001 From: Ishika Choudhury <117741714+Rimeeeeee@users.noreply.github.com> Date: Tue, 27 May 2025 20:19:41 +0530 Subject: [PATCH 151/244] chore: replaced anvil hardforks with alloy hardforks (#10612) * chore: replaced anvil hardforks with alloy hardforks * fixes * fixes * fixes * removed redundant op and alloy hardforks enum * fixes * fixes * bumped alloy hardforks and kept default to prague and isthmus * bumped alloy-hardforks and fixes --------- Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- Cargo.lock | 12 +- Cargo.toml | 2 + crates/anvil/Cargo.toml | 2 + crates/anvil/src/cmd.rs | 7 +- crates/anvil/src/config.rs | 15 +- crates/anvil/src/hardfork.rs | 274 ++++++++------------------- crates/anvil/src/lib.rs | 3 +- crates/anvil/tests/it/anvil.rs | 3 +- crates/anvil/tests/it/anvil_api.rs | 3 +- crates/anvil/tests/it/eip4844.rs | 3 +- crates/anvil/tests/it/eip7702.rs | 3 +- crates/anvil/tests/it/otterscan.rs | 3 +- crates/anvil/tests/it/traces.rs | 3 +- crates/anvil/tests/it/transaction.rs | 3 +- crates/cast/Cargo.toml | 1 + crates/cast/tests/cli/main.rs | 3 +- crates/forge/Cargo.toml | 1 + crates/forge/tests/cli/script.rs | 3 +- 18 files changed, 126 insertions(+), 218 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c05a8b99f5d05..1fa7e6a150282 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -253,9 +253,9 @@ dependencies = [ [[package]] name = "alloy-hardforks" -version = "0.2.3" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6b8067561eb8f884b215ace4c962313c5467e47bde6b457c8c51e268fb5d99" +checksum = "fbff8445282ec080c2673692062bd4930d7a0d6bda257caf138cfc650c503000" dependencies = [ "alloy-chains", "alloy-eip2124", @@ -348,9 +348,9 @@ dependencies = [ [[package]] name = "alloy-op-hardforks" -version = "0.2.3" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08043c9284e597f9b5cf741cc6d906fdb26c195a01d88423c84c00ffda835713" +checksum = "9ddfbb5cc9f614efa5d56e0d7226214bb67b29271d44b6ddfcbbe25eb0ff898b" dependencies = [ "alloy-hardforks", "auto_impl", @@ -1023,8 +1023,10 @@ dependencies = [ "alloy-eips", "alloy-evm", "alloy-genesis", + "alloy-hardforks", "alloy-network", "alloy-op-evm", + "alloy-op-hardforks", "alloy-primitives", "alloy-provider", "alloy-pubsub", @@ -2351,6 +2353,7 @@ dependencies = [ "alloy-contract", "alloy-dyn-abi", "alloy-ens", + "alloy-hardforks", "alloy-json-abi", "alloy-json-rpc", "alloy-network", @@ -3778,6 +3781,7 @@ version = "1.2.1" dependencies = [ "alloy-chains", "alloy-dyn-abi", + "alloy-hardforks", "alloy-json-abi", "alloy-network", "alloy-primitives", diff --git a/Cargo.toml b/Cargo.toml index 8686f046c2c14..3baefd5dca836 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -230,6 +230,8 @@ alloy-transport = { version = "1.0.7", default-features = false } alloy-transport-http = { version = "1.0.7", default-features = false } alloy-transport-ipc = { version = "1.0.7", default-features = false } alloy-transport-ws = { version = "1.0.7", default-features = false } +alloy-hardforks = { version = "0.2.6", default-features = false } +alloy-op-hardforks = { version = "0.2.6", default-features = false } ## alloy-core alloy-dyn-abi = "1.0" diff --git a/crates/anvil/Cargo.toml b/crates/anvil/Cargo.toml index e45c95e49f85e..23ff53b271895 100644 --- a/crates/anvil/Cargo.toml +++ b/crates/anvil/Cargo.toml @@ -55,6 +55,8 @@ alloy-transport.workspace = true alloy-chains.workspace = true alloy-genesis.workspace = true alloy-trie.workspace = true +alloy-hardforks.workspace = true +alloy-op-hardforks.workspace = true op-alloy-consensus = { workspace = true, features = ["serde"] } # revm diff --git a/crates/anvil/src/cmd.rs b/crates/anvil/src/cmd.rs index d4b91e14f20fd..c8223a76ed959 100644 --- a/crates/anvil/src/cmd.rs +++ b/crates/anvil/src/cmd.rs @@ -1,9 +1,10 @@ use crate::{ config::{ForkChoice, DEFAULT_MNEMONIC}, eth::{backend::db::SerializableState, pool::transactions::TransactionOrder, EthApi}, - AccountGenerator, EthereumHardfork, NodeConfig, OptimismHardfork, CHAIN_ID, + AccountGenerator, EthereumHardfork, NodeConfig, CHAIN_ID, }; use alloy_genesis::Genesis; +use alloy_op_hardforks::OpHardfork; use alloy_primitives::{utils::Unit, B256, U256}; use alloy_signer_local::coins_bip39::{English, Mnemonic}; use anvil_server::ServerConfig; @@ -218,7 +219,7 @@ impl NodeArgs { let hardfork = match &self.hardfork { Some(hf) => { if self.evm.optimism { - Some(OptimismHardfork::from_str(hf)?.into()) + Some(OpHardfork::from_str(hf)?.into()) } else { Some(EthereumHardfork::from_str(hf)?.into()) } @@ -836,7 +837,7 @@ mod tests { let args: NodeArgs = NodeArgs::parse_from(["anvil", "--optimism", "--hardfork", "Regolith"]); let config = args.into_node_config().unwrap(); - assert_eq!(config.hardfork, Some(OptimismHardfork::Regolith.into())); + assert_eq!(config.hardfork, Some(OpHardfork::Regolith.into())); } #[test] diff --git a/crates/anvil/src/config.rs b/crates/anvil/src/config.rs index 722408c72a9c4..1cde743c3e952 100644 --- a/crates/anvil/src/config.rs +++ b/crates/anvil/src/config.rs @@ -11,13 +11,14 @@ use crate::{ fees::{INITIAL_BASE_FEE, INITIAL_GAS_PRICE}, pool::transactions::{PoolTransaction, TransactionOrder}, }, - hardfork::ChainHardfork, + hardfork::{ethereum_hardfork_from_block_tag, spec_id_from_ethereum_hardfork, ChainHardfork}, mem::{self, in_memory_db::MemDb}, - EthereumHardfork, FeeManager, OptimismHardfork, PrecompileFactory, + EthereumHardfork, FeeManager, PrecompileFactory, }; use alloy_consensus::BlockHeader; use alloy_genesis::Genesis; use alloy_network::{AnyNetwork, TransactionResponse}; +use alloy_op_hardforks::OpHardfork; use alloy_primitives::{hex, map::HashMap, utils::Unit, BlockNumber, TxHash, U256}; use alloy_provider::Provider; use alloy_rpc_types::{Block, BlockNumberOrTag}; @@ -530,9 +531,9 @@ impl NodeConfig { return hardfork; } if self.enable_optimism { - return OptimismHardfork::default().into(); + return OpHardfork::Isthmus.into(); } - EthereumHardfork::default().into() + EthereumHardfork::Cancun.into() } /// Sets a custom code size limit @@ -1186,8 +1187,10 @@ impl NodeConfig { let chain_id = provider.get_chain_id().await.wrap_err("failed to fetch network chain ID")?; if alloy_chains::NamedChain::Mainnet == chain_id { - let hardfork: EthereumHardfork = fork_block_number.into(); - env.evm_env.cfg_env.spec = hardfork.into(); + let hardfork: EthereumHardfork = + ethereum_hardfork_from_block_tag(fork_block_number); + + env.evm_env.cfg_env.spec = spec_id_from_ethereum_hardfork(hardfork); self.hardfork = Some(ChainHardfork::Ethereum(hardfork)); } Some(U256::from(chain_id)) diff --git a/crates/anvil/src/hardfork.rs b/crates/anvil/src/hardfork.rs index 34fe97fa1de41..f5e063aafc625 100644 --- a/crates/anvil/src/hardfork.rs +++ b/crates/anvil/src/hardfork.rs @@ -1,14 +1,14 @@ -use std::str::FromStr; - +use alloy_hardforks::EthereumHardfork; +use alloy_op_hardforks::OpHardfork::{self}; use alloy_rpc_types::BlockNumberOrTag; -use eyre::bail; + use op_revm::OpSpecId; use revm::primitives::hardfork::SpecId; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum ChainHardfork { Ethereum(EthereumHardfork), - Optimism(OptimismHardfork), + Optimism(OpHardfork), } impl From for ChainHardfork { @@ -17,8 +17,8 @@ impl From for ChainHardfork { } } -impl From for ChainHardfork { - fn from(value: OptimismHardfork) -> Self { +impl From for ChainHardfork { + fn from(value: OpHardfork) -> Self { Self::Optimism(value) } } @@ -26,213 +26,99 @@ impl From for ChainHardfork { impl From for SpecId { fn from(fork: ChainHardfork) -> Self { match fork { - ChainHardfork::Ethereum(hardfork) => hardfork.into(), - ChainHardfork::Optimism(hardfork) => hardfork.into_eth_spec(), - } - } -} - -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum EthereumHardfork { - Frontier, - Homestead, - Dao, - Tangerine, - SpuriousDragon, - Byzantium, - Constantinople, - Petersburg, - Istanbul, - Muirglacier, - Berlin, - London, - ArrowGlacier, - GrayGlacier, - Paris, - Shanghai, - Cancun, - Prague, - #[default] - Latest, -} - -impl EthereumHardfork { - /// Get the first block number of the hardfork. - pub fn fork_block(&self) -> u64 { - match *self { - Self::Frontier => 0, - Self::Homestead => 1150000, - Self::Dao => 1920000, - Self::Tangerine => 2463000, - Self::SpuriousDragon => 2675000, - Self::Byzantium => 4370000, - Self::Constantinople | Self::Petersburg => 7280000, - Self::Istanbul => 9069000, - Self::Muirglacier => 9200000, - Self::Berlin => 12244000, - Self::London => 12965000, - Self::ArrowGlacier => 13773000, - Self::GrayGlacier => 15050000, - Self::Paris => 15537394, - Self::Shanghai => 17034870, - Self::Cancun | Self::Latest => 19426587, - Self::Prague => 22431084, + ChainHardfork::Ethereum(hardfork) => spec_id_from_ethereum_hardfork(hardfork), + ChainHardfork::Optimism(hardfork) => spec_id_from_optimism_hardfork(hardfork).into(), } } } -impl FromStr for EthereumHardfork { - type Err = eyre::Report; - - fn from_str(s: &str) -> Result { - let s = s.to_lowercase(); - let hardfork = match s.as_str() { - "frontier" | "1" => Self::Frontier, - "homestead" | "2" => Self::Homestead, - "dao" | "3" => Self::Dao, - "tangerine" | "4" => Self::Tangerine, - "spuriousdragon" | "5" => Self::SpuriousDragon, - "byzantium" | "6" => Self::Byzantium, - "constantinople" | "7" => Self::Constantinople, - "petersburg" | "8" => Self::Petersburg, - "istanbul" | "9" => Self::Istanbul, - "muirglacier" | "10" => Self::Muirglacier, - "berlin" | "11" => Self::Berlin, - "london" | "12" => Self::London, - "arrowglacier" | "13" => Self::ArrowGlacier, - "grayglacier" | "14" => Self::GrayGlacier, - "paris" | "merge" | "15" => Self::Paris, - "shanghai" | "16" => Self::Shanghai, - "cancun" | "17" => Self::Cancun, - "prague" | "18" => Self::Prague, - "latest" => Self::Latest, - _ => bail!("Unknown hardfork {s}"), - }; - Ok(hardfork) +/// Map an EthereumHardfork enum into its corresponding SpecId. +pub fn spec_id_from_ethereum_hardfork(hardfork: EthereumHardfork) -> SpecId { + match hardfork { + EthereumHardfork::Frontier => SpecId::FRONTIER, + EthereumHardfork::Homestead => SpecId::HOMESTEAD, + EthereumHardfork::Dao => SpecId::DAO_FORK, + EthereumHardfork::Tangerine => SpecId::TANGERINE, + EthereumHardfork::SpuriousDragon => SpecId::SPURIOUS_DRAGON, + EthereumHardfork::Byzantium => SpecId::BYZANTIUM, + EthereumHardfork::Constantinople => SpecId::CONSTANTINOPLE, + EthereumHardfork::Petersburg => SpecId::PETERSBURG, + EthereumHardfork::Istanbul => SpecId::ISTANBUL, + EthereumHardfork::MuirGlacier => SpecId::MUIR_GLACIER, + EthereumHardfork::Berlin => SpecId::BERLIN, + EthereumHardfork::London => SpecId::LONDON, + EthereumHardfork::ArrowGlacier => SpecId::ARROW_GLACIER, + EthereumHardfork::GrayGlacier => SpecId::GRAY_GLACIER, + EthereumHardfork::Paris => SpecId::MERGE, + EthereumHardfork::Shanghai => SpecId::SHANGHAI, + EthereumHardfork::Cancun => SpecId::CANCUN, + EthereumHardfork::Prague => SpecId::PRAGUE, + EthereumHardfork::Osaka => SpecId::OSAKA, } } -impl From for SpecId { - fn from(fork: EthereumHardfork) -> Self { - match fork { - EthereumHardfork::Frontier => Self::FRONTIER, - EthereumHardfork::Homestead => Self::HOMESTEAD, - EthereumHardfork::Dao => Self::HOMESTEAD, - EthereumHardfork::Tangerine => Self::TANGERINE, - EthereumHardfork::SpuriousDragon => Self::SPURIOUS_DRAGON, - EthereumHardfork::Byzantium => Self::BYZANTIUM, - EthereumHardfork::Constantinople => Self::CONSTANTINOPLE, - EthereumHardfork::Petersburg => Self::PETERSBURG, - EthereumHardfork::Istanbul => Self::ISTANBUL, - EthereumHardfork::Muirglacier => Self::MUIR_GLACIER, - EthereumHardfork::Berlin => Self::BERLIN, - EthereumHardfork::London => Self::LONDON, - EthereumHardfork::ArrowGlacier => Self::LONDON, - EthereumHardfork::GrayGlacier => Self::GRAY_GLACIER, - EthereumHardfork::Paris => Self::MERGE, - EthereumHardfork::Shanghai => Self::SHANGHAI, - EthereumHardfork::Cancun | EthereumHardfork::Latest => Self::CANCUN, - EthereumHardfork::Prague => Self::PRAGUE, - } +/// Map an OptimismHardfork enum into its corresponding OpSpecId. +pub fn spec_id_from_optimism_hardfork(hardfork: OpHardfork) -> OpSpecId { + match hardfork { + OpHardfork::Bedrock => OpSpecId::BEDROCK, + OpHardfork::Regolith => OpSpecId::REGOLITH, + OpHardfork::Canyon => OpSpecId::CANYON, + OpHardfork::Ecotone => OpSpecId::ECOTONE, + OpHardfork::Fjord => OpSpecId::FJORD, + OpHardfork::Granite => OpSpecId::GRANITE, + OpHardfork::Holocene => OpSpecId::HOLOCENE, + OpHardfork::Isthmus => OpSpecId::ISTHMUS, + OpHardfork::Interop => OpSpecId::INTEROP, } } -impl> From for EthereumHardfork { - fn from(block: T) -> Self { - let num = match block.into() { - BlockNumberOrTag::Earliest => 0, - BlockNumberOrTag::Number(num) => num, - _ => u64::MAX, - }; - - match num { - _i if num < 1_150_000 => Self::Frontier, - _i if num < 1_920_000 => Self::Dao, - _i if num < 2_463_000 => Self::Homestead, - _i if num < 2_675_000 => Self::Tangerine, - _i if num < 4_370_000 => Self::SpuriousDragon, - _i if num < 7_280_000 => Self::Byzantium, - _i if num < 9_069_000 => Self::Constantinople, - _i if num < 9_200_000 => Self::Istanbul, - _i if num < 12_244_000 => Self::Muirglacier, - _i if num < 12_965_000 => Self::Berlin, - _i if num < 13_773_000 => Self::London, - _i if num < 15_050_000 => Self::ArrowGlacier, - _i if num < 17_034_870 => Self::Paris, - _i if num < 19_426_587 => Self::Shanghai, - _ => Self::Latest, - } - } -} +/// Convert a `BlockNumberOrTag` into an `EthereumHardfork`. +pub fn ethereum_hardfork_from_block_tag(block: impl Into) -> EthereumHardfork { + let num = match block.into() { + BlockNumberOrTag::Earliest => 0, + BlockNumberOrTag::Number(num) => num, + _ => u64::MAX, + }; -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum OptimismHardfork { - Bedrock, - Regolith, - Canyon, - Ecotone, - Fjord, - Granite, - Holocene, - #[default] - Isthmus, + EthereumHardfork::from_mainnet_block_number(num) } -impl OptimismHardfork { - pub fn into_eth_spec(self) -> SpecId { - let op_spec: OpSpecId = self.into(); - op_spec.into_eth_spec() - } -} +#[cfg(test)] +mod tests { + use super::*; + use alloy_hardforks::ethereum::mainnet::*; + #[allow(unused_imports)] + use alloy_rpc_types::BlockNumberOrTag; -impl FromStr for OptimismHardfork { - type Err = eyre::Report; + #[test] + fn test_ethereum_spec_id_mapping() { + assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Frontier), SpecId::FRONTIER); + assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Homestead), SpecId::HOMESTEAD); - fn from_str(s: &str) -> Result { - let s = s.to_lowercase(); - let hardfork = match s.as_str() { - "bedrock" => Self::Bedrock, - "regolith" => Self::Regolith, - "canyon" => Self::Canyon, - "ecotone" => Self::Ecotone, - "fjord" => Self::Fjord, - "granite" => Self::Granite, - "holocene" => Self::Holocene, - "isthmus" => Self::Isthmus, - _ => bail!("Unknown hardfork {s}"), - }; - Ok(hardfork) + // Test latest hardforks + assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Cancun), SpecId::CANCUN); + assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Prague), SpecId::PRAGUE); } -} - -impl From for OpSpecId { - fn from(fork: OptimismHardfork) -> Self { - match fork { - OptimismHardfork::Bedrock => Self::BEDROCK, - OptimismHardfork::Regolith => Self::REGOLITH, - OptimismHardfork::Canyon => Self::CANYON, - OptimismHardfork::Ecotone => Self::ECOTONE, - OptimismHardfork::Fjord => Self::FJORD, - OptimismHardfork::Granite => Self::GRANITE, - OptimismHardfork::Holocene => Self::HOLOCENE, - OptimismHardfork::Isthmus => Self::ISTHMUS, - } - } -} - -#[cfg(test)] -mod tests { - use crate::EthereumHardfork; #[test] - fn test_hardfork_blocks() { - let hf: EthereumHardfork = 12_965_000u64.into(); - assert_eq!(hf, EthereumHardfork::London); + fn test_optimism_spec_id_mapping() { + assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Bedrock), OpSpecId::BEDROCK); + assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Regolith), OpSpecId::REGOLITH); - let hf: EthereumHardfork = 4370000u64.into(); - assert_eq!(hf, EthereumHardfork::Byzantium); + // Test latest hardforks + assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Holocene), OpSpecId::HOLOCENE); + assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Interop), OpSpecId::INTEROP); + } - let hf: EthereumHardfork = 12244000u64.into(); - assert_eq!(hf, EthereumHardfork::Berlin); + #[test] + fn test_hardfork_from_block_tag_numbers() { + assert_eq!( + ethereum_hardfork_from_block_tag(MAINNET_HOMESTEAD_BLOCK - 1), + EthereumHardfork::Frontier + ); + assert_eq!( + ethereum_hardfork_from_block_tag(MAINNET_LONDON_BLOCK + 1), + EthereumHardfork::London + ); } } diff --git a/crates/anvil/src/lib.rs b/crates/anvil/src/lib.rs index 77e072e0aa1f2..5ee4fead559b2 100644 --- a/crates/anvil/src/lib.rs +++ b/crates/anvil/src/lib.rs @@ -47,8 +47,7 @@ pub use config::{ }; mod hardfork; -pub use hardfork::{EthereumHardfork, OptimismHardfork}; - +pub use alloy_hardforks::EthereumHardfork; /// ethereum related implementations pub mod eth; /// Evm related abstractions diff --git a/crates/anvil/tests/it/anvil.rs b/crates/anvil/tests/it/anvil.rs index 329caea844b45..721aa404b36e1 100644 --- a/crates/anvil/tests/it/anvil.rs +++ b/crates/anvil/tests/it/anvil.rs @@ -2,9 +2,10 @@ use alloy_consensus::EMPTY_ROOT_HASH; use alloy_eips::BlockNumberOrTag; +use alloy_hardforks::EthereumHardfork; use alloy_primitives::Address; use alloy_provider::Provider; -use anvil::{spawn, EthereumHardfork, NodeConfig}; +use anvil::{spawn, NodeConfig}; #[tokio::test(flavor = "multi_thread")] async fn test_can_change_mining_mode() { diff --git a/crates/anvil/tests/it/anvil_api.rs b/crates/anvil/tests/it/anvil_api.rs index ce337714587b9..d4af986814ed6 100644 --- a/crates/anvil/tests/it/anvil_api.rs +++ b/crates/anvil/tests/it/anvil_api.rs @@ -6,6 +6,7 @@ use crate::{ utils::http_provider_with_signer, }; use alloy_consensus::{SignableTransaction, TxEip1559}; +use alloy_hardforks::EthereumHardfork; use alloy_network::{EthereumWallet, TransactionBuilder, TxSignerSync}; use alloy_primitives::{address, fixed_bytes, utils::Unit, Address, Bytes, TxKind, U256}; use alloy_provider::{ext::TxPoolApi, Provider}; @@ -21,7 +22,7 @@ use anvil::{ api::CLIENT_VERSION, backend::mem::{EXECUTOR, P256_DELEGATION_CONTRACT, P256_DELEGATION_RUNTIME_CODE}, }, - spawn, EthereumHardfork, NodeConfig, + spawn, NodeConfig, }; use anvil_core::{ eth::{ diff --git a/crates/anvil/tests/it/eip4844.rs b/crates/anvil/tests/it/eip4844.rs index 633c8a01bdef0..2d713c3d955e3 100644 --- a/crates/anvil/tests/it/eip4844.rs +++ b/crates/anvil/tests/it/eip4844.rs @@ -4,12 +4,13 @@ use alloy_eips::{ eip4844::{BLOB_TX_MIN_BLOB_GASPRICE, DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK_DENCUN}, Typed2718, }; +use alloy_hardforks::EthereumHardfork; use alloy_network::{EthereumWallet, ReceiptResponse, TransactionBuilder, TransactionBuilder4844}; use alloy_primitives::{b256, Address, U256}; use alloy_provider::Provider; use alloy_rpc_types::{BlockId, TransactionRequest}; use alloy_serde::WithOtherFields; -use anvil::{spawn, EthereumHardfork, NodeConfig}; +use anvil::{spawn, NodeConfig}; #[tokio::test(flavor = "multi_thread")] async fn can_send_eip4844_transaction() { diff --git a/crates/anvil/tests/it/eip7702.rs b/crates/anvil/tests/it/eip7702.rs index c09412c85e306..9424360119e4e 100644 --- a/crates/anvil/tests/it/eip7702.rs +++ b/crates/anvil/tests/it/eip7702.rs @@ -1,12 +1,13 @@ use crate::utils::http_provider; use alloy_consensus::{transaction::TxEip7702, SignableTransaction}; +use alloy_hardforks::EthereumHardfork; use alloy_network::{ReceiptResponse, TransactionBuilder, TxSignerSync}; use alloy_primitives::{bytes, U256}; use alloy_provider::{PendingTransactionConfig, Provider}; use alloy_rpc_types::{Authorization, TransactionRequest}; use alloy_serde::WithOtherFields; use alloy_signer::SignerSync; -use anvil::{spawn, EthereumHardfork, NodeConfig}; +use anvil::{spawn, NodeConfig}; #[tokio::test(flavor = "multi_thread")] async fn can_send_eip7702_tx() { diff --git a/crates/anvil/tests/it/otterscan.rs b/crates/anvil/tests/it/otterscan.rs index 3809e3183e1a7..ffd70d1349ddb 100644 --- a/crates/anvil/tests/it/otterscan.rs +++ b/crates/anvil/tests/it/otterscan.rs @@ -1,6 +1,7 @@ //! Tests for otterscan endpoints. use crate::abi::Multicall; +use alloy_hardforks::EthereumHardfork; use alloy_network::TransactionResponse; use alloy_primitives::{address, Address, Bytes, U256}; use alloy_provider::Provider; @@ -10,7 +11,7 @@ use alloy_rpc_types::{ }; use alloy_serde::WithOtherFields; use alloy_sol_types::{sol, SolCall, SolError, SolValue}; -use anvil::{spawn, EthereumHardfork, NodeConfig}; +use anvil::{spawn, NodeConfig}; use std::collections::VecDeque; #[tokio::test(flavor = "multi_thread")] diff --git a/crates/anvil/tests/it/traces.rs b/crates/anvil/tests/it/traces.rs index 849956cabe5dd..2e073ca9c8735 100644 --- a/crates/anvil/tests/it/traces.rs +++ b/crates/anvil/tests/it/traces.rs @@ -4,6 +4,7 @@ use crate::{ utils::http_provider_with_signer, }; use alloy_eips::BlockId; +use alloy_hardforks::EthereumHardfork; use alloy_network::{EthereumWallet, TransactionBuilder}; use alloy_primitives::{ hex::{self, FromHex}, @@ -27,7 +28,7 @@ use alloy_rpc_types::{ }; use alloy_serde::WithOtherFields; use alloy_sol_types::sol; -use anvil::{spawn, EthereumHardfork, NodeConfig}; +use anvil::{spawn, NodeConfig}; #[tokio::test(flavor = "multi_thread")] async fn test_get_transfer_parity_traces() { diff --git a/crates/anvil/tests/it/transaction.rs b/crates/anvil/tests/it/transaction.rs index 953c30515d3ef..7cb681af85a14 100644 --- a/crates/anvil/tests/it/transaction.rs +++ b/crates/anvil/tests/it/transaction.rs @@ -2,6 +2,7 @@ use crate::{ abi::{Greeter, Multicall, SimpleStorage}, utils::{connect_pubsub, http_provider_with_signer}, }; +use alloy_hardforks::EthereumHardfork; use alloy_network::{EthereumWallet, TransactionBuilder, TransactionResponse}; use alloy_primitives::{address, hex, map::B256HashSet, Address, Bytes, FixedBytes, U256}; use alloy_provider::{Provider, WsConnect}; @@ -12,7 +13,7 @@ use alloy_rpc_types::{ }; use alloy_serde::WithOtherFields; use alloy_sol_types::SolValue; -use anvil::{spawn, EthereumHardfork, NodeConfig}; +use anvil::{spawn, NodeConfig}; use eyre::Ok; use futures::{future::join_all, FutureExt, StreamExt}; use std::{str::FromStr, time::Duration}; diff --git a/crates/cast/Cargo.toml b/crates/cast/Cargo.toml index 26f001132baff..2dda3ba341872 100644 --- a/crates/cast/Cargo.toml +++ b/crates/cast/Cargo.toml @@ -53,6 +53,7 @@ alloy-signer.workspace = true alloy-sol-types.workspace = true alloy-transport.workspace = true alloy-ens = { workspace = true, features = ["provider"] } +alloy-hardforks.workspace = true op-alloy-flz.workspace = true op-alloy-consensus = { workspace = true, features = ["alloy-compat"] } diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 1a0c0bf958cf8..eca950b2f89d4 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -1,11 +1,12 @@ //! Contains various tests for checking cast commands use alloy_chains::NamedChain; +use alloy_hardforks::EthereumHardfork; use alloy_network::{TransactionBuilder, TransactionResponse}; use alloy_primitives::{address, b256, Bytes, B256}; use alloy_provider::{Provider, ProviderBuilder}; use alloy_rpc_types::{BlockNumberOrTag, Index, TransactionRequest}; -use anvil::{EthereumHardfork, NodeConfig}; +use anvil::NodeConfig; use foundry_test_utils::{ rpc::{ next_etherscan_api_key, next_http_archive_rpc_url, next_http_rpc_endpoint, diff --git a/crates/forge/Cargo.toml b/crates/forge/Cargo.toml index c3251ed76c9eb..d823ca3285140 100644 --- a/crates/forge/Cargo.toml +++ b/crates/forge/Cargo.toml @@ -63,6 +63,7 @@ alloy-rpc-types.workspace = true alloy-serde.workspace = true alloy-signer.workspace = true alloy-transport.workspace = true +alloy-hardforks.workspace = true revm.workspace = true diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index d72c21fce60ff..1d6f415aef1d4 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -1,8 +1,9 @@ //! Contains various tests related to `forge script`. use crate::constants::TEMPLATE_CONTRACT; +use alloy_hardforks::EthereumHardfork; use alloy_primitives::{address, hex, Address, Bytes}; -use anvil::{spawn, EthereumHardfork, NodeConfig}; +use anvil::{spawn, NodeConfig}; use forge_script_sequence::ScriptSequence; use foundry_test_utils::{ rpc::{self, next_http_archive_rpc_url}, From db0ce45719a703c06f789c0c9e6514e1cc4e1c0c Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Wed, 28 May 2025 13:03:08 +0100 Subject: [PATCH 152/244] fix(`anvil`): latest evm version should be prague (#10653) * fix(`anvil`): latest evm version should be prague * fix test * nit --- crates/anvil/src/cmd.rs | 2 +- crates/anvil/src/config.rs | 6 +++--- crates/anvil/tests/it/anvil_api.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/anvil/src/cmd.rs b/crates/anvil/src/cmd.rs index c8223a76ed959..4ca9624d57f6e 100644 --- a/crates/anvil/src/cmd.rs +++ b/crates/anvil/src/cmd.rs @@ -79,7 +79,7 @@ pub struct NodeArgs { /// The EVM hardfork to use. /// - /// Choose the hardfork by name, e.g. `cancun`, `shanghai`, `paris`, `london`, etc... + /// Choose the hardfork by name, e.g. `prague`, `cancun`, `shanghai`, `paris`, `london`, etc... /// [default: latest] #[arg(long)] pub hardfork: Option, diff --git a/crates/anvil/src/config.rs b/crates/anvil/src/config.rs index 1cde743c3e952..d86515f9f8fba 100644 --- a/crates/anvil/src/config.rs +++ b/crates/anvil/src/config.rs @@ -525,15 +525,15 @@ impl NodeConfig { /// Returns the hardfork to use pub fn get_hardfork(&self) -> ChainHardfork { if self.odyssey { - return ChainHardfork::Ethereum(EthereumHardfork::Prague); + return ChainHardfork::Ethereum(EthereumHardfork::default()); } if let Some(hardfork) = self.hardfork { return hardfork; } if self.enable_optimism { - return OpHardfork::Isthmus.into(); + return OpHardfork::default().into(); } - EthereumHardfork::Cancun.into() + EthereumHardfork::default().into() } /// Sets a custom code size limit diff --git a/crates/anvil/tests/it/anvil_api.rs b/crates/anvil/tests/it/anvil_api.rs index d4af986814ed6..5b4bcd78d2059 100644 --- a/crates/anvil/tests/it/anvil_api.rs +++ b/crates/anvil/tests/it/anvil_api.rs @@ -449,7 +449,7 @@ async fn can_get_node_info() { let block_number = provider.get_block_number().await.unwrap(); let block = provider.get_block(BlockId::from(block_number)).await.unwrap().unwrap(); - let hard_fork: &str = SpecId::CANCUN.into(); + let hard_fork: &str = SpecId::PRAGUE.into(); let expected_node_info = NodeInfo { current_block_number: 0_u64, From 7e68208eaae86342998f4a713d27a538ce5a3fbb Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Wed, 28 May 2025 18:41:22 +0200 Subject: [PATCH 153/244] fix(fmt): 'layout' is not a keyword (#10656) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- crates/fmt/testdata/NonKeywords/fmt.sol | 13 +++++++------ crates/fmt/testdata/NonKeywords/original.sol | 13 +++++++------ crates/fmt/tests/formatter.rs | 2 +- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1fa7e6a150282..4386f1cc79c86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4586,9 +4586,9 @@ dependencies = [ [[package]] name = "foundry-solang-parser" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c5fc5210af6b311ab9c6bce41d651d1cd0ab62ea5e0e7fde9635697fb19180" +checksum = "9645e75b89f977423690f3b4bfd8d84825e5fdabd7803cbce6d4a2c4d54972b4" dependencies = [ "itertools 0.14.0", "lalrpop", diff --git a/Cargo.toml b/Cargo.toml index 3baefd5dca836..3bec268c9722f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -201,7 +201,7 @@ foundry-linking = { path = "crates/linking" } foundry-block-explorers = { version = "0.17.0", default-features = false } foundry-compilers = { version = "0.16.1", default-features = false } foundry-fork-db = "0.15" -solang-parser = { version = "=0.3.8", package = "foundry-solang-parser" } +solang-parser = { version = "=0.3.9", package = "foundry-solang-parser" } solar-ast = { version = "=0.1.3", default-features = false } solar-parse = { version = "=0.1.3", default-features = false } solar-interface = { version = "=0.1.3", default-features = false } diff --git a/crates/fmt/testdata/NonKeywords/fmt.sol b/crates/fmt/testdata/NonKeywords/fmt.sol index 9a6a31539d8de..207eed1c96816 100644 --- a/crates/fmt/testdata/NonKeywords/fmt.sol +++ b/crates/fmt/testdata/NonKeywords/fmt.sol @@ -1,13 +1,13 @@ struct S { uint256 error; - // uint256 layout; + uint256 layout; uint256 at; } // uint256 transient; function f() { uint256 error = 0; - // uint256 layout = 0; + uint256 layout = 0; uint256 at = 0; // uint256 transient = 0; @@ -17,25 +17,26 @@ function f() { // transient = 0; S memory x = S({ + // format error: 0, - // layout: 0, + layout: 0, at: 0 }); // transient: 0 x.error = 0; - // x.layout = 0; + x.layout = 0; x.at = 0; // x.transient = 0; assembly { let error := 0 - // let layout := 0 + let layout := 0 let at := 0 // let transient := 0 error := 0 - // layout := 0 + layout := 0 at := 0 // transient := 0 } diff --git a/crates/fmt/testdata/NonKeywords/original.sol b/crates/fmt/testdata/NonKeywords/original.sol index 010bd3296e406..2786450ba571e 100644 --- a/crates/fmt/testdata/NonKeywords/original.sol +++ b/crates/fmt/testdata/NonKeywords/original.sol @@ -1,13 +1,13 @@ struct S { uint256 error; - // uint256 layout; + uint256 layout; uint256 at; // uint256 transient; } function f() { uint256 error = 0; - // uint256 layout = 0; + uint256 layout = 0; uint256 at = 0; // uint256 transient = 0; @@ -17,25 +17,26 @@ function f() { // transient = 0; S memory x = S({ + // format error: 0, - // layout: 0, + layout: 0, at: 0 // transient: 0 }); x.error = 0; - // x.layout = 0; + x.layout = 0; x.at = 0; // x.transient = 0; assembly { let error := 0 - // let layout := 0 + let layout := 0 let at := 0 // let transient := 0 error := 0 - // layout := 0 + layout := 0 at := 0 // transient := 0 } diff --git a/crates/fmt/tests/formatter.rs b/crates/fmt/tests/formatter.rs index 454b26c46ccc6..2e0a8dc896296 100644 --- a/crates/fmt/tests/formatter.rs +++ b/crates/fmt/tests/formatter.rs @@ -217,7 +217,6 @@ test_directories! { TryStatement, ConditionalOperatorExpression, NamedFunctionCallExpression, - NonKeywords, ArrayExpressions, UnitExpression, ThisExpression, @@ -242,3 +241,4 @@ test_directories! { } test_dir!(SortedImports, TestConfig::skip_compare_ast_eq()); +test_dir!(NonKeywords, TestConfig::skip_compare_ast_eq()); From ab753e9cafc5937bcc868fd7c61237c34ef9ac74 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Fri, 30 May 2025 11:34:19 +0300 Subject: [PATCH 154/244] chore: bump version to 1.2.2 (#10668) --- Cargo.lock | 62 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4386f1cc79c86..9857ec20187bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1014,7 +1014,7 @@ dependencies = [ [[package]] name = "anvil" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-chains", "alloy-consensus", @@ -1080,7 +1080,7 @@ dependencies = [ [[package]] name = "anvil-core" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -1104,7 +1104,7 @@ dependencies = [ [[package]] name = "anvil-rpc" -version = "1.2.1" +version = "1.2.2" dependencies = [ "serde", "serde_json", @@ -1112,7 +1112,7 @@ dependencies = [ [[package]] name = "anvil-server" -version = "1.2.1" +version = "1.2.2" dependencies = [ "anvil-rpc", "async-trait", @@ -2346,7 +2346,7 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "cast" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-chains", "alloy-consensus", @@ -2448,7 +2448,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chisel" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -3777,7 +3777,7 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "forge" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-chains", "alloy-dyn-abi", @@ -3862,7 +3862,7 @@ dependencies = [ [[package]] name = "forge-doc" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-primitives", "derive_more 2.0.1", @@ -3885,7 +3885,7 @@ dependencies = [ [[package]] name = "forge-fmt" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-primitives", "ariadne", @@ -3901,7 +3901,7 @@ dependencies = [ [[package]] name = "forge-lint" -version = "1.2.1" +version = "1.2.2" dependencies = [ "foundry-compilers", "foundry-config", @@ -3915,7 +3915,7 @@ dependencies = [ [[package]] name = "forge-script" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-chains", "alloy-consensus", @@ -3960,7 +3960,7 @@ dependencies = [ [[package]] name = "forge-script-sequence" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-network", "alloy-primitives", @@ -3976,7 +3976,7 @@ dependencies = [ [[package]] name = "forge-sol-macro-gen" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -3992,7 +3992,7 @@ dependencies = [ [[package]] name = "forge-verify" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4053,7 +4053,7 @@ dependencies = [ [[package]] name = "foundry-cheatcodes" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-chains", "alloy-consensus", @@ -4104,7 +4104,7 @@ dependencies = [ [[package]] name = "foundry-cheatcodes-spec" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-sol-types", "foundry-macros", @@ -4115,7 +4115,7 @@ dependencies = [ [[package]] name = "foundry-cli" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-chains", "alloy-dyn-abi", @@ -4161,7 +4161,7 @@ dependencies = [ [[package]] name = "foundry-common" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -4216,7 +4216,7 @@ dependencies = [ [[package]] name = "foundry-common-fmt" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -4343,7 +4343,7 @@ dependencies = [ [[package]] name = "foundry-config" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-chains", "alloy-primitives", @@ -4382,7 +4382,7 @@ dependencies = [ [[package]] name = "foundry-debugger" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-primitives", "crossterm", @@ -4400,7 +4400,7 @@ dependencies = [ [[package]] name = "foundry-evm" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-dyn-abi", "alloy-evm", @@ -4428,7 +4428,7 @@ dependencies = [ [[package]] name = "foundry-evm-abi" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -4440,7 +4440,7 @@ dependencies = [ [[package]] name = "foundry-evm-core" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -4477,7 +4477,7 @@ dependencies = [ [[package]] name = "foundry-evm-coverage" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-primitives", "eyre", @@ -4492,7 +4492,7 @@ dependencies = [ [[package]] name = "foundry-evm-fuzz" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4516,7 +4516,7 @@ dependencies = [ [[package]] name = "foundry-evm-traces" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4566,7 +4566,7 @@ dependencies = [ [[package]] name = "foundry-linking" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-primitives", "foundry-compilers", @@ -4576,7 +4576,7 @@ dependencies = [ [[package]] name = "foundry-macros" -version = "1.2.1" +version = "1.2.2" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -4600,7 +4600,7 @@ dependencies = [ [[package]] name = "foundry-test-utils" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-primitives", "alloy-provider", @@ -4626,7 +4626,7 @@ dependencies = [ [[package]] name = "foundry-wallets" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy-consensus", "alloy-dyn-abi", diff --git a/Cargo.toml b/Cargo.toml index 3bec268c9722f..468f65510b0ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ members = [ resolver = "2" [workspace.package] -version = "1.2.1" +version = "1.2.2" edition = "2021" # Remember to update clippy.toml as well rust-version = "1.86" From 788ba28bdbaae1c1e076bd965bbadc757760ce32 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Fri, 30 May 2025 14:27:09 +0300 Subject: [PATCH 155/244] fix(cast): read all lines for message to hash (#10671) --- crates/cast/src/args.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cast/src/args.rs b/crates/cast/src/args.rs index 6c686e24d0706..cf2fea5e47d28 100644 --- a/crates/cast/src/args.rs +++ b/crates/cast/src/args.rs @@ -626,7 +626,7 @@ pub async fn run_command(args: CastArgs) -> Result<()> { }; } CastSubcommand::HashMessage { message } => { - let message = stdin::unwrap_line(message)?; + let message = stdin::unwrap(message, false)?; sh_println!("{}", eip191_hash_message(message))? } CastSubcommand::SigEvent { event_string } => { From 197586f2c8a663b2c2607e93c6cc63958ba546ad Mon Sep 17 00:00:00 2001 From: Mablr <59505383+mablr@users.noreply.github.com> Date: Fri, 30 May 2025 16:05:12 +0200 Subject: [PATCH 156/244] feat(forge build): cache project selectors by default (#10651) * feat(forge build): cache project selectors by default Calls `cache_local_signatures` function like the "forge selectors cache" command. * refactor(forge build): update `cache_local_signatures` to accept an optional `cache_dir` No more need to unwrap the option value returned foundry's `config` crate * Move cache dir in cache sigs fn --------- Co-authored-by: grandizzy --- crates/cli/src/utils/cmd.rs | 5 +++- crates/forge/src/cmd/build.rs | 8 ++++++- crates/forge/src/cmd/selectors.rs | 3 +-- crates/forge/tests/cli/test_cmd.rs | 38 ++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/crates/cli/src/utils/cmd.rs b/crates/cli/src/utils/cmd.rs index 5f6d5b1074a92..1396d964db8aa 100644 --- a/crates/cli/src/utils/cmd.rs +++ b/crates/cli/src/utils/cmd.rs @@ -440,7 +440,10 @@ pub async fn print_traces( /// Traverse the artifacts in the project to generate local signatures and merge them into the cache /// file. -pub fn cache_local_signatures(output: &ProjectCompileOutput, cache_dir: &Path) -> Result<()> { +pub fn cache_local_signatures(output: &ProjectCompileOutput) -> Result<()> { + let Some(cache_dir) = Config::foundry_cache_dir() else { + eyre::bail!("Failed to get `cache_dir` to generate local signatures."); + }; let path = cache_dir.join("signatures"); let mut signatures = SignaturesCache::load(&path); for (_, artifact) in output.artifacts() { diff --git a/crates/forge/src/cmd/build.rs b/crates/forge/src/cmd/build.rs index e64569206775b..43b4c89104407 100644 --- a/crates/forge/src/cmd/build.rs +++ b/crates/forge/src/cmd/build.rs @@ -1,7 +1,10 @@ use super::{install, watch::WatchArgs}; use clap::Parser; use eyre::Result; -use foundry_cli::{opts::BuildOpts, utils::LoadConfig}; +use foundry_cli::{ + opts::BuildOpts, + utils::{cache_local_signatures, LoadConfig}, +}; use foundry_common::{compile::ProjectCompiler, shell}; use foundry_compilers::{ compilers::{multi::MultiCompilerLanguage, Language}, @@ -100,6 +103,9 @@ impl BuildArgs { let output = compiler.compile(&project)?; + // Cache project selectors. + cache_local_signatures(&output)?; + if format_json && !self.names && !self.sizes { sh_println!("{}", serde_json::to_string_pretty(&output.output())?)?; } diff --git a/crates/forge/src/cmd/selectors.rs b/crates/forge/src/cmd/selectors.rs index 5e858c9da9c58..e6ecdcbac7962 100644 --- a/crates/forge/src/cmd/selectors.rs +++ b/crates/forge/src/cmd/selectors.rs @@ -11,7 +11,6 @@ use foundry_common::{ selectors::{import_selectors, SelectorImportData}, }; use foundry_compilers::{artifacts::output_selection::ContractOutputSelection, info::ContractInfo}; -use foundry_config::Config; use std::fs::canonicalize; /// CLI arguments for `forge selectors`. @@ -95,7 +94,7 @@ impl SelectorsSubcommands { // compile the project to get the artifacts/abis let project = build_args.project()?; let outcome = ProjectCompiler::new().quiet(true).compile(&project)?; - cache_local_signatures(&outcome, &Config::foundry_cache_dir().unwrap())? + cache_local_signatures(&outcome)?; } Self::Upload { contract, all, project_paths } => { let build_args = BuildOpts { diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index af4b2aed7d0e7..0d33025249075 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -3828,3 +3828,41 @@ Encountered a total of 1 failing tests, 0 tests succeeded "#]]); }); + +// This test is a copy of `error_event_decode_with_cache` in cast/tests/cli/selectors.rs +// but it uses `forge build` to check that the project selectors are cached by default. +forgetest_init!(build_with_selectors_cache, |prj, cmd| { + prj.add_source( + "LocalProjectContract", + r#" +contract ContractWithCustomError { + error AnotherValueTooHigh(uint256, address); + event MyUniqueEventWithinLocalProject(uint256 a, address b); +} + "#, + ) + .unwrap(); + // Build and cache project selectors. + cmd.forge_fuse().args(["build"]).assert_success(); + + // Assert cast can decode custom error with local cache. + cmd.cast_fuse() + .args(["decode-error", "0x7191bc6200000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000D0004F"]) + .assert_success() + .stdout_eq(str![[r#" +AnotherValueTooHigh(uint256,address) +101 +0x0000000000000000000000000000000000D0004F + +"#]]); + // Assert cast can decode event with local cache. + cmd.cast_fuse() + .args(["decode-event", "0xbd3699995dcc867b64dbb607be2c33be38df9134bef1178df13bfb9446e73104000000000000000000000000000000000000000000000000000000000000004e00000000000000000000000000000000000000000000000000000dd00000004e"]) + .assert_success() + .stdout_eq(str![[r#" +MyUniqueEventWithinLocalProject(uint256,address) +78 +0x00000000000000000000000000000DD00000004e + +"#]]); +}); From 2d5161d443c3a4c124fb4de32c0b1b55bfdb0ce9 Mon Sep 17 00:00:00 2001 From: 0xrusowsky <90208954+0xrusowsky@users.noreply.github.com> Date: Fri, 30 May 2025 16:34:53 +0200 Subject: [PATCH 157/244] fix(forge lint): gas lints (#10667) * fix: gas lints * fix: use project paths to identify tests/scripts --- crates/forge/src/cmd/lint.rs | 3 ++- crates/lint/src/sol/gas/keccak.rs | 12 ++++++++++-- crates/lint/src/sol/mod.rs | 14 ++++++++++---- crates/lint/testdata/Keccak256.sol | 12 +++++++++--- crates/lint/testdata/Keccak256.stderr | 22 +++++++++++++++------- 5 files changed, 46 insertions(+), 17 deletions(-) diff --git a/crates/forge/src/cmd/lint.rs b/crates/forge/src/cmd/lint.rs index f81c252c40fdb..9de86faf276ec 100644 --- a/crates/forge/src/cmd/lint.rs +++ b/crates/forge/src/cmd/lint.rs @@ -45,6 +45,7 @@ impl LintArgs { pub fn run(self) -> Result<()> { let config = self.load_config()?; let project = config.project()?; + let path_config = config.project_paths(); // Expand ignore globs and canonicalize from the get go let ignored = expand_globs(&config.root, config.lint.ignore.iter())? @@ -105,7 +106,7 @@ impl LintArgs { return Err(eyre!("Linting not supported for this language")); } - let linter = SolidityLinter::new() + let linter = SolidityLinter::new(path_config) .with_json_emitter(self.json) .with_description(true) .with_lints(include) diff --git a/crates/lint/src/sol/gas/keccak.rs b/crates/lint/src/sol/gas/keccak.rs index 7316f4c4239b7..d6df396f27779 100644 --- a/crates/lint/src/sol/gas/keccak.rs +++ b/crates/lint/src/sol/gas/keccak.rs @@ -4,7 +4,7 @@ use crate::{ linter::EarlyLintPass, sol::{Severity, SolLint}, }; -use solar_ast::{Expr, ExprKind}; +use solar_ast::{CallArgsKind, Expr, ExprKind}; use solar_interface::kw; declare_forge_lint!( @@ -16,9 +16,17 @@ declare_forge_lint!( impl<'ast> EarlyLintPass<'ast> for AsmKeccak256 { fn check_expr(&mut self, ctx: &crate::linter::LintContext<'_>, expr: &'ast Expr<'ast>) { - if let ExprKind::Call(expr, _) = &expr.kind { + if let ExprKind::Call(expr, args) = &expr.kind { if let ExprKind::Ident(ident) = &expr.kind { if ident.name == kw::Keccak256 { + // Do not flag when hashing a single literal, as the compiler should optimize it + if let CallArgsKind::Unnamed(ref exprs) = args.kind { + if exprs.len() == 1 { + if let ExprKind::Lit(_, _) = exprs[0].kind { + return; + } + } + } ctx.emit(&ASM_KECCAK256, expr.span); } } diff --git a/crates/lint/src/sol/mod.rs b/crates/lint/src/sol/mod.rs index 463777d5b194a..47e08296c1eee 100644 --- a/crates/lint/src/sol/mod.rs +++ b/crates/lint/src/sol/mod.rs @@ -1,5 +1,5 @@ use crate::linter::{EarlyLintPass, EarlyLintVisitor, Lint, LintContext, Linter}; -use foundry_compilers::solc::SolcLanguage; +use foundry_compilers::{solc::SolcLanguage, ProjectPathsConfig}; use foundry_config::lint::Severity; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use solar_ast::{visit::Visit, Arena}; @@ -22,8 +22,9 @@ pub mod med; /// Linter implementation to analyze Solidity source code responsible for identifying /// vulnerabilities gas optimizations, and best practices. -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct SolidityLinter { + path_config: ProjectPathsConfig, severity: Option>, lints_included: Option>, lints_excluded: Option>, @@ -32,8 +33,9 @@ pub struct SolidityLinter { } impl SolidityLinter { - pub fn new() -> Self { + pub fn new(path_config: ProjectPathsConfig) -> Self { Self { + path_config, severity: None, lints_included: None, lints_excluded: None, @@ -73,11 +75,15 @@ impl SolidityLinter { let _ = sess.enter(|| -> Result<(), diagnostics::ErrorGuaranteed> { // Declare all available passes and lints let mut passes_and_lints = Vec::new(); - passes_and_lints.extend(gas::create_lint_passes()); passes_and_lints.extend(high::create_lint_passes()); passes_and_lints.extend(med::create_lint_passes()); passes_and_lints.extend(info::create_lint_passes()); + // Do not apply gas-severity rules on tests and scripts + if !self.path_config.is_test_or_script(file) { + passes_and_lints.extend(gas::create_lint_passes()); + } + // Filter based on linter config let mut passes: Vec>> = passes_and_lints .into_iter() diff --git a/crates/lint/testdata/Keccak256.sol b/crates/lint/testdata/Keccak256.sol index 8d3a3044bc8cd..f24d0d1d70344 100644 --- a/crates/lint/testdata/Keccak256.sol +++ b/crates/lint/testdata/Keccak256.sol @@ -1,13 +1,19 @@ contract AsmKeccak256 { + + // constants are optimized by the compiler + bytes32 constant HASH = keccak256("hello"); + bytes32 constant OTHER_HASH = keccak256(1234); + constructor(uint256 a, uint256 b) { keccak256(abi.encodePacked(a, b)); //~NOTE: hash using inline assembly to save gas } - function solidityHash(uint256 a, uint256 b) public view { - keccak256(abi.encodePacked(a, b)); //~NOTE: hash using inline assembly to save gas + function solidityHash(uint256 a, uint256 b) public view returns (bytes32) { + bytes32 hash = keccak256(a); //~NOTE: hash using inline assembly to save gas + return keccak256(abi.encodePacked(a, b)); //~NOTE: hash using inline assembly to save gas } - function assemblyHash(uint256 a, uint256 b) public view { + function assemblyHash(uint256 a, uint256 b) public view returns (bytes32){ //optimized assembly { mstore(0x00, a) diff --git a/crates/lint/testdata/Keccak256.stderr b/crates/lint/testdata/Keccak256.stderr index 8011afa89a112..49957a7e97d85 100644 --- a/crates/lint/testdata/Keccak256.stderr +++ b/crates/lint/testdata/Keccak256.stderr @@ -1,16 +1,24 @@ note[asm-keccak256]: hash using inline assembly to save gas --> ROOT/testdata/Keccak256.sol:LL:CC | -3 | keccak256(abi.encodePacked(a, b)); +8 | keccak256(abi.encodePacked(a, b)); | --------- | = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 note[asm-keccak256]: hash using inline assembly to save gas - --> ROOT/testdata/Keccak256.sol:LL:CC - | -7 | keccak256(abi.encodePacked(a, b)); - | --------- - | - = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 + --> ROOT/testdata/Keccak256.sol:LL:CC + | +12 | bytes32 hash = keccak256(a); + | --------- + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 + +note[asm-keccak256]: hash using inline assembly to save gas + --> ROOT/testdata/Keccak256.sol:LL:CC + | +13 | return keccak256(abi.encodePacked(a, b)); + | --------- + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256 From 62ce5bc62f5951ea0575c8df70b4f855beef3af1 Mon Sep 17 00:00:00 2001 From: Cypher Pepe <125112044+cypherpepe@users.noreply.github.com> Date: Sat, 31 May 2025 22:07:34 +0300 Subject: [PATCH 158/244] chore: fixed dead link in `ui_runner.rs` (#10645) * Update dead link in `ui_runner.rs` * Update crates/test-utils/src/ui_runner.rs --------- Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- crates/test-utils/src/ui_runner.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/test-utils/src/ui_runner.rs b/crates/test-utils/src/ui_runner.rs index 9f6b87a8055ce..6e9f94d3c6ee9 100644 --- a/crates/test-utils/src/ui_runner.rs +++ b/crates/test-utils/src/ui_runner.rs @@ -1,7 +1,7 @@ use std::path::Path; use ui_test::spanned::Spanned; -/// Test runner based on `ui_test`. Adapted from `https://github.com/paradigmxyz/solar/tools/tester`. +/// Test runner based on `ui_test`. Adapted from `https://github.com/paradigmxyz/solar/blob/main/tools/tester/src/lib.rs`. pub fn run_tests<'a>(cmd: &str, cmd_path: &'a Path, testdata: &'a Path) -> eyre::Result<()> { ui_test::color_eyre::install()?; From 7b18dc8f5be44ad248cbea0bf45723f689627555 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Sun, 1 Jun 2025 19:54:01 +0200 Subject: [PATCH 159/244] fix: populate missing fields for eth simulate (#10682) * fix: populate missing fields for eth simulate * fmt --- crates/anvil/src/eth/backend/mem/mod.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 321ed41ea3925..31448721e139c 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -1680,6 +1680,7 @@ impl Backend { request, Signature::new(Default::default(), Default::default(), false), )?; + let tx_hash = tx.hash(); let rpc_tx = transaction_build( None, MaybeImpersonatedTransaction::impersonated(tx, from), @@ -1713,20 +1714,22 @@ impl Backend { removed: false, block_hash: None, - transaction_hash: None, + transaction_hash: Some(tx_hash), }) .collect(), }; + let receipt = Receipt { status: result.is_success().into(), cumulative_gas_used: result.gas_used(), - logs:sim_res.logs.clone() + logs: sim_res.logs.clone() }; receipts.push(receipt.with_bloom()); logs.extend(sim_res.logs.clone().iter().map(|log| log.inner.clone())); log_index += sim_res.logs.len(); call_res.push(sim_res); } + let transactions_envelopes: Vec = transactions .iter() .map(|tx| AnyTxEnvelope::from(tx.clone())) @@ -1736,7 +1739,6 @@ impl Backend { transactions_root: calculate_transaction_root(&transactions_envelopes), receipts_root: calculate_receipt_root(&transactions_envelopes), parent_hash: Default::default(), - ommers_hash: Default::default(), beneficiary: block_env.beneficiary, state_root: Default::default(), difficulty: Default::default(), @@ -1753,6 +1755,7 @@ impl Backend { excess_blob_gas: None, parent_beacon_block_root: None, requests_hash: None, + ..Default::default() }; let mut block = alloy_rpc_types::Block { header: AnyRpcHeader { @@ -1770,6 +1773,12 @@ impl Backend { block.transactions.convert_to_hashes(); } + for res in &mut call_res { + res.logs.iter_mut().for_each(|log| { + log.block_hash = Some(block.header.hash); + }); + } + let simulated_block = SimulatedBlock { inner: AnyRpcBlock::new(WithOtherFields::new(block)), calls: call_res, From b42d5121ba3f03099b1d649ab71f2100a212d3f3 Mon Sep 17 00:00:00 2001 From: Ethan Nguyen Date: Mon, 2 Jun 2025 06:43:38 -0700 Subject: [PATCH 160/244] chore: Add unused deps lint (#10666) * add missing dependency linters * add dependency linter to binaries * remove comment * remove linter from main.rs * remove unused deps, silence linter warnings * move imports to dev dependencies --- Cargo.lock | 4 ---- crates/anvil/Cargo.toml | 2 +- crates/anvil/src/lib.rs | 1 + crates/cast/Cargo.toml | 14 ++++---------- crates/cast/src/lib.rs | 1 + crates/chisel/src/lib.rs | 1 + crates/common/fmt/src/lib.rs | 2 ++ crates/forge/Cargo.toml | 12 +++++------- crates/forge/src/lib.rs | 1 + crates/script-sequence/src/lib.rs | 1 + crates/sol-macro-gen/src/lib.rs | 1 + 11 files changed, 18 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9857ec20187bf..c7fc1c0c56603 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2367,7 +2367,6 @@ dependencies = [ "alloy-sol-types", "alloy-transport", "anvil", - "aws-sdk-kms", "chrono", "clap", "clap_complete", @@ -2386,7 +2385,6 @@ dependencies = [ "foundry-test-utils", "foundry-wallets", "futures", - "gcloud-sdk", "itertools 0.14.0", "op-alloy-consensus", "op-alloy-flz", @@ -3842,7 +3840,6 @@ dependencies = [ "serde_json", "similar", "similar-asserts", - "solar-interface", "solar-parse", "soldeer-commands", "strum 0.27.1", @@ -3850,7 +3847,6 @@ dependencies = [ "tempfile", "thiserror 2.0.12", "tokio", - "toml 0.8.22", "toml_edit", "tower-http", "tracing", diff --git a/crates/anvil/Cargo.toml b/crates/anvil/Cargo.toml index 23ff53b271895..35aee11fcdeb3 100644 --- a/crates/anvil/Cargo.toml +++ b/crates/anvil/Cargo.toml @@ -91,7 +91,6 @@ thiserror.workspace = true yansi.workspace = true tempfile.workspace = true itertools.workspace = true -rand.workspace = true rand_08.workspace = true eyre.workspace = true @@ -110,6 +109,7 @@ clap_complete_fig = "4" [dev-dependencies] alloy-provider = { workspace = true, features = ["txpool-api"] } alloy-pubsub.workspace = true +rand.workspace = true foundry-test-utils.workspace = true tokio = { workspace = true, features = ["full"] } diff --git a/crates/anvil/src/lib.rs b/crates/anvil/src/lib.rs index 5ee4fead559b2..903afeea8b50a 100644 --- a/crates/anvil/src/lib.rs +++ b/crates/anvil/src/lib.rs @@ -1,6 +1,7 @@ //! Anvil is a fast local Ethereum development node. #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] use crate::{ eth::{ diff --git a/crates/cast/Cargo.toml b/crates/cast/Cargo.toml index 2dda3ba341872..d08d10fc6fce9 100644 --- a/crates/cast/Cargo.toml +++ b/crates/cast/Cargo.toml @@ -53,7 +53,6 @@ alloy-signer.workspace = true alloy-sol-types.workspace = true alloy-transport.workspace = true alloy-ens = { workspace = true, features = ["provider"] } -alloy-hardforks.workspace = true op-alloy-flz.workspace = true op-alloy-consensus = { workspace = true, features = ["alloy-compat"] } @@ -68,12 +67,6 @@ rayon.workspace = true serde_json.workspace = true serde.workspace = true -# aws-kms -aws-sdk-kms = { workspace = true, default-features = false, optional = true } - -# gcp-kms -gcloud-sdk = { version = "0.27", default-features = false, optional = true } - # bin foundry-cli.workspace = true @@ -95,6 +88,7 @@ evmole.workspace = true [dev-dependencies] anvil.workspace = true foundry-test-utils.workspace = true +alloy-hardforks.workspace = true [features] default = ["jemalloc"] @@ -102,6 +96,6 @@ asm-keccak = ["alloy-primitives/asm-keccak"] jemalloc = ["foundry-cli/jemalloc"] mimalloc = ["foundry-cli/mimalloc"] tracy-allocator = ["foundry-cli/tracy-allocator"] -aws-kms = ["foundry-wallets/aws-kms", "dep:aws-sdk-kms"] -gcp-kms = ["foundry-wallets/gcp-kms", "dep:gcloud-sdk"] -isolate-by-default = ["foundry-config/isolate-by-default"] +aws-kms = ["foundry-wallets/aws-kms"] +gcp-kms = ["foundry-wallets/gcp-kms"] +isolate-by-default = ["foundry-config/isolate-by-default"] \ No newline at end of file diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 434d1fec892ba..1b5db80406f30 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -1,6 +1,7 @@ //! Cast is a Swiss Army knife for interacting with Ethereum applications from the command line. #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] use alloy_consensus::TxEnvelope; use alloy_dyn_abi::{DynSolType, DynSolValue, FunctionExt}; diff --git a/crates/chisel/src/lib.rs b/crates/chisel/src/lib.rs index b369dec13b1ea..32a29caefc1b8 100644 --- a/crates/chisel/src/lib.rs +++ b/crates/chisel/src/lib.rs @@ -1,6 +1,7 @@ //! Chisel is a fast, utilitarian, and verbose Solidity REPL. #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] #[macro_use] extern crate foundry_common; diff --git a/crates/common/fmt/src/lib.rs b/crates/common/fmt/src/lib.rs index fa1c4543d6463..473e5d8a33c38 100644 --- a/crates/common/fmt/src/lib.rs +++ b/crates/common/fmt/src/lib.rs @@ -1,5 +1,7 @@ //! Helpers for formatting Ethereum types. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + mod console; pub use console::{console_format, ConsoleFmt, FormatSpec}; diff --git a/crates/forge/Cargo.toml b/crates/forge/Cargo.toml index d823ca3285140..f9845b8a80180 100644 --- a/crates/forge/Cargo.toml +++ b/crates/forge/Cargo.toml @@ -30,9 +30,7 @@ foundry-compilers = { workspace = true, features = ["full"] } foundry-config.workspace = true foundry-evm.workspace = true foundry-evm-core.workspace = true -foundry-wallets.workspace = true foundry-linking.workspace = true -forge-script-sequence.workspace = true comfy-table.workspace = true eyre.workspace = true @@ -63,7 +61,6 @@ alloy-rpc-types.workspace = true alloy-serde.workspace = true alloy-signer.workspace = true alloy-transport.workspace = true -alloy-hardforks.workspace = true revm.workspace = true @@ -71,23 +68,19 @@ clap = { version = "4", features = ["derive", "env", "unicode", "wrap_help"] } clap_complete = "4" clap_complete_fig = "4" dunce.workspace = true -futures.workspace = true indicatif.workspace = true inferno = { version = "0.12", default-features = false } itertools.workspace = true parking_lot.workspace = true regex = { workspace = true, default-features = false } -reqwest = { workspace = true, features = ["json"] } semver.workspace = true serde_json.workspace = true similar = { version = "2", features = ["inline"] } solang-parser.workspace = true solar-parse.workspace = true -solar-interface.workspace = true strum = { workspace = true, features = ["derive"] } thiserror.workspace = true tokio = { workspace = true, features = ["time"] } -toml = { workspace = true, features = ["preserve_order"] } toml_edit = "0.22" watchexec = "8.0" watchexec-events = "6.0" @@ -105,8 +98,13 @@ soldeer-commands.workspace = true quick-junit = "0.5.0" [dev-dependencies] +alloy-hardforks.workspace = true anvil.workspace = true +forge-script-sequence.workspace = true foundry-test-utils.workspace = true +foundry-wallets.workspace = true +futures.workspace = true +reqwest = { workspace = true, features = ["json"] } mockall = "0.13" globset = "0.4" diff --git a/crates/forge/src/lib.rs b/crates/forge/src/lib.rs index 4c7d135767719..fc2f71466bda4 100644 --- a/crates/forge/src/lib.rs +++ b/crates/forge/src/lib.rs @@ -1,5 +1,6 @@ //! Forge is a fast and flexible Ethereum testing framework. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #[macro_use] diff --git a/crates/script-sequence/src/lib.rs b/crates/script-sequence/src/lib.rs index 929f44a724b8c..7f253d7437ef2 100644 --- a/crates/script-sequence/src/lib.rs +++ b/crates/script-sequence/src/lib.rs @@ -1,4 +1,5 @@ //! Script Sequence and related types. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] #[macro_use] extern crate foundry_common; diff --git a/crates/sol-macro-gen/src/lib.rs b/crates/sol-macro-gen/src/lib.rs index 9984c6cce2b21..2cc229621155e 100644 --- a/crates/sol-macro-gen/src/lib.rs +++ b/crates/sol-macro-gen/src/lib.rs @@ -1,4 +1,5 @@ //! This crate contains the logic for Rust bindings generating from Solidity contracts +#![cfg_attr(not(test), warn(unused_crate_dependencies))] pub mod sol_macro_gen; From 1d25ca5fa79c95d293111c0d83ee6260881dce16 Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Tue, 3 Jun 2025 08:28:53 +0200 Subject: [PATCH 161/244] chore(`Makefile`): add .PHONY, fix help formatting (#10686) --- Makefile | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 8b9ccd21acdb8..0e98b93d9f48f 100644 --- a/Makefile +++ b/Makefile @@ -5,8 +5,10 @@ # Cargo profile for builds. PROFILE ?= dev + # The docker image name DOCKER_IMAGE_NAME ?= ghcr.io/foundry-rs/foundry:latest + BIN_DIR = dist/bin CARGO_TARGET_DIR ?= target @@ -22,7 +24,7 @@ endif .PHONY: help help: ## Display this help. - @awk 'BEGIN {FS = ":.*##"; printf "Usage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + @awk 'BEGIN {FS = ":.*##"; printf "Usage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) ##@ Build @@ -90,10 +92,12 @@ test: ## Run all tests. ##@ Linting +.PHONY: fmt fmt: ## Run all formatters. cargo +nightly fmt ./.github/scripts/format.sh --check +.PHONY: lint-clippy lint-clippy: ## Run clippy on the codebase. cargo +nightly clippy \ --workspace \ @@ -101,6 +105,7 @@ lint-clippy: ## Run clippy on the codebase. --all-features \ -- -D warnings +.PHONY: lint-codespell lint-codespell: ## Run codespell on the codebase. @command -v codespell >/dev/null || { \ echo "codespell not found. Please install it by running the command `pipx install codespell` or refer to the following link for more information: https://github.com/codespell-project/codespell" \ @@ -108,6 +113,7 @@ lint-codespell: ## Run codespell on the codebase. } codespell --skip "*.json" +.PHONY: lint lint: ## Run all linters. make fmt && \ make lint-clippy && \ @@ -119,6 +125,12 @@ lint: ## Run all linters. clean: ## Clean the project. cargo clean -pr: ## Run all tests and linters in preparation for a PR. +.PHONY: deny +deny: ## Perform a `cargo` deny check. + cargo deny --all-features check all + +.PHONY: pr +pr: ## Run all checks and tests. + make deny && \ make lint && \ - make test + make test \ No newline at end of file From 132cb13fca169b5580b88639c0bde74638ce1e3f Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 3 Jun 2025 09:29:36 +0300 Subject: [PATCH 162/244] chore: fix clippy (#10687) --- crates/evm/core/src/opts.rs | 2 +- crates/forge/src/cmd/eip712.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/evm/core/src/opts.rs b/crates/evm/core/src/opts.rs index 11a602aab868f..d02050112716b 100644 --- a/crates/evm/core/src/opts.rs +++ b/crates/evm/core/src/opts.rs @@ -220,7 +220,7 @@ impl EvmOpts { if self.no_rpc_rate_limit { u64::MAX } else if let Some(cups) = self.compute_units_per_second { - return cups; + cups } else { ALCHEMY_FREE_TIER_CUPS } diff --git a/crates/forge/src/cmd/eip712.rs b/crates/forge/src/cmd/eip712.rs index 3c85840673d6a..72fbea0a4874a 100644 --- a/crates/forge/src/cmd/eip712.rs +++ b/crates/forge/src/cmd/eip712.rs @@ -229,9 +229,9 @@ impl Resolver { name }; - return Ok(Some(name)) + Ok(Some(name)) } else { - return Ok(None) + Ok(None) } } } From 665fc043921a32cf7c718af7efbf2e00266fb6ff Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Tue, 3 Jun 2025 10:40:57 +0200 Subject: [PATCH 163/244] chore: activate `prague` hardfork and Solidity version `0.8.30` as default (#10565) * start defaulting to prague, add fix for blob handle scaling post cancun * fix anvil test * switch to 0.8.30 for tests * switch foundry-compilers to default to prague, small test fixes * add workaround for Vyper not yet supporting Prague * fix issues * fix tests, questionable gas difference and address difference * make prague explicit * fix clippy * bump compilers version * bump to 0.16.3 * pass in blob params, add normalize vyper evm version helper, fix solar iter 0.1.4 * temporarily allow compilers git patch * bump to msrv 1.87 in line with foundry-compilers * bump compilers version * bump to foundry-compilers 0.17.1 --- Cargo.lock | 351 ++++++++++++----------- Cargo.toml | 15 +- clippy.toml | 2 +- crates/anvil/src/eth/backend/mem/mod.rs | 14 +- crates/anvil/src/eth/fees.rs | 14 +- crates/anvil/src/lib.rs | 7 + crates/cast/src/cmd/run.rs | 2 +- crates/cast/tests/cli/main.rs | 2 +- crates/common/src/preprocessor/deps.rs | 2 +- crates/config/README.md | 2 +- crates/config/src/lib.rs | 6 +- crates/config/src/vyper.rs | 12 +- crates/forge/src/cmd/compiler.rs | 17 +- crates/forge/tests/cli/cmd.rs | 2 +- crates/forge/tests/cli/compiler.rs | 16 +- crates/forge/tests/cli/config.rs | 12 +- crates/forge/tests/cli/script.rs | 2 +- crates/forge/tests/cli/test_cmd.rs | 22 +- crates/forge/tests/cli/test_optimizer.rs | 4 +- crates/forge/tests/it/test_helpers.rs | 2 +- crates/test-utils/src/util.rs | 2 +- deny.toml | 1 + 22 files changed, 275 insertions(+), 234 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c7fc1c0c56603..846624478eeac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,9 +70,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7329eb72d95576dfb8813175bcf671198fb24266b0b3e520052a513e30c284df" +checksum = "ad451f9a70c341d951bca4e811d74dbe1e193897acd17e9dbac1353698cc430b" dependencies = [ "alloy-eips", "alloy-primitives", @@ -94,9 +94,9 @@ dependencies = [ [[package]] name = "alloy-consensus-any" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31b286aeef04a32720c10defd21c3aa6c626154ac442b55f6d472caeb1c6741" +checksum = "142daffb15d5be1a2b20d2cd540edbcef03037b55d4ff69dc06beb4d06286dba" dependencies = [ "alloy-consensus", "alloy-eips", @@ -108,9 +108,9 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1658352ca9425d7b5bbb3ae364bc276ab18d4afae06f5faf00377b6964fdf68" +checksum = "ebf25443920ecb9728cb087fe4dc04a0b290bd6ac85638c58fe94aba70f1a44e" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -187,9 +187,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fa190bfa5340aee544ac831114876fa73bc8da487095b49a5ea153a6a4656ea" +checksum = "3056872f6da48046913e76edb5ddced272861f6032f09461aea1a2497be5ae5d" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -207,9 +207,9 @@ dependencies = [ [[package]] name = "alloy-ens" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecbc80925fcfa5fa20ad45392535a98f586ee96ad75f8e801ca7e4d9176e0c4" +checksum = "939f8a617f883de8c8da812fa1164abe83f5ece081322ac072483fa0775a9898" dependencies = [ "alloy-contract", "alloy-primitives", @@ -240,9 +240,9 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b81b2dfd278d58af8bfde8753fa4685407ba8fbad8bc88a2bb0e065eed48478" +checksum = "c98fb40f07997529235cc474de814cd7bd9de561e101716289095696c0e4639d" dependencies = [ "alloy-eips", "alloy-primitives", @@ -278,9 +278,9 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ab2dba5dca01ad4281b4d4726a18e2012a20e3950bfc2a90c5376840555366" +checksum = "dc08b31ebf9273839bd9a01f9333cbb7a3abb4e820c312ade349dd18bdc79581" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -292,9 +292,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ed07e76fbc72790a911ea100cdfbe85b1f12a097c91b948042e854959d140e" +checksum = "ed117b08f0cc190312bf0c38c34cf4f0dabfb4ea8f330071c587cd7160a88cb2" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -318,9 +318,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05aa52713c376f797b3c7077708585f22a5c3053a7b1b2b355ea98edeb2052d" +checksum = "c7162ff7be8649c0c391f4e248d1273e85c62076703a1f3ec7daf76b283d886d" dependencies = [ "alloy-consensus", "alloy-eips", @@ -389,9 +389,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05a3f7a59c276c6e410267e77a166f9297dbe74e4605f1abf625e29d85c53144" +checksum = "d84eba1fd8b6fe8b02f2acd5dd7033d0f179e304bd722d11e817db570d1fa6c4" dependencies = [ "alloy-chains", "alloy-consensus", @@ -434,9 +434,9 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc3cbf02fdedbec7aadc7a77080b6b143752fa792c7fd49b86fd854257688bd4" +checksum = "8550f7306e0230fc835eb2ff4af0a96362db4b6fc3f25767d161e0ad0ac765bf" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -477,9 +477,9 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f185483536cbcbf55971077140e03548dad4f3a4ddb35044bcdc01b8f02ce1" +checksum = "518a699422a3eab800f3dac2130d8f2edba8e4fff267b27a9c7dc6a2b0d313ee" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -505,9 +505,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "347dfd77ba4d74886dba9e2872ff64fb246001b08868d27baec94e7248503e08" +checksum = "c000cab4ec26a4b3e29d144e999e1c539c2fa0abed871bf90311eb3466187ca8" dependencies = [ "alloy-primitives", "alloy-rpc-types-anvil", @@ -521,9 +521,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e15bd6456742d6dcadacf3cd238a90a8a7aa9f00bc7cc641ae272f5d3f5d4f" +checksum = "8abecc34549a208b5f91bc7f02df3205c36e2aa6586f1d9375c3382da1066b3b" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -533,9 +533,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67971a228100ac65bd86e90439028853435f21796330ef08f00a70a918a84126" +checksum = "508b2fbe66d952089aa694e53802327798806498cd29ff88c75135770ecaabfc" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -544,9 +544,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-debug" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe8bc37b23e788c0f8081a7eec34fd439cfa8d4f137f6e987803fb2a733866ca" +checksum = "8c832f2e851801093928dbb4b7bd83cd22270faf76b2e080646b806a285c8757" dependencies = [ "alloy-primitives", "serde", @@ -554,9 +554,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bcf49fe91b3d621440dcc5bb067afaeba5ca4b07f59e42fb7af42944146a8c0" +checksum = "cab52691970553d84879d777419fa7b6a2e92e9fe8641f9324cc071008c2f656" dependencies = [ "alloy-consensus", "alloy-eips", @@ -572,9 +572,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d9b4293dfd4721781d33ee40de060376932d4a55d421cf6618ad66ff97cc52" +checksum = "fcaf7dff0fdd756a714d58014f4f8354a1706ebf9fa2cf73431e0aeec3c9431e" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -592,9 +592,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f68f020452c0d570b4eee22d4ffda9e4eda68ebcf67e1199d6dff48097f442b" +checksum = "6e3507a04e868dd83219ad3cd6a8c58aefccb64d33f426b3934423a206343e84" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -606,9 +606,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62a82f15f296c2c83c55519d21ca07801fb58b118878b0f4777250968e49f4fe" +checksum = "eec36272621c3ac82b47dd77f0508346687730b1c2e3e10d3715705c217c0a05" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -618,9 +618,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7d927aa39ca51545ae4c9cf4bdb2cbc1f6b46ab4b54afc3ed9255f93eedbce" +checksum = "730e8f2edf2fc224cabd1c25d090e1655fa6137b2e409f92e5eec735903f1507" dependencies = [ "alloy-primitives", "serde", @@ -629,9 +629,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c63771b50008d2b079187e9e74a08235ab16ecaf4609b4eb895e2890a3bcd465" +checksum = "6b0d2428445ec13edc711909e023d7779618504c4800be055a5b940025dbafe3" dependencies = [ "alloy-dyn-abi", "alloy-primitives", @@ -646,9 +646,9 @@ dependencies = [ [[package]] name = "alloy-signer-aws" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27a8f3d6f2e11b5a4f73ab34f3b2b526684e6b26e2a2ebf2264c1dae45030451" +checksum = "6be3d371299b62eac5aa459fa58e8d1c761aabdc637573ae258ab744457fcc88" dependencies = [ "alloy-consensus", "alloy-network", @@ -664,9 +664,9 @@ dependencies = [ [[package]] name = "alloy-signer-gcp" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af53c8eb7b94b8a9b915b64a0fc56b4c1fde247d8aeb421504f25d673a4d360a" +checksum = "df298e47bbb7d0a8e06b603046b91062c11ba70d22f8a6c9bab1c1468bd856d0" dependencies = [ "alloy-consensus", "alloy-network", @@ -682,9 +682,9 @@ dependencies = [ [[package]] name = "alloy-signer-ledger" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86a43041a6f1c5b63659860311ab14ea765bf9cef3293322988d896a0b8c88c" +checksum = "3b0e049299cc7e131a438a904f89a493bcea45cd92bbed3e50116a28bc27987c" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -702,9 +702,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db906294ee7876bd332cd760f460d30de183554434e07fc19d7d54e16a7aeaf0" +checksum = "e14fe6fedb7fe6e0dfae47fe020684f1d8e063274ef14bca387ddb7a6efa8ec1" dependencies = [ "alloy-consensus", "alloy-network", @@ -721,9 +721,9 @@ dependencies = [ [[package]] name = "alloy-signer-trezor" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2277b489b01e6178fc5404c978bdc82b211c9c50de4b1e0efb75ecea3eb2bf54" +checksum = "26c7df3624131eeecf74c18e5cd59bcc125633bad407b1938161edf89eb71485" dependencies = [ "alloy-consensus", "alloy-network", @@ -811,9 +811,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca9b645fe4f4e6582cfbb4a8d20cedcf5aa23548e92eacbdacac6278b425e023" +checksum = "a712bdfeff42401a7dd9518f72f617574c36226a9b5414537fedc34350b73bf9" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -834,9 +834,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee18869ecabe658ff6316e7db7c25d958c7d10f0a1723c2f7447d4f402920b66" +checksum = "7ea5a76d7f2572174a382aedf36875bedf60bcc41116c9f031cf08040703a2dc" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -849,9 +849,9 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff95f0b3a3bd2b80a53a52f7649ea6ef3e7e91ff4bd439871199ec68b1b69038" +checksum = "606af17a7e064d219746f6d2625676122c79d78bf73dfe746d6db9ecd7dbcb85" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -869,9 +869,9 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c838e7562d16110fba3590a20c7765281c1a302cf567e1806d0c3ce1352b58" +checksum = "e0c6f9b37cd8d44aab959613966cc9d4d7a9b429c575cec43b3e5b46ea109a79" dependencies = [ "alloy-pubsub", "alloy-transport", @@ -1675,9 +1675,9 @@ dependencies = [ [[package]] name = "aws-sdk-kms" -version = "1.71.0" +version = "1.72.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de993b5250e1aa051f4091ab772ce164de8c078ee9793fdee033b20f7d371ad" +checksum = "0eef6a94141a43ee28404bf135828ad9bdd4936bfa2a84ad8dea355c94646a35" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1697,9 +1697,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.70.0" +version = "1.71.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83447efb7179d8e2ad2afb15ceb9c113debbc2ecdf109150e338e2e28b86190b" +checksum = "95a4fd09d6e863655d99cd2260f271c6d1030dc6bfad68e19e126d2e4c8ceb18" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1719,9 +1719,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.71.0" +version = "1.72.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f9bfbbda5e2b9fe330de098f14558ee8b38346408efe9f2e9cee82dc1636a4" +checksum = "3224ab02ebb3074467a33d57caf6fcb487ca36f3697fdd381b0428dc72380696" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1741,9 +1741,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.71.0" +version = "1.72.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17b984a66491ec08b4f4097af8911251db79296b3e4a763060b45805746264f" +checksum = "f6933f189ed1255e78175fbd73fb200c0aae7240d220ed3346f567b0ddca3083" dependencies = [ "aws-credential-types", "aws-runtime", @@ -2414,9 +2414,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.24" +version = "1.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7" +checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" dependencies = [ "jobserver", "libc", @@ -2541,9 +2541,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" dependencies = [ "clap_builder", "clap_derive", @@ -2561,9 +2561,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" dependencies = [ "anstream", "anstyle", @@ -2576,9 +2576,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.50" +version = "4.5.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91d3baa3bcd889d60e6ef28874126a0b384fd225ab83aa6d8a801c519194ce1" +checksum = "1a554639e42d0c838336fc4fbedb9e2df3ad1fa4acda149f9126b4ccfcd7900f" dependencies = [ "clap", ] @@ -2732,9 +2732,9 @@ dependencies = [ [[package]] name = "color-eyre" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e1761c0e16f8883bbbb8ce5990867f4f06bf11a0253da6495a04ce4b6ef0ec" +checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" dependencies = [ "backtrace", "color-spantrace", @@ -2747,9 +2747,9 @@ dependencies = [ [[package]] name = "color-spantrace" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5" +checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" dependencies = [ "once_cell", "owo-colors 4.2.1", @@ -2902,9 +2902,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -4031,9 +4031,9 @@ dependencies = [ [[package]] name = "foundry-block-explorers" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6129df264d2bd245ade4ed21a92f605bfd592dca8fb8e6e1adde1b9bd4288681" +checksum = "7dd57f39a860475780c0b001167b2bb9039e78d8d09323c6949897f5351ffae6" dependencies = [ "alloy-chains", "alloy-json-abi", @@ -4231,9 +4231,9 @@ dependencies = [ [[package]] name = "foundry-compilers" -version = "0.16.2" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a43ecf9100de8d31242b7a7cf965196e3d8fb424a931a975a7882897726f4c46" +checksum = "d14093062732cc5085a2ad6eb5ec1f20e5b6704b86fc4eeef7ba15f53f75178d" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4268,9 +4268,9 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts" -version = "0.16.2" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07ebb99f087075b97b68837de385f6cba07ca32314852a6507ce0dac5d66cd8" +checksum = "d2dfbae2e37ccb536b7dd85303fb0f006902a71218587f649129e9311e2ea646" dependencies = [ "foundry-compilers-artifacts-solc", "foundry-compilers-artifacts-vyper", @@ -4278,9 +4278,9 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-solc" -version = "0.16.2" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ddf6d61defb08103e351dc16df637c42d69407bae0f8789f2662a6161e73f5" +checksum = "d17f0a8f8c4ff296546cdb1985a460542bb39ab853815de8ba51b43c134e4051" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4301,9 +4301,9 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-vyper" -version = "0.16.2" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65a777326b8e0bba45345043ed80ceab5e84f3e474ba2ac19673b31076f3c6b4" +checksum = "5e87c18e3fed59ac0b7012f690eb3b0cc0e289e8e60601f438d427d9d85b8760" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4316,9 +4316,9 @@ dependencies = [ [[package]] name = "foundry-compilers-core" -version = "0.16.2" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be02912b222eb5bd8a4e8a249a488af3e2fb4fc08e0f17a3bc402406a91295b5" +checksum = "053b13c3ee670c41e86235df99805bdfedd88a5efb6bbe697925b69028218481" dependencies = [ "alloy-primitives", "cfg-if", @@ -4988,12 +4988,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "hermit-abi" version = "0.5.1" @@ -5197,22 +5191,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9f1e950e0d9d1d3c47184416723cf29c0d1f93bd8cccf37e4beb6b44f31710" +checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", + "futures-core", "futures-util", "http 1.3.1", "http-body 1.0.1", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -5451,13 +5451,23 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-terminal" version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi 0.5.1", + "hermit-abi", "libc", "windows-sys 0.59.0", ] @@ -5728,9 +5738,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", "windows-targets 0.53.0", @@ -5835,9 +5845,9 @@ checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -5978,9 +5988,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "mdbook" -version = "0.4.50" +version = "0.4.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f72bc08f096e1fb15cfc382babe218317c2897d2040f967c4db40d156ca28e21" +checksum = "a87e65420ab45ca9c1b8cdf698f95b710cc826d373fa550f0f7fad82beac9328" dependencies = [ "ammonia", "anyhow", @@ -5993,7 +6003,7 @@ dependencies = [ "hex", "log", "memchr", - "opener 0.8.1", + "opener 0.8.2", "pulldown-cmark", "regex", "serde", @@ -6365,11 +6375,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", ] @@ -6457,9 +6467,9 @@ dependencies = [ [[package]] name = "op-alloy-consensus" -version = "0.17.1" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb35d16e5420e43e400a235783e3d18b6ba564917139b668b48e9ac42cb3d35a" +checksum = "b2423a125ef2daa0d15dacc361805a0b6f76d6acfc6e24a1ff6473582087fe75" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6481,9 +6491,9 @@ checksum = "4ef71f23a8caf6f2a2d5cafbdc44956d44e6014dcb9aa58abf7e4e6481c6ec34" [[package]] name = "op-alloy-rpc-types" -version = "0.17.1" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7534a0ec6b8409edc511acbe77abe7805aa63129b98e9a915bb4eb8555eaa6ff" +checksum = "f82a315004b6720fbf756afdcfdc97ea7ddbcdccfec86ea7df7562bb0da29a3f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6500,9 +6510,9 @@ dependencies = [ [[package]] name = "op-revm" -version = "5.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47296d449fbe2d5cc74ab6e1213dee88cae3e2fd238343bec605c3c687bbcfab" +checksum = "c0e8a3830a2be82166fbe9ead34361149ff4320743ed7ee5502ab779de221361" dependencies = [ "auto_impl", "once_cell", @@ -6530,9 +6540,9 @@ dependencies = [ [[package]] name = "opener" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de96cad6ee771be7f68df884d3767460b4684012308d8342ed5623fe62b2628c" +checksum = "771b9704f8cd8b424ec747a320b30b47517a6966ba2c7da90047c16f4a962223" dependencies = [ "bstr", "normpath", @@ -6632,9 +6642,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -6642,9 +6652,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -6992,9 +7002,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" +checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" dependencies = [ "proc-macro2", "syn 2.0.101", @@ -7503,9 +7513,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "e98ff6b0dbbe4d5a37318f433d4fc82babd21631f194d370409ceb2e40b2f0b5" dependencies = [ "async-compression", "base64 0.22.1", @@ -7532,33 +7542,31 @@ dependencies = [ "quinn", "rustls", "rustls-native-certs", - "rustls-pemfile", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-rustls", "tokio-socks", "tokio-util", "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 0.26.11", - "windows-registry", + "webpki-roots 1.0.0", ] [[package]] name = "revm" -version = "24.0.0" +version = "24.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d3ae9d1b08303eb5150dcf820a29e14235cf3f24f6c09024458a4dcbffe6695" +checksum = "01d277408ff8d6f747665ad9e52150ab4caf8d5eaf0d787614cf84633c8337b4" dependencies = [ "revm-bytecode", "revm-context", @@ -7588,9 +7596,9 @@ dependencies = [ [[package]] name = "revm-context" -version = "5.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b181214eb2bbb76ee9d6195acba19857d991d2cdb9a65b7cb6939c30250a3966" +checksum = "b01aad49e1233f94cebda48a4e5cef022f7c7ed29b4edf0d202b081af23435ef" dependencies = [ "cfg-if", "derive-where", @@ -7646,9 +7654,9 @@ dependencies = [ [[package]] name = "revm-handler" -version = "5.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a9204e3ac1a8edb850cc441a6a1d0f2251c0089e5fffdaba11566429e6c64e" +checksum = "481e8c3290ff4fa1c066592fdfeb2b172edfd14d12e6cade6f6f5588cad9359a" dependencies = [ "auto_impl", "revm-bytecode", @@ -7664,9 +7672,9 @@ dependencies = [ [[package]] name = "revm-inspector" -version = "5.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae4881eeae6ff35417c8569bc7cc03b6c0969869ee2c9b3945a39b4f9fa58bc5" +checksum = "fdc1167ef8937d8867888e63581d8ece729a72073d322119ef4627d813d99ecb" dependencies = [ "auto_impl", "revm-context", @@ -7985,15 +7993,6 @@ dependencies = [ "security-framework", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" version = "1.12.0" @@ -8202,7 +8201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ "bitflags 2.9.1", - "core-foundation 0.10.0", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -8598,9 +8597,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -8608,9 +8607,9 @@ dependencies = [ [[package]] name = "solar-ast" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7960f42b73c63b78df9e223ea88ca87b7aaef91e3b5084b89d79ec31ad9fc8e3" +checksum = "acb0d9abd88c1325e5c0f9bb153ebfb02ed40bc9639067d0ad120f5d29ee8777" dependencies = [ "alloy-primitives", "bumpalo", @@ -8627,18 +8626,18 @@ dependencies = [ [[package]] name = "solar-config" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00ff62c74517305ddee6fdfa741bac8195826d2820586659341063c991fa4a9e" +checksum = "908d455bb7c04acd783bd157b63791bf010cf6a495a845e48f7aee334aad319f" dependencies = [ "strum 0.27.1", ] [[package]] name = "solar-data-structures" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c5934e613b60cfb0b2eadc035bac1fb57641026e4c2fb3683e9580391bd109" +checksum = "a8b5a697cab81241c4623b4546c69e57182202847a75d7c0047c0dd10b923d8c" dependencies = [ "bumpalo", "index_vec", @@ -8651,9 +8650,9 @@ dependencies = [ [[package]] name = "solar-interface" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a614174b9fa673b0a01cc8308d18578f32dd091359786368964bbd19e94e59f7" +checksum = "33e49e5a714ec80d7f9c8942584e5e86add1c5e824aa175d0681e9ac7a10e5cc" dependencies = [ "annotate-snippets", "anstream", @@ -8681,9 +8680,9 @@ dependencies = [ [[package]] name = "solar-macros" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccbdb5d9ecd4127af47279f99475f9fbff6ad3d03afc98ba78e1998bc07c0d46" +checksum = "e17f8b99f28f358b41acb6efe4d7b8f326541b3c58a15dd1931d6fe581feefef" dependencies = [ "proc-macro2", "quote", @@ -8692,9 +8691,9 @@ dependencies = [ [[package]] name = "solar-parse" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7965e27a45ca85135ffd45839f9623131175fb43d2ad3526d32de0946f250f1b" +checksum = "c6982ef2ecfb1338c774c743ab7166ce8c3dcc92089ab77fad58eeb632b201e9" dependencies = [ "alloy-primitives", "bitflags 2.9.1", @@ -8713,9 +8712,9 @@ dependencies = [ [[package]] name = "solar-sema" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e695824aaf984aa01493ebd5e7e83ddf84629d4a2667a0adf25cb6b65fa63e" +checksum = "fe8e0a3a6dfc7f4987bfb93f9b56079150407ef55c459964a1541c669554b74d" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -9507,9 +9506,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" +checksum = "5cc2d9e086a412a451384326f521c8123a99a466b329941a9403696bff9b0da2" dependencies = [ "bitflags 2.9.1", "bytes", @@ -9519,12 +9518,14 @@ dependencies = [ "http-body-util", "http-range-header", "httpdate", + "iri-string", "mime", "mime_guess", "percent-encoding", "pin-project-lite", "tokio", "tokio-util", + "tower", "tower-layer", "tower-service", "tracing", @@ -9660,9 +9661,9 @@ dependencies = [ [[package]] name = "tracy-client" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d90a2c01305b02b76fdd89ac8608bae27e173c829a35f7d76a345ab5d33836db" +checksum = "3927832d93178f979a970d26deed7b03510586e328f31b0f9ad7a73985b8332a" dependencies = [ "loom", "once_cell", @@ -9672,9 +9673,9 @@ dependencies = [ [[package]] name = "tracy-client-sys" -version = "0.24.3" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69fff37da548239c3bf9e64a12193d261e8b22b660991c6fd2df057c168f435f" +checksum = "c032d68a49d25d9012a864fef1c64ac17aee43c87e0477bf7301d8ae8bfea7b7" dependencies = [ "cc", "windows-targets 0.52.6", diff --git a/Cargo.toml b/Cargo.toml index 468f65510b0ec..61c0b30109e76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ resolver = "2" version = "1.2.2" edition = "2021" # Remember to update clippy.toml as well -rust-version = "1.86" +rust-version = "1.87" authors = ["Foundry Contributors"] license = "MIT OR Apache-2.0" homepage = "https://github.com/foundry-rs/foundry" @@ -198,14 +198,14 @@ foundry-wallets = { path = "crates/wallets" } foundry-linking = { path = "crates/linking" } # solc & compilation utilities -foundry-block-explorers = { version = "0.17.0", default-features = false } -foundry-compilers = { version = "0.16.1", default-features = false } +foundry-block-explorers = { version = "0.18.0", default-features = false } +foundry-compilers = { version = "0.17.1", default-features = false } foundry-fork-db = "0.15" solang-parser = { version = "=0.3.9", package = "foundry-solang-parser" } -solar-ast = { version = "=0.1.3", default-features = false } -solar-parse = { version = "=0.1.3", default-features = false } -solar-interface = { version = "=0.1.3", default-features = false } -solar-sema = { version = "=0.1.3", default-features = false } +solar-ast = { version = "=0.1.4", default-features = false } +solar-parse = { version = "=0.1.4", default-features = false } +solar-interface = { version = "=0.1.4", default-features = false } +solar-sema = { version = "=0.1.4", default-features = false } ## alloy alloy-consensus = { version = "1.0.7", default-features = false } @@ -401,4 +401,5 @@ zip-extract = "=0.2.1" # revm-inspectors = { git = "https://github.com/paradigmxyz/revm-inspectors.git", rev = "a625c04" } ## foundry +# foundry-compilers = { git = "https://github.com/foundry-rs/compilers.git", rev = "855dee4" } # foundry-fork-db = { git = "https://github.com/foundry-rs/foundry-fork-db", rev = "811a61a" } diff --git a/clippy.toml b/clippy.toml index f4a551607f2fe..6f0698f3c87ab 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,4 +1,4 @@ -msrv = "1.86" +msrv = "1.87" # `bytes::Bytes` is included by default and `alloy_primitives::Bytes` is a wrapper around it, # so it is safe to ignore it as well. diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 31448721e139c..4f34ca161eab5 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -780,11 +780,17 @@ impl Backend { /// Returns [`BlobParams`] corresponding to the current spec. pub fn blob_params(&self) -> BlobParams { - if self.env.read().evm_env.cfg_env.spec >= SpecId::PRAGUE { - BlobParams::prague() - } else { - BlobParams::cancun() + let spec_id = self.env.read().evm_env.cfg_env.spec; + + if spec_id >= SpecId::OSAKA { + return BlobParams::osaka(); } + + if spec_id >= SpecId::PRAGUE { + return BlobParams::prague(); + } + + BlobParams::cancun() } /// Returns an error if EIP1559 is not active (pre Berlin) diff --git a/crates/anvil/src/eth/fees.rs b/crates/anvil/src/eth/fees.rs index acec3a29201ac..a81c4117758f7 100644 --- a/crates/anvil/src/eth/fees.rs +++ b/crates/anvil/src/eth/fees.rs @@ -192,6 +192,8 @@ pub fn calculate_next_block_base_fee(gas_used: u64, gas_limit: u64, base_fee: u6 /// An async service that takes care of the `FeeHistory` cache pub struct FeeHistoryService { + /// blob parameters for the current spec + blob_params: BlobParams, /// incoming notifications about new blocks new_blocks: NewBlockNotifications, /// contains all fee history related entries @@ -204,11 +206,18 @@ pub struct FeeHistoryService { impl FeeHistoryService { pub fn new( + blob_params: BlobParams, new_blocks: NewBlockNotifications, cache: FeeHistoryCache, storage_info: StorageInfo, ) -> Self { - Self { new_blocks, cache, fee_history_limit: MAX_FEE_HISTORY_CACHE_SIZE, storage_info } + Self { + blob_params, + new_blocks, + cache, + fee_history_limit: MAX_FEE_HISTORY_CACHE_SIZE, + storage_info, + } } /// Returns the configured history limit @@ -245,7 +254,8 @@ impl FeeHistoryService { let base_fee = header.base_fee_per_gas.map(|g| g as u128).unwrap_or_default(); let excess_blob_gas = header.excess_blob_gas.map(|g| g as u128); let blob_gas_used = header.blob_gas_used.map(|g| g as u128); - let base_fee_per_blob_gas = header.blob_fee(BlobParams::cancun()); + let base_fee_per_blob_gas = header.blob_fee(self.blob_params); + let mut item = FeeHistoryCacheItem { base_fee, gas_used_ratio: 0f64, diff --git a/crates/anvil/src/lib.rs b/crates/anvil/src/lib.rs index 903afeea8b50a..c5ae402917b53 100644 --- a/crates/anvil/src/lib.rs +++ b/crates/anvil/src/lib.rs @@ -19,6 +19,7 @@ use crate::{ shutdown::Signal, tasks::TaskManager, }; +use alloy_eips::eip7840::BlobParams; use alloy_primitives::{Address, U256}; use alloy_signer_local::PrivateKeySigner; use eth::backend::fork::ClientFork; @@ -26,6 +27,7 @@ use eyre::Result; use foundry_common::provider::{ProviderBuilder, RetryProvider}; use futures::{FutureExt, TryFutureExt}; use parking_lot::Mutex; +use revm::primitives::hardfork::SpecId; use server::try_spawn_ipc; use std::{ future::Future, @@ -198,6 +200,11 @@ pub async fn try_spawn(mut config: NodeConfig) -> Result<(EthApi, NodeHandle)> { let fee_history_cache = Arc::new(Mutex::new(Default::default())); let fee_history_service = FeeHistoryService::new( + match backend.spec_id() { + SpecId::OSAKA => BlobParams::osaka(), + SpecId::PRAGUE => BlobParams::prague(), + _ => BlobParams::cancun(), + }, backend.new_block_notifications(), Arc::clone(&fee_history_cache), StorageInfo::new(Arc::clone(&backend)), diff --git a/crates/cast/src/cmd/run.rs b/crates/cast/src/cmd/run.rs index c586cf4c9ded4..04f52957ef668 100644 --- a/crates/cast/src/cmd/run.rs +++ b/crates/cast/src/cmd/run.rs @@ -165,7 +165,7 @@ impl RunArgs { if evm_version.is_none() { // if the block has the excess_blob_gas field, we assume it's a Cancun block if block.header.excess_blob_gas.is_some() { - evm_version = Some(EvmVersion::Cancun); + evm_version = Some(EvmVersion::Prague); } } apply_chain_and_block_specific_env_changes::(env.as_env_mut(), block); diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index eca950b2f89d4..c8ed087356250 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -2329,7 +2329,7 @@ contract CounterInExternalLibScript is Script { ... Traces: [..] → new @0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 - ├─ [..] 0x52F3e85EC3F0f9D0a2200D646482fcD134D5adc9::updateCounterInExternalLib(0, 100) [delegatecall] + ├─ [..] 0x6fD8bf6770F4bEe578348D24028000cE9c4D2bB9::updateCounterInExternalLib(0, 100) [delegatecall] │ └─ ← [Stop] └─ ← [Return] 62 bytes of code diff --git a/crates/common/src/preprocessor/deps.rs b/crates/common/src/preprocessor/deps.rs index 1348a1928e60e..7d0f31b1d6b92 100644 --- a/crates/common/src/preprocessor/deps.rs +++ b/crates/common/src/preprocessor/deps.rs @@ -234,7 +234,7 @@ impl<'hir> Visit<'hir> for BytecodeDependencyCollector<'hir> { for &var in clause.args { self.visit_nested_var(var)?; } - for stmt in clause.block { + for stmt in clause.block.stmts { self.visit_stmt(stmt)?; } } diff --git a/crates/config/README.md b/crates/config/README.md index be3055f5816f7..bd2b683f1bae4 100644 --- a/crates/config/README.md +++ b/crates/config/README.md @@ -79,7 +79,7 @@ allow_paths = [] # additional solc include paths include_paths = [] force = false -evm_version = 'shanghai' +evm_version = 'prague' gas_reports = ['*'] gas_reports_ignore = [] ## Sets the concrete solc version to use, this overrides the `auto_detect_solc` value diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 8224b6b203155..60ede7122f793 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -118,7 +118,7 @@ pub mod soldeer; use soldeer::{SoldeerConfig, SoldeerDependencyConfig}; mod vyper; -use vyper::VyperConfig; +pub use vyper::{normalize_evm_version_vyper, VyperConfig}; mod bind_json; use bind_json::BindJsonConfig; @@ -1549,7 +1549,7 @@ impl Config { /// - evm version pub fn vyper_settings(&self) -> Result { Ok(VyperSettings { - evm_version: Some(self.evm_version), + evm_version: Some(normalize_evm_version_vyper(self.evm_version)), optimize: self.vyper.optimize, bytecode_metadata: None, // TODO: We don't yet have a way to deserialize other outputs correctly, so request only @@ -2315,7 +2315,7 @@ impl Default for Config { allow_paths: vec![], include_paths: vec![], force: false, - evm_version: EvmVersion::Cancun, + evm_version: EvmVersion::Prague, gas_reports: vec!["*".to_string()], gas_reports_ignore: vec![], gas_reports_include_tests: false, diff --git a/crates/config/src/vyper.rs b/crates/config/src/vyper.rs index dbd47faec208d..12596e3bce401 100644 --- a/crates/config/src/vyper.rs +++ b/crates/config/src/vyper.rs @@ -1,6 +1,6 @@ //! Vyper specific configuration types. -use foundry_compilers::artifacts::vyper::VyperOptimizationMode; +use foundry_compilers::artifacts::{vyper::VyperOptimizationMode, EvmVersion}; use serde::{Deserialize, Serialize}; use std::path::PathBuf; @@ -16,3 +16,13 @@ pub struct VyperConfig { #[serde(default, skip_serializing_if = "Option::is_none")] pub experimental_codegen: Option, } + +/// Vyper does not yet support the Prague EVM version, so we normalize it to Cancun. +/// This is a temporary workaround until Vyper supports Prague. +pub fn normalize_evm_version_vyper(evm_version: EvmVersion) -> EvmVersion { + if evm_version >= EvmVersion::Prague { + return EvmVersion::Cancun; + } + + evm_version +} diff --git a/crates/forge/src/cmd/compiler.rs b/crates/forge/src/cmd/compiler.rs index 19e4354ca9cb4..82e9bf14ecee0 100644 --- a/crates/forge/src/cmd/compiler.rs +++ b/crates/forge/src/cmd/compiler.rs @@ -2,7 +2,7 @@ use clap::{Parser, Subcommand, ValueHint}; use eyre::Result; use foundry_common::shell; use foundry_compilers::{artifacts::EvmVersion, Graph}; -use foundry_config::Config; +use foundry_config::{normalize_evm_version_vyper, Config}; use semver::Version; use serde::Serialize; use std::{collections::BTreeMap, path::PathBuf}; @@ -93,11 +93,16 @@ impl ResolveArgs { .collect(); let evm_version = if shell::verbosity() > 1 { - Some( - EvmVersion::default() - .normalize_version_solc(version) - .unwrap_or_default(), - ) + let evm = EvmVersion::default() + .normalize_version_solc(version) + .unwrap_or_default(); + + // Vyper does not yet support Prague, so we normalize it to Cancun. + if language.is_vyper() { + Some(normalize_evm_version_vyper(evm)) + } else { + Some(evm) + } } else { None }; diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 3f76a179a0994..95d0c2b8bc61b 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -3673,7 +3673,7 @@ forgetest_init!(can_inspect_standard_json, |prj, cmd| { ] } }, - "evmVersion": "cancun", + "evmVersion": "prague", "viaIR": false, "libraries": {} } diff --git a/crates/forge/tests/cli/compiler.rs b/crates/forge/tests/cli/compiler.rs index 0b58221f2a1d0..f58d5c3ef1511 100644 --- a/crates/forge/tests/cli/compiler.rs +++ b/crates/forge/tests/cli/compiler.rs @@ -18,14 +18,14 @@ contract ContractB {} const CONTRACT_C: &str = r#" // SPDX-license-identifier: MIT -pragma solidity 0.8.27; +pragma solidity 0.8.30; contract ContractC {} "#; const CONTRACT_D: &str = r#" // SPDX-license-identifier: MIT -pragma solidity 0.8.27; +pragma solidity 0.8.30; contract ContractD {} "#; @@ -111,7 +111,7 @@ forgetest!(can_list_resolved_compiler_versions_verbose, |prj, cmd| { cmd.args(["compiler", "resolve", "-v"]).assert_success().stdout_eq(str![[r#" Solidity: -0.8.27: +0.8.30: ├── src/ContractC.sol └── src/ContractD.sol @@ -128,7 +128,7 @@ forgetest!(can_list_resolved_compiler_versions_verbose_json, |prj, cmd| { { "Solidity": [ { - "version": "0.8.27", + "version": "0.8.30", "paths": [ "src/ContractC.sol", "src/ContractD.sol" @@ -153,7 +153,7 @@ forgetest!(can_list_resolved_multiple_compiler_versions, |prj, cmd| { Solidity: - 0.8.4 - 0.8.11 -- 0.8.27 +- 0.8.30 Vyper: - 0.4.0 @@ -198,7 +198,7 @@ forgetest!(can_list_resolved_multiple_compiler_versions_skipped_json, |prj, cmd| { "Solidity": [ { - "version": "0.8.27", + "version": "0.8.30", "paths": [ "src/ContractD.sol" ] @@ -236,7 +236,7 @@ Solidity: 0.8.11 (<= london): └── src/ContractB.sol -0.8.27 (<= [..]): +0.8.30 (<= prague): ├── src/ContractC.sol └── src/ContractD.sol @@ -277,7 +277,7 @@ forgetest!(can_list_resolved_multiple_compiler_versions_verbose_json, |prj, cmd| ] }, { - "version": "0.8.27", + "version": "0.8.30", "evm_version": "[..]", "paths": [ "src/ContractC.sol", diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index 522fb2c01c786..9159f73ed53a2 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -983,7 +983,7 @@ allow_paths = [] include_paths = [] skip = [] force = false -evm_version = "cancun" +evm_version = "prague" gas_reports = ["*"] gas_reports_ignore = [] gas_reports_include_tests = false @@ -1146,7 +1146,7 @@ exclude = [] "include_paths": [], "skip": [], "force": false, - "evm_version": "cancun", + "evm_version": "prague", "gas_reports": [ "*" ], @@ -1712,7 +1712,7 @@ contract Counter { let v1_profile = SettingsOverrides { name: "v1".to_string(), via_ir: Some(true), - evm_version: Some(EvmVersion::Cancun), + evm_version: Some(EvmVersion::Prague), optimizer: None, optimizer_runs: Some(44444444), bytecode_hash: None, @@ -1798,19 +1798,19 @@ contract Counter { let (via_ir, evm_version, enabled, runs) = artifact_settings("Counter.sol/Counter.json"); assert_eq!(None, via_ir); - assert_eq!("\"cancun\"", evm_version.unwrap().to_string()); + assert_eq!("\"prague\"", evm_version.unwrap().to_string()); assert_eq!("false", enabled.unwrap().to_string()); assert_eq!("200", runs.unwrap().to_string()); let (via_ir, evm_version, enabled, runs) = artifact_settings("v1/Counter.sol/Counter.json"); assert_eq!("true", via_ir.unwrap().to_string()); - assert_eq!("\"cancun\"", evm_version.unwrap().to_string()); + assert_eq!("\"prague\"", evm_version.unwrap().to_string()); assert_eq!("true", enabled.unwrap().to_string()); assert_eq!("44444444", runs.unwrap().to_string()); let (via_ir, evm_version, enabled, runs) = artifact_settings("v2/Counter.sol/Counter.json"); assert_eq!("true", via_ir.unwrap().to_string()); - assert_eq!("\"cancun\"", evm_version.unwrap().to_string()); + assert_eq!("\"prague\"", evm_version.unwrap().to_string()); assert_eq!("true", enabled.unwrap().to_string()); assert_eq!("111", runs.unwrap().to_string()); diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index 1d6f415aef1d4..8f866150a4d8b 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -2576,7 +2576,7 @@ Chain 31337 accessList [] chainId 31337 -gasLimit 228231 +gasLimit [..] gasPrice input [..] maxFeePerBlobGas diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index 0d33025249075..b119eaa210600 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -1582,7 +1582,7 @@ contract ATest is Test { cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... -[PASS] test_negativeGas() (gas: 0) +[PASS] test_negativeGas() (gas: 96) ... "#]]); }); @@ -1779,17 +1779,17 @@ contract ATest is DSTest { cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... -[PASS] testResetGas() (gas: 40) -[PASS] testResetGas1() (gas: 40) -[PASS] testResetGas2() (gas: 40) +[PASS] testResetGas() (gas: 96) +[PASS] testResetGas1() (gas: 96) +[PASS] testResetGas2() (gas: 96) [PASS] testResetGas3() (gas: [..]) [PASS] testResetGas4() (gas: [..]) -[PASS] testResetGas5() (gas: 40) -[PASS] testResetGas6() (gas: 40) -[PASS] testResetGas7() (gas: 49) +[PASS] testResetGas5() (gas: 96) +[PASS] testResetGas6() (gas: 96) +[PASS] testResetGas7() (gas: 96) [PASS] testResetGas8() (gas: [..]) -[PASS] testResetGas9() (gas: 40) -[PASS] testResetNegativeGas() (gas: 0) +[PASS] testResetGas9() (gas: 96) +[PASS] testResetNegativeGas() (gas: 96) ... "#]]); }); @@ -2788,7 +2788,7 @@ forgetest_async!(can_get_broadcast_txs, |prj, cmd| { 31337 ); - assertEq(deployedAddress, address(0x90d4E26f2e78feDf488c7F3C46B8053a0515c71F)); + assertEq(deployedAddress, address(0xD32c10E38A626Db0b0978B1A5828eb2957665668)); } function test_getDeployments() public { @@ -2798,7 +2798,7 @@ forgetest_async!(can_get_broadcast_txs, |prj, cmd| { ); assertEq(deployments.length, 2); - assertEq(deployments[0], address(0x90d4E26f2e78feDf488c7F3C46B8053a0515c71F)); // Create2 address - latest deployment + assertEq(deployments[0], address(0xD32c10E38A626Db0b0978B1A5828eb2957665668)); // Create2 address - latest deployment assertEq(deployments[1], address(0x5FbDB2315678afecb367f032d93F642f64180aa3)); // Create address - oldest deployment } } diff --git a/crates/forge/tests/cli/test_optimizer.rs b/crates/forge/tests/cli/test_optimizer.rs index 6c286c52793ec..de0f57022a96b 100644 --- a/crates/forge/tests/cli/test_optimizer.rs +++ b/crates/forge/tests/cli/test_optimizer.rs @@ -1082,7 +1082,7 @@ contract CounterTest is Test { function test_Increment_In_Counter_With_Salt() public { CounterWithSalt counter = new CounterWithSalt{value: 111, salt: bytes32("preprocess_counter_with_salt")}(1); - assertEq(address(counter), 0x3Efe9ecFc73fB3baB7ECafBB40D3e134260Be6AB); + assertEq(address(counter), 0x223e63BE3BF01DD04f852d70f1bE217017055f49); } } "#, @@ -1160,7 +1160,7 @@ contract CounterWithSalt { Compiling 1 files with [..] ... [FAIL: assertion failed: 113 != 112] test_Increment_In_Counter() (gas: [..]) -[FAIL: assertion failed: 0x6cDcb015cFcAd0C23560322EdEE8f324520E4b93 != 0x3Efe9ecFc73fB3baB7ECafBB40D3e134260Be6AB] test_Increment_In_Counter_With_Salt() (gas: [..]) +[FAIL: assertion failed: 0x11acEfcD29A1BA964A05C0E7F3901054BEfb17c0 != 0x223e63BE3BF01DD04f852d70f1bE217017055f49] test_Increment_In_Counter_With_Salt() (gas: [..]) ... "#]]); diff --git a/crates/forge/tests/it/test_helpers.rs b/crates/forge/tests/it/test_helpers.rs index 4de095be9e473..2043af8c01580 100644 --- a/crates/forge/tests/it/test_helpers.rs +++ b/crates/forge/tests/it/test_helpers.rs @@ -332,7 +332,7 @@ pub static TEST_DATA_DEFAULT: LazyLock = pub static TEST_DATA_PARIS: LazyLock = LazyLock::new(|| ForgeTestData::new(ForgeTestProfile::Paris)); -/// Data for tests requiring Cancun support on Solc and EVM level. +/// Data for tests requiring Prague support on Solc and EVM level. pub static TEST_DATA_MULTI_VERSION: LazyLock = LazyLock::new(|| ForgeTestData::new(ForgeTestProfile::MultiVersion)); diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index 3179503f28f90..a72c36df8b081 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -48,7 +48,7 @@ static TEMPLATE_LOCK: LazyLock = static NEXT_ID: AtomicUsize = AtomicUsize::new(0); /// The default Solc version used when compiling tests. -pub const SOLC_VERSION: &str = "0.8.27"; +pub const SOLC_VERSION: &str = "0.8.30"; /// Another Solc version used when compiling tests. /// diff --git a/deny.toml b/deny.toml index be6615d08685f..b1f10b3a4a852 100644 --- a/deny.toml +++ b/deny.toml @@ -98,6 +98,7 @@ unknown-registry = "warn" unknown-git = "deny" allow-git = [ "https://github.com/alloy-rs/alloy", + "https://github.com/foundry-rs/compilers", "https://github.com/foundry-rs/foundry-fork-db", "https://github.com/paradigmxyz/revm-inspectors", "https://github.com/bluealloy/revm", From 213d27dae11e20e20bbe0f0d3229fef904a07b40 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 3 Jun 2025 11:56:05 +0300 Subject: [PATCH 164/244] chore: add license to preprocessor deploy helper (#10684) chore: add license to prepreocessor deploy helper --- crates/common/src/preprocessor/data.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/common/src/preprocessor/data.rs b/crates/common/src/preprocessor/data.rs index 78fe1098fcc56..6cc988137e167 100644 --- a/crates/common/src/preprocessor/data.rs +++ b/crates/common/src/preprocessor/data.rs @@ -178,6 +178,7 @@ impl ContractData { let helper = format!( r#" +// SPDX-License-Identifier: MIT pragma solidity >=0.4.0; import "{path}"; From cde1f320c7bf0308946eb17a2aeb1d5b1fed5ae1 Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Tue, 3 Jun 2025 11:57:29 +0200 Subject: [PATCH 165/244] chore: update announcements link in `nightly` warning for Foundry book (#10690) update announcements link --- crates/common/src/version.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/common/src/version.rs b/crates/common/src/version.rs index f69457bf7c1e3..323bd94ce88ec 100644 --- a/crates/common/src/version.rs +++ b/crates/common/src/version.rs @@ -23,5 +23,5 @@ pub const IS_NIGHTLY_VERSION: bool = option_env!("FOUNDRY_IS_NIGHTLY_VERSION").i /// The warning message for nightly versions. pub const NIGHTLY_VERSION_WARNING_MESSAGE: &str = "This is a nightly build of Foundry. It is recommended to use the latest stable version. \ - Visit https://book.getfoundry.sh/announcements for more information. \n\ + Visit https://book.getfoundry.sh/misc/announcements for more information. \n\ To mute this warning set `FOUNDRY_DISABLE_NIGHTLY_WARNING` in your environment. \n"; From b2bcaf5f1162de531dd3533eff68a1e454b76fd7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 12:50:14 +0200 Subject: [PATCH 166/244] chore(deps): weekly `cargo update` (#10680) * chore(deps): weekly `cargo update` Locking 71 packages to latest compatible versions Updating alloy-consensus v1.0.7 -> v1.0.9 Updating alloy-consensus-any v1.0.7 -> v1.0.9 Updating alloy-contract v1.0.7 -> v1.0.9 Updating alloy-eips v1.0.7 -> v1.0.9 Updating alloy-ens v1.0.7 -> v1.0.9 Updating alloy-genesis v1.0.7 -> v1.0.9 Updating alloy-json-rpc v1.0.7 -> v1.0.9 Updating alloy-network v1.0.7 -> v1.0.9 Updating alloy-network-primitives v1.0.7 -> v1.0.9 Updating alloy-provider v1.0.7 -> v1.0.9 Updating alloy-pubsub v1.0.7 -> v1.0.9 Updating alloy-rpc-client v1.0.7 -> v1.0.9 Updating alloy-rpc-types v1.0.7 -> v1.0.9 Updating alloy-rpc-types-anvil v1.0.7 -> v1.0.9 Updating alloy-rpc-types-any v1.0.7 -> v1.0.9 Updating alloy-rpc-types-debug v1.0.7 -> v1.0.9 Updating alloy-rpc-types-engine v1.0.7 -> v1.0.9 Updating alloy-rpc-types-eth v1.0.7 -> v1.0.9 Updating alloy-rpc-types-trace v1.0.7 -> v1.0.9 Updating alloy-rpc-types-txpool v1.0.7 -> v1.0.9 Updating alloy-serde v1.0.7 -> v1.0.9 Updating alloy-signer v1.0.7 -> v1.0.9 Updating alloy-signer-aws v1.0.7 -> v1.0.9 Updating alloy-signer-gcp v1.0.7 -> v1.0.9 Updating alloy-signer-ledger v1.0.7 -> v1.0.9 Updating alloy-signer-local v1.0.7 -> v1.0.9 Updating alloy-signer-trezor v1.0.7 -> v1.0.9 Updating alloy-transport v1.0.7 -> v1.0.9 Updating alloy-transport-http v1.0.7 -> v1.0.9 Updating alloy-transport-ipc v1.0.7 -> v1.0.9 Updating alloy-transport-ws v1.0.7 -> v1.0.9 Updating aws-sdk-kms v1.71.0 -> v1.72.0 Updating aws-sdk-sso v1.70.0 -> v1.71.0 Updating aws-sdk-ssooidc v1.71.0 -> v1.72.0 Updating aws-sdk-sts v1.71.0 -> v1.72.0 Updating cc v1.2.24 -> v1.2.25 Updating clap v4.5.38 -> v4.5.39 Updating clap_builder v4.5.38 -> v4.5.39 Updating clap_complete v4.5.50 -> v4.5.52 Updating color-eyre v0.6.4 -> v0.6.5 Updating color-spantrace v0.2.2 -> v0.3.0 Updating core-foundation v0.10.0 -> v0.10.1 Unchanged crossterm v0.28.1 (available: v0.29.0) Unchanged foundry-block-explorers v0.17.0 (available: v0.18.0) Updating foundry-compilers v0.16.2 -> v0.16.3 (available: v0.17.0) Updating foundry-compilers-artifacts v0.16.2 -> v0.16.3 Updating foundry-compilers-artifacts-solc v0.16.2 -> v0.16.3 Updating foundry-compilers-artifacts-vyper v0.16.2 -> v0.16.3 Updating foundry-compilers-core v0.16.2 -> v0.16.3 Removing hermit-abi v0.3.9 Updating hyper-util v0.1.12 -> v0.1.13 Unchanged idna_adapter v1.1.0 (available: v1.2.1) Adding iri-string v0.7.8 Updating libloading v0.8.7 -> v0.8.8 Updating lock_api v0.4.12 -> v0.4.13 Unchanged matchit v0.8.4 (available: v0.8.6) Updating mdbook v0.4.50 -> v0.4.51 Updating num_cpus v1.16.0 -> v1.17.0 Updating op-alloy-consensus v0.17.1 -> v0.17.2 Updating op-alloy-rpc-types v0.17.1 -> v0.17.2 Updating op-revm v5.0.0 -> v5.0.1 Updating opener v0.8.1 -> v0.8.2 Unchanged opener v0.7.2 (available: v0.8.2) Updating parking_lot v0.12.3 -> v0.12.4 Updating parking_lot_core v0.9.10 -> v0.9.11 Updating prettyplease v0.2.32 -> v0.2.33 Unchanged protobuf v3.3.0 (available: v3.7.2) Unchanged protobuf-support v3.3.0 (available: v3.7.2) Unchanged rand v0.8.5 (available: v0.9.1) Updating reqwest v0.12.15 -> v0.12.18 Updating revm v24.0.0 -> v24.0.1 Updating revm-context v5.0.0 -> v5.0.1 Updating revm-handler v5.0.0 -> v5.0.1 Updating revm-inspector v5.0.0 -> v5.0.1 Removing rustls-pemfile v2.2.0 Unchanged rustyline v15.0.0 (available: v16.0.0) Unchanged schemars v0.8.22 (available: v0.9.0) Updating socket2 v0.5.9 -> v0.5.10 Unchanged solar-ast v0.1.3 (available: v0.1.4) Updating solar-config v0.1.3 -> v0.1.4 Updating solar-data-structures v0.1.3 -> v0.1.4 Unchanged solar-interface v0.1.3 (available: v0.1.4) Updating solar-macros v0.1.3 -> v0.1.4 Unchanged solar-parse v0.1.3 (available: v0.1.4) Unchanged solar-sema v0.1.3 (available: v0.1.4) Updating tracy-client v0.18.0 -> v0.18.1 Updating tracy-client-sys v0.24.3 -> v0.25.0 Unchanged ui_test v0.29.2 (available: v0.30.1) Unchanged vergen v8.3.2 (available: v9.0.6) Unchanged zip-extract v0.2.1 (available: v0.2.3) note: to see how you depend on a package, run `cargo tree --invert --package @` * bump deps --------- Co-authored-by: mattsse <19890894+mattsse@users.noreply.github.com> Co-authored-by: zerosnacks Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- Cargo.lock | 26 +++++++------- Cargo.toml | 78 ++++++++++++++++++++--------------------- crates/anvil/Cargo.toml | 2 +- crates/forge/Cargo.toml | 2 +- 4 files changed, 54 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 846624478eeac..34370220f4b36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,9 +58,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-chains" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "517e5acbd38b6d4c59da380e8bbadc6d365bf001903ce46cf5521c53c647e07b" +checksum = "d6967ca1ed656766e471bc323da42fb0db320ca5e1418b408650e98e4757b3d2" dependencies = [ "alloy-primitives", "num_enum", @@ -2308,9 +2308,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" dependencies = [ "serde", ] @@ -6485,9 +6485,9 @@ dependencies = [ [[package]] name = "op-alloy-flz" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ef71f23a8caf6f2a2d5cafbdc44956d44e6014dcb9aa58abf7e4e6481c6ec34" +checksum = "a79f352fc3893dcd670172e615afef993a41798a1d3fc0db88a3e60ef2e70ecc" [[package]] name = "op-alloy-rpc-types" @@ -7145,7 +7145,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.14.0", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.101", @@ -7513,9 +7513,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.18" +version = "0.12.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e98ff6b0dbbe4d5a37318f433d4fc82babd21631f194d370409ceb2e40b2f0b5" +checksum = "a2f8e5513d63f2e5b386eb5106dc67eaf3f84e95258e210489136b8b92ad6119" dependencies = [ "async-compression", "base64 0.22.1", @@ -8661,7 +8661,7 @@ dependencies = [ "derive_builder", "derive_more 2.0.1", "dunce", - "itertools 0.14.0", + "itertools 0.12.1", "itoa", "lasso", "match_cfg", @@ -8673,7 +8673,7 @@ dependencies = [ "solar-config", "solar-data-structures", "solar-macros", - "thiserror 2.0.12", + "thiserror 1.0.69", "tracing", "unicode-width 0.2.0", ] @@ -8698,7 +8698,7 @@ dependencies = [ "alloy-primitives", "bitflags 2.9.1", "bumpalo", - "itertools 0.14.0", + "itertools 0.12.1", "memchr", "num-bigint", "num-rational", @@ -9009,7 +9009,7 @@ dependencies = [ "serde_json", "sha2 0.10.9", "tempfile", - "thiserror 2.0.12", + "thiserror 1.0.69", "url", "zip", ] diff --git a/Cargo.toml b/Cargo.toml index 61c0b30109e76..6355d1d945316 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -208,57 +208,57 @@ solar-interface = { version = "=0.1.4", default-features = false } solar-sema = { version = "=0.1.4", default-features = false } ## alloy -alloy-consensus = { version = "1.0.7", default-features = false } -alloy-contract = { version = "1.0.7", default-features = false } -alloy-eips = { version = "1.0.7", default-features = false } -alloy-ens = { version = "1.0.7", default-features = false } -alloy-genesis = { version = "1.0.7", default-features = false } -alloy-json-rpc = { version = "1.0.7", default-features = false } -alloy-network = { version = "1.0.7", default-features = false } -alloy-provider = { version = "1.0.7", default-features = false } -alloy-pubsub = { version = "1.0.7", default-features = false } -alloy-rpc-client = { version = "1.0.7", default-features = false } -alloy-rpc-types = { version = "1.0.7", default-features = true } -alloy-serde = { version = "1.0.7", default-features = false } -alloy-signer = { version = "1.0.7", default-features = false } -alloy-signer-aws = { version = "1.0.7", default-features = false } -alloy-signer-gcp = { version = "1.0.7", default-features = false } -alloy-signer-ledger = { version = "1.0.7", default-features = false } -alloy-signer-local = { version = "1.0.7", default-features = false } -alloy-signer-trezor = { version = "1.0.7", default-features = false } -alloy-transport = { version = "1.0.7", default-features = false } -alloy-transport-http = { version = "1.0.7", default-features = false } -alloy-transport-ipc = { version = "1.0.7", default-features = false } -alloy-transport-ws = { version = "1.0.7", default-features = false } +alloy-consensus = { version = "1.0.9", default-features = false } +alloy-contract = { version = "1.0.9", default-features = false } +alloy-eips = { version = "1.0.9", default-features = false } +alloy-ens = { version = "1.0.9", default-features = false } +alloy-genesis = { version = "1.0.9", default-features = false } +alloy-json-rpc = { version = "1.0.9", default-features = false } +alloy-network = { version = "1.0.9", default-features = false } +alloy-provider = { version = "1.0.9", default-features = false } +alloy-pubsub = { version = "1.0.9", default-features = false } +alloy-rpc-client = { version = "1.0.9", default-features = false } +alloy-rpc-types = { version = "1.0.9", default-features = true } +alloy-serde = { version = "1.0.9", default-features = false } +alloy-signer = { version = "1.0.9", default-features = false } +alloy-signer-aws = { version = "1.0.9", default-features = false } +alloy-signer-gcp = { version = "1.0.9", default-features = false } +alloy-signer-ledger = { version = "1.0.9", default-features = false } +alloy-signer-local = { version = "1.0.9", default-features = false } +alloy-signer-trezor = { version = "1.0.9", default-features = false } +alloy-transport = { version = "1.0.9", default-features = false } +alloy-transport-http = { version = "1.0.9", default-features = false } +alloy-transport-ipc = { version = "1.0.9", default-features = false } +alloy-transport-ws = { version = "1.0.9", default-features = false } alloy-hardforks = { version = "0.2.6", default-features = false } alloy-op-hardforks = { version = "0.2.6", default-features = false } ## alloy-core -alloy-dyn-abi = "1.0" -alloy-json-abi = "1.0" -alloy-primitives = { version = "1.0", features = [ +alloy-dyn-abi = "1.1" +alloy-json-abi = "1.1" +alloy-primitives = { version = "1.1", features = [ "getrandom", "rand", "map-fxhash", "map-foldhash", ] } -alloy-sol-macro-expander = "1.0" -alloy-sol-macro-input = "1.0" -alloy-sol-types = "1.0" +alloy-sol-macro-expander = "1.1" +alloy-sol-macro-input = "1.1" +alloy-sol-types = "1.1" alloy-chains = "0.2" alloy-rlp = "0.3" alloy-trie = "0.8.1" ## op-alloy -op-alloy-consensus = "0.17.1" -op-alloy-rpc-types = "0.17.1" -op-alloy-flz = "0.13.0" +op-alloy-consensus = "0.17.2" +op-alloy-rpc-types = "0.17.2" +op-alloy-flz = "0.13.1" ## revm -revm = { version = "24.0.0", default-features = false } +revm = { version = "24.0.1", default-features = false } revm-inspectors = { version = "0.23.0", features = ["serde"] } -op-revm = { version = "5.0.0", default-features = false } +op-revm = { version = "5.0.1", default-features = false } ## alloy-evm alloy-evm = "0.10.0" @@ -286,7 +286,7 @@ tracy-client = "0.18" auto_impl = "1" aws-config = { version = "1", default-features = true } aws-sdk-kms = { version = "1", default-features = false } -bytes = "1.8" +bytes = "1.10" walkdir = "2" prettyplease = "0.2" base64 = "0.22" @@ -305,7 +305,7 @@ evmole = "0.8" eyre = "0.6" figment = "0.10" futures = "0.3" -hyper = "1.5" +hyper = "1.6" indicatif = "0.17" itertools = "0.14" jsonpath_lib = "0.3" @@ -327,11 +327,11 @@ rustls = "0.23" semver = "1" serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["arbitrary_precision"] } -similar-asserts = "1.6" +similar-asserts = "1.7" soldeer-commands = "=0.5.4" soldeer-core = { version = "=0.5.4", features = ["serde"] } strum = "0.27" -tempfile = "3.13" +tempfile = "3.20" tokio = "1" toml = "0.8" tower = "0.5" @@ -392,8 +392,8 @@ zip-extract = "=0.2.1" # alloy-transport-ws = { git = "https://github.com/alloy-rs/alloy", rev = "7fab7ee" } ## alloy-evm -# alloy-evm = { git = "https://github.com/alloy-rs/evm.git", rev = "8076e12" } -# alloy-op-evm = { git = "https://github.com/alloy-rs/evm.git", rev = "8076e12" } +# alloy-evm = { git = "https://github.com/alloy-rs/evm.git", rev = "dce752f" } +# alloy-op-evm = { git = "https://github.com/alloy-rs/evm.git", rev = "dce752f" } ## revm # revm = { git = "https://github.com/bluealloy/revm.git", rev = "b5808253" } diff --git a/crates/anvil/Cargo.toml b/crates/anvil/Cargo.toml index 35aee11fcdeb3..24abbca6feeb6 100644 --- a/crates/anvil/Cargo.toml +++ b/crates/anvil/Cargo.toml @@ -84,7 +84,7 @@ futures.workspace = true async-trait.workspace = true # misc -flate2 = "1.0" +flate2 = "1.1" serde_json.workspace = true serde.workspace = true thiserror.workspace = true diff --git a/crates/forge/Cargo.toml b/crates/forge/Cargo.toml index f9845b8a80180..17e8449aac79a 100644 --- a/crates/forge/Cargo.toml +++ b/crates/forge/Cargo.toml @@ -95,7 +95,7 @@ opener = "0.7" # soldeer soldeer-commands.workspace = true -quick-junit = "0.5.0" +quick-junit = "0.5.1" [dev-dependencies] alloy-hardforks.workspace = true From 18159b1ff99f74a822bc3f67bdec6d2d3cc3e54f Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 3 Jun 2025 14:20:37 +0300 Subject: [PATCH 167/244] chore: fix flaky test, bump timeout max rejects, use http provider (#10691) chore: flaky test, bump timeout max rejects, use http provider --- crates/anvil/tests/it/anvil_api.rs | 2 +- crates/forge/tests/it/fuzz.rs | 2 +- testdata/default/repros/Issue10527.t.sol | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/anvil/tests/it/anvil_api.rs b/crates/anvil/tests/it/anvil_api.rs index 5b4bcd78d2059..47c63a12af048 100644 --- a/crates/anvil/tests/it/anvil_api.rs +++ b/crates/anvil/tests/it/anvil_api.rs @@ -669,7 +669,7 @@ async fn can_remove_pool_transactions() { #[tokio::test(flavor = "multi_thread")] async fn test_reorg() { let (api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider(); + let provider = handle.http_provider(); let accounts = handle.dev_wallets().collect::>(); diff --git a/crates/forge/tests/it/fuzz.rs b/crates/forge/tests/it/fuzz.rs index 0d256d820dcd2..756c9b88fa0a9 100644 --- a/crates/forge/tests/it/fuzz.rs +++ b/crates/forge/tests/it/fuzz.rs @@ -254,7 +254,7 @@ forgetest_init!(test_fuzz_timeout, |prj, cmd| { import {Test} from "forge-std/Test.sol"; contract FuzzTimeoutTest is Test { - /// forge-config: default.fuzz.max-test-rejects = 10000 + /// forge-config: default.fuzz.max-test-rejects = 50000 /// forge-config: default.fuzz.timeout = 1 function test_fuzz_bound(uint256 a) public pure { vm.assume(a == 0); diff --git a/testdata/default/repros/Issue10527.t.sol b/testdata/default/repros/Issue10527.t.sol index f9149267dbde3..fdf62b22db35c 100644 --- a/testdata/default/repros/Issue10527.t.sol +++ b/testdata/default/repros/Issue10527.t.sol @@ -18,6 +18,9 @@ contract A { } contract Issue10527Test is DSTest { + event Event1(); + event Event2(); + Vm constant vm = Vm(HEVM_ADDRESS); A a; @@ -28,14 +31,14 @@ contract Issue10527Test is DSTest { function test_foo_Event1() public { vm.expectEmit(address(a)); - emit A.Event1(); + emit Event1(); a.foo(); } function test_foo_Event2() public { vm.expectEmit({emitter: address(a), count: 0}); - emit A.Event2(); + emit Event2(); a.foo(); } From 5ae91c65e9834477c3ad1a0f2909158835a6f157 Mon Sep 17 00:00:00 2001 From: Soubhik Singha Mahapatra <160333583+Soubhik-10@users.noreply.github.com> Date: Tue, 3 Jun 2025 19:58:25 +0530 Subject: [PATCH 168/244] feat: added disable-code-size-limit flag in forge script (#10661) added disable-code-size-limit flag in forge script Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> --- crates/script/src/lib.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/crates/script/src/lib.rs b/crates/script/src/lib.rs index ac5954924fa47..138bff6c9d7e4 100644 --- a/crates/script/src/lib.rs +++ b/crates/script/src/lib.rs @@ -179,6 +179,10 @@ pub struct ScriptArgs { #[arg(long)] pub non_interactive: bool, + /// Disables the contract size limit during script execution. + #[arg(long)] + pub disable_code_size_limit: bool, + /// The Etherscan (or equivalent) API key #[arg(long, env = "ETHERSCAN_API_KEY", value_name = "KEY")] pub etherscan_api_key: Option, @@ -401,6 +405,11 @@ impl ScriptArgs { known_contracts: &ContractsByArtifact, create2_deployer: Address, ) -> Result<()> { + // If disable-code-size-limit flag is enabled then skip the size check + if self.disable_code_size_limit { + return Ok(()) + } + // (name, &init, &deployed)[] let mut bytecodes: Vec<(String, &[u8], &[u8])> = vec![]; @@ -709,6 +718,18 @@ mod tests { assert_eq!(config.etherscan_api_key, Some("goerli".to_string())); } + #[test] + fn can_disable_code_size_limit() { + let args = + ScriptArgs::parse_from(["foundry-cli", "Contract.sol", "--disable-code-size-limit"]); + assert!(args.disable_code_size_limit); + + let result = ScriptResult::default(); + let contracts = ContractsByArtifact::default(); + let create = Address::ZERO; + assert!(args.check_contract_sizes(&result, &contracts, create).is_ok()); + } + #[test] fn can_parse_verifier_url() { let args = ScriptArgs::parse_from([ From 82159b502efad5846f59c4d219a809ba760fe3dc Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Tue, 3 Jun 2025 19:37:08 +0200 Subject: [PATCH 169/244] chore: remove unused opcodes file (#10695) remove unused opcodes file --- crates/evm/core/src/lib.rs | 1 - crates/evm/core/src/opcodes.rs | 25 ------------------------- 2 files changed, 26 deletions(-) delete mode 100644 crates/evm/core/src/opcodes.rs diff --git a/crates/evm/core/src/lib.rs b/crates/evm/core/src/lib.rs index 76d6be35dd6cb..4a9bad9392107 100644 --- a/crates/evm/core/src/lib.rs +++ b/crates/evm/core/src/lib.rs @@ -31,7 +31,6 @@ pub mod either_evm; pub mod evm; pub mod fork; pub mod ic; -pub mod opcodes; pub mod opts; pub mod precompiles; pub mod state_snapshot; diff --git a/crates/evm/core/src/opcodes.rs b/crates/evm/core/src/opcodes.rs deleted file mode 100644 index 7fad7ca5f3a3e..0000000000000 --- a/crates/evm/core/src/opcodes.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Opcode utils - -use revm::bytecode::opcode::OpCode; - -/// Returns true if the opcode modifies memory. -/// -/// -#[inline] -pub const fn modifies_memory(opcode: OpCode) -> bool { - matches!( - opcode, - OpCode::EXTCODECOPY | - OpCode::MLOAD | - OpCode::MSTORE | - OpCode::MSTORE8 | - OpCode::MCOPY | - OpCode::CODECOPY | - OpCode::CALLDATACOPY | - OpCode::RETURNDATACOPY | - OpCode::CALL | - OpCode::CALLCODE | - OpCode::DELEGATECALL | - OpCode::STATICCALL - ) -} From 66edc26f387c34788c46e4dba9ca51c08b15bdf3 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Wed, 4 Jun 2025 13:51:18 +0200 Subject: [PATCH 170/244] chore: add additional check for is_impersonanted (#10701) --- crates/common/src/constants.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/common/src/constants.rs b/crates/common/src/constants.rs index 31c0a2345a9d7..ad944c10d4bc7 100644 --- a/crates/common/src/constants.rs +++ b/crates/common/src/constants.rs @@ -65,7 +65,9 @@ pub fn is_impersonated_tx(tx: &AnyTxEnvelope) -> bool { pub fn is_impersonated_sig(sig: &Signature, ty: u8) -> bool { let impersonated_sig = Signature::from_scalars_and_parity(B256::with_last_byte(1), B256::with_last_byte(1), false); - if ty != SYSTEM_TRANSACTION_TYPE && sig == &impersonated_sig { + if ty != SYSTEM_TRANSACTION_TYPE && + (sig == &impersonated_sig || sig.r() == impersonated_sig.r()) + { return true; } false From 365cbb43b67707fdbe594ae212bd7b718079b70f Mon Sep 17 00:00:00 2001 From: 0xrusowsky <90208954+0xrusowsky@users.noreply.github.com> Date: Wed, 4 Jun 2025 17:14:48 +0200 Subject: [PATCH 171/244] feat(forge): eip712 cheatcodes + forge cmd (eip712 + bind-json) with solar (#10510) * wip * feat: eip712 type hash PoC * style: json * style: json * style: json * style: comments * wip * initial impl using solar * fix: untracked change * fix: optimize resolve_type * initial working impl * feat: eip712 solar resolver * style: docs + fmt + clippy * todo: cheatcode * docs: comments * fix: use HIR rather than AST * from build opts * docs * fix: rmv hashset * create utils for solar_pcx_from_build_opts * incorporate version logic into `solar_pcx_from_build_opts` * wip bind-json: eip712 resolver integration * forge(bind-json): integrate solar * fix: tests * style: clippy * undo cheatcode setup (will tackle it on its own PR) * rmv old test * style: fix typo * fix: win path * fix: merge conflicts * fix: dani's feedback * docs: explain bindings overriding * chore: patch solar * feat(forge): eip712 cheatcodes (#10570) * fix: bump solang parser * Remove unused from forge crate * Move tests to eip712 * Nit: comments --------- Co-authored-by: grandizzy --- Cargo.lock | 3 + crates/anvil/core/src/eth/mod.rs | 2 +- crates/cheatcodes/assets/cheatcodes.json | 100 ++++ crates/cheatcodes/spec/src/vm.rs | 49 ++ crates/cheatcodes/src/config.rs | 4 + crates/cheatcodes/src/utils.rs | 152 +++++- crates/cli/Cargo.toml | 4 +- crates/cli/src/opts/build/mod.rs | 3 + crates/cli/src/opts/build/utils.rs | 105 +++++ crates/common/src/constants.rs | 5 +- crates/forge/Cargo.toml | 3 +- crates/forge/src/cmd/bind_json.rs | 205 ++++---- crates/forge/src/cmd/eip712.rs | 313 +++++------- crates/forge/tests/cli/eip712.rs | 575 ++++++++++++++++++++++- docs/dev/cheatcodes.md | 2 +- testdata/cheats/Vm.sol | 5 + 16 files changed, 1209 insertions(+), 321 deletions(-) create mode 100644 crates/cli/src/opts/build/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 34370220f4b36..797e25fc4c9a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3841,6 +3841,7 @@ dependencies = [ "similar", "similar-asserts", "solar-parse", + "solar-sema", "soldeer-commands", "strum 0.27.1", "svm-rs", @@ -4125,6 +4126,7 @@ dependencies = [ "clap", "color-eyre", "dotenvy", + "dunce", "eyre", "forge-fmt", "foundry-block-explorers", @@ -4143,6 +4145,7 @@ dependencies = [ "rustls", "serde", "serde_json", + "solar-sema", "strsim", "strum 0.27.1", "tempfile", diff --git a/crates/anvil/core/src/eth/mod.rs b/crates/anvil/core/src/eth/mod.rs index ac7db74892003..5b77e4d0ce380 100644 --- a/crates/anvil/core/src/eth/mod.rs +++ b/crates/anvil/core/src/eth/mod.rs @@ -664,7 +664,7 @@ pub enum EthRequest { /// Add an address to the [`DelegationCapability`] of the wallet /// - /// [`DelegationCapability`]: wallet::DelegationCapability + /// [`DelegationCapability`]: wallet::DelegationCapability #[serde(rename = "anvil_addCapability", with = "sequence")] AnvilAddCapability(Address), diff --git a/crates/cheatcodes/assets/cheatcodes.json b/crates/cheatcodes/assets/cheatcodes.json index eb541e269a888..f1d2b617e3a5f 100644 --- a/crates/cheatcodes/assets/cheatcodes.json +++ b/crates/cheatcodes/assets/cheatcodes.json @@ -4294,6 +4294,106 @@ "status": "stable", "safety": "unsafe" }, + { + "func": { + "id": "eip712HashStruct_0", + "description": "Generates the struct hash of the canonical EIP-712 type representation and its abi-encoded data.\nSupports 2 different inputs:\n 1. Name of the type (i.e. \"PermitSingle\"):\n * requires previous binding generation with `forge bind-json`.\n * bindings will be retrieved from the path configured in `foundry.toml`.\n 2. String representation of the type (i.e. \"Foo(Bar bar) Bar(uint256 baz)\").\n * Note: the cheatcode will use the canonical type even if the input is malformated\n with the wrong order of elements or with extra whitespaces.", + "declaration": "function eip712HashStruct(string calldata typeNameOrDefinition, bytes calldata abiEncodedData) external pure returns (bytes32 typeHash);", + "visibility": "external", + "mutability": "pure", + "signature": "eip712HashStruct(string,bytes)", + "selector": "0xaedeaebc", + "selectorBytes": [ + 174, + 222, + 174, + 188 + ] + }, + "group": "utilities", + "status": "stable", + "safety": "safe" + }, + { + "func": { + "id": "eip712HashStruct_1", + "description": "Generates the struct hash of the canonical EIP-712 type representation and its abi-encoded data.\nRequires previous binding generation with `forge bind-json`.\nParams:\n * `bindingsPath`: path where the output of `forge bind-json` is stored.\n * `typeName`: Name of the type (i.e. \"PermitSingle\").\n * `abiEncodedData`: ABI-encoded data for the struct that is being hashed.", + "declaration": "function eip712HashStruct(string calldata bindingsPath, string calldata typeName, bytes calldata abiEncodedData) external pure returns (bytes32 typeHash);", + "visibility": "external", + "mutability": "pure", + "signature": "eip712HashStruct(string,string,bytes)", + "selector": "0x6d06c57c", + "selectorBytes": [ + 109, + 6, + 197, + 124 + ] + }, + "group": "utilities", + "status": "stable", + "safety": "safe" + }, + { + "func": { + "id": "eip712HashType_0", + "description": "Generates the hash of the canonical EIP-712 type representation.\nSupports 2 different inputs:\n 1. Name of the type (i.e. \"Transaction\"):\n * requires previous binding generation with `forge bind-json`.\n * bindings will be retrieved from the path configured in `foundry.toml`.\n 2. String representation of the type (i.e. \"Foo(Bar bar) Bar(uint256 baz)\").\n * Note: the cheatcode will output the canonical type even if the input is malformated\n with the wrong order of elements or with extra whitespaces.", + "declaration": "function eip712HashType(string calldata typeNameOrDefinition) external pure returns (bytes32 typeHash);", + "visibility": "external", + "mutability": "pure", + "signature": "eip712HashType(string)", + "selector": "0x6792e9e2", + "selectorBytes": [ + 103, + 146, + 233, + 226 + ] + }, + "group": "utilities", + "status": "stable", + "safety": "safe" + }, + { + "func": { + "id": "eip712HashType_1", + "description": "Generates the hash of the canonical EIP-712 type representation.\nRequires previous binding generation with `forge bind-json`.\nParams:\n * `bindingsPath`: path where the output of `forge bind-json` is stored.\n * `typeName`: Name of the type (i.e. \"Transaction\").", + "declaration": "function eip712HashType(string calldata bindingsPath, string calldata typeName) external pure returns (bytes32 typeHash);", + "visibility": "external", + "mutability": "pure", + "signature": "eip712HashType(string,string)", + "selector": "0x18fb6406", + "selectorBytes": [ + 24, + 251, + 100, + 6 + ] + }, + "group": "utilities", + "status": "stable", + "safety": "safe" + }, + { + "func": { + "id": "eip712HashTypedData", + "description": "Generates a ready-to-sign digest of human-readable typed data following the EIP-712 standard.", + "declaration": "function eip712HashTypedData(string calldata jsonData) external pure returns (bytes32 digest);", + "visibility": "external", + "mutability": "pure", + "signature": "eip712HashTypedData(string)", + "selector": "0xea25e615", + "selectorBytes": [ + 234, + 37, + 230, + 21 + ] + }, + "group": "utilities", + "status": "stable", + "safety": "safe" + }, { "func": { "id": "ensNamehash", diff --git a/crates/cheatcodes/spec/src/vm.rs b/crates/cheatcodes/spec/src/vm.rs index 1dac51fd0ca5a..a734c7a033ef1 100644 --- a/crates/cheatcodes/spec/src/vm.rs +++ b/crates/cheatcodes/spec/src/vm.rs @@ -2888,6 +2888,55 @@ interface Vm { /// catch (bytes memory interceptedInitcode) { initcode = interceptedInitcode; } #[cheatcode(group = Utilities, safety = Unsafe)] function interceptInitcode() external; + + /// Generates the hash of the canonical EIP-712 type representation. + /// + /// Supports 2 different inputs: + /// 1. Name of the type (i.e. "Transaction"): + /// * requires previous binding generation with `forge bind-json`. + /// * bindings will be retrieved from the path configured in `foundry.toml`. + /// + /// 2. String representation of the type (i.e. "Foo(Bar bar) Bar(uint256 baz)"). + /// * Note: the cheatcode will output the canonical type even if the input is malformated + /// with the wrong order of elements or with extra whitespaces. + #[cheatcode(group = Utilities)] + function eip712HashType(string calldata typeNameOrDefinition) external pure returns (bytes32 typeHash); + + /// Generates the hash of the canonical EIP-712 type representation. + /// Requires previous binding generation with `forge bind-json`. + /// + /// Params: + /// * `bindingsPath`: path where the output of `forge bind-json` is stored. + /// * `typeName`: Name of the type (i.e. "Transaction"). + #[cheatcode(group = Utilities)] + function eip712HashType(string calldata bindingsPath, string calldata typeName) external pure returns (bytes32 typeHash); + + /// Generates the struct hash of the canonical EIP-712 type representation and its abi-encoded data. + /// + /// Supports 2 different inputs: + /// 1. Name of the type (i.e. "PermitSingle"): + /// * requires previous binding generation with `forge bind-json`. + /// * bindings will be retrieved from the path configured in `foundry.toml`. + /// + /// 2. String representation of the type (i.e. "Foo(Bar bar) Bar(uint256 baz)"). + /// * Note: the cheatcode will use the canonical type even if the input is malformated + /// with the wrong order of elements or with extra whitespaces. + #[cheatcode(group = Utilities)] + function eip712HashStruct(string calldata typeNameOrDefinition, bytes calldata abiEncodedData) external pure returns (bytes32 typeHash); + + /// Generates the struct hash of the canonical EIP-712 type representation and its abi-encoded data. + /// Requires previous binding generation with `forge bind-json`. + /// + /// Params: + /// * `bindingsPath`: path where the output of `forge bind-json` is stored. + /// * `typeName`: Name of the type (i.e. "PermitSingle"). + /// * `abiEncodedData`: ABI-encoded data for the struct that is being hashed. + #[cheatcode(group = Utilities)] + function eip712HashStruct(string calldata bindingsPath, string calldata typeName, bytes calldata abiEncodedData) external pure returns (bytes32 typeHash); + + /// Generates a ready-to-sign digest of human-readable typed data following the EIP-712 standard. + #[cheatcode(group = Utilities)] + function eip712HashTypedData(string calldata jsonData) external pure returns (bytes32 digest); } } diff --git a/crates/cheatcodes/src/config.rs b/crates/cheatcodes/src/config.rs index 210c76553cba7..1ad98cd93e92b 100644 --- a/crates/cheatcodes/src/config.rs +++ b/crates/cheatcodes/src/config.rs @@ -33,6 +33,8 @@ pub struct CheatsConfig { pub rpc_endpoints: ResolvedRpcEndpoints, /// Project's paths as configured pub paths: ProjectPathsConfig, + /// Path to the directory that contains the bindings generated by `forge bind-json`. + pub bind_json_path: PathBuf, /// Filesystem permissions for cheatcodes like `writeFile`, `readFile` pub fs_permissions: FsPermissions, /// Project root @@ -98,6 +100,7 @@ impl CheatsConfig { no_storage_caching: config.no_storage_caching, rpc_endpoints, paths: config.project_paths(), + bind_json_path: config.bind_json.out.clone(), fs_permissions: config.fs_permissions.clone().joined(config.root.as_ref()), root: config.root.clone(), broadcast: config.root.clone().join(&config.broadcast), @@ -303,6 +306,7 @@ impl Default for CheatsConfig { paths: ProjectPathsConfig::builder().build_with_root("./"), fs_permissions: Default::default(), root: Default::default(), + bind_json_path: PathBuf::default().join("utils").join("jsonBindings.sol"), broadcast: Default::default(), allowed_paths: vec![], evm_opts: Default::default(), diff --git a/crates/cheatcodes/src/utils.rs b/crates/cheatcodes/src/utils.rs index 4bdc239036d53..3eed1b1bad230 100644 --- a/crates/cheatcodes/src/utils.rs +++ b/crates/cheatcodes/src/utils.rs @@ -1,14 +1,17 @@ //! Implementations of [`Utilities`](spec::Group::Utilities) cheatcodes. use crate::{Cheatcode, Cheatcodes, CheatcodesExecutor, CheatsCtxt, Result, Vm::*}; -use alloy_dyn_abi::{DynSolType, DynSolValue}; +use alloy_dyn_abi::{eip712_parser::EncodeType, DynSolType, DynSolValue, Resolver, TypedData}; use alloy_ens::namehash; -use alloy_primitives::{aliases::B32, map::HashMap, B64, U256}; +use alloy_primitives::{aliases::B32, keccak256, map::HashMap, Bytes, B64, U256}; use alloy_sol_types::SolValue; +use foundry_common::{fs, TYPE_BINDING_PREFIX}; +use foundry_config::fs_permissions::FsAccessKind; use foundry_evm_core::constants::DEFAULT_CREATE2_DEPLOYER; use proptest::prelude::Strategy; use rand::{seq::SliceRandom, Rng, RngCore}; use revm::context::JournalTr; +use std::path::PathBuf; /// Contains locations of traces ignored via cheatcodes. /// @@ -314,3 +317,148 @@ fn random_int(state: &mut Cheatcodes, bits: Option) -> Result { .current() .abi_encode()) } + +impl Cheatcode for eip712HashType_0Call { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { typeNameOrDefinition } = self; + + let type_def = get_canonical_type_def(typeNameOrDefinition, state, None)?; + + Ok(keccak256(type_def.as_bytes()).to_vec()) + } +} + +impl Cheatcode for eip712HashType_1Call { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { bindingsPath, typeName } = self; + + let path = state.config.ensure_path_allowed(bindingsPath, FsAccessKind::Read)?; + let type_def = get_type_def_from_bindings(typeName, path, &state.config.root)?; + + Ok(keccak256(type_def.as_bytes()).to_vec()) + } +} + +impl Cheatcode for eip712HashStruct_0Call { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { typeNameOrDefinition, abiEncodedData } = self; + + let type_def = get_canonical_type_def(typeNameOrDefinition, state, None)?; + let primary = &type_def[..type_def.find('(').unwrap_or(type_def.len())]; + + get_struct_hash(primary, &type_def, abiEncodedData) + } +} + +impl Cheatcode for eip712HashStruct_1Call { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { bindingsPath, typeName, abiEncodedData } = self; + + let path = state.config.ensure_path_allowed(bindingsPath, FsAccessKind::Read)?; + let type_def = get_type_def_from_bindings(typeName, path, &state.config.root)?; + + get_struct_hash(typeName, &type_def, abiEncodedData) + } +} + +impl Cheatcode for eip712HashTypedDataCall { + fn apply(&self, _state: &mut Cheatcodes) -> Result { + let Self { jsonData } = self; + let typed_data: TypedData = serde_json::from_str(jsonData)?; + let digest = typed_data.eip712_signing_hash()?; + + Ok(digest.to_vec()) + } +} + +/// Returns EIP-712 canonical type definition from the provided string type representation or type +/// name. If type name provided, then it looks up bindings from file generated by `forge bind-json`. +fn get_canonical_type_def( + name_or_def: &String, + state: &mut Cheatcodes, + path: Option, +) -> Result { + let type_def = if name_or_def.contains('(') { + // If the input contains '(', it must be the type definition. + EncodeType::parse(name_or_def).and_then(|parsed| parsed.canonicalize())? + } else { + // Otherwise, it must be the type name. + let path = path.as_ref().unwrap_or(&state.config.bind_json_path); + let path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?; + get_type_def_from_bindings(name_or_def, path, &state.config.root)? + }; + + Ok(type_def) +} + +/// Returns the EIP-712 type definition from the bindings in the provided path. +/// Assumes that read validation for the path has already been checked. +fn get_type_def_from_bindings(name: &String, path: PathBuf, root: &PathBuf) -> Result { + let content = fs::read_to_string(&path)?; + + let type_defs: HashMap<&str, &str> = content + .lines() + .filter_map(|line| { + let relevant = line.trim().strip_prefix(TYPE_BINDING_PREFIX)?; + let (name, def) = relevant.split_once('=')?; + Some((name.trim(), def.trim().strip_prefix('"')?.strip_suffix("\";")?)) + }) + .collect(); + + match type_defs.get(name.as_str()) { + Some(value) => Ok(value.to_string()), + None => { + let bindings = + type_defs.keys().map(|k| format!(" - {k}")).collect::>().join("\n"); + + bail!( + "'{}' not found in '{}'.{}", + name, + path.strip_prefix(root).unwrap_or(&path).to_string_lossy(), + if bindings.is_empty() { + String::new() + } else { + format!("\nAvailable bindings:\n{bindings}\n") + } + ); + } + } +} + +/// Returns the EIP-712 struct hash for provided name, definition and ABI encoded data. +fn get_struct_hash(primary: &str, type_def: &String, abi_encoded_data: &Bytes) -> Result { + let mut resolver = Resolver::default(); + + // Populate the resolver by ingesting the canonical type definition, and then get the + // corresponding `DynSolType` of the primary type. + resolver + .ingest_string(type_def) + .map_err(|e| fmt_err!("Resolver failed to ingest type definition: {e}"))?; + + let resolved_sol_type = resolver + .resolve(primary) + .map_err(|e| fmt_err!("Failed to resolve EIP-712 primary type '{primary}': {e}"))?; + + // ABI-decode the bytes into `DynSolValue::CustomStruct`. + let sol_value = resolved_sol_type.abi_decode(abi_encoded_data.as_ref()).map_err(|e| { + fmt_err!("Failed to ABI decode using resolved_sol_type directly for '{primary}': {e}.") + })?; + + // Use the resolver to properly encode the data. + let encoded_data: Vec = resolver + .encode_data(&sol_value) + .map_err(|e| fmt_err!("Failed to EIP-712 encode data for struct '{primary}': {e}"))? + .ok_or_else(|| fmt_err!("EIP-712 data encoding returned 'None' for struct '{primary}'"))?; + + // Compute the type hash of the primary type. + let type_hash = resolver + .type_hash(primary) + .map_err(|e| fmt_err!("Failed to compute typeHash for EIP712 type '{primary}': {e}"))?; + + // Compute the struct hash of the concatenated type hash and encoded data. + let mut bytes_to_hash = Vec::with_capacity(32 + encoded_data.len()); + bytes_to_hash.extend_from_slice(type_hash.as_slice()); + bytes_to_hash.extend_from_slice(&encoded_data); + + Ok(keccak256(&bytes_to_hash).to_vec()) +} diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 2eade5bdd2ccd..0bff1f1f0461c 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -19,9 +19,10 @@ foundry-config.workspace = true foundry-debugger.workspace = true foundry-evm.workspace = true foundry-wallets.workspace = true +foundry-block-explorers.workspace = true foundry-compilers = { workspace = true, features = ["full"] } -foundry-block-explorers.workspace = true +solar-sema.workspace = true alloy-eips.workspace = true alloy-dyn-abi.workspace = true @@ -53,6 +54,7 @@ tracing.workspace = true tracy-client = { workspace = true, optional = true, features = ["demangle"] } yansi.workspace = true rustls = { workspace = true, features = ["ring"] } +dunce.workspace = true tracing-tracy = { version = "0.11", optional = true } diff --git a/crates/cli/src/opts/build/mod.rs b/crates/cli/src/opts/build/mod.rs index 55c61dcbbedd7..4deffb2a4c37d 100644 --- a/crates/cli/src/opts/build/mod.rs +++ b/crates/cli/src/opts/build/mod.rs @@ -8,6 +8,9 @@ pub use self::core::BuildOpts; mod paths; pub use self::paths::ProjectPathOpts; +mod utils; +pub use self::utils::{solar_pcx_from_build_opts, solar_pcx_from_solc_project}; + // A set of solc compiler settings that can be set via command line arguments, which are intended // to be merged into an existing `foundry_config::Config`. // diff --git a/crates/cli/src/opts/build/utils.rs b/crates/cli/src/opts/build/utils.rs new file mode 100644 index 0000000000000..004416c588439 --- /dev/null +++ b/crates/cli/src/opts/build/utils.rs @@ -0,0 +1,105 @@ +use crate::{opts::BuildOpts, utils::LoadConfig}; + +use eyre::Result; +use foundry_compilers::{ + artifacts::{Source, Sources}, + multi::{MultiCompilerLanguage, MultiCompilerParsedSource}, + solc::{SolcLanguage, SolcVersionedInput}, + CompilerInput, Graph, Project, +}; +use solar_sema::{interface::Session, ParsingContext}; +use std::path::PathBuf; + +/// Builds a Solar [`solar_sema::ParsingContext`] from [`BuildOpts`]. +/// +/// * Configures include paths, remappings and registers all in-memory sources so that solar can +/// operate without touching disk. +/// * If no `target_paths` are provided, all project files are processed. +/// * Only processes the subset of sources with the most up-to-date Solitidy version. +pub fn solar_pcx_from_build_opts<'sess>( + sess: &'sess Session, + build: BuildOpts, + target_paths: Option>, +) -> Result> { + // Process build options + let config = build.load_config()?; + let project = config.ephemeral_project()?; + + let sources = match target_paths { + // If target files are provided, only process those sources + Some(targets) => { + let mut sources = Sources::new(); + for t in targets.into_iter() { + let path = dunce::canonicalize(t)?; + let source = Source::read(&path)?; + sources.insert(path, source); + } + sources + } + // Otherwise, process all project files + None => project.paths.read_input_files()?, + }; + + // Only process sources with latest Solidity version to avoid conflicts. + let graph = Graph::::resolve_sources(&project.paths, sources)?; + let (version, sources, _) = graph + // resolve graph into mapping language -> version -> sources + .into_sources_by_version(&project)? + .sources + .into_iter() + // only interested in Solidity sources + .find(|(lang, _)| *lang == MultiCompilerLanguage::Solc(SolcLanguage::Solidity)) + .ok_or_else(|| eyre::eyre!("no Solidity sources"))? + .1 + .into_iter() + // always pick the latest version + .max_by(|(v1, _, _), (v2, _, _)| v1.cmp(v2)) + .unwrap(); + + let solc = SolcVersionedInput::build( + sources, + config.solc_settings()?, + SolcLanguage::Solidity, + version, + ); + + Ok(solar_pcx_from_solc_project(sess, &project, &solc, true)) +} + +/// Builds a Solar [`solar_sema::ParsingContext`] from a [`foundry_compilers::Project`] and a +/// [`SolcVersionedInput`]. +/// +/// * Configures include paths, remappings. +/// * Source files can be manually added if the param `add_source_file` is set to `false`. +pub fn solar_pcx_from_solc_project<'sess>( + sess: &'sess Session, + project: &Project, + solc: &SolcVersionedInput, + add_source_files: bool, +) -> ParsingContext<'sess> { + // Configure the parsing context with the paths, remappings and sources + let mut pcx = ParsingContext::new(sess); + + pcx.file_resolver + .set_current_dir(solc.cli_settings.base_path.as_ref().unwrap_or(&project.paths.root)); + for remapping in &project.paths.remappings { + pcx.file_resolver.add_import_remapping(solar_sema::interface::config::ImportRemapping { + context: remapping.context.clone().unwrap_or_default(), + prefix: remapping.name.clone(), + path: remapping.path.clone(), + }); + } + pcx.file_resolver.add_include_paths(solc.cli_settings.include_paths.iter().cloned()); + + if add_source_files { + for (path, source) in &solc.input.sources { + if let Ok(src_file) = + sess.source_map().new_source_file(path.clone(), source.content.as_str()) + { + pcx.add_file(src_file); + } + } + } + + pcx +} diff --git a/crates/common/src/constants.rs b/crates/common/src/constants.rs index ad944c10d4bc7..5e30eec89c9f0 100644 --- a/crates/common/src/constants.rs +++ b/crates/common/src/constants.rs @@ -45,7 +45,10 @@ pub const SYSTEM_TRANSACTION_TYPE: u8 = 126; /// Default user agent set as the header for requests that don't specify one. pub const DEFAULT_USER_AGENT: &str = concat!("foundry/", env!("CARGO_PKG_VERSION")); -/// Returns whether the sender is a known system sender that is the first tx in every block. +/// Prefix for auto-generated type bindings using `forge bind-json`. +pub const TYPE_BINDING_PREFIX: &str = "string constant schema_"; + +/// Returns whether the sender is a known L2 system sender that is the first tx in every block. /// /// Transactions from these senders usually don't have a any fee information OR set absurdly high fees that exceed the gas limit (See: ) /// diff --git a/crates/forge/Cargo.toml b/crates/forge/Cargo.toml index 17e8449aac79a..ee5727837862c 100644 --- a/crates/forge/Cargo.toml +++ b/crates/forge/Cargo.toml @@ -78,6 +78,7 @@ serde_json.workspace = true similar = { version = "2", features = ["inline"] } solang-parser.workspace = true solar-parse.workspace = true +solar-sema.workspace = true strum = { workspace = true, features = ["derive"] } thiserror.workspace = true tokio = { workspace = true, features = ["time"] } @@ -87,6 +88,7 @@ watchexec-events = "6.0" watchexec-signals = "5.0" clearscreen = "4.0" evm-disassembler.workspace = true +path-slash.workspace = true # doc server axum = { workspace = true, features = ["ws"] } @@ -109,7 +111,6 @@ reqwest = { workspace = true, features = ["json"] } mockall = "0.13" globset = "0.4" paste = "1.0" -path-slash = "0.2" similar-asserts.workspace = true svm = { package = "svm-rs", version = "0.5", default-features = false, features = [ "rustls", diff --git a/crates/forge/src/cmd/bind_json.rs b/crates/forge/src/cmd/bind_json.rs index 7c6bfaa52ad74..ecb76515b16a3 100644 --- a/crates/forge/src/cmd/bind_json.rs +++ b/crates/forge/src/cmd/bind_json.rs @@ -1,28 +1,30 @@ use super::eip712::Resolver; use clap::{Parser, ValueHint}; use eyre::Result; -use foundry_cli::{opts::BuildOpts, utils::LoadConfig}; -use foundry_common::{compile::with_compilation_reporter, fs}; +use foundry_cli::{ + opts::{solar_pcx_from_solc_project, BuildOpts}, + utils::LoadConfig, +}; +use foundry_common::{fs, TYPE_BINDING_PREFIX}; use foundry_compilers::{ - artifacts::{ - output_selection::OutputSelection, ContractDefinitionPart, Source, SourceUnit, - SourceUnitPart, Sources, - }, + artifacts::{Source, Sources}, multi::{MultiCompilerLanguage, MultiCompilerParsedSource}, - project::ProjectCompiler, - solc::SolcLanguage, - Graph, Project, + solc::{SolcLanguage, SolcVersionedInput}, + CompilerInput, Graph, Project, }; use foundry_config::Config; use itertools::Itertools; +use path_slash::PathExt; use rayon::prelude::*; +use semver::Version; use solar_parse::{ ast::{self, interface::source_map::FileName, visit::Visit, Arena, FunctionKind, Span, VarMut}, interface::Session, Parser as SolarParser, }; +use solar_sema::thread_local::ThreadLocal; use std::{ - collections::{BTreeMap, BTreeSet}, + collections::{BTreeMap, BTreeSet, HashSet}, fmt::{self, Write}, ops::ControlFlow, path::PathBuf, @@ -31,6 +33,8 @@ use std::{ foundry_config::impl_figment_convert!(BindJsonArgs, build); +const JSON_BINDINGS_PLACEHOLDER: &str = "library JsonBindings {}"; + /// CLI arguments for `forge bind-json`. #[derive(Clone, Debug, Parser)] pub struct BindJsonArgs { @@ -44,7 +48,7 @@ pub struct BindJsonArgs { impl BindJsonArgs { pub fn run(self) -> Result<()> { - self.preprocess()?.compile()?.find_structs()?.resolve_imports_and_aliases().write()?; + self.preprocess()?.find_structs()?.resolve_imports_and_aliases().write()?; Ok(()) } @@ -74,7 +78,7 @@ impl BindJsonArgs { let graph = Graph::::resolve_sources(&project.paths, sources)?; // We only generate bindings for a single Solidity version to avoid conflicts. - let mut sources = graph + let (version, mut sources, _) = graph // resolve graph into mapping language -> version -> sources .into_sources_by_version(&project)? .sources @@ -86,8 +90,7 @@ impl BindJsonArgs { .into_iter() // For now, we are always picking the latest version. .max_by(|(v1, _, _), (v2, _, _)| v1.cmp(v2)) - .unwrap() - .1; + .unwrap(); let sess = Session::builder().with_stderr_emitter().build(); let result = sess.enter_parallel(|| -> solar_parse::interface::Result<()> { @@ -114,9 +117,9 @@ impl BindJsonArgs { eyre::ensure!(result.is_ok(), "failed parsing"); // Insert empty bindings file. - sources.insert(target_path.clone(), Source::new("library JsonBindings {}")); + sources.insert(target_path.clone(), Source::new(JSON_BINDINGS_PLACEHOLDER)); - Ok(PreprocessedState { sources, target_path, project, config }) + Ok(PreprocessedState { version, sources, target_path, project, config }) } } @@ -237,8 +240,8 @@ impl StructToWrite { } } -#[derive(Debug)] struct PreprocessedState { + version: Version, sources: Sources, target_path: PathBuf, project: Project, @@ -246,117 +249,87 @@ struct PreprocessedState { } impl PreprocessedState { - fn compile(self) -> Result { - let Self { sources, target_path, mut project, config } = self; - - project.update_output_selection(|selection| { - *selection = OutputSelection::ast_output_selection(); - }); - - let output = with_compilation_reporter(false, || { - ProjectCompiler::with_sources(&project, sources)?.compile() - })?; + fn find_structs(self) -> Result { + let mut structs_to_write = Vec::new(); + let Self { version, sources, target_path, config, project } = self; - if output.has_compiler_errors() { - eyre::bail!("{output}"); - } + let settings = config.solc_settings()?; + let include = config.bind_json.include; + let exclude = config.bind_json.exclude; + let root = config.root; - // Collect ASTs by getting them from sources and converting into strongly typed - // `SourceUnit`s. Also strips root from paths. - let asts = output - .into_output() - .sources - .into_iter() - .filter_map(|(path, mut sources)| Some((path, sources.swap_remove(0).source_file.ast?))) - .map(|(path, ast)| { - Ok(( - path.strip_prefix(project.root()).unwrap_or(&path).to_path_buf(), - serde_json::from_str::(&serde_json::to_string(&ast)?)?, - )) - }) - .collect::>>()?; + let input = SolcVersionedInput::build(sources, settings, SolcLanguage::Solidity, version); - Ok(CompiledState { asts, target_path, config, project }) - } -} + let mut sess = Session::builder().with_stderr_emitter().build(); + sess.dcx = sess.dcx.set_flags(|flags| flags.track_diagnostics = false); -#[derive(Debug, Clone)] -struct CompiledState { - asts: BTreeMap, - target_path: PathBuf, - config: Config, - project: Project, -} + let result = sess.enter_parallel(|| -> Result<()> { + // Set up the parsing context with the project paths, without adding the source files + let mut parsing_context = solar_pcx_from_solc_project(&sess, &project, &input, false); -impl CompiledState { - fn find_structs(self) -> Result { - let Self { asts, target_path, config, project } = self; - - // construct mapping (file, id) -> (struct definition, optional parent contract name) - let structs = asts - .iter() - .flat_map(|(path, ast)| { - let mut structs = Vec::new(); - // we walk AST directly instead of using visitors because we need to distinguish - // between file-level and contract-level struct definitions - for node in &ast.nodes { - match node { - SourceUnitPart::StructDefinition(def) => { - structs.push((def, None)); - } - SourceUnitPart::ContractDefinition(contract) => { - for node in &contract.nodes { - if let ContractDefinitionPart::StructDefinition(def) = node { - structs.push((def, Some(contract.name.clone()))); - } - } - } - _ => {} + let mut target_files = HashSet::new(); + for (path, source) in &input.input.sources { + if !include.is_empty() { + if !include.iter().any(|matcher| matcher.is_match(path)) { + continue; + } + } else { + // Exclude library files by default + if project.paths.has_library_ancestor(path) { + continue; } } - structs.into_iter().map(|(def, parent)| ((path.as_path(), def.id), (def, parent))) - }) - .collect::>(); - - // Resolver for EIP712 schemas - let resolver = Resolver::new(&asts); - - let mut structs_to_write = Vec::new(); - - let include = config.bind_json.include; - let exclude = config.bind_json.exclude; - - for ((path, id), (def, contract_name)) in structs { - // For some structs there's no schema (e.g. if they contain a mapping), so we just skip - // those. - let Some(schema) = resolver.resolve_struct_eip712(id)? else { continue }; - if !include.is_empty() { - if !include.iter().any(|matcher| matcher.is_match(path)) { + if exclude.iter().any(|matcher| matcher.is_match(path)) { continue; } - } else { - // Exclude library files by default - if project.paths.has_library_ancestor(path) { - continue; + + if let Ok(src_file) = + sess.source_map().new_source_file(path.clone(), source.content.as_str()) + { + target_files.insert(src_file.stable_id); + parsing_context.add_file(src_file); } } - if exclude.iter().any(|matcher| matcher.is_match(path)) { - continue; - } + // Parse and resolve + let hir_arena = ThreadLocal::new(); + if let Ok(Some(gcx)) = parsing_context.parse_and_lower(&hir_arena) { + let hir = &gcx.get().hir; + let resolver = Resolver::new(gcx); + for id in &resolver.struct_ids() { + if let Some(schema) = resolver.resolve_struct_eip712(*id) { + let def = hir.strukt(*id); + let source = hir.source(def.source); + + if !target_files.contains(&source.file.stable_id) { + continue; + } - structs_to_write.push(StructToWrite { - name: def.name.clone(), - contract_name, - path: path.to_path_buf(), - schema, + if let FileName::Real(ref path) = source.file.name { + structs_to_write.push(StructToWrite { + name: def.name.as_str().into(), + contract_name: def + .contract + .map(|id| hir.contract(id).name.as_str().into()), + path: path + .strip_prefix(&root) + .unwrap_or_else(|_| path) + .to_path_buf(), + schema, + + // will be filled later + import_alias: None, + name_in_fns: String::new(), + }); + } + } + } + } + Ok(()) + }); - // will be filled later - import_alias: None, - name_in_fns: String::new(), - }) - } + eyre::ensure!(result.is_ok() && sess.dcx.has_errors().is_ok(), "failed parsing"); Ok(StructsState { structs_to_write, target_path }) } @@ -482,7 +455,7 @@ impl ResolvedState { result, "import {{{}}} from \"{}\";", names.iter().join(", "), - path.display() + path.to_slash_lossy() )?; } @@ -514,8 +487,8 @@ library JsonBindings { for struct_to_write in &self.structs_to_write { writeln!( result, - " string constant schema_{} = \"{}\";", - struct_to_write.name_in_fns, struct_to_write.schema + " {}{} = \"{}\";", + TYPE_BINDING_PREFIX, struct_to_write.name_in_fns, struct_to_write.schema )?; } diff --git a/crates/forge/src/cmd/eip712.rs b/crates/forge/src/cmd/eip712.rs index 72fbea0a4874a..2df5087592f00 100644 --- a/crates/forge/src/cmd/eip712.rs +++ b/crates/forge/src/cmd/eip712.rs @@ -1,11 +1,12 @@ use clap::{Parser, ValueHint}; -use eyre::{Ok, OptionExt, Result}; -use foundry_cli::{opts::BuildOpts, utils::LoadConfig}; -use foundry_common::compile::ProjectCompiler; -use foundry_compilers::artifacts::{ - output_selection::OutputSelection, - visitor::{Visitor, Walk}, - ContractDefinition, EnumDefinition, SourceUnit, StructDefinition, TypeDescriptions, TypeName, +use eyre::Result; +use foundry_cli::opts::{solar_pcx_from_build_opts, BuildOpts}; +use solar_parse::interface::Session; +use solar_sema::{ + hir::StructId, + thread_local::ThreadLocal, + ty::{Ty, TyKind}, + GcxWrapper, Hir, }; use std::{collections::BTreeMap, fmt::Write, path::PathBuf}; @@ -24,232 +25,154 @@ pub struct Eip712Args { impl Eip712Args { pub fn run(self) -> Result<()> { - let config = self.load_config()?; - let mut project = config.ephemeral_project()?; - let target_path = dunce::canonicalize(self.target_path)?; - project.update_output_selection(|selection| { - *selection = OutputSelection::ast_output_selection(); - }); - - let output = ProjectCompiler::new().files([target_path.clone()]).compile(&project)?; - - // Collect ASTs by getting them from sources and converting into strongly typed - // `SourceUnit`s. - let asts = output - .into_output() - .sources - .into_iter() - .filter_map(|(path, mut sources)| Some((path, sources.swap_remove(0).source_file.ast?))) - .map(|(path, ast)| { - Ok((path, serde_json::from_str::(&serde_json::to_string(&ast)?)?)) - }) - .collect::>>()?; - - let resolver = Resolver::new(&asts); - - let target_ast = asts - .get(&target_path) - .ok_or_else(|| eyre::eyre!("Could not find AST for target file {target_path:?}"))?; - - let structs_in_target = { - let mut collector = StructCollector::default(); - target_ast.walk(&mut collector); - collector.0 - }; - - for id in structs_in_target.keys() { - if let Some(resolved) = resolver.resolve_struct_eip712(*id)? { - sh_println!("{resolved}\n")?; + let mut sess = Session::builder().with_stderr_emitter().build(); + sess.dcx = sess.dcx.set_flags(|flags| flags.track_diagnostics = false); + + let result = sess.enter(|| -> Result<()> { + // Set up the parsing context with the project paths and sources. + let parsing_context = + solar_pcx_from_build_opts(&sess, self.build, Some(vec![self.target_path]))?; + + // Parse and resolve + let hir_arena = ThreadLocal::new(); + if let Ok(Some(gcx)) = parsing_context.parse_and_lower(&hir_arena) { + let resolver = Resolver::new(gcx); + for id in &resolver.struct_ids() { + if let Some(resolved) = resolver.resolve_struct_eip712(*id) { + _ = sh_println!("{resolved}\n"); + } + } } - } - Ok(()) - } -} + Ok(()) + }); -/// AST [Visitor] used for collecting struct definitions. -#[derive(Debug, Clone, Default)] -pub struct StructCollector(pub BTreeMap); + eyre::ensure!(result.is_ok() && sess.dcx.has_errors().is_ok(), "failed parsing"); -impl Visitor for StructCollector { - fn visit_struct_definition(&mut self, def: &StructDefinition) { - self.0.insert(def.id, def.clone()); + Ok(()) } } -/// Collects mapping from AST id of type definition to representation of this type for EIP-712 -/// encoding. +/// Generates the EIP-712 `encodeType` string for a given struct. /// -/// For now, maps contract definitions to `address` and enums to `uint8`. -#[derive(Debug, Clone, Default)] -struct SimpleCustomTypesCollector(BTreeMap); - -impl Visitor for SimpleCustomTypesCollector { - fn visit_contract_definition(&mut self, def: &ContractDefinition) { - self.0.insert(def.id, "address".to_string()); - } - - fn visit_enum_definition(&mut self, def: &EnumDefinition) { - self.0.insert(def.id, "uint8".to_string()); - } -} - -pub struct Resolver { - simple_types: BTreeMap, - structs: BTreeMap, +/// Requires a reference to the source HIR. +pub struct Resolver<'hir> { + hir: &'hir Hir<'hir>, + gcx: GcxWrapper<'hir>, } -impl Resolver { - pub fn new(asts: &BTreeMap) -> Self { - let simple_types = { - let mut collector = SimpleCustomTypesCollector::default(); - asts.values().for_each(|ast| ast.walk(&mut collector)); - - collector.0 - }; - - let structs = { - let mut collector = StructCollector::default(); - asts.values().for_each(|ast| ast.walk(&mut collector)); - collector.0 - }; +impl<'hir> Resolver<'hir> { + /// Constructs a new [`Resolver`] for the supplied [`Hir`] instance. + pub fn new(gcx: GcxWrapper<'hir>) -> Self { + Self { hir: &gcx.get().hir, gcx } + } - Self { simple_types, structs } + /// Returns the [`StructId`]s of every user-defined struct in source order. + pub fn struct_ids(&self) -> Vec { + self.hir.strukt_ids().collect() } - /// Converts a given struct definition into EIP-712 `encodeType` representation. + /// Converts a given struct into its EIP-712 `encodeType` representation. /// - /// Returns `None` if struct contains any fields that are not supported by EIP-712 (e.g. - /// mappings or function pointers). - pub fn resolve_struct_eip712(&self, id: usize) -> Result> { + /// Returns `None` if the struct, or any of its fields, contains constructs + /// not supported by EIP-712 (mappings, function types, errors, etc). + pub fn resolve_struct_eip712(&self, id: StructId) -> Option { let mut subtypes = BTreeMap::new(); - subtypes.insert(self.structs[&id].name.clone(), id); + subtypes.insert(self.hir.strukt(id).name.as_str().into(), id); self.resolve_eip712_inner(id, &mut subtypes, true, None) } fn resolve_eip712_inner( &self, - id: usize, - subtypes: &mut BTreeMap, + id: StructId, + subtypes: &mut BTreeMap, append_subtypes: bool, rename: Option<&str>, - ) -> Result> { - let def = &self.structs[&id]; - let mut result = format!("{}(", rename.unwrap_or(&def.name)); - - for (idx, member) in def.members.iter().enumerate() { - let Some(ty) = self.resolve_type( - member.type_name.as_ref().ok_or_eyre("missing type name")?, - subtypes, - )? - else { - return Ok(None) - }; - - write!(result, "{ty} {name}", name = member.name)?; - - if idx < def.members.len() - 1 { + ) -> Option { + let def = self.hir.strukt(id); + let mut result = format!("{}(", rename.unwrap_or(def.name.as_str())); + + for (idx, field_id) in def.fields.iter().enumerate() { + let field = self.hir.variable(*field_id); + let ty = self.resolve_type(self.gcx.get().type_of_hir_ty(&field.ty), subtypes)?; + + write!(result, "{ty} {name}", name = field.name?.as_str()).ok()?; + + if idx < def.fields.len() - 1 { result.push(','); } } result.push(')'); - if !append_subtypes { - return Ok(Some(result)) - } + if append_subtypes { + for (subtype_name, subtype_id) in + subtypes.iter().map(|(name, id)| (name.clone(), *id)).collect::>() + { + if subtype_id == id { + continue + } + let encoded_subtype = + self.resolve_eip712_inner(subtype_id, subtypes, false, Some(&subtype_name))?; - for (subtype_name, subtype_id) in - subtypes.iter().map(|(name, id)| (name.clone(), *id)).collect::>() - { - if subtype_id == id { - continue + result.push_str(&encoded_subtype); } - let Some(encoded_subtype) = - self.resolve_eip712_inner(subtype_id, subtypes, false, Some(&subtype_name))? - else { - return Ok(None) - }; - result.push_str(&encoded_subtype); } - Ok(Some(result)) + Some(result) } - /// Converts given [TypeName] into a type which can be converted to - /// [`alloy_dyn_abi::DynSolType`]. - /// - /// Returns `None` if the type is not supported for EIP712 encoding. - pub fn resolve_type( + fn resolve_type( &self, - type_name: &TypeName, - subtypes: &mut BTreeMap, - ) -> Result> { - match type_name { - TypeName::FunctionTypeName(_) | TypeName::Mapping(_) => Ok(None), - TypeName::ElementaryTypeName(ty) => Ok(Some(ty.name.clone())), - TypeName::ArrayTypeName(ty) => { - let Some(inner) = self.resolve_type(&ty.base_type, subtypes)? else { - return Ok(None) + ty: Ty<'hir>, + subtypes: &mut BTreeMap, + ) -> Option { + let ty = ty.peel_refs(); + match ty.kind { + TyKind::Elementary(elem_ty) => Some(elem_ty.to_abi_str().to_string()), + TyKind::Array(element_ty, size) => { + let inner_type = self.resolve_type(element_ty, subtypes)?; + let size = size.to_string(); + Some(format!("{inner_type}[{size}]")) + } + TyKind::DynArray(element_ty) => { + let inner_type = self.resolve_type(element_ty, subtypes)?; + Some(format!("{inner_type}[]")) + } + TyKind::Udvt(ty, _) => self.resolve_type(ty, subtypes), + TyKind::Struct(id) => { + let def = self.hir.strukt(id); + let name = match subtypes.iter().find(|(_, cached_id)| id == **cached_id) { + Some((name, _)) => name.to_string(), + None => { + // Otherwise, assign new name + let mut i = 0; + let mut name = def.name.as_str().into(); + while subtypes.contains_key(&name) { + i += 1; + name = format!("{}_{i}", def.name.as_str()); + } + + subtypes.insert(name.clone(), id); + + // Recursively resolve fields to populate subtypes + for field_id in def.fields { + let field_ty = + self.gcx.get().type_of_hir_ty(&self.hir.variable(*field_id).ty); + self.resolve_type(field_ty, subtypes)?; + } + name + } }; - let len = parse_array_length(&ty.type_descriptions)?; - Ok(Some(format!("{inner}[{}]", len.unwrap_or("")))) - } - TypeName::UserDefinedTypeName(ty) => { - if let Some(name) = self.simple_types.get(&(ty.referenced_declaration as usize)) { - Ok(Some(name.clone())) - } else if let Some(def) = self.structs.get(&(ty.referenced_declaration as usize)) { - let name = - // If we've already seen struct with this ID, just use assigned name. - if let Some((name, _)) = subtypes.iter().find(|(_, id)| **id == def.id) { - name.clone() - } else { - // Otherwise, assign new name. - let mut i = 0; - let mut name = def.name.clone(); - while subtypes.contains_key(&name) { - i += 1; - name = format!("{}_{i}", def.name); - } - - subtypes.insert(name.clone(), def.id); - - // iterate over members to check if they are resolvable and to populate subtypes - for member in &def.members { - if self.resolve_type( - member.type_name.as_ref().ok_or_eyre("missing type name")?, - subtypes, - )? - .is_none() - { - return Ok(None) - } - } - name - }; - - Ok(Some(name)) - } else { - Ok(None) - } + Some(name) } + // For now, map enums to `uint8` + TyKind::Enum(_) => Some("uint8".to_string()), + // For now, map contracts to `address` + TyKind::Contract(_) => Some("address".to_string()), + // EIP-712 doesn't support tuples (should use structs), functions, mappings, nor errors + _ => None, } } } - -fn parse_array_length(type_description: &TypeDescriptions) -> Result> { - let type_string = - type_description.type_string.as_ref().ok_or_eyre("missing typeString for array type")?; - let Some(inside_brackets) = - type_string.rsplit_once("[").and_then(|(_, right)| right.split("]").next()) - else { - eyre::bail!("failed to parse array type string: {type_string}") - }; - - if inside_brackets.is_empty() { - Ok(None) - } else { - Ok(Some(inside_brackets)) - } -} diff --git a/crates/forge/tests/cli/eip712.rs b/crates/forge/tests/cli/eip712.rs index 9ec944631d9db..165942563d157 100644 --- a/crates/forge/tests/cli/eip712.rs +++ b/crates/forge/tests/cli/eip712.rs @@ -1,3 +1,5 @@ +use foundry_config::fs_permissions::PathPermission; + forgetest!(test_eip712, |prj, cmd| { let path = prj .add_source( @@ -55,9 +57,6 @@ library Structs2 { cmd.forge_fuse().args(["eip712", path.to_string_lossy().as_ref()]).assert_success().stdout_eq( str![[r#" -[COMPILING_FILES] with [SOLC_VERSION] -[SOLC_VERSION] [ELAPSED] -No files changed, compilation skipped Foo(Bar bar)Art(uint256 id)Bar(Art art) Bar(Art art)Art(uint256 id) @@ -80,3 +79,573 @@ FooBar(Foo[] foos,Bar[] bars,Foo_1 foo,Bar_1 bar,Rec[] recs,Rec_1 rec)Art(uint25 "#]], ); }); + +forgetest!(test_eip712_cheatcode_simple, |prj, cmd| { + prj.insert_ds_test(); + prj.insert_vm(); + prj.insert_console(); + + prj.add_source( + "Eip712", + r#" +contract Eip712Structs { + struct EIP712Domain { + string name; + string version; + uint256 chainId; + address verifyingContract; + } +} + "#, + ) + .unwrap(); + + prj.add_source("Eip712Cheat.sol", r#" +import "./test.sol"; +import "./Vm.sol"; +import "./console.sol"; + +string constant CANONICAL = "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"; + +contract Eip712Test is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + function testEip712HashType() public { + bytes32 canonicalHash = keccak256(bytes(CANONICAL)); + console.logBytes32(canonicalHash); + + // Can figure out the canonical type from a messy string representation of the type, + // with an invalid order and extra whitespaces + bytes32 fromTypeDef = vm.eip712HashType( + "EIP712Domain(string name, string version, uint256 chainId, address verifyingContract)" + ); + assertEq(fromTypeDef, canonicalHash); + + // Can figure out the canonical type from the previously generated bindings + bytes32 fromTypeName = vm.eip712HashType("EIP712Domain"); + assertEq(fromTypeName, canonicalHash); + } +} +"#, + ) + .unwrap(); + + cmd.forge_fuse().args(["bind-json"]).assert_success(); + + let bindings = prj.root().join("utils").join("JsonBindings.sol"); + assert!(bindings.exists(), "'JsonBindings.sol' was not generated at {bindings:?}"); + + prj.update_config(|config| config.fs_permissions.add(PathPermission::read(bindings))); + cmd.forge_fuse().args(["test", "--mc", "Eip712Test", "-vv"]).assert_success().stdout_eq(str![ + [r#" +[COMPILING_FILES] with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 1 test for src/Eip712Cheat.sol:Eip712Test +[PASS] testEip712HashType() ([GAS]) +Logs: + 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f + +Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) + +"#] + ]); +}); + +forgetest!(test_eip712_cheatcode_nested, |prj, cmd| { + prj.insert_ds_test(); + prj.insert_vm(); + prj.insert_console(); + + prj.add_source( + "Eip712", + r#" +contract Eip712Structs { + struct Transaction { + Person from; + Person to; + Asset tx; + } + struct Person { + address wallet; + string name; + } + struct Asset { + address token; + uint256 amount; + } +} + "#, + ) + .unwrap(); + + prj.add_source("Eip712Cheat.sol", r#" +import "./test.sol"; +import "./Vm.sol"; + +string constant CANONICAL = "Transaction(Person from,Person to,Asset tx)Asset(address token,uint256 amount)Person(address wallet,string name)"; + +contract Eip712Test is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + function testEip712HashType_byDefinition() public { + bytes32 canonicalHash = keccak256(bytes(CANONICAL)); + + // Can figure out the canonical type from a messy string representation of the type, + // with an invalid order and extra whitespaces + bytes32 fromTypeDef = vm.eip712HashType( + "Person(address wallet, string name) Asset(address token, uint256 amount) Transaction(Person from, Person to, Asset tx)" + ); + assertEq(fromTypeDef, canonicalHash); + } + + function testEip712HashType_byTypeName() public { + bytes32 canonicalHash = keccak256(bytes(CANONICAL)); + + // Can figure out the canonical type from the previously generated bindings + bytes32 fromTypeName = vm.eip712HashType("Transaction"); + assertEq(fromTypeName, canonicalHash); + } + + function testReverts_Eip712HashType_invalidName() public { + // Reverts if the input type is not found in the bindings + vm._expectCheatcodeRevert(); + bytes32 fromTypeName = vm.eip712HashType("InvalidTypeName"); + } + + function testEip712HashType_byCustomPathAndTypeName() public { + bytes32 canonicalHash = keccak256(bytes(CANONICAL)); + + // Can figure out the canonical type from the previously generated bindings + bytes32 fromTypeName = vm.eip712HashType("utils/CustomJsonBindings.sol", "Transaction"); + assertEq(fromTypeName, canonicalHash); + } +} +"#, + ) + .unwrap(); + + // cheatcode by type definition can run without bindings + cmd.forge_fuse() + .args(["test", "--mc", "Eip712Test", "--match-test", "testEip712HashType_byDefinition"]) + .assert_success(); + + let bindings = prj.root().join("utils").join("JsonBindings.sol"); + prj.update_config(|config| config.fs_permissions.add(PathPermission::read(&bindings))); + + // cheatcode by type name fails if bindings haven't been generated + cmd.forge_fuse() + .args(["test", "--mc", "Eip712Test", "--match-test", "testEip712HashType_byTypeName"]) + .assert_failure() + .stdout_eq(str![[r#" +... +Ran 1 test for src/Eip712Cheat.sol:Eip712Test +[FAIL: vm.eip712HashType: failed to read from [..] testEip712HashType_byTypeName() ([GAS]) +Suite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests) + +Failing tests: +Encountered 1 failing test in src/Eip712Cheat.sol:Eip712Test +[FAIL: vm.eip712HashType: failed to read from [..] testEip712HashType_byTypeName() ([GAS]) + +Encountered a total of 1 failing tests, 0 tests succeeded + +"#]]); + + cmd.forge_fuse().args(["bind-json"]).assert_success(); + assert!(bindings.exists(), "'JsonBindings.sol' was not generated at {bindings:?}"); + + // with generated bindings, cheatcode by type name works + cmd.forge_fuse() + .args(["test", "--mc", "Eip712Test", "--match-test", "testEip712HashType_byTypeName"]) + .assert_success(); + + // even with generated bindings, cheatcode by type name fails if name is not present + cmd.forge_fuse() + .args([ + "test", + "--mc", + "Eip712Test", + "--match-test", + "testReverts_Eip712HashType_invalidName", + ]) + .assert_success(); + + let bindings_2 = prj.root().join("utils").join("CustomJsonBindings.sol"); + prj.update_config(|config| { + config.fs_permissions.add(PathPermission::read(&bindings_2)); + }); + + // cheatcode by custom path and type name fails if bindings haven't been generated for that path + cmd.forge_fuse() + .args(["test", "--mc", "Eip712Test", "--match-test", "testEip712HashType_byCustomPathAndTypeName"]) + .assert_failure() + .stdout_eq(str![[r#" +... +Ran 1 test for src/Eip712Cheat.sol:Eip712Test +[FAIL: vm.eip712HashType: failed to read from [..] testEip712HashType_byCustomPathAndTypeName() ([GAS]) +Suite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests) + +Failing tests: +Encountered 1 failing test in src/Eip712Cheat.sol:Eip712Test +[FAIL: vm.eip712HashType: failed to read from [..] testEip712HashType_byCustomPathAndTypeName() ([GAS]) + +Encountered a total of 1 failing tests, 0 tests succeeded + +"#]]); + + cmd.forge_fuse().args(["bind-json", "utils/CustomJsonBindings.sol"]).assert_success(); + assert!(bindings_2.exists(), "'CustomJsonBindings.sol' was not generated at {bindings_2:?}"); + + // with generated bindings, cheatcode by custom path and type name works + cmd.forge_fuse() + .args([ + "test", + "--mc", + "Eip712Test", + "--match-test", + "testEip712HashType_byCustomPathAndTypeName", + ]) + .assert_success(); +}); + +forgetest!(test_eip712_hash_struct_simple, |prj, cmd| { + prj.insert_ds_test(); + prj.insert_vm(); + prj.insert_console(); + + prj.add_source( + "Eip712HashStructDomainTest.sol", + r#" +import "./Vm.sol"; +import "./test.sol"; +import "./console.sol"; + +struct EIP712Domain { + string name; + string version; + uint256 chainId; + address verifyingContract; +} + +string constant _EIP712_DOMAIN_TYPE_DEF = "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"; +bytes32 constant _EIP712_DOMAIN_TYPE_HASH = keccak256(bytes(_EIP712_DOMAIN_TYPE_DEF)); + +contract Eip712HashStructDomainTest is DSTest { + Vm constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function testHashEIP712Domain() public { + EIP712Domain memory domain = EIP712Domain({ + name: "Foo", + version: "Bar", + chainId: 1, + verifyingContract: 0xdEADBEeF00000000000000000000000000000000 + }); + + // simulate user-computed domain hash + bytes memory encodedData = abi.encode( + keccak256(bytes(domain.name)), + keccak256(bytes(domain.version)), + bytes32(domain.chainId), + bytes32(uint256(uint160(domain.verifyingContract))) + ); + bytes32 userStructHash = keccak256(abi.encodePacked(_EIP712_DOMAIN_TYPE_HASH, encodedData)); + + // cheatcode-computed domain hash + bytes32 cheatStructHash = vm.eip712HashStruct(_EIP712_DOMAIN_TYPE_DEF, abi.encode(domain)); + console.log("EIP712Domain struct hash from cheatcode:"); + console.logBytes32(cheatStructHash); + + assertEq(cheatStructHash, userStructHash, "EIP712Domain struct hash mismatch"); + } +} +"#, + ) + .unwrap(); + + cmd.forge_fuse().args(["test", "--mc", "Eip712HashStructDomainTest", "-vvvv"]).assert_success(); +}); + +forgetest!(test_eip712_hash_struct_complex, |prj, cmd| { + prj.insert_ds_test(); + prj.insert_vm(); + prj.insert_console(); + + prj.add_source( + "Eip712Permit.sol", + r#" +struct PermitDetails { + address token; + uint160 amount; + uint48 expiration; + uint48 nonce; +} + +bytes32 constant _PERMIT_DETAILS_TYPEHASH = keccak256( + "PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)" +); + +struct PermitSingle { + PermitDetails details; + address spender; + uint256 sigDeadline; +} + +bytes32 constant _PERMIT_SINGLE_TYPEHASH = keccak256( + "PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)" +); + +// borrowed from https://github.com/Uniswap/permit2/blob/main/src/libraries/PermitHash.sol +library PermitHash { + function hash(PermitSingle memory permitSingle) internal pure returns (bytes32) { + bytes32 permitHash = _hashDetails(permitSingle.details); + return + keccak256(abi.encode(_PERMIT_SINGLE_TYPEHASH, permitHash, permitSingle.spender, permitSingle.sigDeadline)); + } + + function _hashDetails(PermitDetails memory details) internal pure returns (bytes32) { + return keccak256(abi.encode(_PERMIT_DETAILS_TYPEHASH, details)); + } +} +"#, + ) + .unwrap(); + + prj.add_source( + "Eip712Transaction.sol", + r#" +struct Asset { + address token; + uint256 amount; +} + +bytes32 constant _ASSET_TYPEHASH = keccak256( + "Asset(address token,uint256 amount)" +); + +struct Person { + address wallet; + string name; +} + +bytes32 constant _PERSON_TYPEHASH = keccak256( + "Person(address wallet,string name)" +); + +struct Transaction { + Person from; + Person to; + Asset tx; +} + +bytes32 constant _TRANSACTION_TYPEHASH = keccak256( + "Transaction(Person from,Person to,Asset tx)Asset(address token,uint256 amount)Person(address wallet,string name)" +); + + +library TransactionHash { + function hash(Transaction memory t) internal pure returns (bytes32) { + bytes32 fromHash = _hashPerson(t.from); + bytes32 toHash = _hashPerson(t.to); + bytes32 assetHash = _hashAsset(t.tx); + return + keccak256(abi.encode(_TRANSACTION_TYPEHASH, fromHash, toHash, assetHash)); + } + + function _hashPerson(Person memory person) internal pure returns (bytes32) { + return keccak256( + abi.encode(_PERSON_TYPEHASH, person.wallet, keccak256(bytes(person.name))) + ); + + } + + function _hashAsset(Asset memory asset) internal pure returns (bytes32) { + return keccak256(abi.encode(_ASSET_TYPEHASH, asset)); + } +} + "#, + ) + .unwrap(); + + let bindings = prj.root().join("utils").join("JsonBindings.sol"); + prj.update_config(|config| config.fs_permissions.add(PathPermission::read(&bindings))); + cmd.forge_fuse().args(["bind-json"]).assert_success(); + + prj.add_source( + "Eip712HashStructTest.sol", + r#" +import "./Vm.sol"; +import "./test.sol"; +import "./console.sol"; +import "./Eip712Permit.sol"; +import "./Eip712Transaction.sol"; + +contract Eip712HashStructTest is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + function testHashPermitSingle_withTypeName() public { + PermitDetails memory details = PermitDetails({ + token: 0x1111111111111111111111111111111111111111, + amount: 1000 ether, + expiration: 12345, + nonce: 1 + }); + + // user-computed permit (using uniswap hash library) + bytes32 userStructHash = PermitHash._hashDetails(details); + + // cheatcode-computed permit + bytes32 cheatStructHash = vm.eip712HashStruct("PermitDetails", abi.encode(details)); + + assertEq(cheatStructHash, userStructHash, "details struct hash mismatch"); + + PermitSingle memory permit = PermitSingle({ + details: details, + spender: 0x2222222222222222222222222222222222222222, + sigDeadline: 12345 + }); + + // user-computed permit (using uniswap hash library) + userStructHash = PermitHash.hash(permit); + + // cheatcode-computed permit + cheatStructHash = vm.eip712HashStruct("PermitSingle", abi.encode(permit)); + console.log("PermitSingle struct hash from cheatcode:"); + console.logBytes32(cheatStructHash); + + assertEq(cheatStructHash, userStructHash, "permit struct hash mismatch"); + } + + function testHashPermitSingle_withTypeDefinion() public { + PermitDetails memory details = PermitDetails({ + token: 0x1111111111111111111111111111111111111111, + amount: 1000 ether, + expiration: 12345, + nonce: 1 + }); + + // user-computed permit (using uniswap hash library) + bytes32 userStructHash = PermitHash._hashDetails(details); + + // cheatcode-computed permit + bytes32 cheatStructHash = vm.eip712HashStruct("PermitDetails(address token, uint160 amount, uint48 expiration, uint48 nonce)", abi.encode(details)); + + assertEq(cheatStructHash, userStructHash, "details struct hash mismatch"); + + PermitSingle memory permit = PermitSingle({ + details: details, + spender: 0x2222222222222222222222222222222222222222, + sigDeadline: 12345 + }); + + // user-computed permit (using uniswap hash library) + userStructHash = PermitHash.hash(permit); + + // cheatcode-computed permit (previously encoding) + cheatStructHash = vm.eip712HashStruct("PermitDetails(address token, uint160 amount, uint48 expiration, uint48 nonce) PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)", abi.encode(permit)); + console.log("PermitSingle struct hash from cheatcode:"); + console.logBytes32(cheatStructHash); + + assertEq(cheatStructHash, userStructHash, "permit struct hash mismatch"); + } + + function testHashTransaction_withTypeName() public { + Asset memory asset = Asset ({ token: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, amount: 100 ether }); + + bytes32 user = TransactionHash._hashAsset(asset); + bytes32 cheat = vm.eip712HashStruct("Asset", abi.encode(asset)); + assertEq(user, cheat, "asset struct hash mismatch"); + + Person memory from = Person ({ wallet: 0x0000000000000000000000000000000000000001, name: "alice" }); + Person memory to = Person ({ wallet: 0x0000000000000000000000000000000000000002, name: "bob" }); + + user = TransactionHash._hashPerson(from); + cheat = vm.eip712HashStruct("Person", abi.encode(from)); + assertEq(user, cheat, "person struct hash mismatch"); + + Transaction memory t = Transaction ({ from: from, to: to, tx: asset }); + + user = TransactionHash.hash(t); + cheat = vm.eip712HashStruct("Transaction", abi.encode(t)); + assertEq(user, cheat, "transaction struct hash mismatch"); + } + + function testHashTransaction_withTypeDefinition() public { + Asset memory asset = Asset ({ token: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, amount: 100 ether }); + + bytes32 user = TransactionHash._hashAsset(asset); + bytes32 cheat = vm.eip712HashStruct("Asset(address token, uint256 amount)", abi.encode(asset)); + assertEq(user, cheat, "asset struct hash mismatch"); + + Person memory from = Person ({ wallet: 0x0000000000000000000000000000000000000001, name: "alice" }); + Person memory to = Person ({ wallet: 0x0000000000000000000000000000000000000002, name: "bob" }); + + user = TransactionHash._hashPerson(from); + cheat = vm.eip712HashStruct("Person(address wallet, string name)", abi.encode(from)); + assertEq(user, cheat, "person struct hash mismatch"); + + Transaction memory t = Transaction ({ from: from, to: to, tx: asset }); + + user = TransactionHash.hash(t); + cheat = vm.eip712HashStruct("Person(address wallet, string name) Asset(address token, uint256 amount) Transaction(Person from, Person to, Asset tx)", abi.encode(t)); + assertEq(user, cheat, "transaction struct hash mismatch"); + } +} +"#, + ) + .unwrap(); + + cmd.forge_fuse() + .args(["test", "--mc", "Eip712HashStructTest", "-vv"]) + .assert_success() + .stdout_eq(str![[r#" +... +[PASS] testHashPermitSingle_withTypeDefinion() ([GAS]) +Logs: + PermitSingle struct hash from cheatcode: + 0x3ed744fdcea02b6b9ad45a9db6e648bf6f18c221909f9ee425191f2a02f9e4a8 + +[PASS] testHashPermitSingle_withTypeName() ([GAS]) +Logs: + PermitSingle struct hash from cheatcode: + 0x3ed744fdcea02b6b9ad45a9db6e648bf6f18c221909f9ee425191f2a02f9e4a8 +... +"#]]); +}); + +forgetest!(test_eip712_hash_typed_data, |prj, cmd| { + prj.insert_ds_test(); + prj.insert_vm(); + prj.insert_console(); + + prj.add_source( + "Eip712HashTypedData.sol", + r#" +import "./Vm.sol"; +import "./test.sol"; +import "./console.sol"; +contract Eip712HashTypedDataTest is DSTest { + Vm constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function testHashEIP712Message() public { + string memory jsonData = + '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"},{"name":"salt","type":"bytes32"}]},"primaryType":"EIP712Domain","domain":{"name":"example.metamask.io","version":"1","chainId":1,"verifyingContract":"0x0000000000000000000000000000000000000000"},"message":{}}'; + + // since this cheatcode simply exposes an alloy fn, the test has been borrowed from: + // + bytes32 expectedHash = hex"122d1c8ef94b76dad44dcb03fa772361e20855c63311a15d5afe02d1b38f6077"; + assertEq(vm.eip712HashTypedData(jsonData), expectedHash, "EIP712Domain struct hash mismatch"); + } +} +"#, + ) + .unwrap(); + + cmd.forge_fuse().args(["test", "--mc", "Eip712HashTypedDataTest"]).assert_success(); +}); diff --git a/docs/dev/cheatcodes.md b/docs/dev/cheatcodes.md index 0815ca66bef50..0c96c4ba7c7f5 100644 --- a/docs/dev/cheatcodes.md +++ b/docs/dev/cheatcodes.md @@ -155,7 +155,7 @@ update of the files. 2. Implement the cheatcode in [`cheatcodes`] in its category's respective module. Follow the existing implementations as a guide. 3. If a struct, enum, error, or event was added to `Vm`, update [`spec::Cheatcodes::new`] 4. Update the JSON interface by running `cargo cheats` twice. This is expected to fail the first time that this is run after adding a new cheatcode; see [JSON interface](#json-interface) -5. Write an integration test for the cheatcode in [`testdata/cheats/`] +5. Write an integration test for the cheatcode in [`testdata/default/cheats/`] [`sol!`]: https://docs.rs/alloy-sol-macro/latest/alloy_sol_macro/macro.sol.html [`cheatcodes/spec/src/vm.rs`]: ../../crates/cheatcodes/spec/src/vm.rs diff --git a/testdata/cheats/Vm.sol b/testdata/cheats/Vm.sol index 6d054abbfc6ec..b439cf9b6f883 100644 --- a/testdata/cheats/Vm.sol +++ b/testdata/cheats/Vm.sol @@ -208,6 +208,11 @@ interface Vm { function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index, string calldata language) external pure returns (uint256 privateKey); function difficulty(uint256 newDifficulty) external; function dumpState(string calldata pathToStateJson) external; + function eip712HashStruct(string calldata typeNameOrDefinition, bytes calldata abiEncodedData) external pure returns (bytes32 typeHash); + function eip712HashStruct(string calldata bindingsPath, string calldata typeName, bytes calldata abiEncodedData) external pure returns (bytes32 typeHash); + function eip712HashType(string calldata typeNameOrDefinition) external pure returns (bytes32 typeHash); + function eip712HashType(string calldata bindingsPath, string calldata typeName) external pure returns (bytes32 typeHash); + function eip712HashTypedData(string calldata jsonData) external pure returns (bytes32 digest); function ensNamehash(string calldata name) external pure returns (bytes32); function envAddress(string calldata name) external view returns (address value); function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value); From dc43e2c1ab70ec111d3272572e1732008f973a06 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Wed, 4 Jun 2025 22:31:52 +0200 Subject: [PATCH 172/244] fix: always update auth txenv var (#10707) --- crates/evm/core/src/utils.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/evm/core/src/utils.rs b/crates/evm/core/src/utils.rs index 29518074644d0..9ff6bcc8aec63 100644 --- a/crates/evm/core/src/utils.rs +++ b/crates/evm/core/src/utils.rs @@ -167,9 +167,7 @@ pub fn configure_tx_req_env( env.tx.max_fee_per_blob_gas = max_fee_per_blob_gas.unwrap_or_default(); // Type 4, EIP-7702 - if let Some(authorization_list) = authorization_list { - env.tx.set_signed_authorization(authorization_list.clone()); - } + env.tx.set_signed_authorization(authorization_list.clone().unwrap_or_default()); Ok(()) } From 8cdf80b6cd273d4abcce65acd829c4445f25b8d4 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Thu, 5 Jun 2025 11:57:28 +0300 Subject: [PATCH 173/244] fix(cast): do not use default overrides if no override arg (#10710) --- crates/cast/src/cmd/call.rs | 20 +++++++++++++++++--- crates/cast/src/lib.rs | 15 +++++++-------- crates/cast/tests/cli/main.rs | 10 ++++++++++ 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/crates/cast/src/cmd/call.rs b/crates/cast/src/cmd/call.rs index 6a13678184d36..c92bedaadf192 100644 --- a/crates/cast/src/cmd/call.rs +++ b/crates/cast/src/cmd/call.rs @@ -313,8 +313,22 @@ impl CallArgs { Ok(()) } - /// Parse state overrides from command line arguments - pub fn get_state_overrides(&self) -> eyre::Result { + + /// Parse state overrides from command line arguments. + pub fn get_state_overrides(&self) -> eyre::Result> { + // Early return if no override set - + if [ + self.balance_overrides.as_ref(), + self.nonce_overrides.as_ref(), + self.code_overrides.as_ref(), + self.state_overrides.as_ref(), + ] + .iter() + .all(Option::is_none) + { + return Ok(None); + } + let mut state_overrides_builder = StateOverridesBuilder::default(); // Parse balance overrides @@ -352,7 +366,7 @@ impl CallArgs { state_overrides_builder.with_state_diff(addr, [(slot.into(), value.into())]); } - Ok(state_overrides_builder.build()) + Ok(Some(state_overrides_builder.build())) } } diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 1b5db80406f30..b8bdc2ba6d03e 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -137,7 +137,7 @@ impl> Cast

{ /// let state_override_object = StateOverridesBuilder::default().build(); /// /// let cast = Cast::new(alloy_provider); - /// let data = cast.call(&tx, None, None, state_override_object).await?; + /// let data = cast.call(&tx, None, None, Some(state_override_object)).await?; /// println!("{}", data); /// # Ok(()) /// # } @@ -147,15 +147,14 @@ impl> Cast

{ req: &WithOtherFields, func: Option<&Function>, block: Option, - state_override: StateOverride, + state_override: Option, ) -> Result { - let res = self - .provider - .call(req.clone()) - .block(block.unwrap_or_default()) - .overrides(state_override) - .await?; + let mut call = self.provider.call(req.clone()).block(block.unwrap_or_default()); + if let Some(state_override) = state_override { + call = call.overrides(state_override) + } + let res = call.await?; let mut decoded = vec![]; if let Some(func) = func { diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index c8ed087356250..cbc7b193f0258 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -2718,3 +2718,13 @@ Estimated data availability size for block 30558838 with 225 transactions: 52916 "#]]); }); + +// +casttest!(cast_call_return_array_of_tuples, |_prj, cmd| { + cmd.args(["call", "0x198FC70Dfe05E755C81e54bd67Bff3F729344B9b", "facets() returns ((address,bytes4[])[])", "--rpc-url", "https://rpc.viction.xyz"]) + .assert_success() + .stdout_eq(str![[r#" +[(0x9640977264aec6d4e9af381F548eee11b9e27aAe, [0x1f931c1c]), (0x395db83A04cC3d3F6C5eFc73896929Cf10D0F301, [0xcdffacc6, 0x52ef6b2c, 0xadfca15e, 0x7a0ed627, 0x01ffc9a7]), (0xC6F7b47F870024B0E2DF6DFd551E10c4A37A1cEa, [0x23452b9c, 0x7200b829, 0x8da5cb5b, 0xf2fde38b]), (0xc1f27c1f6c87e73e089Ffac23C236Fc4A9E3fccc, [0x1458d7ad, 0xd9caed12]), (0x70e272A93bc8344277a1f4390Ea6153A1D5fe450, [0x536db266, 0xfbb2d381, 0xfcd8e49e, 0x9afc19c7, 0x44e2b18c, 0x2d2506a9, 0x124f1ead, 0xc3a6a96b]), (0x662BCADB7A2CBb22367b2471d8A91E5b13FCe96B, [0x612ad9cb, 0xa4c3366e]), (0x190e03D49Ce76DDabC634a98629EDa6246aB5196, [0xa516f0f3, 0x5c2ed36a]), (0xAF69C0E3BBBf6AdE78f1466f86DfF86d64C8dA2A, [0x4630a0d8]), (0xD1317DA862AC5C145519E60D24372dc186EF7426, [0xd5bcb610, 0x5fd9ae2e, 0x2c57e884, 0x736eac0b, 0x4666fc80, 0x733214a3, 0xaf7060fd]), (0x176f558949e2a7C5217dD9C27Bf7A43c6783ee28, [0x7f99d7af, 0x103c5200, 0xc318eeda, 0xee0aa320, 0xdf1c3a5b, 0x070e81f1, 0xd53482cf, 0xf58ae2ce]), (0x531d69A3fAb6CB56A77B8402E6c217cB9cC902A9, [0xf86368ae, 0x5ad317a4, 0x0340e905, 0x2fc487ae])] + +"#]]); +}); From b3fe111c5d0382651617675c73987c2e37d36f24 Mon Sep 17 00:00:00 2001 From: taikoon Date: Thu, 5 Jun 2025 19:37:24 +0800 Subject: [PATCH 174/244] feat: add some clippy lint (#10479) Co-authored-by: grandizzy --- Cargo.toml | 5 +++++ crates/anvil/src/eth/api.rs | 6 +++--- crates/anvil/src/eth/backend/mem/mod.rs | 13 ++----------- crates/anvil/src/eth/fees.rs | 2 +- crates/anvil/src/eth/otterscan/api.rs | 2 +- crates/anvil/src/eth/pool/transactions.rs | 2 +- crates/anvil/src/eth/sign.rs | 2 +- crates/anvil/tests/it/txpool.rs | 4 +--- crates/cheatcodes/src/script.rs | 4 ++-- crates/common/src/contracts.rs | 2 +- crates/common/src/fs.rs | 2 +- crates/config/src/lib.rs | 2 +- crates/doc/src/parser/comment.rs | 6 +++--- crates/evm/fuzz/src/strategies/param.rs | 7 ++----- crates/fmt/src/formatter.rs | 2 +- crates/forge/src/cmd/clone.rs | 4 +--- crates/test-utils/src/util.rs | 6 +++--- 17 files changed, 30 insertions(+), 41 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6355d1d945316..48c72f61a9661 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,11 @@ repository = "https://github.com/foundry-rs/foundry" exclude = ["benches/", "tests/", "test-data/", "testdata/"] [workspace.lints.clippy] +borrow_as_ptr = "warn" +branches_sharing_code = "warn" +clear_with_drain = "warn" +cloned_instead_of_copied = "warn" +collection_is_never_read = "warn" dbg-macro = "warn" explicit_iter_loop = "warn" manual-string-new = "warn" diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index ec6fbeb4227a1..59c5ab2fc681a 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -998,7 +998,7 @@ impl EthApi { node_info!("eth_signTransaction"); let from = request.from.map(Ok).unwrap_or_else(|| { - self.accounts()?.first().cloned().ok_or(BlockchainError::NoSignerAvailable) + self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable) })?; let (nonce, _) = self.request_nonce(&request, from).await?; @@ -1027,7 +1027,7 @@ impl EthApi { node_info!("eth_sendTransaction"); let from = request.from.map(Ok).unwrap_or_else(|| { - self.accounts()?.first().cloned().ok_or(BlockchainError::NoSignerAvailable) + self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable) })?; let (nonce, on_chain_nonce) = self.request_nonce(&request, from).await?; @@ -2185,7 +2185,7 @@ impl EthApi { let from = tx_req.from.map(Ok).unwrap_or_else(|| { self.accounts()? .first() - .cloned() + .copied() .ok_or(BlockchainError::NoSignerAvailable) })?; diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 4f34ca161eab5..0d20355a48747 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -994,8 +994,8 @@ impl Backend { // Defaults to block number for compatibility with existing state files. let fork_num_and_hash = self.get_fork().map(|f| (f.block_number(), f.block_hash())); + let best_number = state.best_block_number.unwrap_or(block.number); if let Some((number, hash)) = fork_num_and_hash { - let best_number = state.best_block_number.unwrap_or(block.number); trace!(target: "backend", state_block_number=?best_number, fork_block_number=?number); // If the state.block_number is greater than the fork block number, set best number // to the state block number. @@ -1018,7 +1018,6 @@ impl Backend { self.blockchain.storage.write().best_hash = hash; } } else { - let best_number = state.best_block_number.unwrap_or(block.number); self.blockchain.storage.write().best_number = best_number; // Set the current best block hash; @@ -1613,7 +1612,6 @@ impl Backend { let mut log_index = 0; let mut gas_used = 0; let mut transactions = Vec::with_capacity(calls.len()); - let mut receipts = Vec::new(); let mut logs= Vec::new(); // apply state overrides before executing the transactions @@ -1724,13 +1722,6 @@ impl Backend { }) .collect(), }; - - let receipt = Receipt { - status: result.is_success().into(), - cumulative_gas_used: result.gas_used(), - logs: sim_res.logs.clone() - }; - receipts.push(receipt.with_bloom()); logs.extend(sim_res.logs.clone().iter().map(|log| log.inner.clone())); log_index += sim_res.logs.len(); call_res.push(sim_res); @@ -2942,7 +2933,7 @@ impl Backend { .zip(storage_proofs) .map(|(key, proof)| { let storage_key: U256 = key.into(); - let value = account.storage.get(&storage_key).cloned().unwrap_or_default(); + let value = account.storage.get(&storage_key).copied().unwrap_or_default(); StorageProof { key: JsonStorageKey::Hash(key), value, proof } }) .collect(), diff --git a/crates/anvil/src/eth/fees.rs b/crates/anvil/src/eth/fees.rs index a81c4117758f7..b9d5a2d9170d7 100644 --- a/crates/anvil/src/eth/fees.rs +++ b/crates/anvil/src/eth/fees.rs @@ -323,7 +323,7 @@ impl FeeHistoryService { .filter_map(|p| { let target_gas = (p * gas_used / 100f64) as u64; let mut sum_gas = 0; - for (gas_used, effective_reward) in transactions.iter().cloned() { + for (gas_used, effective_reward) in transactions.iter().copied() { sum_gas += gas_used; if target_gas <= sum_gas { return Some(effective_reward) diff --git a/crates/anvil/src/eth/otterscan/api.rs b/crates/anvil/src/eth/otterscan/api.rs index 129329991c03b..66322bd21a392 100644 --- a/crates/anvil/src/eth/otterscan/api.rs +++ b/crates/anvil/src/eth/otterscan/api.rs @@ -418,7 +418,7 @@ impl EthApi { txs.iter().skip(page * page_size).take(page_size).cloned().collect(), ), BlockTransactions::Hashes(txs) => BlockTransactions::Hashes( - txs.iter().skip(page * page_size).take(page_size).cloned().collect(), + txs.iter().skip(page * page_size).take(page_size).copied().collect(), ), BlockTransactions::Uncle => unreachable!(), }; diff --git a/crates/anvil/src/eth/pool/transactions.rs b/crates/anvil/src/eth/pool/transactions.rs index 6cafa4c4cd3ce..293c7ce3b6e7b 100644 --- a/crates/anvil/src/eth/pool/transactions.rs +++ b/crates/anvil/src/eth/pool/transactions.rs @@ -521,7 +521,7 @@ impl ReadyTransactions { } } - unlocked_tx.extend(to_remove.unlocks.iter().cloned()) + unlocked_tx.extend(to_remove.unlocks.iter().copied()) } } diff --git a/crates/anvil/src/eth/sign.rs b/crates/anvil/src/eth/sign.rs index 44f8a6be33f64..3dc07f347f16c 100644 --- a/crates/anvil/src/eth/sign.rs +++ b/crates/anvil/src/eth/sign.rs @@ -49,7 +49,7 @@ pub struct DevSigner { impl DevSigner { pub fn new(accounts: Vec) -> Self { let addresses = accounts.iter().map(|wallet| wallet.address()).collect::>(); - let accounts = addresses.iter().cloned().zip(accounts).collect(); + let accounts = addresses.iter().copied().zip(accounts).collect(); Self { addresses, accounts } } } diff --git a/crates/anvil/tests/it/txpool.rs b/crates/anvil/tests/it/txpool.rs index c329b27fa9130..a883380a5f9aa 100644 --- a/crates/anvil/tests/it/txpool.rs +++ b/crates/anvil/tests/it/txpool.rs @@ -26,10 +26,8 @@ async fn geth_txpool() { let tx = WithOtherFields::new(tx); // send a few transactions - let mut txs = Vec::new(); for _ in 0..10 { - let tx_hash = provider.send_transaction(tx.clone()).await.unwrap(); - txs.push(tx_hash); + let _ = provider.send_transaction(tx.clone()).await.unwrap(); } // we gave a 20s block time, should be plenty for us to get the txpool's content diff --git a/crates/cheatcodes/src/script.rs b/crates/cheatcodes/src/script.rs index ce27b79253cd3..2935a0d5a5955 100644 --- a/crates/cheatcodes/src/script.rs +++ b/crates/cheatcodes/src/script.rs @@ -285,7 +285,7 @@ impl Wallets { /// Locks inner Mutex and returns all signer addresses in the [MultiWallet]. pub fn signers(&self) -> Result> { - Ok(self.inner.lock().multi_wallet.signers()?.keys().cloned().collect()) + Ok(self.inner.lock().multi_wallet.signers()?.keys().copied().collect()) } /// Number of signers in the [MultiWallet]. @@ -313,7 +313,7 @@ fn broadcast(ccx: &mut CheatsCtxt, new_origin: Option<&Address>, single_call: bo ); ensure!(ccx.state.broadcast.is_none(), "a broadcast is active already"); - let mut new_origin = new_origin.cloned(); + let mut new_origin = new_origin.copied(); if new_origin.is_none() { let mut wallets = ccx.state.wallets().inner.lock(); diff --git a/crates/common/src/contracts.rs b/crates/common/src/contracts.rs index 86556f7194402..789491d074dbf 100644 --- a/crates/common/src/contracts.rs +++ b/crates/common/src/contracts.rs @@ -280,7 +280,7 @@ impl ContractsByArtifact { eyre::bail!("{id} has more than one implementation."); } - Ok(contracts.first().cloned()) + Ok(contracts.first().copied()) } /// Finds abi for contract which has the same contract name or identifier as `id`. diff --git a/crates/common/src/fs.rs b/crates/common/src/fs.rs index 3d061759c50cf..19675e425a4ce 100644 --- a/crates/common/src/fs.rs +++ b/crates/common/src/fs.rs @@ -118,7 +118,7 @@ pub fn open(path: impl AsRef) -> Result { /// ref: pub fn normalize_path(path: &Path) -> PathBuf { let mut components = path.components().peekable(); - let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { + let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().copied() { components.next(); PathBuf::from(c.as_os_str()) } else { diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 60ede7122f793..fd495e2fba837 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -1478,7 +1478,7 @@ impl Config { extra_output.push(ContractOutputSelection::Metadata); } - ConfigurableArtifacts::new(extra_output, self.extra_output_files.iter().cloned()) + ConfigurableArtifacts::new(extra_output, self.extra_output_files.iter().copied()) } /// Parses all libraries in the form of diff --git a/crates/doc/src/parser/comment.rs b/crates/doc/src/parser/comment.rs index bf2b0ad7b4f0d..9a64662665c31 100644 --- a/crates/doc/src/parser/comment.rs +++ b/crates/doc/src/parser/comment.rs @@ -170,13 +170,13 @@ impl<'a> CommentsRef<'a> { /// Filter a collection of comments and return only those that match provided tags. pub fn include_tags(&self, tags: &[CommentTag]) -> Self { // Cloning only references here - CommentsRef(self.iter().cloned().filter(|c| tags.contains(&c.tag)).collect()) + CommentsRef(self.iter().copied().filter(|c| tags.contains(&c.tag)).collect()) } /// Filter a collection of comments and return only those that do not match provided tags. pub fn exclude_tags(&self, tags: &[CommentTag]) -> Self { // Cloning only references here - CommentsRef(self.iter().cloned().filter(|c| !tags.contains(&c.tag)).collect()) + CommentsRef(self.iter().copied().filter(|c| !tags.contains(&c.tag)).collect()) } /// Check if the collection contains a target comment. @@ -200,7 +200,7 @@ impl<'a> CommentsRef<'a> { /// Filter a collection of comments and only return the custom tags. pub fn get_custom_tags(&self) -> Self { - CommentsRef(self.iter().cloned().filter(|c| c.is_custom()).collect()) + CommentsRef(self.iter().copied().filter(|c| c.is_custom()).collect()) } } diff --git a/crates/evm/fuzz/src/strategies/param.rs b/crates/evm/fuzz/src/strategies/param.rs index a8834bcef9942..07732332d90e0 100644 --- a/crates/evm/fuzz/src/strategies/param.rs +++ b/crates/evm/fuzz/src/strategies/param.rs @@ -135,9 +135,7 @@ pub fn fuzz_param_from_state( value() .prop_map(move |value| { let mut fuzzed_addr = Address::from_word(value); - if !deployed_libs.contains(&fuzzed_addr) { - DynSolValue::Address(fuzzed_addr) - } else { + if deployed_libs.contains(&fuzzed_addr) { let mut rng = StdRng::seed_from_u64(0x1337); // use deterministic rng // Do not use addresses of deployed libraries as fuzz input, instead return @@ -151,9 +149,8 @@ pub fn fuzz_param_from_state( break; } } - - DynSolValue::Address(fuzzed_addr) } + DynSolValue::Address(fuzzed_addr) }) .boxed() } diff --git a/crates/fmt/src/formatter.rs b/crates/fmt/src/formatter.rs index 641be5943012a..7b14bd8c6cd43 100644 --- a/crates/fmt/src/formatter.rs +++ b/crates/fmt/src/formatter.rs @@ -132,7 +132,7 @@ impl<'a, W: Write> Formatter<'a, W> { /// Casts the current writer `w` as a `String` reference. Should only be used for debugging. unsafe fn buf_contents(&self) -> &String { - *(&self.buf.w as *const W as *const &mut String) + *(&raw const self.buf.w as *const &mut String) } /// Casts the current `W` writer or the current temp buffer as a `String` reference. diff --git a/crates/forge/src/cmd/clone.rs b/crates/forge/src/cmd/clone.rs index a5bc4b2aa4676..b1a28b60c70f5 100644 --- a/crates/forge/src/cmd/clone.rs +++ b/crates/forge/src/cmd/clone.rs @@ -556,10 +556,8 @@ fn dump_sources(meta: &Metadata, root: &PathBuf, no_reorg: bool) -> Result Date: Thu, 5 Jun 2025 15:01:03 +0300 Subject: [PATCH 175/244] chore: bump version 1.2.3 (#10712) --- Cargo.lock | 62 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 797e25fc4c9a1..e16dcf3113735 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1014,7 +1014,7 @@ dependencies = [ [[package]] name = "anvil" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-chains", "alloy-consensus", @@ -1080,7 +1080,7 @@ dependencies = [ [[package]] name = "anvil-core" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -1104,7 +1104,7 @@ dependencies = [ [[package]] name = "anvil-rpc" -version = "1.2.2" +version = "1.2.3" dependencies = [ "serde", "serde_json", @@ -1112,7 +1112,7 @@ dependencies = [ [[package]] name = "anvil-server" -version = "1.2.2" +version = "1.2.3" dependencies = [ "anvil-rpc", "async-trait", @@ -2346,7 +2346,7 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "cast" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-chains", "alloy-consensus", @@ -2446,7 +2446,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chisel" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -3775,7 +3775,7 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "forge" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-chains", "alloy-dyn-abi", @@ -3859,7 +3859,7 @@ dependencies = [ [[package]] name = "forge-doc" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-primitives", "derive_more 2.0.1", @@ -3882,7 +3882,7 @@ dependencies = [ [[package]] name = "forge-fmt" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-primitives", "ariadne", @@ -3898,7 +3898,7 @@ dependencies = [ [[package]] name = "forge-lint" -version = "1.2.2" +version = "1.2.3" dependencies = [ "foundry-compilers", "foundry-config", @@ -3912,7 +3912,7 @@ dependencies = [ [[package]] name = "forge-script" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-chains", "alloy-consensus", @@ -3957,7 +3957,7 @@ dependencies = [ [[package]] name = "forge-script-sequence" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-network", "alloy-primitives", @@ -3973,7 +3973,7 @@ dependencies = [ [[package]] name = "forge-sol-macro-gen" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -3989,7 +3989,7 @@ dependencies = [ [[package]] name = "forge-verify" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4050,7 +4050,7 @@ dependencies = [ [[package]] name = "foundry-cheatcodes" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-chains", "alloy-consensus", @@ -4101,7 +4101,7 @@ dependencies = [ [[package]] name = "foundry-cheatcodes-spec" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-sol-types", "foundry-macros", @@ -4112,7 +4112,7 @@ dependencies = [ [[package]] name = "foundry-cli" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-chains", "alloy-dyn-abi", @@ -4160,7 +4160,7 @@ dependencies = [ [[package]] name = "foundry-common" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -4215,7 +4215,7 @@ dependencies = [ [[package]] name = "foundry-common-fmt" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -4342,7 +4342,7 @@ dependencies = [ [[package]] name = "foundry-config" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-chains", "alloy-primitives", @@ -4381,7 +4381,7 @@ dependencies = [ [[package]] name = "foundry-debugger" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-primitives", "crossterm", @@ -4399,7 +4399,7 @@ dependencies = [ [[package]] name = "foundry-evm" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-dyn-abi", "alloy-evm", @@ -4427,7 +4427,7 @@ dependencies = [ [[package]] name = "foundry-evm-abi" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -4439,7 +4439,7 @@ dependencies = [ [[package]] name = "foundry-evm-core" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -4476,7 +4476,7 @@ dependencies = [ [[package]] name = "foundry-evm-coverage" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-primitives", "eyre", @@ -4491,7 +4491,7 @@ dependencies = [ [[package]] name = "foundry-evm-fuzz" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4515,7 +4515,7 @@ dependencies = [ [[package]] name = "foundry-evm-traces" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4565,7 +4565,7 @@ dependencies = [ [[package]] name = "foundry-linking" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-primitives", "foundry-compilers", @@ -4575,7 +4575,7 @@ dependencies = [ [[package]] name = "foundry-macros" -version = "1.2.2" +version = "1.2.3" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -4599,7 +4599,7 @@ dependencies = [ [[package]] name = "foundry-test-utils" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-primitives", "alloy-provider", @@ -4625,7 +4625,7 @@ dependencies = [ [[package]] name = "foundry-wallets" -version = "1.2.2" +version = "1.2.3" dependencies = [ "alloy-consensus", "alloy-dyn-abi", diff --git a/Cargo.toml b/Cargo.toml index 48c72f61a9661..9b6ed5ab76212 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ members = [ resolver = "2" [workspace.package] -version = "1.2.2" +version = "1.2.3" edition = "2021" # Remember to update clippy.toml as well rust-version = "1.87" From f914e011c89c7f462ab9e4517f4e96b7d11ac433 Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Thu, 5 Jun 2025 14:34:36 +0100 Subject: [PATCH 176/244] fix(anvil): guard against the blockchain advancing while checking latest block (#10714) fix: guard against the blockchain advancing while checking latest block --- crates/anvil/src/eth/backend/mem/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 0d20355a48747..d0cc3b8795404 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -2290,7 +2290,7 @@ impl Backend { .number } BlockId::Number(num) => match num { - BlockNumber::Latest | BlockNumber::Pending => self.best_number(), + BlockNumber::Latest | BlockNumber::Pending => current, BlockNumber::Earliest => U64::ZERO.to::(), BlockNumber::Number(num) => num, BlockNumber::Safe => current.saturating_sub(self.slots_in_an_epoch), From 01328a96fe8003bc7ef8b776702a40173c0181d6 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Thu, 5 Jun 2025 17:39:31 +0300 Subject: [PATCH 177/244] feat(script): keep script / tx timestamp as milis instead seconds (#10711) feat(script): keep script timestamp as milis instead seconds --- crates/script-sequence/src/sequence.rs | 4 ++-- crates/script/src/multi_sequence.rs | 6 +++--- crates/script/src/simulate.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/script-sequence/src/sequence.rs b/crates/script-sequence/src/sequence.rs index 4b2b434e11793..547938cd4ad2f 100644 --- a/crates/script-sequence/src/sequence.rs +++ b/crates/script-sequence/src/sequence.rs @@ -34,7 +34,7 @@ pub struct ScriptSequence { /// None if sequence should not be saved to disk (e.g. part of a multi-chain sequence) pub paths: Option<(PathBuf, PathBuf)>, pub returns: HashMap, - pub timestamp: u64, + pub timestamp: u128, pub chain: u64, pub commit: Option, } @@ -101,7 +101,7 @@ impl ScriptSequence { let Some((path, sensitive_path)) = self.paths.clone() else { return Ok(()) }; - self.timestamp = now().as_secs(); + self.timestamp = now().as_millis(); let ts_name = format!("run-{}.json", self.timestamp); let sensitive_script_sequence: SensitiveScriptSequence = self.clone().into(); diff --git a/crates/script/src/multi_sequence.rs b/crates/script/src/multi_sequence.rs index e0fd4d1bc7e68..c132ae22531c9 100644 --- a/crates/script/src/multi_sequence.rs +++ b/crates/script/src/multi_sequence.rs @@ -19,7 +19,7 @@ pub struct MultiChainSequence { pub path: PathBuf, #[serde(skip)] pub sensitive_path: PathBuf, - pub timestamp: u64, + pub timestamp: u128, } /// Sensitive values from script sequences. @@ -46,7 +46,7 @@ impl MultiChainSequence { ) -> Result { let (path, sensitive_path) = Self::get_paths(config, sig, target, dry_run)?; - Ok(Self { deployments, path, sensitive_path, timestamp: now().as_secs() }) + Ok(Self { deployments, path, sensitive_path, timestamp: now().as_millis() }) } /// Gets paths in the formats @@ -113,7 +113,7 @@ impl MultiChainSequence { pub fn save(&mut self, silent: bool, save_ts: bool) -> Result<()> { self.deployments.iter_mut().for_each(|sequence| sequence.sort_receipts()); - self.timestamp = now().as_secs(); + self.timestamp = now().as_millis(); let sensitive_sequence = SensitiveMultiChainSequence::from_multi_sequence(self.clone()); diff --git a/crates/script/src/simulate.rs b/crates/script/src/simulate.rs index 372cb4b250381..9c56cd0ee5d73 100644 --- a/crates/script/src/simulate.rs +++ b/crates/script/src/simulate.rs @@ -454,7 +454,7 @@ impl FilledTransactionsState { receipts: vec![], pending: vec![], paths, - timestamp: now().as_secs(), + timestamp: now().as_millis(), libraries, chain, commit, From 99634144b6c9371982dcfc551a7975c5dbf9fad8 Mon Sep 17 00:00:00 2001 From: Akshat Chhajer Date: Thu, 5 Jun 2025 21:50:16 +0530 Subject: [PATCH 178/244] fix: eip7702 cheatcodes multiple auth (#10623) * fix: eip7702 cheatcodes multiple auth * fix: eip7702 cheatcodes nonce * Fmt and nonce fix * Active delegations as vec * Fix nonce for non senders and add test * Fix tests * Update crates/cheatcodes/src/inspector.rs Co-authored-by: Arsenii Kulikov * Nit: do not unwrap when looking for last delegation --------- Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> Co-authored-by: grandizzy Co-authored-by: Arsenii Kulikov --- crates/cheatcodes/src/inspector.rs | 45 +++--- crates/cheatcodes/src/script.rs | 58 ++++++- crates/forge/tests/cli/script.rs | 153 ++++++++++++++++++ crates/forge/tests/cli/test_cmd.rs | 4 +- .../default/cheats/AttachDelegation.t.sol | 25 ++- 5 files changed, 258 insertions(+), 27 deletions(-) diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index 4d9b5cd5ef5ed..14c185c317f42 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -371,10 +371,10 @@ pub struct Cheatcodes { /// execution block environment. pub block: Option, - /// Currently active EIP-7702 delegation that will be consumed when building the next + /// Currently active EIP-7702 delegations that will be consumed when building the next /// transaction. Set by `vm.attachDelegation()` and consumed via `.take()` during /// transaction construction. - pub active_delegation: Option, + pub active_delegations: Vec, /// The active EIP-4844 blob that will be attached to the next call. pub active_blob_sidecar: Option, @@ -517,7 +517,7 @@ impl Cheatcodes { labels: config.labels.clone(), config, block: Default::default(), - active_delegation: Default::default(), + active_delegations: Default::default(), active_blob_sidecar: Default::default(), gas_price: Default::default(), pranks: Default::default(), @@ -573,6 +573,11 @@ impl Cheatcodes { self.wallets = Some(wallets); } + /// Adds a delegation to the active delegations list. + pub fn add_delegation(&mut self, authorization: SignedAuthorization) { + self.active_delegations.push(authorization); + } + /// Decodes the input data and applies the cheatcode. fn apply_cheatcode( &mut self, @@ -1136,8 +1141,11 @@ impl Cheatcodes { ..Default::default() }; - match (self.active_delegation.take(), self.active_blob_sidecar.take()) { - (Some(_), Some(_)) => { + let active_delegations = std::mem::take(&mut self.active_delegations); + // Set active blob sidecar, if any. + if let Some(blob_sidecar) = self.active_blob_sidecar.take() { + // Ensure blob and delegation are not set for the same tx. + if !active_delegations.is_empty() { let msg = "both delegation and blob are active; `attachBlob` and `attachDelegation` are not compatible"; return Some(CallOutcome { result: InterpreterResult { @@ -1148,21 +1156,22 @@ impl Cheatcodes { memory_offset: call.return_memory_offset.clone(), }); } - (Some(auth_list), None) => { - tx_req.authorization_list = Some(vec![auth_list]); - tx_req.sidecar = None; + tx_req.set_blob_sidecar(blob_sidecar); + } - // Increment nonce to reflect the signed authorization. - account.info.nonce += 1; - } - (None, Some(blob_sidecar)) => { - tx_req.set_blob_sidecar(blob_sidecar); - tx_req.authorization_list = None; - } - (None, None) => { - tx_req.sidecar = None; - tx_req.authorization_list = None; + // Apply active EIP-7702 delegations, if any. + if !active_delegations.is_empty() { + for auth in &active_delegations { + let Ok(authority) = auth.recover_authority() else { + continue; + }; + if authority == broadcast.new_origin { + // Increment nonce of broadcasting account to reflect signed + // authorization. + account.info.nonce += 1; + } } + tx_req.authorization_list = Some(active_delegations); } self.broadcastable_transactions.push_back(BroadcastableTransaction { diff --git a/crates/cheatcodes/src/script.rs b/crates/cheatcodes/src/script.rs index 2935a0d5a5955..6e2fad1f09213 100644 --- a/crates/cheatcodes/src/script.rs +++ b/crates/cheatcodes/src/script.rs @@ -113,7 +113,7 @@ fn attach_delegation( U256::from_be_bytes(s.0), ); write_delegation(ccx, signed_auth.clone())?; - ccx.state.active_delegation = Some(signed_auth); + ccx.state.add_delegation(signed_auth); Ok(Default::default()) } @@ -132,8 +132,13 @@ fn sign_delegation( nonce } else { let authority_acc = ccx.ecx.journaled_state.load_account(signer.address())?; - // If we don't have a nonce then use next auth account nonce. - authority_acc.data.info.nonce + 1 + // Calculate next nonce considering existing active delegations + next_delegation_nonce( + &ccx.state.active_delegations, + signer.address(), + &ccx.state.broadcast, + authority_acc.data.info.nonce, + ) }; let chain_id = if cross_chain { U256::from(0) } else { U256::from(ccx.ecx.cfg.chain_id) }; @@ -143,7 +148,7 @@ fn sign_delegation( if attach { let signed_auth = SignedAuthorization::new_unchecked(auth, sig.v() as u8, sig.r(), sig.s()); write_delegation(ccx, signed_auth.clone())?; - ccx.state.active_delegation = Some(signed_auth); + ccx.state.add_delegation(signed_auth); } Ok(SignedDelegation { v: sig.v() as u8, @@ -155,11 +160,52 @@ fn sign_delegation( .abi_encode()) } +/// Returns the next valid nonce for a delegation, considering existing active delegations. +fn next_delegation_nonce( + active_delegations: &[SignedAuthorization], + authority: Address, + broadcast: &Option, + account_nonce: u64, +) -> u64 { + match active_delegations + .iter() + .rfind(|auth| auth.recover_authority().is_ok_and(|recovered| recovered == authority)) + { + Some(auth) => { + // Increment nonce of last recorded delegation. + auth.nonce + 1 + } + None => { + // First time a delegation is added for this authority. + if let Some(broadcast) = broadcast { + // Increment nonce if authority is the sender of transaction. + if broadcast.new_origin == authority { + return account_nonce + 1 + } + } + // Return current nonce if authority is not the sender of transaction. + account_nonce + } + } +} + fn write_delegation(ccx: &mut CheatsCtxt, auth: SignedAuthorization) -> Result<()> { let authority = auth.recover_authority().map_err(|e| format!("{e}"))?; let authority_acc = ccx.ecx.journaled_state.load_account(authority)?; - if authority_acc.data.info.nonce + 1 != auth.nonce { - return Err("invalid nonce".into()); + + let expected_nonce = next_delegation_nonce( + &ccx.state.active_delegations, + authority, + &ccx.state.broadcast, + authority_acc.data.info.nonce, + ); + + if expected_nonce != auth.nonce { + return Err(format!( + "invalid nonce for {authority:?}: expected {expected_nonce}, got {}", + auth.nonce + ) + .into()); } if auth.address.is_zero() { diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index 8f866150a4d8b..64af01bdb1566 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -2858,3 +2858,156 @@ ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. "#]]); }); + +// Tests EIP-7702 with multiple auth +// Alice sends 5 ETH from Bob to Receiver1 and 1 ETH to Receiver2 +forgetest_async!(can_broadcast_txes_with_multiple_auth, |prj, cmd| { + foundry_test_utils::util::initialize(prj.root()); + prj.add_source( + "BatchCallDelegation.sol", + r#" +contract BatchCallDelegation { + event CallExecuted(address indexed to, uint256 indexed value, bytes data, bool success); + + struct Call { + bytes data; + address to; + uint256 value; + } + + function execute(Call[] calldata calls) external payable { + for (uint256 i = 0; i < calls.length; i++) { + Call memory call = calls[i]; + (bool success,) = call.to.call{value: call.value}(call.data); + require(success, "call reverted"); + emit CallExecuted(call.to, call.value, call.data, success); + } + } +} + "#, + ) + .unwrap(); + + prj.add_script( + "BatchCallDelegationScript.s.sol", + r#" +import {Script, console} from "forge-std/Script.sol"; +import {Vm} from "forge-std/Vm.sol"; +import {BatchCallDelegation} from "../src/BatchCallDelegation.sol"; + +contract BatchCallDelegationScript is Script { + // Alice's address and private key (EOA with no initial contract code). + address payable ALICE_ADDRESS = payable(0x70997970C51812dc3A010C7d01b50e0d17dc79C8); + uint256 constant ALICE_PK = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d; + + // Bob's address and private key (Bob will execute transactions on Alice's behalf). + address constant BOB_ADDRESS = 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC; + uint256 constant BOB_PK = 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a; + + address constant RECEIVER_1 = 0x14dC79964da2C08b23698B3D3cc7Ca32193d9955; + address constant RECEIVER_2 = 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc; + + uint256 constant DEPLOYER_PK = 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6; + + function run() public { + BatchCallDelegation.Call[] memory aliceCalls = new BatchCallDelegation.Call[](1); + aliceCalls[0] = BatchCallDelegation.Call({to: RECEIVER_1, value: 5 ether, data: ""}); + + BatchCallDelegation.Call[] memory bobCalls = new BatchCallDelegation.Call[](2); + bobCalls[0] = BatchCallDelegation.Call({to: RECEIVER_1, value: 5 ether, data: ""}); + bobCalls[1] = BatchCallDelegation.Call({to: RECEIVER_2, value: 1 ether, data: ""}); + + vm.startBroadcast(DEPLOYER_PK); + BatchCallDelegation batcher = new BatchCallDelegation(); + vm.stopBroadcast(); + + vm.startBroadcast(ALICE_PK); + vm.signAndAttachDelegation(address(batcher), ALICE_PK); + vm.signAndAttachDelegation(address(batcher), BOB_PK); + vm.signAndAttachDelegation(address(batcher), BOB_PK); + + BatchCallDelegation(BOB_ADDRESS).execute(bobCalls); + + vm.stopBroadcast(); + } +} + "#, + ) + .unwrap(); + + let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into())); + let (api, handle) = spawn(node_config).await; + + cmd.args([ + "script", + "script/BatchCallDelegationScript.s.sol", + "--rpc-url", + &handle.http_endpoint(), + "--non-interactive", + "--slow", + "--broadcast", + "--evm-version", + "prague", + ]) + .assert_success() + .stdout_eq(str![[r#" +[COMPILING_FILES] with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! +Script ran successfully. + +## Setting up 1 EVM. + +========================== + +Chain 31337 + +[ESTIMATED_GAS_PRICE] + +[ESTIMATED_TOTAL_GAS_USED] + +[ESTIMATED_AMOUNT_REQUIRED] + +========================== + + +========================== + +ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. + +[SAVED_TRANSACTIONS] + +[SAVED_SENSITIVE_VALUES] + + +"#]]); + + // Alice nonce should be 2 (tx sender and one auth) + let alice_acc = api + .get_account(address!("0x70997970C51812dc3A010C7d01b50e0d17dc79C8"), None) + .await + .unwrap(); + assert_eq!(alice_acc.nonce, 2); + + // Bob nonce should be 2 (two auths) and balance reduced by 6 ETH. + let bob_acc = api + .get_account(address!("0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"), None) + .await + .unwrap(); + assert_eq!(bob_acc.nonce, 2); + assert_eq!(bob_acc.balance.to_string(), "94000000000000000000"); + + // Receiver balances should be updated with 5 ETH and 1 ETH. + let receiver1 = api + .get_account(address!("0x14dC79964da2C08b23698B3D3cc7Ca32193d9955"), None) + .await + .unwrap(); + assert_eq!(receiver1.nonce, 0); + assert_eq!(receiver1.balance.to_string(), "105000000000000000000"); + let receiver2 = api + .get_account(address!("0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc"), None) + .await + .unwrap(); + assert_eq!(receiver2.nonce, 0); + assert_eq!(receiver2.balance.to_string(), "101000000000000000000"); +}); diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index b119eaa210600..c486eba1049ae 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -3306,9 +3306,9 @@ Traces: ├─ [0] VM::label(alice: [0x328809Bc894f92807417D2dAD6b7C998c1aFdac6], "alice") │ └─ ← [Return] ├─ [0] VM::signDelegation(0x0000000000000000000000000000000000000000, "") - │ └─ ← [Return] (0, 0x38db2a0ada75402af7cd5bdb8248a1a5b4fec65fdafea4f935084f00dc2ff3c5, 0x29ce7b1c82f9ceaec21f12d690ba8fe6ecba65869caf6ab2d85d79890dc42df2, 1, 0x0000000000000000000000000000000000000000) + │ └─ ← [Return] (0, 0x3d6ad67cc3dc94101a049f85f96937513a05485ae0f8b27545d25c4f71b12cf9, 0x3c0f2d62834f59d6ef0209e8a935f80a891a236eb18ac0e3700dd8f7ac8ae279, 0, 0x0000000000000000000000000000000000000000) ├─ [0] VM::signAndAttachDelegation(0x0000000000000000000000000000000000000000, "") - │ └─ ← [Return] (0, 0x38db2a0ada75402af7cd5bdb8248a1a5b4fec65fdafea4f935084f00dc2ff3c5, 0x29ce7b1c82f9ceaec21f12d690ba8fe6ecba65869caf6ab2d85d79890dc42df2, 1, 0x0000000000000000000000000000000000000000) + │ └─ ← [Return] (0, 0x3d6ad67cc3dc94101a049f85f96937513a05485ae0f8b27545d25c4f71b12cf9, 0x3c0f2d62834f59d6ef0209e8a935f80a891a236eb18ac0e3700dd8f7ac8ae279, 0, 0x0000000000000000000000000000000000000000) └─ ← [Stop] ... diff --git a/testdata/default/cheats/AttachDelegation.t.sol b/testdata/default/cheats/AttachDelegation.t.sol index 91535b85718f0..3efc5f5229d19 100644 --- a/testdata/default/cheats/AttachDelegation.t.sol +++ b/testdata/default/cheats/AttachDelegation.t.sol @@ -62,7 +62,7 @@ contract AttachDelegationTest is DSTest { vm._expectCheatcodeRevert("vm.attachDelegation: invalid nonce"); vm.attachDelegation(signedDelegation); - signedDelegation = vm.signDelegation(address(implementation), alice_pk, 1); + signedDelegation = vm.signDelegation(address(implementation), alice_pk, 0); vm.attachDelegation(signedDelegation); } @@ -192,7 +192,30 @@ contract AttachDelegationTest is DSTest { vm._expectCheatcodeRevert("vm.signAndAttachDelegation: invalid nonce"); vm.signAndAttachDelegation(address(implementation), alice_pk, 11); + vm.signAndAttachDelegation(address(implementation), alice_pk, 0); + } + + function testMultipleDelegationsOnTransaction() public { + vm.signAndAttachDelegation(address(implementation), alice_pk); + vm.signAndAttachDelegation(address(implementation2), bob_pk); + SimpleDelegateContract.Call[] memory calls = new SimpleDelegateContract.Call[](2); + calls[0] = SimpleDelegateContract.Call({ + to: address(token), + data: abi.encodeCall(ERC20.mint, (50, address(this))), + value: 0 + }); + calls[1] = + SimpleDelegateContract.Call({to: address(token), data: abi.encodeCall(ERC20.mint, (50, alice)), value: 0}); + vm.broadcast(bob_pk); + SimpleDelegateContract(alice).execute(calls); + + assertEq(token.balanceOf(address(this)), 50); + assertEq(token.balanceOf(alice), 50); + + vm._expectCheatcodeRevert("vm.signAndAttachDelegation: invalid nonce"); vm.signAndAttachDelegation(address(implementation), alice_pk, 1); + vm.signAndAttachDelegation(address(implementation), alice_pk, 0); + vm.signAndAttachDelegation(address(implementation2), bob_pk, 2); } } From fe04be84384ceabe11f02befd91a5772f56897fb Mon Sep 17 00:00:00 2001 From: 0xredtrama <60705940+redtrama@users.noreply.github.com> Date: Fri, 6 Jun 2025 10:43:03 +0200 Subject: [PATCH 179/244] docs: add uninstall instructions (#10335) * add uninstall instructions * Update foundryup/README.md Co-authored-by: Matthias Seitz --------- Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> Co-authored-by: Matthias Seitz --- foundryup/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/foundryup/README.md b/foundryup/README.md index 5504063abfe37..8d649eb623d8a 100644 --- a/foundryup/README.md +++ b/foundryup/README.md @@ -79,3 +79,22 @@ foundryup --path ./git/foundry **Tip**: All flags have a single character shorthand equivalent! You can use `-i` instead of `--install`, etc. --- + + +## Uninstalling + +Foundry contains everything in a `.foundry` directory, usually located in `/home/user/.foundry/`. + +- To uninstall Foundry remove the `.foundry` directory. + +##### Note: .foundry directory can contain keystores. Make sure to backup any keystores you want to keep. + + +Remove Foundry from PATH: + +- Optionally Foundry can be removed from editing shell configuration file (`.bashrc`, `.zshrc`, etc.) and remove the line that adds Foundry to PATH: + +``` +export PATH="$PATH:/home/user/.foundry/bin" +``` + From eefb8a08996503af6241b281eedd4f7ffd6d4397 Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Fri, 6 Jun 2025 19:08:07 +0530 Subject: [PATCH 180/244] chore(`forge bind`): pin alloy to 1.0 + e2e test (#10724) --- crates/forge/tests/cli/cmd.rs | 19 +++++++++++++++++++ crates/sol-macro-gen/src/sol_macro_gen.rs | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 95d0c2b8bc61b..ae9984f27f32e 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -3869,3 +3869,22 @@ Generating bindings for 1 contracts Bindings have been generated to [..]"# ]]); }); + +// forge bind e2e +forgetest_init!(can_bind_e2e, |prj, cmd| { + cmd.args(["bind"]).assert_success().stdout_eq(str![[r#"No files changed, compilation skipped +Generating bindings for 2 contracts +Bindings have been generated to [..]"#]]); + + let bindings_path = prj.root().join("out/bindings"); + + assert!(bindings_path.exists(), "Bindings directory should exist"); + let out = Command::new("cargo") + .arg("build") + .current_dir(&bindings_path) + .output() + .expect("Failed to run cargo build"); + // RUn `cargo build` + + assert!(out.status.success(), "Cargo build should succeed"); +}); diff --git a/crates/sol-macro-gen/src/sol_macro_gen.rs b/crates/sol-macro-gen/src/sol_macro_gen.rs index 1e40d51169695..824054cb7f6c3 100644 --- a/crates/sol-macro-gen/src/sol_macro_gen.rs +++ b/crates/sol-macro-gen/src/sol_macro_gen.rs @@ -420,7 +420,7 @@ edition = "2021" r#"alloy = {{ git = "https://github.com/alloy-rs/alloy", rev = "{alloy_rev}", features = ["sol-types", "contract"] }}"#, ) } else { - r#"alloy = { git = "https://github.com/alloy-rs/alloy", features = ["sol-types", "contract"] }"#.to_string() + r#"alloy = { version = "1.0", features = ["sol-types", "contract"] }"#.to_string() } } } From 192332ef39d61b9c5762de4567569619380d92cf Mon Sep 17 00:00:00 2001 From: Jennifer Date: Fri, 6 Jun 2025 19:01:40 +0200 Subject: [PATCH 181/244] Update README.md (#10725) --- README.md | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 4fa5510481304..3d8a1f35f098f 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ [tg-support-badge]: https://img.shields.io/endpoint?color=neon&logo=telegram&label=support&style=flat-square&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Ffoundry_support [tg-support-url]: https://t.me/foundry_support -**[Install](https://book.getfoundry.sh/getting-started/installation)** -| [User Book][foundry-book] -| [Developer Docs](./docs/dev/README.md) +**[Install](https://getfoundry.sh/getting-started/installation)** +| [Docs][foundry-docs] +| [Developer Guidelines](./docs/dev/README.md) | [Contributing](./CONTRIBUTING.md) @@ -31,7 +31,7 @@ Foundry consists of: - [**Anvil**](#anvil): Fast local Ethereum development node, akin to Hardhat Network, Tenderly. - [**Chisel**](#chisel): Fast, utilitarian, and verbose Solidity REPL. -**Need help getting started with Foundry? Read the [📖 Foundry Book][foundry-book]!** +**Need help getting started with Foundry? Read the [📖 Foundry Docs][foundry-docs]!** ![Demo](.github/assets/demo.gif) @@ -82,9 +82,9 @@ foundryup **Done!** -For additional details see the [installation guide](https://book.getfoundry.sh/getting-started/installation) in the [Foundry Book][foundry-book]. +For additional details see the [installation guide](https://getfoundry.sh/getting-started/installation) in the [Foundry Docs][foundry-docs]. -If you're experiencing any issues while installing, check out [Getting Help](#getting-help) and the [FAQ](https://book.getfoundry.sh/faq). +If you're experiencing any issues while installing, check out [Getting Help](#getting-help) and the [FAQ](https://getfoundry.sh/faq). ## How Fast? @@ -151,7 +151,7 @@ forge build Compiler run successful! ``` -Let's [test](https://book.getfoundry.sh/forge/tests#tests) our contracts: +Let's [test](https://getfoundry.sh/forge/tests#tests) our contracts: ```sh forge test @@ -186,7 +186,7 @@ If you wish to simulate on-chain transactions pass a RPC URL. Run `forge --help` to explore the full list of available subcommands and their usage. -More documentation can be found in the [forge][foundry-book-forge] section of the Foundry Book. +More documentation can be found in the [forge](https://getfoundry.sh/forge/overview) section of the Foundry Docs. ## Cast @@ -218,7 +218,7 @@ Optionally, pass `--etherscan-api-key ` to decode transaction traces us Run `cast --help` to explore the full list of available subcommands and their usage. -More documentation can be found in the [cast][foundry-book-cast] section of the Foundry Book. +More documentation can be found in the [cast](https://getfoundry.sh/cast/overview) section of the Foundry Docs. ## Anvil @@ -240,7 +240,7 @@ cast block-number Run `anvil --help` to explore the full list of available features and their usage. -More documentation can be found in the [anvil][foundry-book-anvil] section of the Foundry Book. +More documentation can be found in the [anvil](https://getfoundry.sh/anvil/overview) section of the Foundry Docs. ## Chisel @@ -287,7 +287,7 @@ contract REPL { Run `chisel --help` to explore the full list of available features and their usage. -More documentation can be found in the [chisel][foundry-book-chisel] section of the Foundry Book. +More documentation can be found in the [chisel](https://getfoundry.sh/chisel/overview) section of the Foundry Docs. ## Configuration @@ -302,9 +302,9 @@ Foundry is highly configurable, allowing you to tailor it to your needs. Configu --- -You can find additional [setup and configurations guides][foundry-book-config] in the [Foundry Book][foundry-book] and in the [config crate](./crates/config/README.md): +You can find additional [setup and configurations guides](https://getfoundry.sh/config/overview) in the [Foundry Docs][foundry-docs] and in the [config crate](./crates/config/README.md): -- [Configuring with `foundry.toml`](https://book.getfoundry.sh/config/) +- [Configuring with `foundry.toml`](https://getfoundry.sh/config/overview) - [Setting up VSCode][vscode-setup] - [Shell autocompletions][shell-setup] @@ -314,7 +314,7 @@ See our [contributing guidelines](./CONTRIBUTING.md). ## Getting Help -First, see if the answer to your question can be found in the [Foundy Book][foundry-book], or in the relevant crate. +First, see if the answer to your question can be found in the [Foundy Docs][foundry-docs], or in the relevant crate. If the answer is not there: @@ -342,12 +342,7 @@ shall be dual licensed as above, without any additional terms or conditions. - All the other [contributors](https://github.com/foundry-rs/foundry/graphs/contributors) to the [ethers-rs](https://github.com/gakonst/ethers-rs), [alloy][alloy] & [foundry](https://github.com/foundry-rs/foundry) repositories and chatrooms. [solidity]: https://soliditylang.org/ -[foundry-book]: https://book.getfoundry.sh -[foundry-book-config]: https://book.getfoundry.sh/config/ -[foundry-book-forge]: https://book.getfoundry.sh/reference/forge/ -[foundry-book-anvil]: https://book.getfoundry.sh/reference/anvil/ -[foundry-book-cast]: https://book.getfoundry.sh/reference/cast/ -[foundry-book-chisel]: https://book.getfoundry.sh/reference/chisel/ +[foundry-docs]: https://getfoundry.sh [foundry-gha]: https://github.com/foundry-rs/foundry-toolchain [foundry-compilers]: https://github.com/foundry-rs/compilers [ethers-solc]: https://github.com/gakonst/ethers-rs/tree/master/ethers-solc/ @@ -359,8 +354,8 @@ shall be dual licensed as above, without any additional terms or conditions. [geb]: https://github.com/reflexer-labs/geb [benchmark-post]: https://www.paradigm.xyz/2022/03/foundry-02#blazing-fast-compilation--testing [convex]: https://github.com/mds1/convex-shutdown-simulation -[vscode-setup]: https://book.getfoundry.sh/config/vscode.html -[shell-setup]: https://book.getfoundry.sh/config/shell-autocompletion.html +[vscode-setup]: https://getfoundry.sh/config/vscode.html +[shell-setup]: https://getfoundry.sh/config/shell-autocompletion.html [foundry-0.2]: https://github.com/foundry-rs/foundry/releases/tag/nightly-5b7e4cb3c882b28f3c32ba580de27ce7381f415a [foundry-1.0]: https://github.com/foundry-rs/foundry/releases/tag/nightly-59f354c179f4e7f6d7292acb3d068815c79286d1 [dapptools]: https://github.com/dapphub/dapptools From 548d1f0ebb811fcebd5fafdec33b7b814d0dbdbd Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Sun, 8 Jun 2025 18:48:02 +0300 Subject: [PATCH 182/244] fix(chisel): memory data location for string and bytes params (#10729) * fix(chisel): memory data location for string and bytes params * fix unrelated failing test --- crates/cast/tests/cli/main.rs | 8 ++++---- crates/chisel/src/dispatcher.rs | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index cbc7b193f0258..531c8e1837563 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -2593,16 +2593,16 @@ Traces: │ │ │ │ └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001 │ │ │ └─ ← [Return] 0x00000000000000000000000000000000000000000000000000000000000000011bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b │ │ └─ ← [Return] 0x00000000000000000000000000000000000000000000000000000000000000011bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b - │ ├─ [5994] 0xA12384c5E52fD646E7BC7F6B3b33A605651F566E::9e49fbf1(0000000000000000000000000000000000000000000000000000000000000017) - │ │ ├─ [5608] 0x0B55b053230E4EFFb6609de652fCa73Fd1C29804::9e49fbf1(0000000000000000000000000000000000000000000000000000000000000017) [delegatecall] + │ ├─ [5994] 0xA12384c5E52fD646E7BC7F6B3b33A605651F566E::checkAndIncrementNonce(23) + │ │ ├─ [5608] 0x0B55b053230E4EFFb6609de652fCa73Fd1C29804::checkAndIncrementNonce(23) [delegatecall] │ │ │ └─ ← [Stop] │ │ └─ ← [Return] │ ├─ [3250] 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913::balanceOf(0x327a25aD5Cfe5c4D4339C1A4267D4a83E8c93312) [staticcall] │ │ ├─ [2553] 0x2Ce6311ddAE708829bc0784C967b7d77D19FD779::balanceOf(0x327a25aD5Cfe5c4D4339C1A4267D4a83E8c93312) [delegatecall] │ │ │ └─ ← [Return] 0x000000000000000000000000000000000000000000000000000000000000968b │ │ └─ ← [Return] 0x000000000000000000000000000000000000000000000000000000000000968b - │ ├─ [16411] 0xA12384c5E52fD646E7BC7F6B3b33A605651F566E::f81d87a7(000000000000000000000000000000000000000000000000000000000000060f1bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b290a4c4039f102eceba2147e1fcc46f994a46d1229faf43ffff26a058e7378ff000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a12384c5e52fd646e7bc7f6b3b33a605651f566e000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000036cd000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000327a25ad5cfe5c4d4339c1a4267d4a83e8c93312000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000b55b053230e4effb6609de652fca73fd1c2980400000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000221000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006cdd519280ec730727f07aa36550bde31a1d5f3097818f3425c2f083ed33a91f080fa2afac0071f6e1af9a0e9c09b851bf01e68bc8a1c1f89f686c48205762f92500000000000000000000000000000000000000000000000000000000000000244242424242424242424242424242424242424242424242424242424242424242010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000827b226368616c6c656e6765223a224b51704d51446e7841757a726f68522d483878472d5a536b625249702d76515f5f5f4a714259357a655038222c2263726f73734f726967696e223a66616c73652c226f726967696e223a2268747470732f2f6974686163612e78797a222c2274797065223a22776562617574686e2e676574227d0000000000000000000000000000000000000000000000000000000000001bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) - │ │ ├─ [15711] 0x0B55b053230E4EFFb6609de652fCa73Fd1C29804::f81d87a7(000000000000000000000000000000000000000000000000000000000000060f1bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b290a4c4039f102eceba2147e1fcc46f994a46d1229faf43ffff26a058e7378ff000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a12384c5e52fd646e7bc7f6b3b33a605651f566e000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000036cd000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000327a25ad5cfe5c4d4339c1a4267d4a83e8c93312000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000b55b053230e4effb6609de652fca73fd1c2980400000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000221000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006cdd519280ec730727f07aa36550bde31a1d5f3097818f3425c2f083ed33a91f080fa2afac0071f6e1af9a0e9c09b851bf01e68bc8a1c1f89f686c48205762f92500000000000000000000000000000000000000000000000000000000000000244242424242424242424242424242424242424242424242424242424242424242010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000827b226368616c6c656e6765223a224b51704d51446e7841757a726f68522d483878472d5a536b625249702d76515f5f5f4a714259357a655038222c2263726f73734f726967696e223a66616c73652c226f726967696e223a2268747470732f2f6974686163612e78797a222c2274797065223a22776562617574686e2e676574227d0000000000000000000000000000000000000000000000000000000000001bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) [delegatecall] + │ ├─ [16411] 0xA12384c5E52fD646E7BC7F6B3b33A605651F566E::pay(1551, 0x1bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b, 0x290a4c4039f102eceba2147e1fcc46f994a46d1229faf43ffff26a058e7378ff, 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a12384c5e52fd646e7bc7f6b3b33a605651f566e000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000036cd000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000327a25ad5cfe5c4d4339c1a4267d4a83e8c93312000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000b55b053230e4effb6609de652fca73fd1c2980400000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000221000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006cdd519280ec730727f07aa36550bde31a1d5f3097818f3425c2f083ed33a91f080fa2afac0071f6e1af9a0e9c09b851bf01e68bc8a1c1f89f686c48205762f92500000000000000000000000000000000000000000000000000000000000000244242424242424242424242424242424242424242424242424242424242424242010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000827b226368616c6c656e6765223a224b51704d51446e7841757a726f68522d483878472d5a536b625249702d76515f5f5f4a714259357a655038222c2263726f73734f726967696e223a66616c73652c226f726967696e223a2268747470732f2f6974686163612e78797a222c2274797065223a22776562617574686e2e676574227d0000000000000000000000000000000000000000000000000000000000001bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) + │ │ ├─ [15711] 0x0B55b053230E4EFFb6609de652fCa73Fd1C29804::pay(1551, 0x1bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b, 0x290a4c4039f102eceba2147e1fcc46f994a46d1229faf43ffff26a058e7378ff, 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a12384c5e52fd646e7bc7f6b3b33a605651f566e000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000036cd000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000327a25ad5cfe5c4d4339c1a4267d4a83e8c93312000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000b55b053230e4effb6609de652fca73fd1c2980400000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000221000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006cdd519280ec730727f07aa36550bde31a1d5f3097818f3425c2f083ed33a91f080fa2afac0071f6e1af9a0e9c09b851bf01e68bc8a1c1f89f686c48205762f92500000000000000000000000000000000000000000000000000000000000000244242424242424242424242424242424242424242424242424242424242424242010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000827b226368616c6c656e6765223a224b51704d51446e7841757a726f68522d483878472d5a536b625249702d76515f5f5f4a714259357a655038222c2263726f73734f726967696e223a66616c73652c226f726967696e223a2268747470732f2f6974686163612e78797a222c2274797065223a22776562617574686e2e676574227d0000000000000000000000000000000000000000000000000000000000001bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) [delegatecall] │ │ │ ├─ [12963] 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913::transfer(0x327a25aD5Cfe5c4D4339C1A4267D4a83E8c93312, 1551) │ │ │ │ ├─ [12263] 0x2Ce6311ddAE708829bc0784C967b7d77D19FD779::transfer(0x327a25aD5Cfe5c4D4339C1A4267D4a83E8c93312, 1551) [delegatecall] │ │ │ │ │ ├─ emit Transfer(param0: 0xA12384c5E52fD646E7BC7F6B3b33A605651F566E, param1: 0x327a25aD5Cfe5c4D4339C1A4267D4a83E8c93312, param2: 1551) diff --git a/crates/chisel/src/dispatcher.rs b/crates/chisel/src/dispatcher.rs index 5dd6c882ffed6..13e63c1715beb 100644 --- a/crates/chisel/src/dispatcher.rs +++ b/crates/chisel/src/dispatcher.rs @@ -116,7 +116,10 @@ pub struct EtherscanABIResponse { macro_rules! format_param { ($param:expr) => {{ let param = $param; - format!("{}{}", param.ty, if param.is_complex_type() { " memory" } else { "" }) + let memory = param.is_complex_type() || + param.selector_type() == "string" || + param.selector_type() == "bytes"; + format!("{}{}", param.ty, if memory { " memory" } else { "" }) }}; } From f0932d04405bfb17f285b238a483366de128d061 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Mon, 9 Jun 2025 15:16:42 +0200 Subject: [PATCH 183/244] chore: update proptest to 1.7.0 (#10733) --- Cargo.lock | 25 ++++++++++---------- Cargo.toml | 2 +- crates/cheatcodes/Cargo.toml | 1 - crates/cheatcodes/src/inspector.rs | 14 ++--------- crates/evm/fuzz/src/strategies/int.rs | 16 ++++++------- crates/evm/fuzz/src/strategies/uint.rs | 14 +++++------ crates/forge/tests/cli/test_cmd.rs | 5 ++-- crates/forge/tests/it/invariant.rs | 32 +++++++++++++------------- 8 files changed, 48 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e16dcf3113735..dcffaaca7bcb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4087,7 +4087,6 @@ dependencies = [ "parking_lot", "proptest", "rand 0.9.1", - "rand_chacha 0.9.0", "revm", "revm-inspectors", "semver 1.0.26", @@ -7102,17 +7101,17 @@ dependencies = [ [[package]] name = "proptest" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" +checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" dependencies = [ "bit-set", "bit-vec", "bitflags 2.9.1", "lazy_static", "num-traits", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand 0.9.1", + "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax 0.8.5", "rusty-fork", @@ -7148,7 +7147,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.14.0", "proc-macro2", "quote", "syn 2.0.101", @@ -7390,11 +7389,11 @@ dependencies = [ [[package]] name = "rand_xorshift" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.6.4", + "rand_core 0.9.3", ] [[package]] @@ -8664,7 +8663,7 @@ dependencies = [ "derive_builder", "derive_more 2.0.1", "dunce", - "itertools 0.12.1", + "itertools 0.14.0", "itoa", "lasso", "match_cfg", @@ -8676,7 +8675,7 @@ dependencies = [ "solar-config", "solar-data-structures", "solar-macros", - "thiserror 1.0.69", + "thiserror 2.0.12", "tracing", "unicode-width 0.2.0", ] @@ -8701,7 +8700,7 @@ dependencies = [ "alloy-primitives", "bitflags 2.9.1", "bumpalo", - "itertools 0.12.1", + "itertools 0.14.0", "memchr", "num-bigint", "num-rational", @@ -9012,7 +9011,7 @@ dependencies = [ "serde_json", "sha2 0.10.9", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.12", "url", "zip", ] diff --git a/Cargo.toml b/Cargo.toml index 9b6ed5ab76212..d635ea33ac0fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -318,7 +318,7 @@ k256 = "0.13" mesc = "0.3" num-format = "0.4" parking_lot = "0.12" -proptest = "1" +proptest = "1.7.0" rand = "0.9" rand_08 = { package = "rand", version = "0.8" } rand_chacha = "0.9.0" diff --git a/crates/cheatcodes/Cargo.toml b/crates/cheatcodes/Cargo.toml index 8269364d231fb..f62bde4323e71 100644 --- a/crates/cheatcodes/Cargo.toml +++ b/crates/cheatcodes/Cargo.toml @@ -54,7 +54,6 @@ memchr = "2.7" p256 = "0.13" ecdsa = "0.16" rand.workspace = true -rand_chacha.workspace = true revm.workspace = true revm-inspectors.workspace = true semver.workspace = true diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index 14c185c317f42..08592fc57a8ae 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -46,8 +46,7 @@ use foundry_evm_traces::{TracingInspector, TracingInspectorConfig}; use foundry_wallets::multi_wallet::MultiWallet; use itertools::Itertools; use proptest::test_runner::{RngAlgorithm, TestRng, TestRunner}; -use rand::{Rng, SeedableRng}; -use rand_chacha::ChaChaRng; +use rand::Rng; use revm::{ bytecode::opcode as op, context::{result::EVMError, BlockEnv, JournalTr, LocalContext, TransactionType}, @@ -485,9 +484,6 @@ pub struct Cheatcodes { /// strategies. test_runner: Option, - /// Temp Rng since proptest hasn't been updated to rand 0.9 - rng: Option, - /// Ignored traces. pub ignored_traces: IgnoredTraces, @@ -552,7 +548,6 @@ impl Cheatcodes { arbitrary_storage: Default::default(), deprecated: Default::default(), wallets: Default::default(), - rng: Default::default(), } } @@ -1256,12 +1251,7 @@ impl Cheatcodes { } pub fn rng(&mut self) -> &mut impl Rng { - // Prop test uses rand 8 whereas alloy-core has been bumped to rand 9 - // self.test_runner().rng() - self.rng.get_or_insert_with(|| match self.config.seed { - Some(seed) => ChaChaRng::from_seed(seed.to_be_bytes::<32>()), - None => ChaChaRng::from_os_rng(), - }) + self.test_runner().rng() } pub fn test_runner(&mut self) -> &mut TestRunner { diff --git a/crates/evm/fuzz/src/strategies/int.rs b/crates/evm/fuzz/src/strategies/int.rs index 53d63ce03f923..c13f9414155b1 100644 --- a/crates/evm/fuzz/src/strategies/int.rs +++ b/crates/evm/fuzz/src/strategies/int.rs @@ -123,10 +123,10 @@ impl IntStrategy { fn generate_edge_tree(&self, runner: &mut TestRunner) -> NewTree { let rng = runner.rng(); - let offset = I256::from_raw(U256::from(rng.gen_range(0..4))); + let offset = I256::from_raw(U256::from(rng.random_range(0..4))); let umax: U256 = (U256::from(1) << (self.bits - 1)) - U256::from(1); // Choose if we want values around min, -0, +0, or max - let kind = rng.gen_range(0..4); + let kind = rng.random_range(0..4); let start = match kind { 0 => { I256::overflowing_from_sign_and_abs(Sign::Negative, umax + U256::from(1)).0 + offset @@ -146,7 +146,7 @@ impl IntStrategy { } // Generate value tree from fixture. - let fixture = &self.fixtures[runner.rng().gen_range(0..self.fixtures.len())]; + let fixture = &self.fixtures[runner.rng().random_range(0..self.fixtures.len())]; if let Some(int_fixture) = fixture.as_int() { if int_fixture.1 == self.bits { return Ok(IntValueTree::new(int_fixture.0, false)); @@ -162,15 +162,15 @@ impl IntStrategy { let rng = runner.rng(); // generate random number of bits uniformly - let bits = rng.gen_range(0..=self.bits); + let bits = rng.random_range(0..=self.bits); if bits == 0 { return Ok(IntValueTree::new(I256::ZERO, false)) } // init 2 128-bit randoms - let mut higher: u128 = rng.gen_range(0..=u128::MAX); - let mut lower: u128 = rng.gen_range(0..=u128::MAX); + let mut higher: u128 = rng.random_range(0..=u128::MAX); + let mut lower: u128 = rng.random_range(0..=u128::MAX); // cut 2 randoms according to bits size match bits - 1 { @@ -192,7 +192,7 @@ impl IntStrategy { // we have a small bias here, i.e. intN::min will never be generated // but it's ok since it's generated in `fn generate_edge_tree(...)` - let sign = if rng.gen_bool(0.5) { Sign::Positive } else { Sign::Negative }; + let sign = if rng.random::() { Sign::Positive } else { Sign::Negative }; let (start, _) = I256::overflowing_from_sign_and_abs(sign, U256::from_limbs(inner)); Ok(IntValueTree::new(start, false)) @@ -205,7 +205,7 @@ impl Strategy for IntStrategy { fn new_tree(&self, runner: &mut TestRunner) -> NewTree { let total_weight = self.random_weight + self.fixtures_weight + self.edge_weight; - let bias = runner.rng().gen_range(0..total_weight); + let bias = runner.rng().random_range(0..total_weight); // randomly select one of 3 strategies match bias { x if x < self.edge_weight => self.generate_edge_tree(runner), diff --git a/crates/evm/fuzz/src/strategies/uint.rs b/crates/evm/fuzz/src/strategies/uint.rs index 4a9dfe955020c..3d63ef92d36b4 100644 --- a/crates/evm/fuzz/src/strategies/uint.rs +++ b/crates/evm/fuzz/src/strategies/uint.rs @@ -111,8 +111,8 @@ impl UintStrategy { fn generate_edge_tree(&self, runner: &mut TestRunner) -> NewTree { let rng = runner.rng(); // Choose if we want values around 0 or max - let is_min = rng.gen_bool(0.5); - let offset = U256::from(rng.gen_range(0..4)); + let is_min = rng.random::(); + let offset = U256::from(rng.random_range(0..4)); let start = if is_min { offset } else { self.type_max().saturating_sub(offset) }; Ok(UintValueTree::new(start, false)) } @@ -124,7 +124,7 @@ impl UintStrategy { } // Generate value tree from fixture. - let fixture = &self.fixtures[runner.rng().gen_range(0..self.fixtures.len())]; + let fixture = &self.fixtures[runner.rng().random_range(0..self.fixtures.len())]; if let Some(uint_fixture) = fixture.as_uint() { if uint_fixture.1 == self.bits { return Ok(UintValueTree::new(uint_fixture.0, false)); @@ -140,11 +140,11 @@ impl UintStrategy { let rng = runner.rng(); // generate random number of bits uniformly - let bits = rng.gen_range(0..=self.bits); + let bits = rng.random_range(0..=self.bits); // init 2 128-bit randoms - let mut higher: u128 = rng.gen_range(0..=u128::MAX); - let mut lower: u128 = rng.gen_range(0..=u128::MAX); + let mut higher: u128 = rng.random_range(0..=u128::MAX); + let mut lower: u128 = rng.random_range(0..=u128::MAX); // cut 2 randoms according to bits size match bits { @@ -182,7 +182,7 @@ impl Strategy for UintStrategy { type Value = U256; fn new_tree(&self, runner: &mut TestRunner) -> NewTree { let total_weight = self.random_weight + self.fixtures_weight + self.edge_weight; - let bias = runner.rng().gen_range(0..total_weight); + let bias = runner.rng().random_range(0..total_weight); // randomly select one of 3 strategies match bias { x if x < self.edge_weight => self.generate_edge_tree(runner), diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index c486eba1049ae..6a6f067722cad 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -793,14 +793,14 @@ contract CounterTest is Test { Compiler run successful! Ran 1 test for test/CounterFuzz.t.sol:CounterTest -[FAIL: panic: arithmetic underflow or overflow (0x11); counterexample: calldata=0xa76d58f5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff args=[115792089237316195423570985008687907853269984665640564039457584007913129639935 [1.157e77]]] testAddOne(uint256) (runs: 61, [AVG_GAS]) +[FAIL: panic: arithmetic underflow or overflow (0x11); counterexample: calldata=0xa76d58f5fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd args=[115792089237316195423570985008687907853269984665640564039457584007913129639933 [1.157e77]]] testAddOne(uint256) (runs: 84, [AVG_GAS]) Suite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED] Ran 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests) Failing tests: Encountered 1 failing test in test/CounterFuzz.t.sol:CounterTest -[FAIL: panic: arithmetic underflow or overflow (0x11); counterexample: calldata=0xa76d58f5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff args=[115792089237316195423570985008687907853269984665640564039457584007913129639935 [1.157e77]]] testAddOne(uint256) (runs: 61, [AVG_GAS]) +[FAIL: panic: arithmetic underflow or overflow (0x11); counterexample: calldata=0xa76d58f5fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd args=[115792089237316195423570985008687907853269984665640564039457584007913129639933 [1.157e77]]] testAddOne(uint256) (runs: 84, [AVG_GAS]) Encountered a total of 1 failing tests, 0 tests succeeded @@ -2456,7 +2456,6 @@ contract Dummy { forgetest_init!(test_assume_no_revert_with_data, |prj, cmd| { prj.update_config(|config| { - config.fuzz.runs = 60; config.fuzz.seed = Some(U256::from(100)); }); diff --git a/crates/forge/tests/it/invariant.rs b/crates/forge/tests/it/invariant.rs index 5a072cedb7195..630afe34cff4d 100644 --- a/crates/forge/tests/it/invariant.rs +++ b/crates/forge/tests/it/invariant.rs @@ -815,7 +815,7 @@ contract BalanceAssumeTest is Test { cmd.args(["test", "--mt", "invariant_balance"]).assert_failure().stdout_eq(str![[r#" ... -[FAIL: `vm.assume` rejected too many inputs (10 allowed)] invariant_balance() (runs: 1, calls: 500, reverts: 0) +[FAIL: `vm.assume` rejected too many inputs (10 allowed)] invariant_balance() (runs: 5, calls: 2500, reverts: 0) ... "#]]); }); @@ -1069,7 +1069,7 @@ contract InvariantSelectorsWeightTest is Test { // Tests switch from regular sequence output to solidity. forgetest_init!(invariant_sequence_len, |prj, cmd| { prj.update_config(|config| { - config.fuzz.seed = Some(U256::from(100u32)); + config.fuzz.seed = Some(U256::from(10u32)); }); prj.add_test( @@ -1113,10 +1113,10 @@ Failing tests: Encountered 1 failing test in test/InvariantSequenceLenTest.t.sol:InvariantSequenceLenTest [FAIL: invariant increment failure] [Sequence] (original: 4, shrunk: 4) - sender=0x00000000000000000000000000000000000018dE addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[1931387396117645594923 [1.931e21]] - sender=0x0000000000000000000000000000000000000C37 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] - sender=0x0000000000000000000000000000000000000106 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] - sender=0x0000000000000000000000000000000000001684 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[996881781832960761274744263729582347 [9.968e35]] + sender=0x000000000000000000000000000000001ed7831C addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] + sender=0x00000000000000000000000000000000000014ba addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] + sender=0x8ef7F804bAd9183981A366EA618d9D47D3124649 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] + sender=0x00000000000000000000000000000000000016b9 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[284406551521730736391345481857560031052359183671404042152984097777 [2.844e65]] invariant_increment() (runs: 0, calls: 0, reverts: 0) Encountered a total of 1 failing tests, 0 tests succeeded @@ -1136,14 +1136,14 @@ Failing tests: Encountered 1 failing test in test/InvariantSequenceLenTest.t.sol:InvariantSequenceLenTest [FAIL: invariant increment failure] [Sequence] (original: 4, shrunk: 4) - vm.prank(0x00000000000000000000000000000000000018dE); - Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).setNumber(1931387396117645594923); - vm.prank(0x0000000000000000000000000000000000000C37); + vm.prank(0x000000000000000000000000000000001ed7831C); + Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).increment(); + vm.prank(0x00000000000000000000000000000000000014ba); Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).increment(); - vm.prank(0x0000000000000000000000000000000000000106); + vm.prank(0x8ef7F804bAd9183981A366EA618d9D47D3124649); Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).increment(); - vm.prank(0x0000000000000000000000000000000000001684); - Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).setNumber(996881781832960761274744263729582347); + vm.prank(0x00000000000000000000000000000000000016b9); + Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).setNumber(284406551521730736391345481857560031052359183671404042152984097777); invariant_increment() (runs: 0, calls: 0, reverts: 0) Encountered a total of 1 failing tests, 0 tests succeeded @@ -1162,10 +1162,10 @@ Failing tests: Encountered 1 failing test in test/InvariantSequenceLenTest.t.sol:InvariantSequenceLenTest [FAIL: invariant_increment replay failure] [Sequence] (original: 4, shrunk: 4) - sender=0x00000000000000000000000000000000000018dE addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[1931387396117645594923 [1.931e21]] - sender=0x0000000000000000000000000000000000000C37 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] - sender=0x0000000000000000000000000000000000000106 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] - sender=0x0000000000000000000000000000000000001684 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[996881781832960761274744263729582347 [9.968e35]] + sender=0x000000000000000000000000000000001ed7831C addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] + sender=0x00000000000000000000000000000000000014ba addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] + sender=0x8ef7F804bAd9183981A366EA618d9D47D3124649 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] + sender=0x00000000000000000000000000000000000016b9 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[284406551521730736391345481857560031052359183671404042152984097777 [2.844e65]] invariant_increment() (runs: 1, calls: 1, reverts: 1) Encountered a total of 1 failing tests, 0 tests succeeded From cdd74cb5a9a7a6e4f58ebe441005dc58f1114f2a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 17:17:31 +0200 Subject: [PATCH 184/244] chore(deps): weekly `cargo update` (#10728) Locking 50 packages to latest compatible versions Updating alloy-chains v0.2.3 -> v0.2.4 Updating alloy-dyn-abi v1.1.2 -> v1.2.0 Updating alloy-hardforks v0.2.6 -> v0.2.7 Updating alloy-json-abi v1.1.2 -> v1.2.0 Updating alloy-op-hardforks v0.2.6 -> v0.2.7 Updating alloy-primitives v1.1.2 -> v1.2.0 Updating alloy-sol-macro v1.1.2 -> v1.2.0 Updating alloy-sol-macro-expander v1.1.2 -> v1.2.0 Updating alloy-sol-macro-input v1.1.2 -> v1.2.0 Updating alloy-sol-type-parser v1.1.2 -> v1.2.0 Updating alloy-sol-types v1.1.2 -> v1.2.0 Updating anstream v0.6.18 -> v0.6.19 Updating anstyle v1.0.10 -> v1.0.11 Updating anstyle-lossy v1.1.3 -> v1.1.4 Updating anstyle-parse v0.2.6 -> v0.2.7 Updating anstyle-query v1.1.2 -> v1.1.3 Updating anstyle-svg v0.1.7 -> v0.1.8 Updating anstyle-wincon v3.0.8 -> v3.0.9 Updating aws-sdk-kms v1.72.0 -> v1.75.0 Updating aws-sdk-sso v1.71.0 -> v1.72.0 Updating aws-sdk-ssooidc v1.72.0 -> v1.73.0 Updating aws-sdk-sts v1.72.0 -> v1.73.0 Updating aws-smithy-http-client v1.0.2 -> v1.0.3 Updating base64ct v1.7.3 -> v1.8.0 Updating blst v0.3.14 -> v0.3.15 Updating bumpalo v3.17.0 -> v3.18.1 Updating bytemuck v1.23.0 -> v1.23.1 Updating cc v1.2.25 -> v1.2.26 Updating colorchoice v1.0.3 -> v1.0.4 Unchanged crossterm v0.28.1 (available: v0.29.0) Updating flate2 v1.1.1 -> v1.1.2 Updating gcloud-sdk v0.27.1 -> v0.27.2 Updating hashbrown v0.15.3 -> v0.15.4 Updating hyper-rustls v0.27.6 -> v0.27.7 Updating hyper-util v0.1.13 -> v0.1.14 Unchanged idna_adapter v1.1.0 (available: v1.2.1) Unchanged matchit v0.8.4 (available: v0.8.6) Unchanged op-revm v5.0.1 (available: v6.0.0) Unchanged opener v0.7.2 (available: v0.8.2) Updating portable-atomic v1.11.0 -> v1.11.1 Unchanged protobuf v3.3.0 (available: v3.7.2) Unchanged protobuf-support v3.3.0 (available: v3.7.2) Unchanged rand v0.8.5 (available: v0.9.1) Unchanged revm v24.0.1 (available: v25.0.0) Updating revm-bytecode v4.0.1 -> v4.1.0 Updating revm-primitives v19.1.0 -> v19.2.0 Unchanged rustyline v15.0.0 (available: v16.0.0) Unchanged schemars v0.8.22 (available: v0.9.0) Updating serde_spanned v0.6.8 -> v0.6.9 Updating smallvec v1.15.0 -> v1.15.1 Updating syn-solidity v1.1.2 -> v1.2.0 Updating toml v0.8.22 -> v0.8.23 Updating toml_datetime v0.6.9 -> v0.6.11 Updating toml_edit v0.22.26 -> v0.22.27 Updating toml_write v0.1.1 -> v0.1.2 Updating tower-http v0.6.5 -> v0.6.6 Updating tracing-attributes v0.1.28 -> v0.1.29 Updating tracing-core v0.1.33 -> v0.1.34 Unchanged ui_test v0.29.2 (available: v0.30.1) Unchanged vergen v8.3.2 (available: v9.0.6) Updating web_atoms v0.1.2 -> v0.1.3 Updating windows-registry v0.4.0 -> v0.5.2 Removing windows-strings v0.3.1 Updating ws_stream_wasm v0.7.4 -> v0.7.5 Unchanged zip-extract v0.2.1 (available: v0.2.3) note: to see how you depend on a package, run `cargo tree --invert --package @` Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> --- Cargo.lock | 244 ++++++++++++++++++++++++++--------------------------- 1 file changed, 118 insertions(+), 126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dcffaaca7bcb1..4ebb5c3ed4097 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,9 +58,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-chains" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6967ca1ed656766e471bc323da42fb0db320ca5e1418b408650e98e4757b3d2" +checksum = "19a9cc9d81ace3da457883b0bdf76776e55f1b84219a9e9d55c27ad308548d3f" dependencies = [ "alloy-primitives", "num_enum", @@ -130,9 +130,9 @@ dependencies = [ [[package]] name = "alloy-dyn-abi" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18cc14d832bc3331ca22a1c7819de1ede99f58f61a7d123952af7dde8de124a6" +checksum = "f9135eb501feccf7f4cb8a183afd406a65483fdad7bbd7332d0470e5d725c92f" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -253,9 +253,9 @@ dependencies = [ [[package]] name = "alloy-hardforks" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbff8445282ec080c2673692062bd4930d7a0d6bda257caf138cfc650c503000" +checksum = "977d2492ce210e34baf7b36afaacea272c96fbe6774c47e23f97d14033c0e94f" dependencies = [ "alloy-chains", "alloy-eip2124", @@ -266,9 +266,9 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ccaa79753d7bf15f06399ea76922afbfaf8d18bebed9e8fc452984b4a90dcc9" +checksum = "8b26fdd571915bafe857fccba4ee1a4f352965800e46a53e4a5f50187b7776fa" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -348,9 +348,9 @@ dependencies = [ [[package]] name = "alloy-op-hardforks" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ddfbb5cc9f614efa5d56e0d7226214bb67b29271d44b6ddfcbbe25eb0ff898b" +checksum = "08b147547aff595aa3d4c2fc2c8146263e18d3372909def423619ed631ecbcfa" dependencies = [ "alloy-hardforks", "auto_impl", @@ -358,9 +358,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c35fc4b03ace65001676358ffbbaefe2a2b27ee50fe777c345082c7c888be8" +checksum = "a326d47106039f38b811057215a92139f46eef7983a4b77b10930a0ea5685b1e" dependencies = [ "alloy-rlp", "arbitrary", @@ -371,7 +371,7 @@ dependencies = [ "derive_more 2.0.1", "foldhash", "getrandom 0.3.3", - "hashbrown 0.15.3", + "hashbrown 0.15.4", "indexmap 2.9.0", "itoa", "k256", @@ -738,9 +738,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8612e0658964d616344f199ab251a49d48113992d81b92dab93ed855faa66383" +checksum = "d4be1ce1274ddd7fdfac86e5ece1b225e9bba1f2327e20fbb30ee6b9cc1423fe" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -752,9 +752,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a384edac7283bc4c010a355fb648082860c04b826bb7a814c45263c8f304c74" +checksum = "01e92f3708ea4e0d9139001c86c051c538af0146944a2a9c7181753bd944bf57" dependencies = [ "alloy-json-abi", "alloy-sol-macro-input", @@ -771,9 +771,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd588c2d516da7deb421b8c166dc60b7ae31bca5beea29ab6621fcfa53d6ca5" +checksum = "9afe1bd348a41f8c9b4b54dfb314886786d6201235b0b3f47198b9d910c86bb2" dependencies = [ "alloy-json-abi", "const-hex", @@ -789,9 +789,9 @@ dependencies = [ [[package]] name = "alloy-sol-type-parser" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86ddeb70792c7ceaad23e57d52250107ebbb86733e52f4a25d8dc1abc931837" +checksum = "d6195df2acd42df92a380a8db6205a5c7b41282d0ce3f4c665ecf7911ac292f1" dependencies = [ "serde", "winnow", @@ -799,9 +799,9 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "584cb97bfc5746cb9dcc4def77da11694b5d6d7339be91b7480a6a68dc129387" +checksum = "6185e98a79cf19010722f48a74b5a65d153631d2f038cabd250f4b9e9813b8ad" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -942,9 +942,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", @@ -957,55 +957,55 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-lossy" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934ff8719effd2023a48cf63e69536c1c3ced9d3895068f6f5cc9a4ff845e59b" +checksum = "04d3a5dc826f84d0ea11882bb8054ff7f3d482602e11bb181101303a279ea01f" dependencies = [ "anstyle", ] [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "anstyle-svg" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3607949e9f6de49ea4bafe12f5e4fd73613ebf24795e48587302a8cc0e4bb35" +checksum = "c681338396641f4e32a29f045d0c70950da7207b4376685b51396c481ee36f1a" dependencies = [ - "anstream", "anstyle", "anstyle-lossy", + "anstyle-parse", "html-escape", "unicode-width 0.2.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.8" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", "once_cell_polyfill", @@ -1193,7 +1193,7 @@ dependencies = [ "ark-std 0.5.0", "educe", "fnv", - "hashbrown 0.15.3", + "hashbrown 0.15.4", "itertools 0.13.0", "num-bigint", "num-integer", @@ -1339,7 +1339,7 @@ dependencies = [ "ark-std 0.5.0", "educe", "fnv", - "hashbrown 0.15.3", + "hashbrown 0.15.4", ] [[package]] @@ -1675,9 +1675,9 @@ dependencies = [ [[package]] name = "aws-sdk-kms" -version = "1.72.0" +version = "1.75.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eef6a94141a43ee28404bf135828ad9bdd4936bfa2a84ad8dea355c94646a35" +checksum = "bb89d6ae47f03ca664f604571d0f29165112543ba1a39878347815b8028c235b" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1697,9 +1697,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.71.0" +version = "1.72.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a4fd09d6e863655d99cd2260f271c6d1030dc6bfad68e19e126d2e4c8ceb18" +checksum = "13118ad30741222f67b1a18e5071385863914da05124652b38e172d6d3d9ce31" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1719,9 +1719,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.72.0" +version = "1.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3224ab02ebb3074467a33d57caf6fcb487ca36f3697fdd381b0428dc72380696" +checksum = "f879a8572b4683a8f84f781695bebf2f25cf11a81a2693c31fc0e0215c2c1726" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1741,9 +1741,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.72.0" +version = "1.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6933f189ed1255e78175fbd73fb200c0aae7240d220ed3346f567b0ddca3083" +checksum = "f1e9c3c24e36183e2f698235ed38dcfbbdff1d09b9232dc866c4be3011e0b47e" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1817,9 +1817,9 @@ dependencies = [ [[package]] name = "aws-smithy-http-client" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e44697a9bded898dcd0b1cb997430d949b87f4f8940d91023ae9062bf218250" +checksum = "073d330f94bdf1f47bb3e0f5d45dda1e372a54a553c39ab6e9646902c8c81594" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -2055,9 +2055,9 @@ dependencies = [ [[package]] name = "base64ct" -version = "1.7.3" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "bech32" @@ -2173,9 +2173,9 @@ dependencies = [ [[package]] name = "blst" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c79a94619fade3c0b887670333513a67ac28a6a7e653eb260bf0d4103db38d" +checksum = "4fd49896f12ac9b6dcd7a5998466b9b58263a695a3dd1ecc1aaca2e12a90b080" dependencies = [ "cc", "glob", @@ -2231,9 +2231,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "byte-slice-cast" @@ -2243,9 +2243,9 @@ checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] name = "bytemuck" -version = "1.23.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" [[package]] name = "byteorder" @@ -2414,9 +2414,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.25" +version = "1.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" +checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" dependencies = [ "jobserver", "libc", @@ -2759,9 +2759,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "colored" @@ -3716,7 +3716,7 @@ dependencies = [ "pear", "serde", "tempfile", - "toml 0.8.22", + "toml 0.8.23", "uncased", "version_check", ] @@ -3753,9 +3753,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "miniz_oxide", @@ -3876,7 +3876,7 @@ dependencies = [ "serde", "serde_json", "thiserror 2.0.12", - "toml 0.8.22", + "toml 0.8.23", "tracing", ] @@ -3891,7 +3891,7 @@ dependencies = [ "itertools 0.14.0", "similar-asserts", "thiserror 2.0.12", - "toml 0.8.22", + "toml 0.8.23", "tracing", "tracing-subscriber 0.3.19", ] @@ -4093,7 +4093,7 @@ dependencies = [ "serde", "serde_json", "thiserror 2.0.12", - "toml 0.8.22", + "toml 0.8.23", "tracing", "walkdir", ] @@ -4371,7 +4371,7 @@ dependencies = [ "soldeer-core", "tempfile", "thiserror 2.0.12", - "toml 0.8.22", + "toml 0.8.23", "toml_edit", "tracing", "walkdir", @@ -4797,9 +4797,9 @@ checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" [[package]] name = "gcloud-sdk" -version = "0.27.1" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44163d7c0d0bc470caa43766beda779e584034abd6b681319d8f9be2fc194eba" +checksum = "a3ec9c312db09dc0dac684dda2f18d76e9ce00effdd27fcaaa90fa811691cd6d" dependencies = [ "async-trait", "bytes", @@ -4974,9 +4974,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "allocator-api2", "equivalent", @@ -5162,9 +5162,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.6" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ "http 1.3.1", "hyper", @@ -5193,9 +5193,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" dependencies = [ "base64 0.22.1", "bytes", @@ -5345,7 +5345,7 @@ checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "arbitrary", "equivalent", - "hashbrown 0.15.3", + "hashbrown 0.15.4", "serde", ] @@ -5883,7 +5883,7 @@ version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.15.3", + "hashbrown 0.15.4", ] [[package]] @@ -5892,7 +5892,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" dependencies = [ - "hashbrown 0.15.3", + "hashbrown 0.15.4", ] [[package]] @@ -6462,7 +6462,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bd2cae3bec3936bbed1ccc5a3343b3738858182419f9c0522c7260c80c430b0" dependencies = [ "ahash", - "hashbrown 0.15.3", + "hashbrown 0.15.4", "parking_lot", "stable_deref_trait", ] @@ -6932,9 +6932,9 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "portable-atomic" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "portable-atomic-util" @@ -7585,9 +7585,9 @@ dependencies = [ [[package]] name = "revm-bytecode" -version = "4.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91f9b90b3bab18942252de2d970ee8559794c49ca7452b2cc1774456040f8fb" +checksum = "942fe4724cf552fd28db6b0a2ca5b79e884d40dd8288a4027ed1e9090e0c6f49" dependencies = [ "bitvec", "once_cell", @@ -7746,9 +7746,9 @@ dependencies = [ [[package]] name = "revm-primitives" -version = "19.1.0" +version = "19.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18ea2ea0134568ee1e14281ce52f60e2710d42be316888d464c53e37ff184fd8" +checksum = "1c1588093530ec4442461163be49c433c07a3235d1ca6f6799fef338dacc50d3" dependencies = [ "alloy-primitives", "num_enum", @@ -8328,9 +8328,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -8558,9 +8558,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" dependencies = [ "serde", ] @@ -9052,9 +9052,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d879005cc1b5ba4e18665be9e9501d9da3a9b95f625497c4cb7ee082b532e" +checksum = "14c8c8f496c33dc6343dac05b4be8d9e0bca180a4caa81d7b8416b10cc2273cd" dependencies = [ "paste", "proc-macro2", @@ -9410,9 +9410,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "indexmap 2.9.0", "serde", @@ -9423,18 +9423,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.26" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap 2.9.0", "serde", @@ -9446,9 +9446,9 @@ dependencies = [ [[package]] name = "toml_write" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "tonic" @@ -9508,12 +9508,13 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc2d9e086a412a451384326f521c8123a99a466b329941a9403696bff9b0da2" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ "bitflags 2.9.1", "bytes", + "futures-core", "futures-util", "http 1.3.1", "http-body 1.0.1", @@ -9571,9 +9572,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" dependencies = [ "proc-macro2", "quote", @@ -9582,9 +9583,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -10241,9 +10242,9 @@ dependencies = [ [[package]] name = "web_atoms" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9c5f0bc545ea3b20b423e33b9b457764de0b3730cd957f6c6aa6c301785f6e" +checksum = "57ffde1dc01240bdf9992e3205668b235e59421fd085e8a317ed98da0178d414" dependencies = [ "phf", "phf_codegen", @@ -10362,7 +10363,7 @@ dependencies = [ "windows-interface", "windows-link", "windows-result", - "windows-strings 0.4.2", + "windows-strings", ] [[package]] @@ -10416,13 +10417,13 @@ dependencies = [ [[package]] name = "windows-registry" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820" dependencies = [ + "windows-link", "windows-result", - "windows-strings 0.3.1", - "windows-targets 0.53.0", + "windows-strings", ] [[package]] @@ -10434,15 +10435,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-strings" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-strings" version = "0.4.2" @@ -10633,9 +10625,9 @@ dependencies = [ [[package]] name = "ws_stream_wasm" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +checksum = "6c173014acad22e83f16403ee360115b38846fe754e735c5d9d3803fe70c6abc" dependencies = [ "async_io_stream", "futures", @@ -10644,7 +10636,7 @@ dependencies = [ "pharos", "rustc_version 0.4.1", "send_wrapper", - "thiserror 1.0.69", + "thiserror 2.0.12", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", From 090f0023c1059fd9852aa77a8c04f497893fe0c3 Mon Sep 17 00:00:00 2001 From: W Date: Mon, 9 Jun 2025 21:50:43 +0200 Subject: [PATCH 185/244] feat(cast): add `--cost` for `estimate` to return the eth cost at current gas price (#9687) feat(cast): add --cost to cast estimate the eth cost at current gas price Co-authored-by: grandizzy --- crates/cast/src/cmd/estimate.rs | 17 +++++++++++++++-- crates/cast/tests/cli/main.rs | 25 +++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/crates/cast/src/cmd/estimate.rs b/crates/cast/src/cmd/estimate.rs index 51368b6d0a538..8bcd29806ee65 100644 --- a/crates/cast/src/cmd/estimate.rs +++ b/crates/cast/src/cmd/estimate.rs @@ -30,6 +30,12 @@ pub struct EstimateArgs { #[arg(long, short = 'B')] block: Option, + /// Calculate the cost of a transaction using the network gas price. + /// + /// If not specified the amount of gas will be estimated. + #[arg(long)] + cost: bool, + #[command(subcommand)] command: Option, @@ -66,7 +72,7 @@ pub enum EstimateSubcommands { impl EstimateArgs { pub async fn run(self) -> Result<()> { - let Self { to, mut sig, mut args, mut tx, block, eth, command } = self; + let Self { to, mut sig, mut args, mut tx, block, cost, eth, command } = self; let config = eth.load_config()?; let provider = utils::get_provider(&config)?; @@ -99,7 +105,14 @@ impl EstimateArgs { .await?; let gas = provider.estimate_gas(tx).block(block.unwrap_or_default()).await?; - sh_println!("{gas}")?; + if cost { + let gas_price_wei = provider.get_gas_price().await?; + let cost = gas_price_wei * gas as u128; + let cost_eth = cost as f64 / 1e18; + sh_println!("{cost_eth}")?; + } else { + sh_println!("{gas}")?; + } Ok(()) } } diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 531c8e1837563..71ced1c71e7b7 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -760,6 +760,31 @@ casttest!(estimate_function_gas, |_prj, cmd| { assert!(output.ge(&0)); }); +// tests that `cast estimate --cost` is working correctly. +casttest!(estimate_function_cost, |_prj, cmd| { + let eth_rpc_url = next_http_rpc_endpoint(); + + // ensure we get a positive non-error value for cost estimate + let output: f64 = cmd + .args([ + "estimate", + "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", // vitalik.eth + "--value", + "100", + "deposit()", + "--rpc-url", + eth_rpc_url.as_str(), + "--cost", + ]) + .assert_success() + .get_output() + .stdout_lossy() + .trim() + .parse() + .unwrap(); + assert!(output > 0f64); +}); + // tests that `cast estimate --create` is working correctly. casttest!(estimate_contract_deploy_gas, |_prj, cmd| { let eth_rpc_url = next_http_rpc_endpoint(); From f13f60e88c0d1076f5f2ebfabee825ce9bcc391f Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 10 Jun 2025 08:49:41 +0200 Subject: [PATCH 186/244] fix: check for op deposit tx when handling cast tx (#10742) --- crates/cast/src/lib.rs | 6 +++++- crates/cast/tests/cli/main.rs | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index b8bdc2ba6d03e..1a47c6877238a 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -37,6 +37,7 @@ use foundry_compilers::flatten::Flattener; use foundry_config::Chain; use foundry_evm_core::ic::decode_instructions; use futures::{future::Either, FutureExt, StreamExt}; +use op_alloy_consensus::OpTxEnvelope; use rayon::prelude::*; use std::{ borrow::Cow, @@ -789,7 +790,10 @@ impl> Cast

{ }; Ok(if raw { - format!("0x{}", hex::encode(tx.inner.inner.encoded_2718())) + // also consider opstack deposit transactions + let either_tx = tx.try_into_either::()?; + let encoded = either_tx.encoded_2718(); + format!("0x{}", hex::encode(encoded)) } else if let Some(field) = field { get_pretty_tx_attr(&tx.inner, field.as_str()) .ok_or_else(|| eyre::eyre!("invalid tx field: {}", field.to_string()))? diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 71ced1c71e7b7..bf825cdd9f95f 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -2753,3 +2753,18 @@ casttest!(cast_call_return_array_of_tuples, |_prj, cmd| { "#]]); }); + +// +casttest!(tx_raw_opstack_deposit, |_prj, cmd| { + cmd.args([ + "tx", + "0xf403cba612d1c01c027455c0d97427ccd5f7f99aac30017e065f81d1e30244ea", + "--raw", + "--rpc-url", + "https://sepolia.base.org", + ]).assert_success() + .stdout_eq(str![[r#" +0x7ef90207a0cbde10ec697aff886f95d2514bab434e455620627b9bb8ba33baaaa4d537d62794d45955f4de64f1840e5686e64278da901e263031944200000000000000000000000000000000000007872386f26fc10000872386f26fc1000083096c4980b901a4d764ad0b0001000000000000000000000000000000000000000000000000000000065132000000000000000000000000fd0bf71f60660e2f608ed56e1659c450eb1131200000000000000000000000004200000000000000000000000000000000000010000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000493e000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000a41635f5fd000000000000000000000000ca11bde05977b3631167028862be2a173976ca110000000000000000000000005703b26fe5a7be820db1bf34c901a79da1a46ba4000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + +"#]]); +}); From c199a5b8357068cc4d506beda9ac3f384462930a Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Tue, 10 Jun 2025 09:50:01 +0200 Subject: [PATCH 187/244] chore: remove announcement link in `nightly` as it is unmaintained (#10745) remove announcement link as it is unmaintained --- crates/common/src/version.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/common/src/version.rs b/crates/common/src/version.rs index 323bd94ce88ec..aae9788aab93f 100644 --- a/crates/common/src/version.rs +++ b/crates/common/src/version.rs @@ -23,5 +23,4 @@ pub const IS_NIGHTLY_VERSION: bool = option_env!("FOUNDRY_IS_NIGHTLY_VERSION").i /// The warning message for nightly versions. pub const NIGHTLY_VERSION_WARNING_MESSAGE: &str = "This is a nightly build of Foundry. It is recommended to use the latest stable version. \ - Visit https://book.getfoundry.sh/misc/announcements for more information. \n\ To mute this warning set `FOUNDRY_DISABLE_NIGHTLY_WARNING` in your environment. \n"; From 8b04d0d177cbfcd5d89ab5c14fdd7873e2025d07 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Tue, 10 Jun 2025 07:03:18 -0500 Subject: [PATCH 188/244] fix: adds remaining ZKsync chains for estimate gas checks (#10719) * feat: adds remaining elastic networks for gas estimation during simulation script * chore: run fmt * chore: run rustfmt * chore: run rustfmt * Update crates/cli/src/utils/cmd.rs --------- Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- crates/cli/src/utils/cmd.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/cli/src/utils/cmd.rs b/crates/cli/src/utils/cmd.rs index 1396d964db8aa..21f411d446235 100644 --- a/crates/cli/src/utils/cmd.rs +++ b/crates/cli/src/utils/cmd.rs @@ -163,6 +163,7 @@ pub fn init_progress(len: u64, label: &str) -> indicatif::ProgressBar { pub fn has_different_gas_calc(chain_id: u64) -> bool { if let Some(chain) = Chain::from(chain_id).named() { return chain.is_arbitrum() || + chain.is_elastic() || matches!( chain, NamedChain::Acala | @@ -179,10 +180,7 @@ pub fn has_different_gas_calc(chain_id: u64) -> bool { NamedChain::Moonbeam | NamedChain::MoonbeamDev | NamedChain::Moonriver | - NamedChain::Metis | - NamedChain::Abstract | - NamedChain::ZkSync | - NamedChain::ZkSyncTestnet + NamedChain::Metis ); } false From 1836d5ef13cce0d44c450f971e5399160df681e2 Mon Sep 17 00:00:00 2001 From: pistomat Date: Tue, 10 Jun 2025 15:46:42 +0200 Subject: [PATCH 189/244] feat: Add anvil set erc20 allowance endpoint (#10746) * feat: Add anvil_setERC20Allowance endpoint * chore: Remove tenderly_setErc20Balance Unfortunately anvil has the parameter order (owner, token) while tenderly has (token, owner), so they are not compatible. Fixing my previous mistake here. * chore: Formatting --- crates/anvil/core/src/eth/mod.rs | 12 ++++- crates/anvil/src/eth/api.rs | 75 ++++++++++++++++++++++++++++++++ crates/anvil/tests/it/fork.rs | 25 +++++++++++ 3 files changed, 110 insertions(+), 2 deletions(-) diff --git a/crates/anvil/core/src/eth/mod.rs b/crates/anvil/core/src/eth/mod.rs index 5b77e4d0ce380..c1d54aa68e005 100644 --- a/crates/anvil/core/src/eth/mod.rs +++ b/crates/anvil/core/src/eth/mod.rs @@ -380,11 +380,19 @@ pub enum EthRequest { #[serde( rename = "anvil_dealERC20", alias = "hardhat_dealERC20", - alias = "anvil_setERC20Balance", - alias = "tenderly_setErc20Balance" + alias = "anvil_setERC20Balance" )] DealERC20(Address, Address, #[serde(deserialize_with = "deserialize_number")] U256), + /// Sets the ERC20 allowance for a spender + #[serde(rename = "anvil_setERC20Allowance")] + SetERC20Allowance( + Address, + Address, + Address, + #[serde(deserialize_with = "deserialize_number")] U256, + ), + /// Sets the code of a contract #[serde(rename = "anvil_setCode", alias = "hardhat_setCode")] SetCode(Address, Bytes), diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 59c5ab2fc681a..5f464fd43b5e8 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -362,6 +362,10 @@ impl EthApi { EthRequest::DealERC20(addr, token_addr, val) => { self.anvil_deal_erc20(addr, token_addr, val).await.to_rpc_result() } + EthRequest::SetERC20Allowance(owner, spender, token_addr, val) => self + .anvil_set_erc20_allowance(owner, spender, token_addr, val) + .await + .to_rpc_result(), EthRequest::SetCode(addr, code) => { self.anvil_set_code(addr, code).await.to_rpc_result() } @@ -1939,6 +1943,77 @@ impl EthApi { Err(BlockchainError::Message("Unable to set ERC20 balance, no slot found".to_string())) } + /// Sets the ERC20 allowance for a spender + /// + /// Handler for RPC call: `anvil_set_erc20_allowance` + pub async fn anvil_set_erc20_allowance( + &self, + owner: Address, + spender: Address, + token_address: Address, + amount: U256, + ) -> Result<()> { + node_info!("anvil_setERC20Allowance"); + + sol! { + #[sol(rpc)] + contract IERC20 { + function allowance(address owner, address spender) external view returns (uint256); + } + } + + let calldata = IERC20::allowanceCall { owner, spender }.abi_encode(); + let tx = TransactionRequest::default().with_to(token_address).with_input(calldata.clone()); + + // first collect all the slots that are used by the allowance call + let access_list_result = + self.create_access_list(WithOtherFields::new(tx.clone()), None).await?; + let access_list = access_list_result.access_list; + + // now we can iterate over all the accessed slots and try to find the one that contains the + // allowance by overriding the slot and checking the `allowanceCall` result + for item in access_list.0 { + if item.address != token_address { + continue; + }; + for slot in &item.storage_keys { + let account_override = AccountOverride::default() + .with_state_diff(std::iter::once((*slot, B256::from(amount.to_be_bytes())))); + + let state_override = StateOverridesBuilder::default() + .append(token_address, account_override) + .build(); + + let evm_override = EvmOverrides::state(Some(state_override)); + + let Ok(result) = + self.call(WithOtherFields::new(tx.clone()), None, evm_override).await + else { + // overriding this slot failed + continue; + }; + + let Ok(result_allowance) = U256::abi_decode(&result) else { + // response returned something other than a U256 + continue; + }; + + if result_allowance == amount { + self.anvil_set_storage_at( + token_address, + U256::from_be_bytes(slot.0), + B256::from(amount.to_be_bytes()), + ) + .await?; + return Ok(()); + } + } + } + + // unable to set the allowance + Err(BlockchainError::Message("Unable to set ERC20 allowance, no slot found".to_string())) + } + /// Sets the code of a contract. /// /// Handler for RPC call: `anvil_setCode` diff --git a/crates/anvil/tests/it/fork.rs b/crates/anvil/tests/it/fork.rs index e4e1cda1a31d3..c0e2eba8181d2 100644 --- a/crates/anvil/tests/it/fork.rs +++ b/crates/anvil/tests/it/fork.rs @@ -1490,6 +1490,31 @@ async fn test_set_erc20_balance() { assert_eq!(new_balance, value); } +#[tokio::test(flavor = "multi_thread")] +async fn test_set_erc20_allowance() { + let config: NodeConfig = fork_config(); + let owner = config.genesis_accounts[0].address(); + let spender = config.genesis_accounts[1].address(); + let (api, handle) = spawn(config).await; + + let provider = handle.http_provider(); + + alloy_sol_types::sol! { + #[sol(rpc)] + contract ERC20 { + function allowance(address owner, address spender) external view returns (uint256); + } + } + let dai = address!("0x6B175474E89094C44Da98b954EedeAC495271d0F"); + let erc20 = ERC20::new(dai, provider); + let value = U256::from(500); + + api.anvil_set_erc20_allowance(owner, spender, dai, value).await.unwrap(); + + let allowance = erc20.allowance(owner, spender).call().await.unwrap(); + assert_eq!(allowance, value); +} + #[tokio::test(flavor = "multi_thread")] async fn test_add_balance() { let config: NodeConfig = fork_config(); From 3aac24986a7d52b416c774e4cc93abcca1f8641f Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 10 Jun 2025 16:34:48 +0200 Subject: [PATCH 190/244] refactor: unify ERC20 storage slot discovery logic (#10749) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: unify ERC20 storage slot discovery logic Extracts duplicated access list handling code from `anvil_deal_erc20` and `anvil_set_erc20_allowance` into a shared `find_erc20_storage_slot` helper function. Changes: - Add comprehensive documentation explaining the slot discovery process - Reduce code duplication by ~80 lines - Improve maintainability and consistency between functions - Fix unfulfilled clippy expectation in cast/tx.rs This is a follow-up cleanup to #10746 which introduced `anvil_set_erc20_allowance`. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * chore: add clippy back --------- Co-authored-by: Claude --- crates/anvil/src/eth/api.rs | 161 ++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 80 deletions(-) diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 5f464fd43b5e8..57af0e68eef84 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -1873,41 +1873,45 @@ impl EthApi { Ok(()) } - /// Deals ERC20 tokens to a address - /// - /// Handler for RPC call: `anvil_dealERC20` - pub async fn anvil_deal_erc20( + /// Helper function to find the storage slot for an ERC20 function call by testing slots + /// from an access list until one produces the expected result. + /// + /// Rather than trying to reverse-engineer the storage layout, this function uses a + /// "trial and error" approach: try overriding each slot that the function accesses, + /// and see which one actually affects the function's return value. + /// + /// ## Parameters + /// - `token_address`: The ERC20 token contract address + /// - `calldata`: The encoded function call (e.g., `balanceOf(user)` or `allowance(owner, + /// spender)`) + /// - `expected_value`: The value we want to set (balance or allowance amount) + /// + /// ## Returns + /// The storage slot (B256) that contains the target ERC20 data, or an error if no slot is + /// found. + async fn find_erc20_storage_slot( &self, - address: Address, token_address: Address, - balance: U256, - ) -> Result<()> { - node_info!("anvil_dealERC20"); - - sol! { - #[sol(rpc)] - contract IERC20 { - function balanceOf(address target) external view returns (uint256); - } - } - - let calldata = IERC20::balanceOfCall { target: address }.abi_encode(); + calldata: Bytes, + expected_value: U256, + ) -> Result { let tx = TransactionRequest::default().with_to(token_address).with_input(calldata.clone()); - // first collect all the slots that are used by the balanceOf call + // first collect all the slots that are used by the function call let access_list_result = self.create_access_list(WithOtherFields::new(tx.clone()), None).await?; let access_list = access_list_result.access_list; - // now we can iterate over all the accessed slots and try to find the one that contains the - // balance by overriding the slot and checking the `balanceOfCall` of + // iterate over all the accessed slots and try to find the one that contains the + // target value by overriding the slot and checking the function call result for item in access_list.0 { if item.address != token_address { continue; }; for slot in &item.storage_keys { - let account_override = AccountOverride::default() - .with_state_diff(std::iter::once((*slot, B256::from(balance.to_be_bytes())))); + let account_override = AccountOverride::default().with_state_diff(std::iter::once( + (*slot, B256::from(expected_value.to_be_bytes())), + )); let state_override = StateOverridesBuilder::default() .append(token_address, account_override) @@ -1922,25 +1926,55 @@ impl EthApi { continue; }; - let Ok(result_balance) = U256::abi_decode(&result) else { + let Ok(result_value) = U256::abi_decode(&result) else { // response returned something other than a U256 continue; }; - if result_balance == balance { - self.anvil_set_storage_at( - token_address, - U256::from_be_bytes(slot.0), - B256::from(balance.to_be_bytes()), - ) - .await?; - return Ok(()); + if result_value == expected_value { + return Ok(*slot); } } } - // unable to set the balance - Err(BlockchainError::Message("Unable to set ERC20 balance, no slot found".to_string())) + Err(BlockchainError::Message("Unable to find storage slot".to_string())) + } + + /// Deals ERC20 tokens to a address + /// + /// Handler for RPC call: `anvil_dealERC20` + pub async fn anvil_deal_erc20( + &self, + address: Address, + token_address: Address, + balance: U256, + ) -> Result<()> { + node_info!("anvil_dealERC20"); + + sol! { + #[sol(rpc)] + contract IERC20 { + function balanceOf(address target) external view returns (uint256); + } + } + + let calldata = IERC20::balanceOfCall { target: address }.abi_encode().into(); + + // Find the storage slot that contains the balance + let slot = + self.find_erc20_storage_slot(token_address, calldata, balance).await.map_err(|_| { + BlockchainError::Message("Unable to set ERC20 balance, no slot found".to_string()) + })?; + + // Set the storage slot to the desired balance + self.anvil_set_storage_at( + token_address, + U256::from_be_bytes(slot.0), + B256::from(balance.to_be_bytes()), + ) + .await?; + + Ok(()) } /// Sets the ERC20 allowance for a spender @@ -1962,56 +1996,23 @@ impl EthApi { } } - let calldata = IERC20::allowanceCall { owner, spender }.abi_encode(); - let tx = TransactionRequest::default().with_to(token_address).with_input(calldata.clone()); - - // first collect all the slots that are used by the allowance call - let access_list_result = - self.create_access_list(WithOtherFields::new(tx.clone()), None).await?; - let access_list = access_list_result.access_list; - - // now we can iterate over all the accessed slots and try to find the one that contains the - // allowance by overriding the slot and checking the `allowanceCall` result - for item in access_list.0 { - if item.address != token_address { - continue; - }; - for slot in &item.storage_keys { - let account_override = AccountOverride::default() - .with_state_diff(std::iter::once((*slot, B256::from(amount.to_be_bytes())))); - - let state_override = StateOverridesBuilder::default() - .append(token_address, account_override) - .build(); - - let evm_override = EvmOverrides::state(Some(state_override)); + let calldata = IERC20::allowanceCall { owner, spender }.abi_encode().into(); - let Ok(result) = - self.call(WithOtherFields::new(tx.clone()), None, evm_override).await - else { - // overriding this slot failed - continue; - }; + // Find the storage slot that contains the allowance + let slot = + self.find_erc20_storage_slot(token_address, calldata, amount).await.map_err(|_| { + BlockchainError::Message("Unable to set ERC20 allowance, no slot found".to_string()) + })?; - let Ok(result_allowance) = U256::abi_decode(&result) else { - // response returned something other than a U256 - continue; - }; - - if result_allowance == amount { - self.anvil_set_storage_at( - token_address, - U256::from_be_bytes(slot.0), - B256::from(amount.to_be_bytes()), - ) - .await?; - return Ok(()); - } - } - } + // Set the storage slot to the desired allowance + self.anvil_set_storage_at( + token_address, + U256::from_be_bytes(slot.0), + B256::from(amount.to_be_bytes()), + ) + .await?; - // unable to set the allowance - Err(BlockchainError::Message("Unable to set ERC20 allowance, no slot found".to_string())) + Ok(()) } /// Sets the code of a contract. From df0ec82f48ef4162d75569378994434b6b953489 Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Tue, 10 Jun 2025 17:34:25 +0200 Subject: [PATCH 191/244] chore: gitignore CLAUDE instructions and settings (#10750) * chore: gitignore CLAUDE instructions and settings * fix --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 9297bbbc7d4f2..12d56ed3c7d97 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ snapshots/ out.json .idea .vscode +.claude +CLAUDE.md From 9b583207b09a73b05490811e5ddd6f1de6f4593d Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 10 Jun 2025 18:29:36 +0200 Subject: [PATCH 192/244] fix: pin action gh release to v2.2.2 (#10752) --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4bf0543fb7482..b94b219cdc312 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -231,7 +231,7 @@ jobs: # Creates the release for this specific version - name: Create release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v2.2.2 with: name: ${{ needs.prepare.outputs.release_name }} tag_name: ${{ needs.prepare.outputs.tag_name }} @@ -254,7 +254,7 @@ jobs: # tagged `nightly` for compatibility with `foundryup` - name: Update nightly release if: ${{ env.IS_NIGHTLY == 'true' }} - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v2.2.2 with: name: "Nightly" tag_name: "nightly" From ac0411d0e3b9632247c9aea9535472eda09a57ae Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 10 Jun 2025 18:54:43 +0200 Subject: [PATCH 193/244] feat(forge vb): creation code from tx trace (#10751) * take 1 impl * feat(forge vb): creation code from tx trace * clippy --- crates/verify/Cargo.toml | 4 +-- crates/verify/src/bytecode.rs | 54 ++++++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/crates/verify/Cargo.toml b/crates/verify/Cargo.toml index 1d3afe7923ced..d4706a9300b2a 100644 --- a/crates/verify/Cargo.toml +++ b/crates/verify/Cargo.toml @@ -22,11 +22,11 @@ foundry-evm-core.workspace = true serde_json.workspace = true alloy-json-abi.workspace = true alloy-primitives.workspace = true -alloy-rpc-types.workspace = true +alloy-rpc-types = { workspace = true, features = ["eth", "trace"] } alloy-dyn-abi.workspace = true serde.workspace = true eyre.workspace = true -alloy-provider.workspace = true +alloy-provider = { workspace = true, features = ["trace-api"] } tracing.workspace = true foundry-compilers = { workspace = true, features = ["full"] } foundry-block-explorers = { workspace = true, features = ["foundry-compilers"] } diff --git a/crates/verify/src/bytecode.rs b/crates/verify/src/bytecode.rs index ee2e96188dab3..191e7b73f90b0 100644 --- a/crates/verify/src/bytecode.rs +++ b/crates/verify/src/bytecode.rs @@ -9,10 +9,14 @@ use crate::{ }; use alloy_primitives::{hex, Address, Bytes, TxKind, U256}; use alloy_provider::{ + ext::TraceApi, network::{AnyTxEnvelope, TransactionBuilder}, Provider, }; -use alloy_rpc_types::{BlockId, BlockNumberOrTag, TransactionInput, TransactionRequest}; +use alloy_rpc_types::{ + trace::parity::{Action, CreateAction, CreateOutput, TraceOutput}, + BlockId, BlockNumberOrTag, TransactionInput, TransactionRequest, +}; use clap::{Parser, ValueHint}; use eyre::{Context, OptionExt, Result}; use foundry_cli::{ @@ -341,23 +345,41 @@ impl VerifyBytecodeArgs { }; // Extract creation code from creation tx input. - let maybe_creation_code = - if receipt.to.is_none() && receipt.contract_address == Some(self.address) { - match &transaction.input.input { - Some(input) => &input[..], - None => unreachable!("creation tx input is None"), - } - } else if receipt.to == Some(DEFAULT_CREATE2_DEPLOYER) { - match &transaction.input.input { - Some(input) => &input[32..], - None => unreachable!("creation tx input is None"), - } - } else { - eyre::bail!( + let maybe_creation_code = if receipt.to.is_none() && + receipt.contract_address == Some(self.address) + { + match &transaction.input.input { + Some(input) => &input[..], + None => unreachable!("creation tx input is None"), + } + } else if receipt.to == Some(DEFAULT_CREATE2_DEPLOYER) { + match &transaction.input.input { + Some(input) => &input[32..], + None => unreachable!("creation tx input is None"), + } + } else { + // Try to get creation bytecode from tx trace. + let traces = provider + .trace_transaction(creation_data.transaction_hash) + .await + .unwrap_or_default(); + + let creation_bytecode = + traces.iter().find_map(|trace| match (&trace.trace.result, &trace.trace.action) { + ( + Some(TraceOutput::Create(CreateOutput { address, .. })), + Action::Create(CreateAction { init, .. }), + ) if *address == self.address => Some(init.clone()), + _ => None, + }); + + &creation_bytecode.ok_or_else(|| { + eyre::eyre!( "Could not extract the creation code for contract at address {}", self.address - ); - }; + ) + })? + }; // In some cases, Etherscan will return incorrect constructor arguments. If this // happens, try extracting arguments ourselves. From d544ae270501b55a62d45b04817869ed948e424d Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Wed, 11 Jun 2025 09:31:28 +0200 Subject: [PATCH 194/244] feat(`forge`): run lint on forge build (#10748) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: integrate SolidityLinter into forge build command Add automatic linting during forge build to provide early feedback on Solidity code quality and security issues. Changes: - Add optional linter field to ProjectCompiler with builder method - Run linting before compilation when linter is configured - Respect --quiet flag to suppress linting output - Configure linter from foundry.toml LinterConfig settings - Support JSON output format for linting diagnostics - Add comprehensive tests for build-time linting behavior The linter runs before compilation and uses all settings from the [lint] section in foundry.toml including severity filtering and lint exclusions. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * feat: add lint_on_build config option to control automatic linting Add new boolean config option `lint_on_build` in LinterConfig that allows users to disable automatic linting during `forge build` while maintaining the improved developer experience by default. Changes: - Add `lint_on_build` field to LinterConfig (defaults to true) - Update forge build to check lint_on_build before configuring linter - Add test for lint_on_build = false behavior - Update existing tests to include new config field - Modify can_build_after_failure test to disable linting Users can now disable build-time linting in foundry.toml: ```toml [lint] lint_on_build = false ``` 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * fmt * Update test_default_config snapshots for lint_on_build property The test_default_config was failing after adding the lint_on_build property to LintConfig. Updated the expected output snapshots to include the new property with its default value of true. - Updated TOML format snapshot to include `lint_on_build = true` in [lint] section - Updated JSON format snapshot to include `"lint_on_build": true` in lint object 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --------- Co-authored-by: Claude --- Cargo.lock | 1 + crates/common/Cargo.toml | 1 + crates/common/src/compile.rs | 37 ++++++ crates/config/src/lint.rs | 17 ++- crates/forge/src/cmd/build.rs | 29 ++++- crates/forge/tests/cli/cmd.rs | 5 + crates/forge/tests/cli/config.rs | 4 +- crates/forge/tests/cli/lint.rs | 192 +++++++++++++++++++++++++++++-- 8 files changed, 273 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4ebb5c3ed4097..4ac6c49a7d038 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4187,6 +4187,7 @@ dependencies = [ "comfy-table", "dunce", "eyre", + "forge-lint", "foundry-block-explorers", "foundry-common-fmt", "foundry-compilers", diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index ecfc9279ac39a..331b07301c753 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -17,6 +17,7 @@ foundry-block-explorers = { workspace = true, features = ["foundry-compilers"] } foundry-common-fmt.workspace = true foundry-compilers.workspace = true foundry-config.workspace = true +forge-lint.workspace = true alloy-dyn-abi = { workspace = true, features = ["arbitrary", "eip712"] } alloy-eips.workspace = true diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index 9d7f3735c5227..55bc3c74c8221 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -9,6 +9,7 @@ use crate::{ }; use comfy_table::{modifiers::UTF8_ROUND_CORNERS, Cell, Color, Table}; use eyre::Result; +use forge_lint::{linter::Linter, sol::SolidityLinter}; use foundry_block_explorers::contract::Metadata; use foundry_compilers::{ artifacts::{remappings::Remapping, BytecodeObject, Contract, Source}, @@ -20,6 +21,7 @@ use foundry_compilers::{ project::Preprocessor, report::{BasicStdoutReporter, NoReporter, Report}, solc::SolcSettings, + utils::source_files_iter, Artifact, Project, ProjectBuilder, ProjectCompileOutput, ProjectPathsConfig, SolcConfig, }; use num_format::{Locale, ToFormattedString}; @@ -64,6 +66,9 @@ pub struct ProjectCompiler { /// Whether to compile with dynamic linking tests and scripts. dynamic_test_linking: bool, + + /// Optional linter to run on Solidity files during compilation. + linter: Option, } impl Default for ProjectCompiler { @@ -87,6 +92,7 @@ impl ProjectCompiler { ignore_eip_3860: false, files: Vec::new(), dynamic_test_linking: false, + linter: None, } } @@ -147,6 +153,13 @@ impl ProjectCompiler { self } + /// Sets the linter to run on Solidity files during compilation. + #[inline] + pub fn linter(mut self, linter: SolidityLinter) -> Self { + self.linter = Some(linter); + self + } + /// Compiles the project. pub fn compile>( mut self, @@ -208,6 +221,13 @@ impl ProjectCompiler { let quiet = self.quiet.unwrap_or(false); let bail = self.bail.unwrap_or(true); + // Run linting before compilation if linter is configured and we're not in quiet mode + if let Some(linter) = &self.linter { + if !quiet { + self.run_linter(linter)?; + } + } + let output = with_compilation_reporter(quiet, || { tracing::debug!("compiling project"); @@ -338,6 +358,23 @@ impl ProjectCompiler { Ok(()) } + + /// Runs the configured linter on project source files + fn run_linter(&self, linter: &SolidityLinter) -> Result<()> { + // Collect Solidity source files from the project root + let solidity_files: Vec<_> = source_files_iter( + &self.project_root, + &["sol"], // Only Solidity files + ) + .filter(|path| path.extension().is_some_and(|ext| ext == "sol")) + .collect(); + + if !solidity_files.is_empty() { + linter.lint(&solidity_files); + } + + Ok(()) + } } // https://eips.ethereum.org/EIPS/eip-170 diff --git a/crates/config/src/lint.rs b/crates/config/src/lint.rs index 10d86c96fb321..ec9b2b4b00748 100644 --- a/crates/config/src/lint.rs +++ b/crates/config/src/lint.rs @@ -8,7 +8,7 @@ use std::str::FromStr; use yansi::Paint; /// Contains the config and rule set -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct LinterConfig { /// Specifies which lints to run based on severity. /// @@ -20,6 +20,21 @@ pub struct LinterConfig { /// Globs to ignore pub ignore: Vec, + + /// Whether to run linting during `forge build`. + /// + /// Defaults to true. Set to false to disable automatic linting during builds. + pub lint_on_build: bool, +} +impl Default for LinterConfig { + fn default() -> Self { + Self { + lint_on_build: true, + severity: Vec::new(), + exclude_lints: Vec::new(), + ignore: Vec::new(), + } + } } /// Severity of a lint diff --git a/crates/forge/src/cmd/build.rs b/crates/forge/src/cmd/build.rs index 43b4c89104407..ecd9058e17bbb 100644 --- a/crates/forge/src/cmd/build.rs +++ b/crates/forge/src/cmd/build.rs @@ -1,6 +1,7 @@ use super::{install, watch::WatchArgs}; use clap::Parser; use eyre::Result; +use forge_lint::sol::SolidityLinter; use foundry_cli::{ opts::BuildOpts, utils::{cache_local_signatures, LoadConfig}, @@ -93,7 +94,7 @@ impl BuildArgs { } let format_json = shell::is_json(); - let compiler = ProjectCompiler::new() + let mut compiler = ProjectCompiler::new() .files(files) .dynamic_test_linking(config.dynamic_test_linking) .print_names(self.names) @@ -101,6 +102,32 @@ impl BuildArgs { .ignore_eip_3860(self.ignore_eip_3860) .bail(!format_json); + // Configure linter if enabled in config and lint_on_build is true + if project.compiler.solc.is_some() && config.lint.lint_on_build { + let linter = SolidityLinter::new(config.project_paths()) + .with_json_emitter(format_json) + .with_description(!format_json) + .with_severity(if config.lint.severity.is_empty() { + None + } else { + Some(config.lint.severity.clone()) + }) + .without_lints(if config.lint.exclude_lints.is_empty() { + None + } else { + Some( + config + .lint + .exclude_lints + .iter() + .filter_map(|s| forge_lint::sol::SolLint::try_from(s.as_str()).ok()) + .collect(), + ) + }); + + compiler = compiler.linter(linter); + } + let output = compiler.compile(&project)?; // Cache project selectors. diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index ae9984f27f32e..5ab6f22ad8a26 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -1208,6 +1208,11 @@ Compiler run successful! forgetest!(can_build_after_failure, |prj, cmd| { prj.insert_ds_test(); + // Disable linting during build to avoid linting output interfering with test assertions + prj.update_config(|config| { + config.lint.lint_on_build = false; + }); + prj.add_source( "ATest.t.sol", r#" diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index 9159f73ed53a2..f51a8b7b7bba2 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -1071,6 +1071,7 @@ sort_imports = false severity = [] exclude_lints = [] ignore = [] +lint_on_build = true [doc] out = "docs" @@ -1275,7 +1276,8 @@ exclude = [] "lint": { "severity": [], "exclude_lints": [], - "ignore": [] + "ignore": [], + "lint_on_build": true }, "doc": { "out": "docs", diff --git a/crates/forge/tests/cli/lint.rs b/crates/forge/tests/cli/lint.rs index 2223d1cf11fce..80427a3e3f4ca 100644 --- a/crates/forge/tests/cli/lint.rs +++ b/crates/forge/tests/cli/lint.rs @@ -13,7 +13,7 @@ contract ContractWithLints { function incorrectShiftHigh() public { uint256 localValue = 50; - result = 8 >> localValue; + uint256 result = 8 >> localValue; } function divideBeforeMultiplyMedium() public { (1 / 2) * 3; @@ -44,7 +44,8 @@ forgetest!(can_use_config, |prj, cmd| { config.lint = LinterConfig { severity: vec![LintSeverity::High, LintSeverity::Med], exclude_lints: vec!["incorrect-shift".into()], - ..Default::default() + ignore: vec![], + lint_on_build: true, }; }); cmd.arg("lint").assert_success().stderr_eq(str![[r#" @@ -67,8 +68,12 @@ forgetest!(can_use_config_ignore, |prj, cmd| { // Check config for `ignore` prj.update_config(|config| { - config.lint = - LinterConfig { ignore: vec!["src/ContractWithLints.sol".into()], ..Default::default() }; + config.lint = LinterConfig { + severity: vec![], + exclude_lints: vec![], + ignore: vec!["src/ContractWithLints.sol".into()], + lint_on_build: true, + }; }); cmd.arg("lint").assert_success().stderr_eq(str![[r#" note[mixed-case-variable]: mutable variables should use mixedCase @@ -85,8 +90,10 @@ note[mixed-case-variable]: mutable variables should use mixedCase // Check config again, ignoring all files prj.update_config(|config| { config.lint = LinterConfig { + severity: vec![], + exclude_lints: vec![], ignore: vec!["src/ContractWithLints.sol".into(), "src/OtherContract.sol".into()], - ..Default::default() + lint_on_build: true, }; }); cmd.arg("lint").assert_success().stderr_eq(str![[""]]); @@ -101,8 +108,9 @@ forgetest!(can_override_config_severity, |prj, cmd| { prj.update_config(|config| { config.lint = LinterConfig { severity: vec![LintSeverity::High, LintSeverity::Med], + exclude_lints: vec![], ignore: vec!["src/ContractWithLints.sol".into()], - ..Default::default() + lint_on_build: true, }; }); cmd.arg("lint").args(["--severity", "info"]).assert_success().stderr_eq(str![[r#" @@ -129,6 +137,7 @@ forgetest!(can_override_config_path, |prj, cmd| { severity: vec![LintSeverity::High, LintSeverity::Med], exclude_lints: vec!["incorrect-shift".into()], ignore: vec!["src/ContractWithLints.sol".into()], + lint_on_build: true, }; }); cmd.arg("lint").arg("src/ContractWithLints.sol").assert_success().stderr_eq(str![[r#" @@ -154,16 +163,17 @@ forgetest!(can_override_config_lint, |prj, cmd| { config.lint = LinterConfig { severity: vec![LintSeverity::High, LintSeverity::Med], exclude_lints: vec!["incorrect-shift".into()], - ..Default::default() + ignore: vec![], + lint_on_build: true, }; }); cmd.arg("lint").args(["--only-lint", "incorrect-shift"]).assert_success().stderr_eq(str![[ r#" warning[incorrect-shift]: the order of args in a shift operation is incorrect - [FILE]:13:18 + [FILE]:13:26 | -13 | result = 8 >> localValue; - | --------------- +13 | uint256 result = 8 >> localValue; + | --------------- | = help: https://book.getfoundry.sh/reference/forge/forge-lint#incorrect-shift @@ -172,6 +182,168 @@ warning[incorrect-shift]: the order of args in a shift operation is incorrect ]]); }); +forgetest!(build_runs_linter_by_default, |prj, cmd| { + prj.wipe_contracts(); + prj.add_source("ContractWithLints", CONTRACT).unwrap(); + + // Configure linter to show only medium severity lints + prj.update_config(|config| { + config.lint = LinterConfig { + severity: vec![LintSeverity::Med], + exclude_lints: vec!["incorrect-shift".into()], + ignore: vec![], + lint_on_build: true, + }; + }); + + // Run forge build and expect linting output before compilation + cmd.arg("build").assert_success().stderr_eq(str![[r#" +warning[divide-before-multiply]: multiplication should occur before division to avoid loss of precision + [FILE]:16:9 + | +16 | (1 / 2) * 3; + | ----------- + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply + + +"#]]).stdout_eq(str![[r#" +[COMPILING_FILES] with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful with warnings: +Warning (2072): Unused local variable. + [FILE]:13:9: + | +13 | uint256 result = 8 >> localValue; + | ^^^^^^^^^^^^^^ + +Warning (6133): Statement has no effect. + [FILE]:16:9: + | +16 | (1 / 2) * 3; + | ^^^^^^^^^^^ + +Warning (2018): Function state mutability can be restricted to pure + [FILE]:11:5: + | +11 | function incorrectShiftHigh() public { + | ^ (Relevant source part starts here and spans across multiple lines). + +Warning (2018): Function state mutability can be restricted to pure + [FILE]:15:5: + | +15 | function divideBeforeMultiplyMedium() public { + | ^ (Relevant source part starts here and spans across multiple lines). + +Warning (2018): Function state mutability can be restricted to pure + [FILE]:18:5: + | +18 | function unoptimizedHashGas(uint256 a, uint256 b) public view { + | ^ (Relevant source part starts here and spans across multiple lines). + + +"#]]); +}); + +forgetest!(build_respects_quiet_flag_for_linting, |prj, cmd| { + prj.wipe_contracts(); + prj.add_source("ContractWithLints", CONTRACT).unwrap(); + + // Configure linter to show medium severity lints + prj.update_config(|config| { + config.lint = LinterConfig { + severity: vec![LintSeverity::Med], + exclude_lints: vec!["incorrect-shift".into()], + ignore: vec![], + lint_on_build: true, + }; + }); + + // Run forge build with --quiet flag - should not show linting output + cmd.arg("build").arg("--quiet").assert_success().stderr_eq(str![[""]]).stdout_eq(str![[""]]); +}); + +forgetest!(build_with_json_uses_json_linter_output, |prj, cmd| { + prj.wipe_contracts(); + prj.add_source("ContractWithLints", CONTRACT).unwrap(); + + // Configure linter to show medium severity lints + prj.update_config(|config| { + config.lint = LinterConfig { + severity: vec![LintSeverity::Med], + exclude_lints: vec!["incorrect-shift".into()], + ignore: vec![], + lint_on_build: true, + }; + }); + + // Run forge build with --json flag - should use JSON formatter for linting + let output = cmd.arg("build").arg("--json").assert_success(); + + // Should contain JSON linting output + let stderr = String::from_utf8_lossy(&output.get_output().stderr); + assert!(stderr.contains("\"code\"")); + assert!(stderr.contains("divide-before-multiply")); + + // Should also contain JSON compilation output + let stdout = String::from_utf8_lossy(&output.get_output().stdout); + assert!(stdout.contains("\"errors\"")); + assert!(stdout.contains("\"sources\"")); +}); + +forgetest!(build_respects_lint_on_build_false, |prj, cmd| { + prj.wipe_contracts(); + prj.add_source("ContractWithLints", CONTRACT).unwrap(); + + // Configure linter with medium severity lints but disable lint_on_build + prj.update_config(|config| { + config.lint = LinterConfig { + severity: vec![LintSeverity::Med], + exclude_lints: vec!["incorrect-shift".into()], + ignore: vec![], + lint_on_build: false, + }; + }); + + // Run forge build - should NOT show linting output because lint_on_build is false + cmd.arg("build").assert_success().stderr_eq(str![[""]]).stdout_eq(str![[r#" +[COMPILING_FILES] with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful with warnings: +Warning (2072): Unused local variable. + [FILE]:13:9: + | +13 | uint256 result = 8 >> localValue; + | ^^^^^^^^^^^^^^ + +Warning (6133): Statement has no effect. + [FILE]:16:9: + | +16 | (1 / 2) * 3; + | ^^^^^^^^^^^ + +Warning (2018): Function state mutability can be restricted to pure + [FILE]:11:5: + | +11 | function incorrectShiftHigh() public { + | ^ (Relevant source part starts here and spans across multiple lines). + +Warning (2018): Function state mutability can be restricted to pure + [FILE]:15:5: + | +15 | function divideBeforeMultiplyMedium() public { + | ^ (Relevant source part starts here and spans across multiple lines). + +Warning (2018): Function state mutability can be restricted to pure + [FILE]:18:5: + | +18 | function unoptimizedHashGas(uint256 a, uint256 b) public view { + | ^ (Relevant source part starts here and spans across multiple lines). + + +"#]]); +}); + #[tokio::test] async fn ensure_lint_rule_docs() { const FOUNDRY_BOOK_LINT_PAGE_URL: &str = From 01e9dc20c46d7654955a3312f7f62068e818289e Mon Sep 17 00:00:00 2001 From: Chad <0xChaddB@proton.me> Date: Wed, 11 Jun 2025 11:36:23 +0200 Subject: [PATCH 195/244] chore(config): enable show_metrics by default in [invariant] section (#10737) * chore(config): enable show_metrics by default in [invariant] section * test(config): enable show_metrics by default in config.rs and test_helper.rs * fix invariant test, now shows metrics --------- Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> Co-authored-by: zerosnacks --- crates/config/src/invariant.rs | 4 ++-- crates/forge/tests/cli/config.rs | 4 ++-- crates/forge/tests/it/invariant.rs | 7 +++++++ crates/forge/tests/it/test_helpers.rs | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/crates/config/src/invariant.rs b/crates/config/src/invariant.rs index 0c5dbc567d363..b5939ad6f5f1d 100644 --- a/crates/config/src/invariant.rs +++ b/crates/config/src/invariant.rs @@ -48,7 +48,7 @@ impl Default for InvariantConfig { max_assume_rejects: 65536, gas_report_samples: 256, failure_persist_dir: None, - show_metrics: false, + show_metrics: true, timeout: None, show_solidity: false, } @@ -68,7 +68,7 @@ impl InvariantConfig { max_assume_rejects: 65536, gas_report_samples: 256, failure_persist_dir: Some(cache_dir), - show_metrics: false, + show_metrics: true, timeout: None, show_solidity: false, } diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index f51a8b7b7bba2..3cea4fca0d31a 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -1107,7 +1107,7 @@ shrink_run_limit = 5000 max_assume_rejects = 65536 gas_report_samples = 256 failure_persist_dir = "cache/invariant" -show_metrics = false +show_metrics = true show_solidity = false [labels] @@ -1214,7 +1214,7 @@ exclude = [] "max_assume_rejects": 65536, "gas_report_samples": 256, "failure_persist_dir": "cache/invariant", - "show_metrics": false, + "show_metrics": true, "timeout": null, "show_solidity": false }, diff --git a/crates/forge/tests/it/invariant.rs b/crates/forge/tests/it/invariant.rs index 630afe34cff4d..f947a4d0d6497 100644 --- a/crates/forge/tests/it/invariant.rs +++ b/crates/forge/tests/it/invariant.rs @@ -982,6 +982,13 @@ Compiler run successful! Ran 1 test for test/TimeoutTest.t.sol:TimeoutTest [PASS] invariant_counter_timeout() (runs: 0, calls: 0, reverts: 0) + +╭----------------+-----------+-------+---------+----------╮ +| Contract | Selector | Calls | Reverts | Discards | ++=========================================================+ +| TimeoutHandler | increment | [..] | [..] | [..] | +╰----------------+-----------+-------+---------+----------╯ + Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) diff --git a/crates/forge/tests/it/test_helpers.rs b/crates/forge/tests/it/test_helpers.rs index 2043af8c01580..877be09c1d016 100644 --- a/crates/forge/tests/it/test_helpers.rs +++ b/crates/forge/tests/it/test_helpers.rs @@ -152,7 +152,7 @@ impl ForgeTestProfile { .unwrap() .keep(), ), - show_metrics: false, + show_metrics: true, timeout: None, show_solidity: false, }; From 2dbd8c91d5ae708eed21c9137ecc9aa385894801 Mon Sep 17 00:00:00 2001 From: Shaun <13260261+shaunkh@users.noreply.github.com> Date: Wed, 11 Jun 2025 12:36:06 +0000 Subject: [PATCH 196/244] chore: update nix flake (#10485) * update flake * update env variables * add nix.yml ci job Co-authored-by: sveitser * review: use nixpkgs for solc --------- Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Co-authored-by: zerosnacks Co-authored-by: sveitser --- .github/workflows/nix.yml | 41 +++++++++++++++ flake.lock | 105 ++++++++++---------------------------- flake.nix | 81 ++++++++++++++--------------- 3 files changed, 104 insertions(+), 123 deletions(-) create mode 100644 .github/workflows/nix.yml diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml new file mode 100644 index 0000000000000..0db166fcbbbe7 --- /dev/null +++ b/.github/workflows/nix.yml @@ -0,0 +1,41 @@ +name: nix + +on: + schedule: + # Run weekly + - cron: "0 0 * * SUN" + workflow_dispatch: + # Needed so we can run it manually + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + # Opens a PR with an updated flake.lock file + update: + runs-on: ubuntu-latest + steps: + - uses: cachix/install-nix-action@v30 + - uses: actions/checkout@v4 + - uses: DeterminateSystems/update-flake-lock@main + with: + pr-title: "Update flake.lock" + pr-labels: | + L-ignore + A-dependencies + + build: + strategy: + matrix: + runs-on: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.runs-on }} + steps: + - uses: cachix/install-nix-action@v30 + - uses: actions/checkout@v4 + + - name: Activate nix env + run: nix develop -c echo Ok + + - name: Check that we can compile all crates + run: nix develop -c cargo check --all-targets diff --git a/flake.lock b/flake.lock index 45ed6bb432ffb..35fa2913ff888 100644 --- a/flake.lock +++ b/flake.lock @@ -1,30 +1,33 @@ { "nodes": { - "flake-utils": { + "fenix": { "inputs": { - "systems": "systems" + "nixpkgs": [ + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "lastModified": 1746772806, + "narHash": "sha256-5/Nq62wjkZrOhUULTFjgi4Dsc7T8kIluUPkoLsyAeUA=", + "owner": "nix-community", + "repo": "fenix", + "rev": "505bf684711e964c8f84d4c804e38f62b24accec", "type": "github" }, "original": { - "owner": "numtide", - "repo": "flake-utils", + "owner": "nix-community", + "repo": "fenix", "type": "github" } }, "nixpkgs": { "locked": { - "lastModified": 1719468428, - "narHash": "sha256-vN5xJAZ4UGREEglh3lfbbkIj+MPEYMuqewMn4atZFaQ=", + "lastModified": 1746576598, + "narHash": "sha256-FshoQvr6Aor5SnORVvh/ZdJ1Sa2U4ZrIMwKBX5k2wu0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1e3deb3d8a86a870d925760db1a5adecc64d329d", + "rev": "b3582c75c7f21ce0b429898980eddbbf05c68e55", "type": "github" }, "original": { @@ -36,80 +39,24 @@ }, "root": { "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs", - "rust-overlay": "rust-overlay", - "solc": "solc" - } - }, - "rust-overlay": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1719714047, - "narHash": "sha256-MeNPopLLv63EZj5L43j4TZkmW4wj1ouoc/h/E20sl/U=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "cb216719ce89a43dfb3d1b86a9575e89f4b727a4", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - }, - "solc": { - "inputs": { - "flake-utils": [ - "flake-utils" - ], - "nixpkgs": [ - "nixpkgs" - ], - "solc-macos-amd64-list-json": "solc-macos-amd64-list-json" - }, - "locked": { - "lastModified": 1717442267, - "narHash": "sha256-6TnQvA6Q/xC3r1M+wGC5gnDc/5XfOPjC8X6LlGDWDNc=", - "owner": "hellwolf", - "repo": "solc.nix", - "rev": "2ac2862f224aa0d67cbc6b3246392489f8a50596", - "type": "github" - }, - "original": { - "owner": "hellwolf", - "repo": "solc.nix", - "type": "github" + "fenix": "fenix", + "nixpkgs": "nixpkgs" } }, - "solc-macos-amd64-list-json": { + "rust-analyzer-src": { "flake": false, "locked": { - "narHash": "sha256-Prwz95BgMHcWd72VwVbcH17LsV9f24K2QMcUiWUQZzI=", - "type": "file", - "url": "https://github.com/ethereum/solc-bin/raw/f743ca7/macosx-amd64/list.json" - }, - "original": { - "type": "file", - "url": "https://github.com/ethereum/solc-bin/raw/f743ca7/macosx-amd64/list.json" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "lastModified": 1746722075, + "narHash": "sha256-t4ZntWiW4C3lE621lV3XyK3KltC5/SW1V9G+CSz70rQ=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "8b624868e4ce2cb5b39559175f0978bee86bdeea", "type": "github" }, "original": { - "owner": "nix-systems", - "repo": "default", + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", "type": "github" } } diff --git a/flake.nix b/flake.nix index ff783b4956e4e..8cf41ed16d3a3 100644 --- a/flake.nix +++ b/flake.nix @@ -1,52 +1,45 @@ { inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; - flake-utils.url = "github:numtide/flake-utils"; - rust-overlay = { - url = "github:oxalica/rust-overlay"; - inputs = { - nixpkgs.follows = "nixpkgs"; - }; - }; - solc = { - url = "github:hellwolf/solc.nix"; - inputs = { - nixpkgs.follows = "nixpkgs"; - flake-utils.follows = "flake-utils"; - }; + fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; }; }; - outputs = { self, nixpkgs, rust-overlay, flake-utils, solc }: - flake-utils.lib.eachDefaultSystem (system: - let - pkgs = import nixpkgs { - inherit system; - overlays = [ rust-overlay.overlays.default solc.overlay ]; - }; - lib = pkgs.lib; - toolchain = pkgs.rust-bin.stable.latest.default.override { - extensions = [ "rustfmt" "clippy" "rust-src" ]; - }; - in - { - devShells.default = pkgs.mkShell { - nativeBuildInputs = with pkgs; [ - pkg-config - solc_0_8_23 - (solc.mkDefault pkgs solc_0_8_23) - toolchain - ]; - buildInputs = lib.optionals pkgs.stdenv.isDarwin [ - pkgs.darwin.apple_sdk.frameworks.AppKit - ]; - packages = with pkgs; [ - rust-analyzer-unwrapped - ]; + outputs = { self, nixpkgs, fenix }: + let eachSystem = nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed; + in { + devShells = eachSystem (system: + let + pkgs = import nixpkgs { + inherit system; + overlays = [ fenix.overlays.default ]; + }; + + lib = pkgs.lib; + toolchain = fenix.packages.${system}.stable.toolchain; + in { + default = pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + pkg-config + toolchain + + # test dependencies + solc + vyper + nodejs + ]; + buildInputs = lib.optionals pkgs.stdenv.isDarwin + [ pkgs.darwin.apple_sdk.frameworks.AppKit ]; - # Environment variables - RUST_SRC_PATH = "${toolchain}/lib/rustlib/src/rust/library"; - LD_LIBRARY_PATH = lib.makeLibraryPath [ pkgs.libusb1 ]; - }; - }); + packages = with pkgs; [ rust-analyzer-unwrapped ]; + + # Environment variables + RUST_SRC_PATH = "${toolchain}/lib/rustlib/src/rust/library"; + LD_LIBRARY_PATH = lib.makeLibraryPath [ pkgs.libusb1 ]; + CFLAGS = "-DJEMALLOC_STRERROR_R_RETURNS_CHAR_WITH_GNU_SOURCE"; + }; + }); + }; } From 2494b701dd12e571ee5bb0ae05e3c5b3172c6b0c Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Thu, 12 Jun 2025 10:30:07 +0200 Subject: [PATCH 197/244] bug(`nix`): fix build in CI (#10767) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: nix CI build (#10760) * update flake * try nix build * remove push from CI * Update flake.lock (#10766) flake.lock: Update Flake lock file updates: • Updated input 'fenix': 'github:nix-community/fenix/873cccc628f5e39407e319e6711f3b7d6d1f15cc?narHash=sha256-QD7e5WNVj4aWS5mlJZZnLJ6Lg0h5RSyyEFo2I6xBUEQ%3D' (2025-06-11) → 'github:nix-community/fenix/b8fda10da7629d856086bbc1e21164c2d55691e3?narHash=sha256-Jte1NonRzaKF6UpPL5FujKHVTVvc8CAIj8fK%2BX/0qVM%3D' (2025-06-12) • Updated input 'fenix/rust-analyzer-src': 'github:rust-lang/rust-analyzer/9c3476d225ccc90c081280c2a20e9f7d8a200325?narHash=sha256-R9vQiqez6Gm0ARJKgbsAeLyX493vwIaexOUAz0vDhak%3D' (2025-06-10) → 'github:rust-lang/rust-analyzer/5b2c8bc9ae90b4ad92dbeb7e52a7f5cbf5ba4d53?narHash=sha256-ewwoJOGE6sMnfXQkydmmjT6ixo1JetBZO0tDEENjOb8%3D' (2025-06-11) • Updated input 'nixpkgs': 'github:NixOS/nixpkgs/a12f3a99614894502e73eb816e9e076b0ab05730?narHash=sha256-DUVAe8E2X2QM0dAnTGlTiqemMqUMMyIeCH7UeNo0g64%3D' (2025-06-10) → 'github:NixOS/nixpkgs/f72be405a10668b8b00937b452f2145244103ebc?narHash=sha256-qX6gXVjaCXXbcn6A9eSLUf8Fm07MgPGe5ir3%2B%2By2O1Q%3D' (2025-06-11) Co-authored-by: github-actions[bot] * make sure build runs on latest deps --------- Co-authored-by: Shaun <13260261+shaunkh@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] --- .github/workflows/nix.yml | 7 +++++-- flake.lock | 18 +++++++++--------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 0db166fcbbbe7..e1091ec923ef7 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -16,7 +16,7 @@ jobs: update: runs-on: ubuntu-latest steps: - - uses: cachix/install-nix-action@v30 + - uses: DeterminateSystems/determinate-nix-action@v3 - uses: actions/checkout@v4 - uses: DeterminateSystems/update-flake-lock@main with: @@ -31,9 +31,12 @@ jobs: runs-on: [ubuntu-latest, macos-latest] runs-on: ${{ matrix.runs-on }} steps: - - uses: cachix/install-nix-action@v30 + - uses: DeterminateSystems/determinate-nix-action@v3 - uses: actions/checkout@v4 + - name: Update flake.lock + run: nix flake update + - name: Activate nix env run: nix develop -c echo Ok diff --git a/flake.lock b/flake.lock index 35fa2913ff888..34e5b529665c9 100644 --- a/flake.lock +++ b/flake.lock @@ -8,11 +8,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1746772806, - "narHash": "sha256-5/Nq62wjkZrOhUULTFjgi4Dsc7T8kIluUPkoLsyAeUA=", + "lastModified": 1749710537, + "narHash": "sha256-Jte1NonRzaKF6UpPL5FujKHVTVvc8CAIj8fK+X/0qVM=", "owner": "nix-community", "repo": "fenix", - "rev": "505bf684711e964c8f84d4c804e38f62b24accec", + "rev": "b8fda10da7629d856086bbc1e21164c2d55691e3", "type": "github" }, "original": { @@ -23,11 +23,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1746576598, - "narHash": "sha256-FshoQvr6Aor5SnORVvh/ZdJ1Sa2U4ZrIMwKBX5k2wu0=", + "lastModified": 1749619289, + "narHash": "sha256-qX6gXVjaCXXbcn6A9eSLUf8Fm07MgPGe5ir3++y2O1Q=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b3582c75c7f21ce0b429898980eddbbf05c68e55", + "rev": "f72be405a10668b8b00937b452f2145244103ebc", "type": "github" }, "original": { @@ -46,11 +46,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1746722075, - "narHash": "sha256-t4ZntWiW4C3lE621lV3XyK3KltC5/SW1V9G+CSz70rQ=", + "lastModified": 1749671345, + "narHash": "sha256-ewwoJOGE6sMnfXQkydmmjT6ixo1JetBZO0tDEENjOb8=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "8b624868e4ce2cb5b39559175f0978bee86bdeea", + "rev": "5b2c8bc9ae90b4ad92dbeb7e52a7f5cbf5ba4d53", "type": "github" }, "original": { From 558d7d5e84889dd55a73e142d4d38d03926d0f7c Mon Sep 17 00:00:00 2001 From: joeblogg801 <98930496+joeblogg801@users.noreply.github.com> Date: Thu, 12 Jun 2025 14:01:11 +0100 Subject: [PATCH 198/244] fix(forge): Ignore file access events to prevent rebuild loop (#10763) fix(forge): Filter out file access events to prevent rebuild loop This fixes an issue introduced by https://github.com/notify-rs/notify/pull/612, where `OPEN` events are now reported on Linux. As a result, file access (e.g., reading a file) triggers spurious change notifications, causing the compilation process to restart repeatedly. To resolve this, we explicitly filter out `OPEN` (access) events during event processing. --- crates/forge/src/cmd/watch.rs | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/crates/forge/src/cmd/watch.rs b/crates/forge/src/cmd/watch.rs index 077604d2d8000..3378d9b148cb0 100644 --- a/crates/forge/src/cmd/watch.rs +++ b/crates/forge/src/cmd/watch.rs @@ -24,7 +24,10 @@ use watchexec::{ paths::summarise_events_to_env, Watchexec, }; -use watchexec_events::{Event, Priority, ProcessEnd}; +use watchexec_events::{ + filekind::{AccessKind, FileEventKind}, + Event, Priority, ProcessEnd, Tag, +}; use watchexec_signals::Signal; use yansi::{Color, Paint}; @@ -179,6 +182,35 @@ impl WatchArgs { return action; } + if cfg!(target_os = "linux") { + // Reading a file now triggers `Access(Open)` events on Linux due to: + // https://github.com/notify-rs/notify/pull/612 + // This causes an infinite rebuild loop: the build reads a file, + // which triggers a notification, which restarts the build, and so on. + // To prevent this, we ignore `Access(Open)` events during event processing. + let mut has_file_events = false; + let mut has_synthetic_events = false; + 'outer: for e in action.events.iter() { + if e.is_empty() { + has_synthetic_events = true; + break; + } else { + for tag in &e.tags { + if let Tag::FileEventKind(kind) = tag { + if !matches!(kind, FileEventKind::Access(AccessKind::Open(_))) { + has_file_events = true; + break 'outer; + } + } + } + } + } + if !has_file_events && !has_synthetic_events { + debug!("no filesystem events (other than Access(Open)) or synthetic events, skip without doing more"); + return action; + } + } + job.run({ let job = job.clone(); move |context| { From 6fb7c5983ab0333006aa40a792c24357c49a92cf Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Thu, 12 Jun 2025 18:16:35 +0200 Subject: [PATCH 199/244] fix(`forge`): don't include lib in lint runs (#10771) * fix(`forge`): don't include lib in lint runs * nit --- Cargo.lock | 1 - crates/common/Cargo.toml | 1 - crates/common/src/compile.rs | 38 ------------------------- crates/forge/src/cmd/build.rs | 53 +++++++++++++++++++++++++---------- 4 files changed, 38 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4ac6c49a7d038..4ebb5c3ed4097 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4187,7 +4187,6 @@ dependencies = [ "comfy-table", "dunce", "eyre", - "forge-lint", "foundry-block-explorers", "foundry-common-fmt", "foundry-compilers", diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index 331b07301c753..ecfc9279ac39a 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -17,7 +17,6 @@ foundry-block-explorers = { workspace = true, features = ["foundry-compilers"] } foundry-common-fmt.workspace = true foundry-compilers.workspace = true foundry-config.workspace = true -forge-lint.workspace = true alloy-dyn-abi = { workspace = true, features = ["arbitrary", "eip712"] } alloy-eips.workspace = true diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index 55bc3c74c8221..f160f2f8de74b 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -9,7 +9,6 @@ use crate::{ }; use comfy_table::{modifiers::UTF8_ROUND_CORNERS, Cell, Color, Table}; use eyre::Result; -use forge_lint::{linter::Linter, sol::SolidityLinter}; use foundry_block_explorers::contract::Metadata; use foundry_compilers::{ artifacts::{remappings::Remapping, BytecodeObject, Contract, Source}, @@ -21,7 +20,6 @@ use foundry_compilers::{ project::Preprocessor, report::{BasicStdoutReporter, NoReporter, Report}, solc::SolcSettings, - utils::source_files_iter, Artifact, Project, ProjectBuilder, ProjectCompileOutput, ProjectPathsConfig, SolcConfig, }; use num_format::{Locale, ToFormattedString}; @@ -66,9 +64,6 @@ pub struct ProjectCompiler { /// Whether to compile with dynamic linking tests and scripts. dynamic_test_linking: bool, - - /// Optional linter to run on Solidity files during compilation. - linter: Option, } impl Default for ProjectCompiler { @@ -92,7 +87,6 @@ impl ProjectCompiler { ignore_eip_3860: false, files: Vec::new(), dynamic_test_linking: false, - linter: None, } } @@ -152,14 +146,6 @@ impl ProjectCompiler { self.dynamic_test_linking = preprocess; self } - - /// Sets the linter to run on Solidity files during compilation. - #[inline] - pub fn linter(mut self, linter: SolidityLinter) -> Self { - self.linter = Some(linter); - self - } - /// Compiles the project. pub fn compile>( mut self, @@ -221,13 +207,6 @@ impl ProjectCompiler { let quiet = self.quiet.unwrap_or(false); let bail = self.bail.unwrap_or(true); - // Run linting before compilation if linter is configured and we're not in quiet mode - if let Some(linter) = &self.linter { - if !quiet { - self.run_linter(linter)?; - } - } - let output = with_compilation_reporter(quiet, || { tracing::debug!("compiling project"); @@ -358,23 +337,6 @@ impl ProjectCompiler { Ok(()) } - - /// Runs the configured linter on project source files - fn run_linter(&self, linter: &SolidityLinter) -> Result<()> { - // Collect Solidity source files from the project root - let solidity_files: Vec<_> = source_files_iter( - &self.project_root, - &["sol"], // Only Solidity files - ) - .filter(|path| path.extension().is_some_and(|ext| ext == "sol")) - .collect(); - - if !solidity_files.is_empty() { - linter.lint(&solidity_files); - } - - Ok(()) - } } // https://eips.ethereum.org/EIPS/eip-170 diff --git a/crates/forge/src/cmd/build.rs b/crates/forge/src/cmd/build.rs index ecd9058e17bbb..4805865311581 100644 --- a/crates/forge/src/cmd/build.rs +++ b/crates/forge/src/cmd/build.rs @@ -1,7 +1,7 @@ use super::{install, watch::WatchArgs}; use clap::Parser; use eyre::Result; -use forge_lint::sol::SolidityLinter; +use forge_lint::{linter::Linter, sol::SolidityLinter}; use foundry_cli::{ opts::BuildOpts, utils::{cache_local_signatures, LoadConfig}, @@ -9,6 +9,7 @@ use foundry_cli::{ use foundry_common::{compile::ProjectCompiler, shell}; use foundry_compilers::{ compilers::{multi::MultiCompilerLanguage, Language}, + solc::SolcLanguage, utils::source_files_iter, Project, ProjectCompileOutput, }; @@ -19,6 +20,7 @@ use foundry_config::{ value::{Dict, Map, Value}, Metadata, Profile, Provider, }, + filter::expand_globs, Config, }; use serde::Serialize; @@ -94,7 +96,7 @@ impl BuildArgs { } let format_json = shell::is_json(); - let mut compiler = ProjectCompiler::new() + let compiler = ProjectCompiler::new() .files(files) .dynamic_test_linking(config.dynamic_test_linking) .print_names(self.names) @@ -102,8 +104,23 @@ impl BuildArgs { .ignore_eip_3860(self.ignore_eip_3860) .bail(!format_json); - // Configure linter if enabled in config and lint_on_build is true - if project.compiler.solc.is_some() && config.lint.lint_on_build { + // Runs the SolidityLinter before compilation. + self.lint(&project, &config)?; + let output = compiler.compile(&project)?; + + // Cache project selectors. + cache_local_signatures(&output)?; + + if format_json && !self.names && !self.sizes { + sh_println!("{}", serde_json::to_string_pretty(&output.output())?)?; + } + + Ok(output) + } + + fn lint(&self, project: &Project, config: &Config) -> Result<()> { + let format_json = shell::is_json(); + if project.compiler.solc.is_some() && config.lint.lint_on_build && !shell::is_quiet() { let linter = SolidityLinter::new(config.project_paths()) .with_json_emitter(format_json) .with_description(!format_json) @@ -125,19 +142,25 @@ impl BuildArgs { ) }); - compiler = compiler.linter(linter); - } - - let output = compiler.compile(&project)?; - - // Cache project selectors. - cache_local_signatures(&output)?; - - if format_json && !self.names && !self.sizes { - sh_println!("{}", serde_json::to_string_pretty(&output.output())?)?; + // Expand ignore globs and canonicalize from the get go + let ignored = expand_globs(&config.root, config.lint.ignore.iter())? + .iter() + .flat_map(foundry_common::fs::canonicalize_path) + .collect::>(); + + let curr_dir = std::env::current_dir()?; + let input_files = config + .project_paths::() + .input_files_iter() + .filter(|p| !(ignored.contains(p) || ignored.contains(&curr_dir.join(p)))) + .collect::>(); + + if !input_files.is_empty() { + linter.lint(&input_files); + } } - Ok(output) + Ok(()) } /// Returns the `Project` for the current workspace From 4416ed2c51ff0aca64c634d45f61d78fa78ab078 Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Fri, 13 Jun 2025 14:11:13 +0200 Subject: [PATCH 200/244] docs: minor fixes for uninstall instructions (#10777) * follow up: https://github.com/foundry-rs/foundry/pull/10335\#discussion_r2144917920 * style nit * add warning * nit --- foundryup/README.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/foundryup/README.md b/foundryup/README.md index 8d649eb623d8a..8f4a6139b86ef 100644 --- a/foundryup/README.md +++ b/foundryup/README.md @@ -68,7 +68,7 @@ foundryup -C 94bfdb2 To install a local directory or repository (e.g. one located at `~/git/foundry`, assuming you're in the home directory) -##### Note: --branch, --repo, and --version flags are ignored during local installations. +#### Note: --branch, --repo, and --version flags are ignored during local installations. ```sh foundryup --path ./git/foundry @@ -80,21 +80,18 @@ foundryup --path ./git/foundry --- - ## Uninstalling -Foundry contains everything in a `.foundry` directory, usually located in `/home/user/.foundry/`. - -- To uninstall Foundry remove the `.foundry` directory. +Foundry contains everything in a `.foundry` directory, usually located in `/home//.foundry/` on Linux, `/Users//.foundry/` on MacOS and `C:\Users\\.foundry` on Windows where `` is your username. -##### Note: .foundry directory can contain keystores. Make sure to backup any keystores you want to keep. +To uninstall Foundry remove the `.foundry` directory. +#### Warning ⚠️: .foundry directory can contain keystores. Make sure to backup any keystores you want to keep. Remove Foundry from PATH: -- Optionally Foundry can be removed from editing shell configuration file (`.bashrc`, `.zshrc`, etc.) and remove the line that adds Foundry to PATH: +- Optionally Foundry can be removed from editing shell configuration file (`.bashrc`, `.zshrc`, etc.). To do so remove the line that adds Foundry to PATH: -``` +```sh export PATH="$PATH:/home/user/.foundry/bin" ``` - From d22e7302b50f3d2c1b53acf6cf65a90d2dd3ca1b Mon Sep 17 00:00:00 2001 From: onbjerg Date: Fri, 13 Jun 2025 14:59:21 +0200 Subject: [PATCH 201/244] deps: bump foundry-fork-db 0.15.1 (#10778) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4ebb5c3ed4097..d3dde13db5966 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4542,9 +4542,9 @@ dependencies = [ [[package]] name = "foundry-fork-db" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b02fb598e4a8ae7b7af7c256081a419b071eacf5e03537806b339b3151409403" +checksum = "5e3ce9907d94f0371f17930a79ced2c2d9f09131da93f8678f21505ed43c1f39" dependencies = [ "alloy-consensus", "alloy-primitives", From ea2b67f6130e275bfa672db46074d70d0e02c9eb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 15 Jun 2025 17:10:10 +0000 Subject: [PATCH 202/244] Update flake.lock (#10780) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit flake.lock: Update Flake lock file updates: • Updated input 'fenix': 'github:nix-community/fenix/b8fda10da7629d856086bbc1e21164c2d55691e3?narHash=sha256-Jte1NonRzaKF6UpPL5FujKHVTVvc8CAIj8fK%2BX/0qVM%3D' (2025-06-12) → 'github:nix-community/fenix/a804172f150bcf81262655324e583bb0cd0f28dd?narHash=sha256-RlcGw3vAnbI3cfZn8aFaovNUd7312VZh%2B/FDWkqdA7E%3D' (2025-06-14) • Updated input 'fenix/rust-analyzer-src': 'github:rust-lang/rust-analyzer/5b2c8bc9ae90b4ad92dbeb7e52a7f5cbf5ba4d53?narHash=sha256-ewwoJOGE6sMnfXQkydmmjT6ixo1JetBZO0tDEENjOb8%3D' (2025-06-11) → 'github:rust-lang/rust-analyzer/a497f4114ccf24978accb56190e60d1e1659e0c7?narHash=sha256-t6x6/PKg8Shnkd3htrxf3WMgycfRLRWvN9JHAmGWf%2Bs%3D' (2025-06-13) • Updated input 'nixpkgs': 'github:NixOS/nixpkgs/f72be405a10668b8b00937b452f2145244103ebc?narHash=sha256-qX6gXVjaCXXbcn6A9eSLUf8Fm07MgPGe5ir3%2B%2By2O1Q%3D' (2025-06-11) → 'github:NixOS/nixpkgs/6afe187897bef7933475e6af374c893f4c84a293?narHash=sha256-K9yBph93OLTNw02Q6e9CYFGrUhvEXnh45vrZqIRWfvQ%3D' (2025-06-14) Co-authored-by: github-actions[bot] --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 34e5b529665c9..dcf4bb4f625f0 100644 --- a/flake.lock +++ b/flake.lock @@ -8,11 +8,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1749710537, - "narHash": "sha256-Jte1NonRzaKF6UpPL5FujKHVTVvc8CAIj8fK+X/0qVM=", + "lastModified": 1749883145, + "narHash": "sha256-RlcGw3vAnbI3cfZn8aFaovNUd7312VZh+/FDWkqdA7E=", "owner": "nix-community", "repo": "fenix", - "rev": "b8fda10da7629d856086bbc1e21164c2d55691e3", + "rev": "a804172f150bcf81262655324e583bb0cd0f28dd", "type": "github" }, "original": { @@ -23,11 +23,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1749619289, - "narHash": "sha256-qX6gXVjaCXXbcn6A9eSLUf8Fm07MgPGe5ir3++y2O1Q=", + "lastModified": 1749871736, + "narHash": "sha256-K9yBph93OLTNw02Q6e9CYFGrUhvEXnh45vrZqIRWfvQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "f72be405a10668b8b00937b452f2145244103ebc", + "rev": "6afe187897bef7933475e6af374c893f4c84a293", "type": "github" }, "original": { @@ -46,11 +46,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1749671345, - "narHash": "sha256-ewwoJOGE6sMnfXQkydmmjT6ixo1JetBZO0tDEENjOb8=", + "lastModified": 1749829309, + "narHash": "sha256-t6x6/PKg8Shnkd3htrxf3WMgycfRLRWvN9JHAmGWf+s=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "5b2c8bc9ae90b4ad92dbeb7e52a7f5cbf5ba4d53", + "rev": "a497f4114ccf24978accb56190e60d1e1659e0c7", "type": "github" }, "original": { From 4435b4602bcbcf2b2e0e26b2fbc6626fe2e0b3ad Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Mon, 16 Jun 2025 07:27:24 +0300 Subject: [PATCH 203/244] feat(forge): table tests (#10775) --- crates/common/src/traits.rs | 15 ++++- crates/forge/src/runner.rs | 114 +++++++++++++++++++++++++++++++- crates/forge/tests/it/main.rs | 1 + crates/forge/tests/it/table.rs | 116 +++++++++++++++++++++++++++++++++ 4 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 crates/forge/tests/it/table.rs diff --git a/crates/common/src/traits.rs b/crates/common/src/traits.rs index f5f3ea14ce460..a3344c57b6dc7 100644 --- a/crates/common/src/traits.rs +++ b/crates/common/src/traits.rs @@ -116,6 +116,8 @@ pub enum TestFunctionKind { FuzzTest { should_fail: bool }, /// `invariant*` or `statefulFuzz*`. InvariantTest, + /// `table*`, with arguments. + TableTest, /// `afterInvariant`. AfterInvariant, /// `fixture*`. @@ -140,6 +142,7 @@ impl TestFunctionKind { _ if name.starts_with("invariant") || name.starts_with("statefulFuzz") => { Self::InvariantTest } + _ if name.starts_with("table") => Self::TableTest, _ if name.eq_ignore_ascii_case("setup") => Self::Setup, _ if name.eq_ignore_ascii_case("afterinvariant") => Self::AfterInvariant, _ if name.starts_with("fixture") => Self::Fixture, @@ -156,6 +159,7 @@ impl TestFunctionKind { Self::FuzzTest { should_fail: false } => "fuzz", Self::FuzzTest { should_fail: true } => "fuzz fail", Self::InvariantTest => "invariant", + Self::TableTest => "table", Self::AfterInvariant => "afterInvariant", Self::Fixture => "fixture", Self::Unknown => "unknown", @@ -171,7 +175,10 @@ impl TestFunctionKind { /// Returns `true` if this function is a unit, fuzz, or invariant test. #[inline] pub const fn is_any_test(&self) -> bool { - matches!(self, Self::UnitTest { .. } | Self::FuzzTest { .. } | Self::InvariantTest) + matches!( + self, + Self::UnitTest { .. } | Self::FuzzTest { .. } | Self::TableTest | Self::InvariantTest + ) } /// Returns `true` if this function is a test that should fail. @@ -198,6 +205,12 @@ impl TestFunctionKind { matches!(self, Self::InvariantTest) } + /// Returns `true` if this function is a table test. + #[inline] + pub const fn is_table_test(&self) -> bool { + matches!(self, Self::TableTest) + } + /// Returns `true` if this function is an `afterInvariant` function. #[inline] pub const fn is_after_invariant(&self) -> bool { diff --git a/crates/forge/src/runner.rs b/crates/forge/src/runner.rs index 3e2f65fde7f8e..5384df363729f 100644 --- a/crates/forge/src/runner.rs +++ b/crates/forge/src/runner.rs @@ -7,7 +7,7 @@ use crate::{ result::{SuiteResult, TestResult, TestSetup}, MultiContractRunner, TestFilter, }; -use alloy_dyn_abi::DynSolValue; +use alloy_dyn_abi::{DynSolValue, JsonAbiExt}; use alloy_json_abi::Function; use alloy_primitives::{address, map::HashMap, Address, Bytes, U256}; use eyre::Result; @@ -31,6 +31,7 @@ use foundry_evm::{ }, traces::{load_contracts, TraceKind, TraceMode}, }; +use itertools::Itertools; use proptest::test_runner::{ FailurePersistence, FileFailurePersistence, RngAlgorithm, TestError, TestRng, TestRunner, }; @@ -512,6 +513,7 @@ impl<'a> FunctionRunner<'a> { match kind { TestFunctionKind::UnitTest { .. } => self.run_unit_test(func), TestFunctionKind::FuzzTest { .. } => self.run_fuzz_test(func), + TestFunctionKind::TableTest => self.run_table_test(func), TestFunctionKind::InvariantTest => { let test_bytecode = &self.cr.contract.bytecode; self.run_invariant_test( @@ -566,6 +568,116 @@ impl<'a> FunctionRunner<'a> { self.result } + /// Runs a table test. + /// The parameters dataset (table) is created from defined parameter fixtures, therefore each + /// test table parameter should have the same number of fixtures defined. + /// E.g. for table test + /// - `table_test(uint256 amount, bool swap)` fixtures are defined as + /// - `uint256[] public fixtureAmount = [2, 5]` + /// - `bool[] public fixtureSwap = [true, false]` The `table_test` is then called with the pair + /// of args `(2, true)` and `(5, false)`. + fn run_table_test(mut self, func: &Function) -> TestResult { + // Prepare unit test execution. + if self.prepare_test(func).is_err() { + return self.result; + } + + // Extract and validate fixtures for the first table test parameter. + let Some(first_param) = func.inputs.first() else { + self.result.single_fail(Some("Table test should have at least one parameter".into())); + return self.result; + }; + + let Some(first_param_fixtures) = + &self.setup.fuzz_fixtures.param_fixtures(first_param.name()) + else { + self.result.single_fail(Some("Table test should have fixtures defined".into())); + return self.result; + }; + + if first_param_fixtures.is_empty() { + self.result.single_fail(Some("Table test should have at least one fixture".into())); + return self.result; + } + + let fixtures_len = first_param_fixtures.len(); + let mut table_fixtures = vec![&first_param_fixtures[..]]; + + // Collect fixtures for remaining parameters. + for param in &func.inputs[1..] { + let param_name = param.name(); + let Some(fixtures) = &self.setup.fuzz_fixtures.param_fixtures(param.name()) else { + self.result.single_fail(Some(format!("No fixture defined for param {param_name}"))); + return self.result; + }; + + if fixtures.len() != fixtures_len { + self.result.single_fail(Some(format!( + "{} fixtures defined for {param_name} (expected {})", + fixtures.len(), + fixtures_len + ))); + return self.result; + } + + table_fixtures.push(&fixtures[..]); + } + + let progress = + start_fuzz_progress(self.cr.progress, self.cr.name, &func.name, fixtures_len as u32); + + for i in 0..fixtures_len { + // Increment progress bar. + if let Some(progress) = progress.as_ref() { + progress.inc(1); + } + + let args = table_fixtures.iter().map(|row| row[i].clone()).collect_vec(); + let (mut raw_call_result, reason) = match self.executor.call( + self.sender, + self.address, + func, + &args, + U256::ZERO, + Some(self.revert_decoder()), + ) { + Ok(res) => (res.raw, None), + Err(EvmError::Execution(err)) => (err.raw, Some(err.reason)), + Err(EvmError::Skip(reason)) => { + self.result.single_skip(reason); + return self.result; + } + Err(err) => { + self.result.single_fail(Some(err.to_string())); + return self.result; + } + }; + + let is_success = + self.executor.is_raw_call_mut_success(self.address, &mut raw_call_result, false); + // Record counterexample if test fails. + if !is_success { + self.result.counterexample = + Some(CounterExample::Single(BaseCounterExample::from_fuzz_call( + Bytes::from(func.abi_encode_input(&args).unwrap()), + args, + raw_call_result.traces.clone(), + ))); + self.result.single_result(false, reason, raw_call_result); + return self.result; + } + + // If it's the last iteration and all other runs succeeded, then use last call result + // for logs and traces. + if i == fixtures_len - 1 { + self.result.single_result(true, None, raw_call_result); + return self.result; + } + } + + self.result + } + fn run_invariant_test( mut self, func: &Function, diff --git a/crates/forge/tests/it/main.rs b/crates/forge/tests/it/main.rs index aaa129796a39a..c8890af3d4614 100644 --- a/crates/forge/tests/it/main.rs +++ b/crates/forge/tests/it/main.rs @@ -10,4 +10,5 @@ mod inline; mod invariant; mod repros; mod spec; +mod table; mod vyper; diff --git a/crates/forge/tests/it/table.rs b/crates/forge/tests/it/table.rs new file mode 100644 index 0000000000000..eaac4f9e44382 --- /dev/null +++ b/crates/forge/tests/it/table.rs @@ -0,0 +1,116 @@ +//! Table tests. + +use foundry_test_utils::{forgetest_init, str}; + +forgetest_init!(should_run_table_tests, |prj, cmd| { + prj.add_test( + "CounterTable.t.sol", + r#" +import "forge-std/Test.sol"; +import {Counter} from "../src/Counter.sol"; + +contract CounterTableTest is Test { + Counter counter = new Counter(); + + uint256[] public fixtureAmount = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + bool[] public fixtureSwap = [true, true, false, true, false, true, false, true, false, true]; + bool[] public fixtureDiffSwap = [true, false]; + function fixtureNoFixture() public returns (address[] memory) { + } + + function tableWithNoParamFail() public { + counter.increment(); + } + + function tableWithParamNoFixtureFail(uint256 noFixture) public { + require(noFixture != 100); + counter.increment(); + } + + function tableSingleParamPass(uint256 amount) public { + require(amount != 100, "Amount cannot be 100"); + counter.increment(); + } + + function tableSingleParamFail(uint256 amount) public { + require(amount != 10, "Amount cannot be 10"); + counter.increment(); + } + + function tableMultipleParamsNoParamFail(uint256 amount, bool noSwap) public { + require(amount != 100 && noSwap, "Amount cannot be 100"); + counter.increment(); + } + + function tableMultipleParamsDifferentFixturesFail(uint256 amount, bool diffSwap) public { + require(amount != 100 && diffSwap, "Amount cannot be 100"); + counter.increment(); + } + + function tableMultipleParamsFail(uint256 amount, bool swap) public { + require(amount == 3 && swap, "Cannot swap"); + counter.increment(); + } + + function tableMultipleParamsPass(uint256 amount, bool swap) public { + if (amount == 3 && swap) { + revert(); + } + counter.increment(); + } +} + "#, + ) + .unwrap(); + + cmd.args(["test", "--mc", "CounterTable", "-vvvv"]).assert_failure().stdout_eq(str![[r#" +[COMPILING_FILES] with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 8 tests for test/CounterTable.t.sol:CounterTableTest +[FAIL: 2 fixtures defined for diffSwap (expected 10)] tableMultipleParamsDifferentFixturesFail(uint256,bool) ([GAS]) +[FAIL: Cannot swap; counterexample: calldata=0x717892ca00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001 args=[1, true]] tableMultipleParamsFail(uint256,bool) ([GAS]) +Traces: + [..] CounterTableTest::tableMultipleParamsFail(1, true) + └─ ← [Revert] Cannot swap + +[FAIL: No fixture defined for param noSwap] tableMultipleParamsNoParamFail(uint256,bool) ([GAS]) +[PASS] tableMultipleParamsPass(uint256,bool) ([GAS]) +Traces: + [..] CounterTableTest::tableMultipleParamsPass(10, true) + ├─ [..] Counter::increment() + │ └─ ← [Stop] + └─ ← [Stop] + +[FAIL: Amount cannot be 10; counterexample: calldata=0x44fa2375000000000000000000000000000000000000000000000000000000000000000a args=[10]] tableSingleParamFail(uint256) ([GAS]) +Traces: + [..] CounterTableTest::tableSingleParamFail(10) + └─ ← [Revert] Amount cannot be 10 + +[PASS] tableSingleParamPass(uint256) ([GAS]) +Traces: + [..] CounterTableTest::tableSingleParamPass(10) + ├─ [..] Counter::increment() + │ └─ ← [Stop] + └─ ← [Stop] + +[FAIL: Table test should have at least one parameter] tableWithNoParamFail() ([GAS]) +[FAIL: Table test should have at least one fixture] tableWithParamNoFixtureFail(uint256) ([GAS]) +Suite result: FAILED. 2 passed; 6 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 2 tests passed, 6 failed, 0 skipped (8 total tests) + +Failing tests: +Encountered 6 failing tests in test/CounterTable.t.sol:CounterTableTest +[FAIL: 2 fixtures defined for diffSwap (expected 10)] tableMultipleParamsDifferentFixturesFail(uint256,bool) ([GAS]) +[FAIL: Cannot swap; counterexample: calldata=0x717892ca00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001 args=[1, true]] tableMultipleParamsFail(uint256,bool) ([GAS]) +[FAIL: No fixture defined for param noSwap] tableMultipleParamsNoParamFail(uint256,bool) ([GAS]) +[FAIL: Amount cannot be 10; counterexample: calldata=0x44fa2375000000000000000000000000000000000000000000000000000000000000000a args=[10]] tableSingleParamFail(uint256) ([GAS]) +[FAIL: Table test should have at least one parameter] tableWithNoParamFail() ([GAS]) +[FAIL: Table test should have at least one fixture] tableWithParamNoFixtureFail(uint256) ([GAS]) + +Encountered a total of 6 failing tests, 2 tests succeeded + +"#]]); +}); From 893da4d80ef8196d78d9f9a25086997c45e371a6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 06:57:45 +0000 Subject: [PATCH 204/244] chore(deps): weekly `cargo update` (#10781) * chore(deps): weekly `cargo update` Locking 51 packages to latest compatible versions Updating adler2 v2.0.0 -> v2.0.1 Unchanged alloy-evm v0.10.0 (available: v0.11.0) Unchanged alloy-op-evm v0.10.0 (available: v0.11.0) Updating async-compression v0.4.23 -> v0.4.24 Updating aws-config v1.6.3 -> v1.8.0 Updating aws-runtime v1.5.7 -> v1.5.8 Updating aws-sdk-kms v1.75.0 -> v1.76.0 Updating aws-sdk-sso v1.72.0 -> v1.73.0 Updating aws-sdk-ssooidc v1.73.0 -> v1.74.0 Updating aws-sdk-sts v1.73.0 -> v1.74.0 Updating aws-sigv4 v1.3.2 -> v1.3.3 Updating aws-smithy-http-client v1.0.3 -> v1.0.5 Updating aws-smithy-json v0.61.3 -> v0.61.4 Updating aws-smithy-runtime-api v1.8.0 -> v1.8.1 Updating aws-smithy-types v1.3.1 -> v1.3.2 Updating aws-smithy-xml v0.60.9 -> v0.60.10 Updating bon v3.6.3 -> v3.6.4 Updating bon-macros v3.6.3 -> v3.6.4 Updating cc v1.2.26 -> v1.2.27 Updating cfg-if v1.0.0 -> v1.0.1 Updating clap v4.5.39 -> v4.5.40 Updating clap_builder v4.5.39 -> v4.5.40 Updating clap_complete v4.5.52 -> v4.5.54 Updating clap_derive v4.5.32 -> v4.5.40 Updating clap_lex v0.7.4 -> v0.7.5 Unchanged crossterm v0.28.1 (available: v0.29.0) Updating foundry-compilers v0.17.1 -> v0.17.3 Updating foundry-compilers-artifacts v0.17.1 -> v0.17.3 Updating foundry-compilers-artifacts-solc v0.17.1 -> v0.17.3 Updating foundry-compilers-artifacts-vyper v0.17.1 -> v0.17.3 Updating foundry-compilers-core v0.17.1 -> v0.17.3 Updating hermit-abi v0.5.1 -> v0.5.2 Unchanged idna_adapter v1.1.0 (available: v1.2.1) Updating jiff v0.2.14 -> v0.2.15 Updating jiff-static v0.2.14 -> v0.2.15 Updating libc v0.2.172 -> v0.2.173 Unchanged matchit v0.8.4 (available: v0.8.6) Updating memchr v2.7.4 -> v2.7.5 Updating miniz_oxide v0.8.8 -> v0.8.9 Unchanged op-alloy-consensus v0.17.2 (available: v0.18.1) Unchanged op-alloy-rpc-types v0.17.2 (available: v0.18.1) Unchanged op-revm v5.0.1 (available: v6.0.0) Unchanged opener v0.7.2 (available: v0.8.2) Updating prettyplease v0.2.33 -> v0.2.34 Unchanged protobuf v3.3.0 (available: v3.7.2) Unchanged protobuf-support v3.3.0 (available: v3.7.2) Unchanged rand v0.8.5 (available: v0.9.1) Updating redox_syscall v0.5.12 -> v0.5.13 Adding ref-cast v1.0.24 Adding ref-cast-impl v1.0.24 Updating reqwest v0.12.19 -> v0.12.20 Unchanged revm v24.0.1 (available: v25.0.0) Unchanged revm-inspectors v0.23.0 (available: v0.24.0) Updating rustc-demangle v0.1.24 -> v0.1.25 Unchanged rustyline v15.0.0 (available: v16.0.0) Adding schemars v0.9.0 Unchanged schemars v0.8.22 (available: v0.9.0) Removing serde_repr v0.1.20 Updating serde_with v3.12.0 -> v3.13.0 Updating serde_with_macros v3.12.0 -> v3.13.0 Updating syn v2.0.101 -> v2.0.103 Updating thread_local v1.1.8 -> v1.1.9 Removing tokio-socks v0.5.2 Unchanged ui_test v0.29.2 (available: v0.30.1) Unchanged unicode-width v0.2.0 (available: v0.2.1) Unchanged vergen v8.3.2 (available: v9.0.6) Updating wasi v0.11.0+wasi-snapshot-preview1 -> v0.11.1+wasi-snapshot-preview1 Updating windows v0.61.1 -> v0.61.3 Updating windows-link v0.1.1 -> v0.1.3 Adding windows-sys v0.60.2 Updating windows-targets v0.53.0 -> v0.53.2 Updating winnow v0.7.10 -> v0.7.11 Unchanged zip-extract v0.2.1 (available: v0.2.3) note: to see how you depend on a package, run `cargo tree --invert --package @` * Remove EOF version --------- Co-authored-by: mattsse <19890894+mattsse@users.noreply.github.com> Co-authored-by: grandizzy --- Cargo.lock | 396 ++++++++++++++++++++------------------- crates/config/src/lib.rs | 1 - 2 files changed, 205 insertions(+), 192 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3dde13db5966..5c3a4af06567e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aes" @@ -472,7 +472,7 @@ checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -747,7 +747,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -764,7 +764,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", "syn-solidity", "tiny-keccak", ] @@ -783,7 +783,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.101", + "syn 2.0.103", "syn-solidity", ] @@ -1286,7 +1286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -1324,7 +1324,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -1413,7 +1413,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -1472,9 +1472,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.23" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b37fc50485c4f3f736a4fb14199f6d5f5ba008d7f28fe710306c92780f004c07" +checksum = "d615619615a650c571269c00dca41db04b9210037fa76ed8239f70404ab56985" dependencies = [ "flate2", "futures-core", @@ -1511,7 +1511,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -1522,7 +1522,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -1575,7 +1575,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -1586,9 +1586,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-config" -version = "1.6.3" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02a18fd934af6ae7ca52410d4548b98eb895aab0f1ea417d168d85db1434a141" +checksum = "455e9fb7743c6f6267eb2830ccc08686fbb3d13c9a689369562fd4d4ef9ea462" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1651,9 +1651,9 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.5.7" +version = "1.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c4063282c69991e57faab9e5cb21ae557e59f5b0fb285c196335243df8dc25c" +checksum = "4f6c68419d8ba16d9a7463671593c54f81ba58cab466e9b759418da606dcc2e2" dependencies = [ "aws-credential-types", "aws-sigv4", @@ -1675,9 +1675,9 @@ dependencies = [ [[package]] name = "aws-sdk-kms" -version = "1.75.0" +version = "1.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb89d6ae47f03ca664f604571d0f29165112543ba1a39878347815b8028c235b" +checksum = "8565497721d9f18fa29a68bc5d8225b39e1cc7399d7fc6f1ad803ca934341804" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1697,9 +1697,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.72.0" +version = "1.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13118ad30741222f67b1a18e5071385863914da05124652b38e172d6d3d9ce31" +checksum = "b2ac1674cba7872061a29baaf02209fefe499ff034dfd91bd4cc59e4d7741489" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1719,9 +1719,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.73.0" +version = "1.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f879a8572b4683a8f84f781695bebf2f25cf11a81a2693c31fc0e0215c2c1726" +checksum = "3a6a22f077f5fd3e3c0270d4e1a110346cddf6769e9433eb9e6daceb4ca3b149" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1741,9 +1741,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.73.0" +version = "1.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1e9c3c24e36183e2f698235ed38dcfbbdff1d09b9232dc866c4be3011e0b47e" +checksum = "19d440e1d368759bd10df0dbdddbfff6473d7cd73e9d9ef2363dc9995ac2d711" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1764,9 +1764,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.3.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3734aecf9ff79aa401a6ca099d076535ab465ff76b46440cf567c8e70b65dc13" +checksum = "ddfb9021f581b71870a17eac25b52335b82211cdc092e02b6876b2bcefa61666" dependencies = [ "aws-credential-types", "aws-smithy-http", @@ -1817,9 +1817,9 @@ dependencies = [ [[package]] name = "aws-smithy-http-client" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "073d330f94bdf1f47bb3e0f5d45dda1e372a54a553c39ab6e9646902c8c81594" +checksum = "7f491388e741b7ca73b24130ff464c1478acc34d5b331b7dd0a2ee4643595a15" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -1840,9 +1840,9 @@ dependencies = [ [[package]] name = "aws-smithy-json" -version = "0.61.3" +version = "0.61.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92144e45819cae7dc62af23eac5a038a58aa544432d2102609654376a900bd07" +checksum = "a16e040799d29c17412943bdbf488fd75db04112d0c0d4b9290bacf5ae0014b9" dependencies = [ "aws-smithy-types", ] @@ -1892,9 +1892,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e5d9e3a80a18afa109391fb5ad09c3daf887b516c6fd805a157c6ea7994a57" +checksum = "bd8531b6d8882fd8f48f82a9754e682e29dd44cff27154af51fa3eb730f59efb" dependencies = [ "aws-smithy-async", "aws-smithy-types", @@ -1909,9 +1909,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40076bd09fadbc12d5e026ae080d0930defa606856186e31d83ccc6a255eeaf3" +checksum = "d498595448e43de7f4296b7b7a18a8a02c61ec9349128c80a368f7c3b4ab11a8" dependencies = [ "base64-simd", "bytes", @@ -1932,9 +1932,9 @@ dependencies = [ [[package]] name = "aws-smithy-xml" -version = "0.60.9" +version = "0.60.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab0b0166827aa700d3dc519f72f8b3a91c35d0b8d042dc5d643a91e6f80648fc" +checksum = "3db87b96cb1b16c024980f133968d52882ca0daaee3a086c6decc500f6c99728" dependencies = [ "xmlparser", ] @@ -2090,7 +2090,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.101", + "syn 2.0.103", "which 4.4.2", ] @@ -2185,9 +2185,9 @@ dependencies = [ [[package]] name = "bon" -version = "3.6.3" +version = "3.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced38439e7a86a4761f7f7d5ded5ff009135939ecb464a24452eaa4c1696af7d" +checksum = "f61138465baf186c63e8d9b6b613b508cd832cba4ce93cf37ce5f096f91ac1a6" dependencies = [ "bon-macros", "rustversion", @@ -2195,9 +2195,9 @@ dependencies = [ [[package]] name = "bon-macros" -version = "3.6.3" +version = "3.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce61d2d3844c6b8d31b2353d9f66cf5e632b3e9549583fe3cac2f4f6136725e" +checksum = "40d1dad34aa19bf02295382f08d9bc40651585bd497266831d40ee6296fb49ca" dependencies = [ "darling", "ident_case", @@ -2205,7 +2205,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -2414,9 +2414,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.26" +version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" dependencies = [ "jobserver", "libc", @@ -2434,9 +2434,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "cfg_aliases" @@ -2541,9 +2541,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.39" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", "clap_derive", @@ -2561,9 +2561,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.39" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -2576,9 +2576,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.52" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a554639e42d0c838336fc4fbedb9e2df3ad1fa4acda149f9126b4ccfcd7900f" +checksum = "aad5b1b4de04fead402672b48897030eec1f3bfe1550776322f59f6d6e6a5677" dependencies = [ "clap", ] @@ -2595,21 +2595,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.32" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "clearscreen" @@ -3056,7 +3056,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -3099,7 +3099,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -3110,7 +3110,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -3190,7 +3190,7 @@ checksum = "e73f2692d4bd3cac41dca28934a39894200c9fabf49586d77d0e5954af1d7902" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -3201,7 +3201,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -3222,7 +3222,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -3232,7 +3232,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -3261,7 +3261,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", "unicode-xid", ] @@ -3274,7 +3274,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", "unicode-xid", ] @@ -3330,7 +3330,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -3341,7 +3341,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -3413,7 +3413,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -3518,7 +3518,7 @@ checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -3984,7 +3984,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -4104,7 +4104,7 @@ version = "1.2.3" dependencies = [ "alloy-sol-types", "foundry-macros", - "schemars", + "schemars 0.8.22", "serde", "serde_json", ] @@ -4233,9 +4233,9 @@ dependencies = [ [[package]] name = "foundry-compilers" -version = "0.17.1" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d14093062732cc5085a2ad6eb5ec1f20e5b6704b86fc4eeef7ba15f53f75178d" +checksum = "72acadbe10bbcf1d2765155808a4b79744061ffba3ce78680ac9c86bd2222802" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4270,9 +4270,9 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts" -version = "0.17.1" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2dfbae2e37ccb536b7dd85303fb0f006902a71218587f649129e9311e2ea646" +checksum = "7f1f4c29ce88d24d1bebc5708bd14104534b0edbc9ddf2e76037bdb29a51c1c9" dependencies = [ "foundry-compilers-artifacts-solc", "foundry-compilers-artifacts-vyper", @@ -4280,9 +4280,9 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-solc" -version = "0.17.1" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d17f0a8f8c4ff296546cdb1985a460542bb39ab853815de8ba51b43c134e4051" +checksum = "03f145ddd61f912cd8dc9cb57acaca6d771dc51ef23908bb98ad9c5859430679" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4293,7 +4293,6 @@ dependencies = [ "semver 1.0.26", "serde", "serde_json", - "serde_repr", "thiserror 2.0.12", "tokio", "tracing", @@ -4303,9 +4302,9 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-vyper" -version = "0.17.1" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e87c18e3fed59ac0b7012f690eb3b0cc0e289e8e60601f438d427d9d85b8760" +checksum = "d553aebe632477cff64cfa20fa3dbd819d3a454a6dfd748fde9206915e3fe0d9" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4318,9 +4317,9 @@ dependencies = [ [[package]] name = "foundry-compilers-core" -version = "0.17.1" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053b13c3ee670c41e86235df99805bdfedd88a5efb6bbe697925b69028218481" +checksum = "afbd404c3ebcba24d0cb4746f78908ac0d681e9afb16a638a15c13d8e324e848" dependencies = [ "alloy-primitives", "cfg-if", @@ -4579,7 +4578,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -4756,7 +4755,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -4857,7 +4856,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "wasm-bindgen", ] @@ -4992,9 +4991,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex" @@ -5311,7 +5310,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -5429,7 +5428,7 @@ dependencies = [ "indoc", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -5524,9 +5523,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -5539,13 +5538,13 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -5724,9 +5723,9 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.173" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" [[package]] name = "libdbus-sys" @@ -5745,7 +5744,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.0", + "windows-targets 0.53.2", ] [[package]] @@ -5936,7 +5935,7 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -5970,7 +5969,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -6019,9 +6018,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memoffset" @@ -6062,7 +6061,7 @@ checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -6098,9 +6097,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] @@ -6113,7 +6112,7 @@ checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "windows-sys 0.59.0", ] @@ -6140,7 +6139,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -6403,7 +6402,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -6633,7 +6632,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -6716,7 +6715,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -6775,7 +6774,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -6850,7 +6849,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -6899,7 +6898,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -7004,12 +7003,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.33" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" +checksum = "6837b9e10d61f45f987d50808f83d1ee3d206c66acf650c3e4ae2e1f6ddedf55" dependencies = [ "proc-macro2", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -7060,7 +7059,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -7080,7 +7079,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", "version_check", "yansi", ] @@ -7127,7 +7126,7 @@ checksum = "4ee1c9ac207483d5e7db4940700de86a9aae46ef90c48b57f99fe7edb8345e49" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -7150,7 +7149,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -7445,9 +7444,9 @@ checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" [[package]] name = "redox_syscall" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ "bitflags 2.9.1", ] @@ -7463,6 +7462,26 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "ref-cast" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "regex" version = "1.11.1" @@ -7515,9 +7534,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.19" +version = "0.12.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f8e5513d63f2e5b386eb5106dc67eaf3f84e95258e210489136b8b92ad6119" +checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" dependencies = [ "async-compression", "base64 0.22.1", @@ -7533,12 +7552,10 @@ dependencies = [ "hyper", "hyper-rustls", "hyper-util", - "ipnet", "js-sys", "log", "mime", "mime_guess", - "once_cell", "percent-encoding", "pin-project-lite", "quinn", @@ -7551,7 +7568,6 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-rustls", - "tokio-socks", "tokio-util", "tower", "tower-http", @@ -7886,9 +7902,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "rustc-hash" @@ -8111,6 +8127,18 @@ dependencies = [ "serde_json", ] +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + [[package]] name = "schemars_derive" version = "0.8.22" @@ -8120,7 +8148,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -8269,7 +8297,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -8280,7 +8308,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -8315,17 +8343,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_repr" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "serde_spanned" version = "0.6.9" @@ -8349,15 +8366,16 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +checksum = "bf65a400f8f66fb7b0552869ad70157166676db75ed8181f8104ea91cf9d0b42" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", "indexmap 2.9.0", + "schemars 0.9.0", "serde", "serde_derive", "serde_json", @@ -8367,14 +8385,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +checksum = "81679d9ed988d5e9a5e6531dc3f2c28efbd639cbd1dfb628df08edea6004da77" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -8688,7 +8706,7 @@ checksum = "e17f8b99f28f358b41acb6efe4d7b8f326541b3c58a15dd1931d6fe581feefef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -8896,7 +8914,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -8909,7 +8927,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -9041,9 +9059,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.101" +version = "2.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" dependencies = [ "proc-macro2", "quote", @@ -9059,7 +9077,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -9197,7 +9215,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -9208,17 +9226,16 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -9333,7 +9350,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -9346,18 +9363,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-socks" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f" -dependencies = [ - "either", - "futures-util", - "thiserror 1.0.69", - "tokio", -] - [[package]] name = "tokio-stream" version = "0.1.17" @@ -9578,7 +9583,7 @@ checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -10054,9 +10059,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" @@ -10089,7 +10094,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", "wasm-bindgen-shared", ] @@ -10124,7 +10129,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -10333,9 +10338,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.61.1" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ "windows-collections", "windows-core", @@ -10385,7 +10390,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -10396,14 +10401,14 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-numerics" @@ -10462,6 +10467,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -10480,9 +10494,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.0" +version = "0.53.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" dependencies = [ "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", @@ -10601,9 +10615,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" dependencies = [ "memchr", ] @@ -10698,7 +10712,7 @@ checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -10718,7 +10732,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index fd495e2fba837..1222b4703fa38 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -1530,7 +1530,6 @@ impl Config { remappings: Vec::new(), // Set with `with_extra_output` below. output_selection: Default::default(), - eof_version: None, } .with_extra_output(self.configured_artifacts_handler().output_selection()); From 66fe662eea664d73c22a0753f5fb9fe78e2ec982 Mon Sep 17 00:00:00 2001 From: Luis_ <73004377+Another-DevX@users.noreply.github.com> Date: Mon, 16 Jun 2025 04:08:51 -0500 Subject: [PATCH 205/244] feat: add useSeed cheatcode to set RNG seed (#10698) * feat: mock deterministic shuffle implementation * feat: implement useSeed() * fix(test): typo * fix(test): correct implementation of randomUint() chore: format * fix: refactor seed handling logic and remove redundant assertion message * chore: remove unused imports and redundant newline * fix(test): add seed validation and tests for shuffle consistency * chore: add Shuffle test * Adapt to updated proptest --------- Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> Co-authored-by: grandizzy --- crates/cheatcodes/assets/cheatcodes.json | 20 ++++++ crates/cheatcodes/spec/src/vm.rs | 4 ++ crates/cheatcodes/src/inspector.rs | 7 ++ crates/cheatcodes/src/utils.rs | 8 +++ testdata/cheats/Vm.sol | 1 + testdata/default/cheats/Seed.t.sol | 92 ++++++++++++++++++++++++ testdata/default/cheats/Shuffle.t.sol | 61 ++++++++++++++++ 7 files changed, 193 insertions(+) create mode 100644 testdata/default/cheats/Seed.t.sol create mode 100644 testdata/default/cheats/Shuffle.t.sol diff --git a/crates/cheatcodes/assets/cheatcodes.json b/crates/cheatcodes/assets/cheatcodes.json index f1d2b617e3a5f..93cdf40cd4393 100644 --- a/crates/cheatcodes/assets/cheatcodes.json +++ b/crates/cheatcodes/assets/cheatcodes.json @@ -9680,6 +9680,26 @@ "status": "stable", "safety": "unsafe" }, + { + "func": { + "id": "setSeed", + "description": "Set RNG seed.", + "declaration": "function setSeed(uint256 seed) external;", + "visibility": "external", + "mutability": "", + "signature": "setSeed(uint256)", + "selector": "0xc32a50f9", + "selectorBytes": [ + 195, + 42, + 80, + 249 + ] + }, + "group": "utilities", + "status": "stable", + "safety": "safe" + }, { "func": { "id": "shuffle", diff --git a/crates/cheatcodes/spec/src/vm.rs b/crates/cheatcodes/spec/src/vm.rs index a734c7a033ef1..93eeaa21cd0bd 100644 --- a/crates/cheatcodes/spec/src/vm.rs +++ b/crates/cheatcodes/spec/src/vm.rs @@ -2879,6 +2879,10 @@ interface Vm { #[cheatcode(group = Utilities)] function shuffle(uint256[] calldata array) external returns (uint256[] memory); + /// Set RNG seed. + #[cheatcode(group = Utilities)] + function setSeed(uint256 seed) external; + /// Causes the next contract creation (via new) to fail and return its initcode in the returndata buffer. /// This allows type-safe access to the initcode payload that would be used for contract creation. /// Example usage: diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index 08592fc57a8ae..c83f39bd59034 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -1264,6 +1264,13 @@ impl Cheatcodes { }) } + pub fn set_seed(&mut self, seed: U256) { + self.test_runner = Some(TestRunner::new_with_rng( + proptest::test_runner::Config::default(), + TestRng::from_seed(RngAlgorithm::ChaCha, &seed.to_be_bytes::<32>()), + )); + } + /// Returns existing or set a default `ArbitraryStorage` option. /// Used by `setArbitraryStorage` cheatcode to track addresses with arbitrary storage. pub fn arbitrary_storage(&mut self) -> &mut ArbitraryStorage { diff --git a/crates/cheatcodes/src/utils.rs b/crates/cheatcodes/src/utils.rs index 3eed1b1bad230..a5d2e1b47ee9f 100644 --- a/crates/cheatcodes/src/utils.rs +++ b/crates/cheatcodes/src/utils.rs @@ -273,6 +273,14 @@ impl Cheatcode for shuffleCall { } } +impl Cheatcode for setSeedCall { + fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { + let Self { seed } = self; + ccx.state.set_seed(*seed); + Ok(Default::default()) + } +} + /// Helper to generate a random `uint` value (with given bits or bounded if specified) /// from type strategy. fn random_uint(state: &mut Cheatcodes, bits: Option, bounds: Option<(U256, U256)>) -> Result { diff --git a/testdata/cheats/Vm.sol b/testdata/cheats/Vm.sol index b439cf9b6f883..b9c88bf74c8a7 100644 --- a/testdata/cheats/Vm.sol +++ b/testdata/cheats/Vm.sol @@ -477,6 +477,7 @@ interface Vm { function setEnv(string calldata name, string calldata value) external; function setNonce(address account, uint64 newNonce) external; function setNonceUnsafe(address account, uint64 newNonce) external; + function setSeed(uint256 seed) external; function shuffle(uint256[] calldata array) external returns (uint256[] memory); function signAndAttachDelegation(address implementation, uint256 privateKey) external returns (SignedDelegation memory signedDelegation); function signAndAttachDelegation(address implementation, uint256 privateKey, uint64 nonce) external returns (SignedDelegation memory signedDelegation); diff --git a/testdata/default/cheats/Seed.t.sol b/testdata/default/cheats/Seed.t.sol new file mode 100644 index 0000000000000..6db1b41da0ef3 --- /dev/null +++ b/testdata/default/cheats/Seed.t.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.18; + +import "ds-test/test.sol"; +import "cheats/Vm.sol"; + +contract SeedTest is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + function testSeedAffectsRandom() public { + // Use a known seed + uint256 seed = 123456789; + vm.setSeed(seed); + + // Call a foundry cheatcode to get a random value (this depends on the integration) + uint256 rand1 = uint256(vm.randomUint()); + + // Reset the seed and verify the result is the same + vm.setSeed(seed); + uint256 rand2 = uint256(vm.randomUint()); + + uint256 rand3 = uint256(vm.randomUint()); + // If the seed is the same, the random value must be equal + assertEq(rand1, rand2); + assertTrue(rand1 != rand3); + } + + function testSeedChangesRandom() public { + // Use one seed + vm.setSeed(1); + uint256 randA = uint256(vm.randomUint()); + + // Use a different seed + vm.setSeed(2); + uint256 randB = uint256(vm.randomUint()); + + // Values must be different + assertTrue(randA != randB, "Random value must be different if seed is different"); + } + + function testSeedAffectsShuffle() public { + // Use a known seed + uint256 seed = 123456789; + vm.setSeed(seed); + + // Create two identical arrays + uint256[] memory array1 = new uint256[](5); + uint256[] memory array2 = new uint256[](5); + for (uint256 i = 0; i < 5; i++) { + array1[i] = i; + array2[i] = i; + } + + // Shuffle both arrays with the same seed + array1 = vm.shuffle(array1); + vm.setSeed(seed); // Reset the seed to get the same shuffle pattern + array2 = vm.shuffle(array2); + + // Compare elements - they should be identical after shuffle + for (uint256 i = 0; i < array1.length; i++) { + assertEq(array1[i], array2[i], "Arrays should be identical with same seed"); + } + } + + function testDifferentSeedsProduceDifferentShuffles() public { + // Create the initial array + uint256[] memory array1 = new uint256[](5); + uint256[] memory array2 = new uint256[](5); + for (uint256 i = 0; i < 5; i++) { + array1[i] = i; + array2[i] = i; + } + + // Use first seed + vm.setSeed(1); + array1 = vm.shuffle(array1); + + // Use second seed + vm.setSeed(2); + array2 = vm.shuffle(array2); + + // Arrays should be different (we'll check at least one difference exists) + bool foundDifference = false; + for (uint256 i = 0; i < array1.length; i++) { + if (array1[i] != array2[i]) { + foundDifference = true; + break; + } + } + assertTrue(foundDifference, "Arrays should be different with different seeds"); + } +} diff --git a/testdata/default/cheats/Shuffle.t.sol b/testdata/default/cheats/Shuffle.t.sol new file mode 100644 index 0000000000000..565f596a6dcb5 --- /dev/null +++ b/testdata/default/cheats/Shuffle.t.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.18; + +import "ds-test/test.sol"; +import "cheats/Vm.sol"; + +contract ShuffleTest is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + function testDeterministicShuffle() public { + // Use a known seed + uint256 seed = 123456789; + vm.setSeed(seed); + + // Create two identical arrays + uint256[] memory array1 = new uint256[](5); + uint256[] memory array2 = new uint256[](5); + for (uint256 i = 0; i < 5; i++) { + array1[i] = i; + array2[i] = i; + } + + // Shuffle both arrays with the same seed + array1 = vm.shuffle(array1); + vm.setSeed(seed); // Reset the seed to get the same shuffle pattern + array2 = vm.shuffle(array2); + + // Compare elements - they should be identical after shuffle + for (uint256 i = 0; i < array1.length; i++) { + assertEq(array1[i], array2[i], "Arrays should be identical with same seed"); + } + } + + function testDifferentSeedsProduceDifferentShuffles() public { + // Create the initial array + uint256[] memory array1 = new uint256[](5); + uint256[] memory array2 = new uint256[](5); + for (uint256 i = 0; i < 5; i++) { + array1[i] = i; + array2[i] = i; + } + + // Use first seed + vm.setSeed(1); + array1 = vm.shuffle(array1); + + // Use second seed + vm.setSeed(2); + array2 = vm.shuffle(array2); + + // Arrays should be different (we'll check at least one difference exists) + bool foundDifference = false; + for (uint256 i = 0; i < array1.length; i++) { + if (array1[i] != array2[i]) { + foundDifference = true; + break; + } + } + assertTrue(foundDifference, "Arrays should be different with different seeds"); + } +} From 361742529fcb9e3d9d56beb85aab1b9e84b08489 Mon Sep 17 00:00:00 2001 From: Mablr <59505383+mablr@users.noreply.github.com> Date: Mon, 16 Jun 2025 11:25:13 +0200 Subject: [PATCH 206/244] feat(cast): `compute_address` add support CREATE2 addresses (#10783) --- crates/cast/src/args.rs | 19 ++++++++++++++----- crates/cast/src/opts.rs | 24 +++++++++++++++++++++++- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/crates/cast/src/args.rs b/crates/cast/src/args.rs index cf2fea5e47d28..6b75b45927f64 100644 --- a/crates/cast/src/args.rs +++ b/crates/cast/src/args.rs @@ -368,12 +368,21 @@ pub async fn run_command(args: CastArgs) -> Result<()> { let who = who.resolve(&provider).await?; sh_println!("{}", Cast::new(provider).codesize(who, block).await?)? } - CastSubcommand::ComputeAddress { address, nonce, rpc } => { - let config = rpc.load_config()?; - let provider = utils::get_provider(&config)?; - + CastSubcommand::ComputeAddress { address, nonce, salt, init_code, init_code_hash, rpc } => { let address = stdin::unwrap_line(address)?; - let computed = Cast::new(provider).compute_address(address, nonce).await?; + let computed = { + // For CREATE2, init_code_hash is needed to compute the address + if let Some(init_code_hash) = init_code_hash { + address.create2(salt.unwrap_or(B256::ZERO), init_code_hash) + } else if let Some(init_code) = init_code { + address.create2(salt.unwrap_or(B256::ZERO), keccak256(hex::decode(init_code)?)) + } else { + // For CREATE, rpc is needed to compute the address + let config = rpc.load_config()?; + let provider = utils::get_provider(&config)?; + Cast::new(provider).compute_address(address, nonce).await? + } + }; sh_println!("Computed Address: {}", computed.to_checksum(None))? } CastSubcommand::Disassemble { bytecode } => { diff --git a/crates/cast/src/opts.rs b/crates/cast/src/opts.rs index 4ba86111bd9e4..f712f43bf0114 100644 --- a/crates/cast/src/opts.rs +++ b/crates/cast/src/opts.rs @@ -422,9 +422,31 @@ pub enum CastSubcommand { address: Option

, /// The nonce of the deployer address. - #[arg(long)] + #[arg( + long, + conflicts_with = "salt", + conflicts_with = "init_code", + conflicts_with = "init_code_hash" + )] nonce: Option, + /// The salt for CREATE2 address computation. + #[arg(long, conflicts_with = "nonce")] + salt: Option, + + /// The init code for CREATE2 address computation. + #[arg( + long, + requires = "salt", + conflicts_with = "init_code_hash", + conflicts_with = "nonce" + )] + init_code: Option, + + /// The init code hash for CREATE2 address computation. + #[arg(long, requires = "salt", conflicts_with = "init_code", conflicts_with = "nonce")] + init_code_hash: Option, + #[command(flatten)] rpc: RpcOpts, }, From d41712278508bb4f283aeeab352f6aa3848d8fab Mon Sep 17 00:00:00 2001 From: Ahsan Javaid <104683677+ahsan-javaiid@users.noreply.github.com> Date: Mon, 16 Jun 2025 14:38:47 +0500 Subject: [PATCH 207/244] show native token symbol on tx broadcast (#10770) * fix: show native token symbol on tx broadcast * Apply suggestions from code review --------- Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- crates/script/src/broadcast.rs | 9 +++++++-- crates/script/src/receipts.rs | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/crates/script/src/broadcast.rs b/crates/script/src/broadcast.rs index d40d03de2a0cc..6c8e3de6d228c 100644 --- a/crates/script/src/broadcast.rs +++ b/crates/script/src/broadcast.rs @@ -2,7 +2,7 @@ use crate::{ build::LinkedBuildData, progress::ScriptProgress, sequence::ScriptSequenceKind, verify::BroadcastedState, ScriptArgs, ScriptConfig, }; -use alloy_chains::Chain; +use alloy_chains::{Chain, NamedChain}; use alloy_consensus::TxEnvelope; use alloy_eips::{eip2718::Encodable2718, BlockId}; use alloy_network::{AnyNetwork, EthereumWallet, TransactionBuilder}; @@ -421,9 +421,14 @@ impl BundledState { let avg_gas_price = format_units(total_gas_price / sequence.receipts.len() as u64, 9) .unwrap_or_else(|_| "N/A".to_string()); + let token_symbol = NamedChain::try_from(sequence.chain) + .unwrap_or_default() + .native_currency_symbol() + .unwrap_or("ETH"); seq_progress.inner.write().set_status(&format!( - "Total Paid: {} ETH ({} gas * avg {} gwei)\n", + "Total Paid: {} {} ({} gas * avg {} gwei)\n", paid.trim_end_matches('0'), + token_symbol, total_gas, avg_gas_price.trim_end_matches('0').trim_end_matches('.') )); diff --git a/crates/script/src/receipts.rs b/crates/script/src/receipts.rs index 605cdf9ddb0de..afdd57fc7e940 100644 --- a/crates/script/src/receipts.rs +++ b/crates/script/src/receipts.rs @@ -1,4 +1,4 @@ -use alloy_chains::Chain; +use alloy_chains::{Chain, NamedChain}; use alloy_network::AnyTransactionReceipt; use alloy_primitives::{utils::format_units, TxHash, U256}; use alloy_provider::{PendingTransactionBuilder, PendingTransactionError, Provider, WatchTxError}; @@ -99,9 +99,14 @@ pub fn format_receipt(chain: Chain, receipt: &AnyTransactionReceipt) -> String { .unwrap_or_else(|_| "N/A".into()); let gas_price = format_units(U256::from(gas_price), 9).unwrap_or_else(|_| "N/A".into()); + let token_symbol = NamedChain::try_from(chain) + .unwrap_or_default() + .native_currency_symbol() + .unwrap_or("ETH"); format!( - "Paid: {} ETH ({gas_used} gas * {} gwei)", + "Paid: {} {} ({gas_used} gas * {} gwei)", paid.trim_end_matches('0'), + token_symbol, gas_price.trim_end_matches('0').trim_end_matches('.') ) }, From 2ddd74aad812411ee59729bfd59bc764a22253ea Mon Sep 17 00:00:00 2001 From: 0xrusowsky <90208954+0xrusowsky@users.noreply.github.com> Date: Mon, 16 Jun 2025 12:57:32 +0200 Subject: [PATCH 208/244] chore: add hash to eip-712 cmd (#10764) * chore: add hash to eip-712 cmd * fix: windows path * feat: add --json flag to forge eip712 command * style: fmt * style: std names * style: lint * fix: free-standing structs * style: clippy --- crates/forge/src/cmd/eip712.rs | 71 +++++++++++++++- crates/forge/tests/cli/eip712.rs | 134 ++++++++++++++++++++++++++++--- 2 files changed, 192 insertions(+), 13 deletions(-) diff --git a/crates/forge/src/cmd/eip712.rs b/crates/forge/src/cmd/eip712.rs index 2df5087592f00..eeaaae4f8b4a0 100644 --- a/crates/forge/src/cmd/eip712.rs +++ b/crates/forge/src/cmd/eip712.rs @@ -1,6 +1,8 @@ +use alloy_primitives::{keccak256, B256}; use clap::{Parser, ValueHint}; use eyre::Result; use foundry_cli::opts::{solar_pcx_from_build_opts, BuildOpts}; +use serde::Serialize; use solar_parse::interface::Session; use solar_sema::{ hir::StructId, @@ -8,7 +10,11 @@ use solar_sema::{ ty::{Ty, TyKind}, GcxWrapper, Hir, }; -use std::{collections::BTreeMap, fmt::Write, path::PathBuf}; +use std::{ + collections::BTreeMap, + fmt::{Display, Formatter, Result as FmtResult, Write}, + path::{Path, PathBuf}, +}; foundry_config::impl_figment_convert!(Eip712Args, build); @@ -19,10 +25,30 @@ pub struct Eip712Args { #[arg(value_hint = ValueHint::FilePath, value_name = "PATH")] pub target_path: PathBuf, + /// Output in JSON format. + #[arg(long, help = "Output in JSON format")] + pub json: bool, + #[command(flatten)] build: BuildOpts, } +#[derive(Debug, Serialize)] +struct Eip712Output { + path: String, + #[serde(rename = "type")] + typ: String, + hash: B256, +} + +impl Display for Eip712Output { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + writeln!(f, "{}:", self.path)?; + writeln!(f, " - type: {}", self.typ)?; + writeln!(f, " - hash: {}", self.hash) + } +} + impl Eip712Args { pub fn run(self) -> Result<()> { let mut sess = Session::builder().with_stderr_emitter().build(); @@ -37,9 +63,25 @@ impl Eip712Args { let hir_arena = ThreadLocal::new(); if let Ok(Some(gcx)) = parsing_context.parse_and_lower(&hir_arena) { let resolver = Resolver::new(gcx); - for id in &resolver.struct_ids() { - if let Some(resolved) = resolver.resolve_struct_eip712(*id) { - _ = sh_println!("{resolved}\n"); + + let outputs = resolver + .struct_ids() + .iter() + .filter_map(|id| { + let resolved = resolver.resolve_struct_eip712(*id)?; + Some(Eip712Output { + path: resolver.get_struct_path(*id), + hash: keccak256(resolved.as_bytes()), + typ: resolved, + }) + }) + .collect::>(); + + if self.json { + sh_println!("{json}", json = serde_json::to_string_pretty(&outputs)?)?; + } else { + for output in &outputs { + sh_println!("{output}")?; } } } @@ -72,6 +114,27 @@ impl<'hir> Resolver<'hir> { self.hir.strukt_ids().collect() } + /// Returns the path for a struct, with the format: `file.sol > MyContract > MyStruct` + pub fn get_struct_path(&self, id: StructId) -> String { + let strukt = self.hir.strukt(id).name.as_str(); + match self.hir.strukt(id).contract { + Some(cid) => { + let full_name = self.gcx.get().contract_fully_qualified_name(cid).to_string(); + let relevant = Path::new(&full_name) + .file_name() + .and_then(|s| s.to_str()) + .unwrap_or(&full_name); + + if let Some((file, contract)) = relevant.rsplit_once(':') { + format!("{file} > {contract} > {strukt}") + } else { + format!("{relevant} > {strukt}") + } + } + None => strukt.to_string(), + } + } + /// Converts a given struct into its EIP-712 `encodeType` representation. /// /// Returns `None` if the struct, or any of its fields, contains constructs diff --git a/crates/forge/tests/cli/eip712.rs b/crates/forge/tests/cli/eip712.rs index 165942563d157..d7df5fa333579 100644 --- a/crates/forge/tests/cli/eip712.rs +++ b/crates/forge/tests/cli/eip712.rs @@ -57,23 +57,139 @@ library Structs2 { cmd.forge_fuse().args(["eip712", path.to_string_lossy().as_ref()]).assert_success().stdout_eq( str![[r#" -Foo(Bar bar)Art(uint256 id)Bar(Art art) +Structs.sol > Structs > Foo: + - type: Foo(Bar bar)Art(uint256 id)Bar(Art art) + - hash: 0x6d9b732373bd999fde4072274c752e03f7437067dd75521eb406d8edf1d30f7d -Bar(Art art)Art(uint256 id) +Structs.sol > Structs > Bar: + - type: Bar(Art art)Art(uint256 id) + - hash: 0xadeb03f4f98fb57c05c9a79d8dd2348220e9bd9fd332ec2fbd92479e5695a596 -Art(uint256 id) +Structs.sol > Structs > Art: + - type: Art(uint256 id) + - hash: 0xbfeb9da97f9dbc2403e9d5ec3853f36414cae141d772601f24e0097d159d302b -Complex(Foo foo2,Foo_1[] foos,Rec[][] recs)Art(uint256 id)Bar(Art art)Foo(uint256 id)Foo_1(Bar bar)Rec(Rec[] rec) +Structs.sol > Structs > Complex: + - type: Complex(Foo foo2,Foo_1[] foos,Rec[][] recs)Art(uint256 id)Bar(Art art)Foo(uint256 id)Foo_1(Bar bar)Rec(Rec[] rec) + - hash: 0xfb0a234a82efcade7c031ebb4c58afd7f5f242ca67ed06f4050c60044dcee425 -Rec(Rec[] rec) +Structs.sol > Structs > Rec: + - type: Rec(Rec[] rec) + - hash: 0x5f060eb740f5aee93a910587a100458c724479d189f6dd67ac39048bf312102e -Foo(uint256 id) +Structs.sol > Structs2 > Foo: + - type: Foo(uint256 id) + - hash: 0xb93d8bb2877cd5cc51979d9fe85339ab570714a6fd974225e2a763851092497e -Rec(Bar[] bar)Bar(Rec rec) +Structs.sol > Structs2 > Rec: + - type: Rec(Bar[] bar)Bar(Rec rec) + - hash: 0xe9dded72c72648f27772620cb4e10b773ce31a3ea26ef980c0b39d1834242cda -Bar(Rec rec)Rec(Bar[] bar) +Structs.sol > Structs2 > Bar: + - type: Bar(Rec rec)Rec(Bar[] bar) + - hash: 0x164eba932ecde04ec75feba228664d08f29c88d6a67e531757e023e6063c3b2c -FooBar(Foo[] foos,Bar[] bars,Foo_1 foo,Bar_1 bar,Rec[] recs,Rec_1 rec)Art(uint256 id)Bar(Rec rec)Bar_1(Art art)Foo(uint256 id)Foo_1(Bar_1 bar)Rec(Bar[] bar)Rec_1(Rec_1[] rec) +Structs.sol > Structs2 > FooBar: + - type: FooBar(Foo[] foos,Bar[] bars,Foo_1 foo,Bar_1 bar,Rec[] recs,Rec_1 rec)Art(uint256 id)Bar(Rec rec)Bar_1(Art art)Foo(uint256 id)Foo_1(Bar_1 bar)Rec(Bar[] bar)Rec_1(Rec_1[] rec) + - hash: 0xce88f333fe5b5d4901ceb2569922ffe741cda3afc383a63d34ed2c3d565e42d8 + + +"#]], + ); + + cmd.forge_fuse().args(["eip712", path.to_string_lossy().as_ref(), "--json"]).assert_success().stdout_eq( + str![[r#" +[ + { + "path": "Structs.sol > Structs > Foo", + "type": "Foo(Bar bar)Art(uint256 id)Bar(Art art)", + "hash": "0x6d9b732373bd999fde4072274c752e03f7437067dd75521eb406d8edf1d30f7d" + }, + { + "path": "Structs.sol > Structs > Bar", + "type": "Bar(Art art)Art(uint256 id)", + "hash": "0xadeb03f4f98fb57c05c9a79d8dd2348220e9bd9fd332ec2fbd92479e5695a596" + }, + { + "path": "Structs.sol > Structs > Art", + "type": "Art(uint256 id)", + "hash": "0xbfeb9da97f9dbc2403e9d5ec3853f36414cae141d772601f24e0097d159d302b" + }, + { + "path": "Structs.sol > Structs > Complex", + "type": "Complex(Foo foo2,Foo_1[] foos,Rec[][] recs)Art(uint256 id)Bar(Art art)Foo(uint256 id)Foo_1(Bar bar)Rec(Rec[] rec)", + "hash": "0xfb0a234a82efcade7c031ebb4c58afd7f5f242ca67ed06f4050c60044dcee425" + }, + { + "path": "Structs.sol > Structs > Rec", + "type": "Rec(Rec[] rec)", + "hash": "0x5f060eb740f5aee93a910587a100458c724479d189f6dd67ac39048bf312102e" + }, + { + "path": "Structs.sol > Structs2 > Foo", + "type": "Foo(uint256 id)", + "hash": "0xb93d8bb2877cd5cc51979d9fe85339ab570714a6fd974225e2a763851092497e" + }, + { + "path": "Structs.sol > Structs2 > Rec", + "type": "Rec(Bar[] bar)Bar(Rec rec)", + "hash": "0xe9dded72c72648f27772620cb4e10b773ce31a3ea26ef980c0b39d1834242cda" + }, + { + "path": "Structs.sol > Structs2 > Bar", + "type": "Bar(Rec rec)Rec(Bar[] bar)", + "hash": "0x164eba932ecde04ec75feba228664d08f29c88d6a67e531757e023e6063c3b2c" + }, + { + "path": "Structs.sol > Structs2 > FooBar", + "type": "FooBar(Foo[] foos,Bar[] bars,Foo_1 foo,Bar_1 bar,Rec[] recs,Rec_1 rec)Art(uint256 id)Bar(Rec rec)Bar_1(Art art)Foo(uint256 id)Foo_1(Bar_1 bar)Rec(Bar[] bar)Rec_1(Rec_1[] rec)", + "hash": "0xce88f333fe5b5d4901ceb2569922ffe741cda3afc383a63d34ed2c3d565e42d8" + } +] + +"#]], + ); +}); + +forgetest!(test_eip712_free_standing_structs, |prj, cmd| { + let path = prj + .add_source( + "FreeStandingStructs.sol", + r#" +// free-standing struct (outside a contract and lib) +struct FreeStanding { + uint256 id; + string name; +} + +contract InsideContract { + struct ContractStruct { + uint256 value; + } +} + +library InsideLibrary { + struct LibraryStruct { + bytes32 hash; + } +} +"#, + ) + .unwrap(); + + cmd.forge_fuse().args(["eip712", path.to_string_lossy().as_ref()]).assert_success().stdout_eq( + str![[r#" +FreeStanding: + - type: FreeStanding(uint256 id,string name) + - hash: 0xfb3c934b2382873277133498bde6eb3914ab323e3bef8b373ebcd423969bf1a2 + +FreeStandingStructs.sol > InsideContract > ContractStruct: + - type: ContractStruct(uint256 value) + - hash: 0xfb63263e7cf823ff50385a991cb1bd5c1ff46b58011119984d52f8736331e3fe + +FreeStandingStructs.sol > InsideLibrary > LibraryStruct: + - type: LibraryStruct(bytes32 hash) + - hash: 0x81d6d25f4d37549244d76a68f23ecdcbf3ae81e5a361ed6c492b6a2e126a2843 "#]], From c49d3638d16bb204d61718c57793abf2be2e3862 Mon Sep 17 00:00:00 2001 From: Toki <105550481+gitToki@users.noreply.github.com> Date: Tue, 17 Jun 2025 11:37:34 +0200 Subject: [PATCH 209/244] bug(anvil): incorrectly adds +1 gas when estimating transactions with explicit empty data field (#10786) * no input + empty input / test * indent * fmt * clippy * add no account auth verif --- crates/anvil/src/eth/api.rs | 4 +++- crates/anvil/tests/it/gas.rs | 43 ++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 57af0e68eef84..fe5ea80838b1e 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -2905,7 +2905,9 @@ impl EthApi { let to = request.to.as_ref().and_then(TxKind::to); // check certain fields to see if the request could be a simple transfer - let maybe_transfer = request.input.input().is_none() && + let maybe_transfer = (request.input.input().is_none() || + request.input.input().is_some_and(|data| data.is_empty())) && + request.authorization_list.is_none() && request.access_list.is_none() && request.blob_versioned_hashes.is_none(); diff --git a/crates/anvil/tests/it/gas.rs b/crates/anvil/tests/it/gas.rs index f3bcd01ddfe47..24f09d7358a0b 100644 --- a/crates/anvil/tests/it/gas.rs +++ b/crates/anvil/tests/it/gas.rs @@ -215,3 +215,46 @@ async fn test_can_use_fee_history() { assert_eq!(latest_fee_history_fee, next_base_fee as u64); } } + +#[tokio::test(flavor = "multi_thread")] +async fn test_estimate_gas_empty_data() { + let (api, handle) = spawn(NodeConfig::test()).await; + let accounts = handle.dev_accounts().collect::>(); + let from = accounts[0]; + let to = accounts[1]; + + let tx_without_data = + TransactionRequest::default().with_from(from).with_to(to).with_value(U256::from(1)); + + let gas_without_data = api + .estimate_gas(WithOtherFields::new(tx_without_data), None, Default::default()) + .await + .unwrap(); + + let tx_with_empty_data = TransactionRequest::default() + .with_from(from) + .with_to(to) + .with_value(U256::from(1)) + .with_input(vec![]); + + let gas_with_empty_data = api + .estimate_gas(WithOtherFields::new(tx_with_empty_data), None, Default::default()) + .await + .unwrap(); + + let tx_with_data = TransactionRequest::default() + .with_from(from) + .with_to(to) + .with_value(U256::from(1)) + .with_input(vec![0x12, 0x34]); + + let gas_with_data = api + .estimate_gas(WithOtherFields::new(tx_with_data), None, Default::default()) + .await + .unwrap(); + + assert_eq!(gas_without_data, U256::from(GAS_TRANSFER)); + assert_eq!(gas_with_empty_data, U256::from(GAS_TRANSFER)); + assert!(gas_with_data > U256::from(GAS_TRANSFER)); + assert_eq!(gas_without_data, gas_with_empty_data); +} From 9ac31cdf725ea4e57c065b3339d4afef9a831ac3 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Tue, 17 Jun 2025 12:18:47 +0200 Subject: [PATCH 210/244] fix: eip712, bind-json solar cleanups (#10789) * fix: eip712, bind-json solar cleanups * rm hir field --- crates/forge/src/cmd/bind_json.rs | 12 ++--- crates/forge/src/cmd/eip712.rs | 77 ++++++++++++++++--------------- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/crates/forge/src/cmd/bind_json.rs b/crates/forge/src/cmd/bind_json.rs index ecb76515b16a3..fc5ca28bccdf7 100644 --- a/crates/forge/src/cmd/bind_json.rs +++ b/crates/forge/src/cmd/bind_json.rs @@ -263,7 +263,7 @@ impl PreprocessedState { let mut sess = Session::builder().with_stderr_emitter().build(); sess.dcx = sess.dcx.set_flags(|flags| flags.track_diagnostics = false); - let result = sess.enter_parallel(|| -> Result<()> { + sess.enter_parallel(|| -> Result<()> { // Set up the parsing context with the project paths, without adding the source files let mut parsing_context = solar_pcx_from_solc_project(&sess, &project, &input, false); @@ -297,9 +297,9 @@ impl PreprocessedState { if let Ok(Some(gcx)) = parsing_context.parse_and_lower(&hir_arena) { let hir = &gcx.get().hir; let resolver = Resolver::new(gcx); - for id in &resolver.struct_ids() { - if let Some(schema) = resolver.resolve_struct_eip712(*id) { - let def = hir.strukt(*id); + for id in resolver.struct_ids() { + if let Some(schema) = resolver.resolve_struct_eip712(id) { + let def = hir.strukt(id); let source = hir.source(def.source); if !target_files.contains(&source.file.stable_id) { @@ -327,9 +327,9 @@ impl PreprocessedState { } } Ok(()) - }); + })?; - eyre::ensure!(result.is_ok() && sess.dcx.has_errors().is_ok(), "failed parsing"); + eyre::ensure!(sess.dcx.has_errors().is_ok(), "errors occurred"); Ok(StructsState { structs_to_write, target_path }) } diff --git a/crates/forge/src/cmd/eip712.rs b/crates/forge/src/cmd/eip712.rs index eeaaae4f8b4a0..4c7196ac5ddd5 100644 --- a/crates/forge/src/cmd/eip712.rs +++ b/crates/forge/src/cmd/eip712.rs @@ -54,42 +54,42 @@ impl Eip712Args { let mut sess = Session::builder().with_stderr_emitter().build(); sess.dcx = sess.dcx.set_flags(|flags| flags.track_diagnostics = false); - let result = sess.enter(|| -> Result<()> { + sess.enter_parallel(|| -> Result<()> { // Set up the parsing context with the project paths and sources. let parsing_context = solar_pcx_from_build_opts(&sess, self.build, Some(vec![self.target_path]))?; // Parse and resolve let hir_arena = ThreadLocal::new(); - if let Ok(Some(gcx)) = parsing_context.parse_and_lower(&hir_arena) { - let resolver = Resolver::new(gcx); - - let outputs = resolver - .struct_ids() - .iter() - .filter_map(|id| { - let resolved = resolver.resolve_struct_eip712(*id)?; - Some(Eip712Output { - path: resolver.get_struct_path(*id), - hash: keccak256(resolved.as_bytes()), - typ: resolved, - }) + let Ok(Some(gcx)) = parsing_context.parse_and_lower(&hir_arena) else { + return Err(eyre::eyre!("failed parsing")); + }; + let resolver = Resolver::new(gcx); + + let outputs = resolver + .struct_ids() + .filter_map(|id| { + let resolved = resolver.resolve_struct_eip712(id)?; + Some(Eip712Output { + path: resolver.get_struct_path(id), + hash: keccak256(resolved.as_bytes()), + typ: resolved, }) - .collect::>(); - - if self.json { - sh_println!("{json}", json = serde_json::to_string_pretty(&outputs)?)?; - } else { - for output in &outputs { - sh_println!("{output}")?; - } + }) + .collect::>(); + + if self.json { + sh_println!("{json}", json = serde_json::to_string_pretty(&outputs)?)?; + } else { + for output in &outputs { + sh_println!("{output}")?; } } Ok(()) - }); + })?; - eyre::ensure!(result.is_ok() && sess.dcx.has_errors().is_ok(), "failed parsing"); + eyre::ensure!(sess.dcx.has_errors().is_ok(), "errors occurred"); Ok(()) } @@ -99,25 +99,29 @@ impl Eip712Args { /// /// Requires a reference to the source HIR. pub struct Resolver<'hir> { - hir: &'hir Hir<'hir>, gcx: GcxWrapper<'hir>, } impl<'hir> Resolver<'hir> { /// Constructs a new [`Resolver`] for the supplied [`Hir`] instance. pub fn new(gcx: GcxWrapper<'hir>) -> Self { - Self { hir: &gcx.get().hir, gcx } + Self { gcx } + } + + #[inline] + fn hir(&self) -> &'hir Hir<'hir> { + &self.gcx.get().hir } /// Returns the [`StructId`]s of every user-defined struct in source order. - pub fn struct_ids(&self) -> Vec { - self.hir.strukt_ids().collect() + pub fn struct_ids(&self) -> impl Iterator { + self.hir().strukt_ids() } /// Returns the path for a struct, with the format: `file.sol > MyContract > MyStruct` pub fn get_struct_path(&self, id: StructId) -> String { - let strukt = self.hir.strukt(id).name.as_str(); - match self.hir.strukt(id).contract { + let strukt = self.hir().strukt(id).name.as_str(); + match self.hir().strukt(id).contract { Some(cid) => { let full_name = self.gcx.get().contract_fully_qualified_name(cid).to_string(); let relevant = Path::new(&full_name) @@ -141,7 +145,7 @@ impl<'hir> Resolver<'hir> { /// not supported by EIP-712 (mappings, function types, errors, etc). pub fn resolve_struct_eip712(&self, id: StructId) -> Option { let mut subtypes = BTreeMap::new(); - subtypes.insert(self.hir.strukt(id).name.as_str().into(), id); + subtypes.insert(self.hir().strukt(id).name.as_str().into(), id); self.resolve_eip712_inner(id, &mut subtypes, true, None) } @@ -152,11 +156,11 @@ impl<'hir> Resolver<'hir> { append_subtypes: bool, rename: Option<&str>, ) -> Option { - let def = self.hir.strukt(id); + let def = self.hir().strukt(id); let mut result = format!("{}(", rename.unwrap_or(def.name.as_str())); for (idx, field_id) in def.fields.iter().enumerate() { - let field = self.hir.variable(*field_id); + let field = self.hir().variable(*field_id); let ty = self.resolve_type(self.gcx.get().type_of_hir_ty(&field.ty), subtypes)?; write!(result, "{ty} {name}", name = field.name?.as_str()).ok()?; @@ -204,7 +208,7 @@ impl<'hir> Resolver<'hir> { } TyKind::Udvt(ty, _) => self.resolve_type(ty, subtypes), TyKind::Struct(id) => { - let def = self.hir.strukt(id); + let def = self.hir().strukt(id); let name = match subtypes.iter().find(|(_, cached_id)| id == **cached_id) { Some((name, _)) => name.to_string(), None => { @@ -219,9 +223,8 @@ impl<'hir> Resolver<'hir> { subtypes.insert(name.clone(), id); // Recursively resolve fields to populate subtypes - for field_id in def.fields { - let field_ty = - self.gcx.get().type_of_hir_ty(&self.hir.variable(*field_id).ty); + for &field_id in def.fields { + let field_ty = self.gcx.get().type_of_item(field_id.into()); self.resolve_type(field_ty, subtypes)?; } name From b515c90b9be9645b844943fc6d54f2304b83f75f Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Tue, 17 Jun 2025 12:54:30 +0200 Subject: [PATCH 211/244] ci: don't check all features (#10790) --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0486f2237f10b..d5e21a495e6b0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -109,7 +109,7 @@ jobs: - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true - - run: cargo hack check --each-feature --exclude-features isolate-by-default + - run: cargo hack check deny: uses: ithacaxyz/ci/.github/workflows/deny.yml@main From 6ceff665477434e38637e741a20d9c9b25e0fffd Mon Sep 17 00:00:00 2001 From: Soubhik Singha Mahapatra <160333583+Soubhik-10@users.noreply.github.com> Date: Wed, 18 Jun 2025 14:11:54 +0530 Subject: [PATCH 212/244] feat: added block.time and block.number override in cast (#10727) * added time override * docs * docs * docs * again doc * block.time as u64 * block.number * alloy bump * fixes * typo * cargo update * fix test * apply review --------- Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> Co-authored-by: Arsenii Kulikov --- Cargo.lock | 205 ++++++++++-------- Cargo.toml | 44 ++-- crates/cast/src/cmd/call.rs | 31 ++- crates/cast/src/lib.rs | 14 +- .../cheats/BroadcastRawTransaction.t.sol | 2 +- 5 files changed, 171 insertions(+), 125 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5c3a4af06567e..fe0c4dcc5d780 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,15 +70,16 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad451f9a70c341d951bca4e811d74dbe1e193897acd17e9dbac1353698cc430b" +checksum = "659c33e85c4a9f8bb1b9a2400f4f3d0dd52fbc4bd3650e08d22df1e17d5d92ee" dependencies = [ "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-serde", "alloy-trie", + "alloy-tx-macros", "auto_impl", "c-kzg", "derive_more 2.0.1", @@ -94,9 +95,9 @@ dependencies = [ [[package]] name = "alloy-consensus-any" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142daffb15d5be1a2b20d2cd540edbcef03037b55d4ff69dc06beb4d06286dba" +checksum = "d48fdc146414932cec2114f749f5f65a8960ee7547b1638a97bb0d04160d09e4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -108,9 +109,9 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebf25443920ecb9728cb087fe4dc04a0b290bd6ac85638c58fe94aba70f1a44e" +checksum = "c711bfed1579611565ab831166c7bbaf123baea785ea945f02ed3620950f6fe1" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -125,6 +126,7 @@ dependencies = [ "alloy-transport", "futures", "futures-util", + "serde_json", "thiserror 2.0.12", ] @@ -187,9 +189,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3056872f6da48046913e76edb5ddced272861f6032f09461aea1a2497be5ae5d" +checksum = "8390cb5c872d53560635dabc02d616c1bb626dd0f7d6893f8725edb822573fed" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -207,9 +209,9 @@ dependencies = [ [[package]] name = "alloy-ens" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "939f8a617f883de8c8da812fa1164abe83f5ece081322ac072483fa0775a9898" +checksum = "0dc0a11ddee117c05e7c614d6cb6fcf87d6aed6a449a4ccca656e5bbfbd0cc8c" dependencies = [ "alloy-contract", "alloy-primitives", @@ -240,9 +242,9 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c98fb40f07997529235cc474de814cd7bd9de561e101716289095696c0e4639d" +checksum = "a18ce1538291d8409d4a7d826176d461a6f9eb28632d7185f801bda43a138260" dependencies = [ "alloy-eips", "alloy-primitives", @@ -278,12 +280,13 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc08b31ebf9273839bd9a01f9333cbb7a3abb4e820c312ade349dd18bdc79581" +checksum = "0b91481d12dcd964f4a838271d6abffac2d4082695fc3f73a15429166ea1692d" dependencies = [ "alloy-primitives", "alloy-sol-types", + "http 1.3.1", "serde", "serde_json", "thiserror 2.0.12", @@ -292,9 +295,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed117b08f0cc190312bf0c38c34cf4f0dabfb4ea8f330071c587cd7160a88cb2" +checksum = "c8b245fa9d76cc9fc58cf78844f2d4e481333449ba679b2044f09b983fc96f85" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -318,9 +321,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7162ff7be8649c0c391f4e248d1273e85c62076703a1f3ec7daf76b283d886d" +checksum = "7cecb975fc2f2e1eb09c513428c34e0d8c13e28b5ff1dbdf68e0f64a1a92c5f3" dependencies = [ "alloy-consensus", "alloy-eips", @@ -389,9 +392,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d84eba1fd8b6fe8b02f2acd5dd7033d0f179e304bd722d11e817db570d1fa6c4" +checksum = "ecac2cbea1cb3da53b4e68a078e57f9da8d12d86e2017db1240df222e2498397" dependencies = [ "alloy-chains", "alloy-consensus", @@ -419,6 +422,7 @@ dependencies = [ "either", "futures", "futures-utils-wasm", + "http 1.3.1", "lru 0.13.0", "parking_lot", "pin-project 1.1.10", @@ -434,9 +438,9 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8550f7306e0230fc835eb2ff4af0a96362db4b6fc3f25767d161e0ad0ac765bf" +checksum = "db1d3c2316590910ba697485aa75cdafef89735010d338d197f8af5baa79df92" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -477,9 +481,9 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518a699422a3eab800f3dac2130d8f2edba8e4fff267b27a9c7dc6a2b0d313ee" +checksum = "e0bed8157038003c702dd1861a6b72d4b1a8f46aeffad35e81580223642170fa" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -505,9 +509,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c000cab4ec26a4b3e29d144e999e1c539c2fa0abed871bf90311eb3466187ca8" +checksum = "82fed036edc62cd79476fe0340277a1c47b07c173f6ac0244f24193e1183b8e4" dependencies = [ "alloy-primitives", "alloy-rpc-types-anvil", @@ -521,9 +525,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8abecc34549a208b5f91bc7f02df3205c36e2aa6586f1d9375c3382da1066b3b" +checksum = "9f2e3dc925ec6722524f8d7412b9a6845a3350c7037f8a37892ada00c9018125" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -533,9 +537,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "508b2fbe66d952089aa694e53802327798806498cd29ff88c75135770ecaabfc" +checksum = "caf6702dd7eb929068ab075869679e745d68c4eb611c5a0cf72617688b85b5f4" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -544,9 +548,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-debug" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c832f2e851801093928dbb4b7bd83cd22270faf76b2e080646b806a285c8757" +checksum = "0e982f72ff47c0f754cb6aa579e456220d768e1ec07675e66cfce970dad70292" dependencies = [ "alloy-primitives", "serde", @@ -554,9 +558,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab52691970553d84879d777419fa7b6a2e92e9fe8641f9324cc071008c2f656" +checksum = "505224e162e239980c6df7632c99f0bc5abbcf630017502810979e9e01f3c86e" dependencies = [ "alloy-consensus", "alloy-eips", @@ -572,9 +576,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcaf7dff0fdd756a714d58014f4f8354a1706ebf9fa2cf73431e0aeec3c9431e" +checksum = "20ff509ca40537042b7cc9bede6b415ef807c9c5c48024e9fe10b8c8ad0757ef" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -592,9 +596,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3507a04e868dd83219ad3cd6a8c58aefccb64d33f426b3934423a206343e84" +checksum = "51dc49d5865f2227c810a416c8d14141db7716a0174bfa6cff1c1a984b678b5e" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -606,9 +610,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eec36272621c3ac82b47dd77f0508346687730b1c2e3e10d3715705c217c0a05" +checksum = "c962ec5193084873353ad7a65568056b4e704203302e6ba81374e95a22deba4d" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -618,9 +622,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730e8f2edf2fc224cabd1c25d090e1655fa6137b2e409f92e5eec735903f1507" +checksum = "f9873512b1e99505f4a65e1d3a3105cb689f112f8e3cab3c632b20a97a46adae" dependencies = [ "alloy-primitives", "serde", @@ -629,9 +633,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b0d2428445ec13edc711909e023d7779618504c4800be055a5b940025dbafe3" +checksum = "c2d4d95d8431a11e0daee724c3b7635dc8e9d3d60d0b803023a8125c74a77899" dependencies = [ "alloy-dyn-abi", "alloy-primitives", @@ -646,9 +650,9 @@ dependencies = [ [[package]] name = "alloy-signer-aws" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6be3d371299b62eac5aa459fa58e8d1c761aabdc637573ae258ab744457fcc88" +checksum = "54a7daec95526f0e005b38ff9dbdcb74ed1a2ea28ea01b84d61b930880fe83f3" dependencies = [ "alloy-consensus", "alloy-network", @@ -664,9 +668,9 @@ dependencies = [ [[package]] name = "alloy-signer-gcp" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df298e47bbb7d0a8e06b603046b91062c11ba70d22f8a6c9bab1c1468bd856d0" +checksum = "7afc41138d41871c554f678c26ea8d1c7796d714996d66d2c618f4ac26cf7aba" dependencies = [ "alloy-consensus", "alloy-network", @@ -682,9 +686,9 @@ dependencies = [ [[package]] name = "alloy-signer-ledger" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0e049299cc7e131a438a904f89a493bcea45cd92bbed3e50116a28bc27987c" +checksum = "3546b3d813008ddf90f90f711d30d3fb5d0804ea42400d59bca1460d2ffb83f1" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -702,9 +706,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14fe6fedb7fe6e0dfae47fe020684f1d8e063274ef14bca387ddb7a6efa8ec1" +checksum = "cb03eca937485b258d8e791d143e95b50dbfae0e18f92e1b1271c38959cd00fb" dependencies = [ "alloy-consensus", "alloy-network", @@ -721,9 +725,9 @@ dependencies = [ [[package]] name = "alloy-signer-trezor" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c7df3624131eeecf74c18e5cd59bcc125633bad407b1938161edf89eb71485" +checksum = "66a28e40ca39d4c4a93165a951aa45554b6496f1439a882e96d9fed849c15ec2" dependencies = [ "alloy-consensus", "alloy-network", @@ -811,9 +815,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a712bdfeff42401a7dd9518f72f617574c36226a9b5414537fedc34350b73bf9" +checksum = "468a871d7ea52e31ef3abf5ccde612cb3723794f484d26dca6a04a3a776db739" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -834,9 +838,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ea5a76d7f2572174a382aedf36875bedf60bcc41116c9f031cf08040703a2dc" +checksum = "6e969c254b189f7da95f07bab53673dd418f8595abfe3397b2cf8d7ba7955487" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -849,9 +853,9 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "606af17a7e064d219746f6d2625676122c79d78bf73dfe746d6db9ecd7dbcb85" +checksum = "cb134aaa80c2e1e03eebc101e7c513f08a529726738506d8c306ec9f3c9a7f3b" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -869,9 +873,9 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c6f9b37cd8d44aab959613966cc9d4d7a9b429c575cec43b3e5b46ea109a79" +checksum = "e57f13346af9441cafa99d5b80d95c2480870dd18bd274464f7131df01ad692a" dependencies = [ "alloy-pubsub", "alloy-transport", @@ -901,6 +905,19 @@ dependencies = [ "tracing", ] +[[package]] +name = "alloy-tx-macros" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d642ba58c32547ad9742c613f9849a2aedc47914b02948224326e4cb62b91040" +dependencies = [ + "alloy-primitives", + "darling", + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "ammonia" version = "4.1.0" @@ -990,9 +1007,9 @@ dependencies = [ [[package]] name = "anstyle-svg" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c681338396641f4e32a29f045d0c70950da7207b4376685b51396c481ee36f1a" +checksum = "0a43964079ef399480603125d5afae2b219aceffb77478956e25f17b9bc3435c" dependencies = [ "anstyle", "anstyle-lossy", @@ -1472,9 +1489,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.24" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d615619615a650c571269c00dca41db04b9210037fa76ed8239f70404ab56985" +checksum = "40f6024f3f856663b45fd0c9b6f2024034a702f453549449e0d84a305900dad4" dependencies = [ "flate2", "futures-core", @@ -3184,9 +3201,9 @@ dependencies = [ [[package]] name = "derive-where" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e73f2692d4bd3cac41dca28934a39894200c9fabf49586d77d0e5954af1d7902" +checksum = "510c292c8cf384b1a340b816a9a6cf2599eb8f566a44949024af88418000c50b" dependencies = [ "proc-macro2", "quote", @@ -5755,9 +5772,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libmimalloc-sys" -version = "0.1.42" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec9d6fac27761dabcd4ee73571cdb06b7022dc99089acbe5435691edffaac0f4" +checksum = "bf88cd67e9de251c1781dbe2f641a1a3ad66eaae831b8a2c38fbdc5ddae16d4d" dependencies = [ "cc", "libc", @@ -6066,9 +6083,9 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.46" +version = "0.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995942f432bbb4822a7e9c3faa87a695185b0d09273ba85f097b54f4e458f2af" +checksum = "b1791cbe101e95af5764f06f20f6760521f7158f69dbf9d6baf941ee1bf6bc40" dependencies = [ "libmimalloc-sys", ] @@ -6150,9 +6167,9 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "newtype-uuid" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8ba303c7a8f8fdee1fe1513cfd918f50f1c69bf65c91b39217bfc2b2af5c081" +checksum = "d5825f69cf354438a53f85b959f0baa6a7ada1f4bd923f63e42c34090bf288fb" dependencies = [ "uuid 1.17.0", ] @@ -6745,9 +6762,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", "thiserror 2.0.12", @@ -6756,9 +6773,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" +checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" dependencies = [ "pest", "pest_generator", @@ -6766,9 +6783,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" +checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966" dependencies = [ "pest", "pest_meta", @@ -6779,11 +6796,10 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" +checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5" dependencies = [ - "once_cell", "pest", "sha2 0.10.9", ] @@ -7304,9 +7320,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "radium" @@ -7985,9 +8001,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.27" +version = "0.23.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" dependencies = [ "aws-lc-rs", "log", @@ -8567,12 +8583,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" [[package]] name = "smallvec" @@ -9577,9 +9590,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", @@ -10158,9 +10171,9 @@ dependencies = [ [[package]] name = "wasmtimer" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0048ad49a55b9deb3953841fa1fc5858f0efbcb7a18868c899a360269fac1b23" +checksum = "d8d49b5d6c64e8558d9b1b065014426f35c18de636895d24893dbbd329743446" dependencies = [ "futures", "js-sys", diff --git a/Cargo.toml b/Cargo.toml index d635ea33ac0fc..6a0eee283ddc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -213,28 +213,28 @@ solar-interface = { version = "=0.1.4", default-features = false } solar-sema = { version = "=0.1.4", default-features = false } ## alloy -alloy-consensus = { version = "1.0.9", default-features = false } -alloy-contract = { version = "1.0.9", default-features = false } -alloy-eips = { version = "1.0.9", default-features = false } -alloy-ens = { version = "1.0.9", default-features = false } -alloy-genesis = { version = "1.0.9", default-features = false } -alloy-json-rpc = { version = "1.0.9", default-features = false } -alloy-network = { version = "1.0.9", default-features = false } -alloy-provider = { version = "1.0.9", default-features = false } -alloy-pubsub = { version = "1.0.9", default-features = false } -alloy-rpc-client = { version = "1.0.9", default-features = false } -alloy-rpc-types = { version = "1.0.9", default-features = true } -alloy-serde = { version = "1.0.9", default-features = false } -alloy-signer = { version = "1.0.9", default-features = false } -alloy-signer-aws = { version = "1.0.9", default-features = false } -alloy-signer-gcp = { version = "1.0.9", default-features = false } -alloy-signer-ledger = { version = "1.0.9", default-features = false } -alloy-signer-local = { version = "1.0.9", default-features = false } -alloy-signer-trezor = { version = "1.0.9", default-features = false } -alloy-transport = { version = "1.0.9", default-features = false } -alloy-transport-http = { version = "1.0.9", default-features = false } -alloy-transport-ipc = { version = "1.0.9", default-features = false } -alloy-transport-ws = { version = "1.0.9", default-features = false } +alloy-consensus = { version = "1.0.11", default-features = false } +alloy-contract = { version = "1.0.11", default-features = false } +alloy-eips = { version = "1.0.11", default-features = false } +alloy-ens = { version = "1.0.11", default-features = false } +alloy-genesis = { version = "1.0.11", default-features = false } +alloy-json-rpc = { version = "1.0.11", default-features = false } +alloy-network = { version = "1.0.11", default-features = false } +alloy-provider = { version = "1.0.11", default-features = false } +alloy-pubsub = { version = "1.0.11", default-features = false } +alloy-rpc-client = { version = "1.0.11", default-features = false } +alloy-rpc-types = { version = "1.0.11", default-features = true } +alloy-serde = { version = "1.0.11", default-features = false } +alloy-signer = { version = "1.0.11", default-features = false } +alloy-signer-aws = { version = "1.0.11", default-features = false } +alloy-signer-gcp = { version = "1.0.11", default-features = false } +alloy-signer-ledger = { version = "1.0.11", default-features = false } +alloy-signer-local = { version = "1.0.11", default-features = false } +alloy-signer-trezor = { version = "1.0.11", default-features = false } +alloy-transport = { version = "1.0.11", default-features = false } +alloy-transport-http = { version = "1.0.11", default-features = false } +alloy-transport-ipc = { version = "1.0.11", default-features = false } +alloy-transport-ws = { version = "1.0.11", default-features = false } alloy-hardforks = { version = "0.2.6", default-features = false } alloy-op-hardforks = { version = "0.2.6", default-features = false } diff --git a/crates/cast/src/cmd/call.rs b/crates/cast/src/cmd/call.rs index c92bedaadf192..c329dbe3cc717 100644 --- a/crates/cast/src/cmd/call.rs +++ b/crates/cast/src/cmd/call.rs @@ -7,7 +7,7 @@ use alloy_ens::NameOrAddress; use alloy_primitives::{Address, Bytes, TxKind, U256}; use alloy_rpc_types::{ state::{StateOverride, StateOverridesBuilder}, - BlockId, BlockNumberOrTag, + BlockId, BlockNumberOrTag, BlockOverrides, }; use clap::Parser; use eyre::Result; @@ -148,6 +148,14 @@ pub struct CallArgs { /// Format: address:slot:value #[arg(long = "override-state-diff", value_name = "ADDRESS:SLOT:VALUE")] pub state_diff_overrides: Option>, + + /// Override the block timestamp. + #[arg(long = "block.time", value_name = "TIME")] + pub block_time: Option, + + /// Override the block number. + #[arg(long = "block.number", value_name = "NUMBER")] + pub block_number: Option, } #[derive(Debug, Parser)] @@ -180,6 +188,7 @@ impl CallArgs { let evm_opts = figment.extract::()?; let mut config = Config::from_provider(figment)?.sanitized(); let state_overrides = self.get_state_overrides()?; + let block_overrides = self.get_block_overrides()?; let Self { to, @@ -308,7 +317,9 @@ impl CallArgs { sh_println!( "{}", - Cast::new(provider).call(&tx, func.as_ref(), block, state_overrides).await? + Cast::new(provider) + .call(&tx, func.as_ref(), block, state_overrides, block_overrides) + .await? )?; Ok(()) @@ -368,6 +379,22 @@ impl CallArgs { Ok(Some(state_overrides_builder.build())) } + + /// Parse block overrides from command line arguments. + pub fn get_block_overrides(&self) -> eyre::Result> { + let mut overrides = BlockOverrides::default(); + if let Some(number) = self.block_number { + overrides = overrides.with_number(U256::from(number)); + } + if let Some(time) = self.block_time { + overrides = overrides.with_time(time); + } + if overrides.is_empty() { + Ok(None) + } else { + Ok(Some(overrides)) + } + } } impl figment::Provider for CallArgs { diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 1a47c6877238a..ac8b08b5cc291 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -19,7 +19,7 @@ use alloy_provider::{ }; use alloy_rlp::Decodable; use alloy_rpc_types::{ - state::StateOverride, BlockId, BlockNumberOrTag, Filter, TransactionRequest, + state::StateOverride, BlockId, BlockNumberOrTag, BlockOverrides, Filter, TransactionRequest, }; use alloy_serde::WithOtherFields; use alloy_sol_types::sol; @@ -110,7 +110,7 @@ impl> Cast

{ /// /// ``` /// use alloy_primitives::{Address, U256, Bytes}; - /// use alloy_rpc_types::{TransactionRequest, state::{StateOverride, AccountOverride}}; + /// use alloy_rpc_types::{TransactionRequest, BlockOverrides, state::{StateOverride, AccountOverride}}; /// use alloy_serde::WithOtherFields; /// use cast::Cast; /// use alloy_provider::{RootProvider, ProviderBuilder, network::AnyNetwork}; @@ -136,9 +136,10 @@ impl> Cast

{ /// account_override.balance = Some(U256::from(1000)); /// state_override.insert(to, account_override); /// let state_override_object = StateOverridesBuilder::default().build(); + /// let block_override_object = BlockOverrides::default(); /// /// let cast = Cast::new(alloy_provider); - /// let data = cast.call(&tx, None, None, Some(state_override_object)).await?; + /// let data = cast.call(&tx, None, None, Some(state_override_object), Some(block_override_object)).await?; /// println!("{}", data); /// # Ok(()) /// # } @@ -149,8 +150,13 @@ impl> Cast

{ func: Option<&Function>, block: Option, state_override: Option, + block_override: Option, ) -> Result { - let mut call = self.provider.call(req.clone()).block(block.unwrap_or_default()); + let mut call = self + .provider + .call(req.clone()) + .block(block.unwrap_or_default()) + .with_block_overrides_opt(block_override); if let Some(state_override) = state_override { call = call.overrides(state_override) } diff --git a/testdata/default/cheats/BroadcastRawTransaction.t.sol b/testdata/default/cheats/BroadcastRawTransaction.t.sol index 36682bc893359..3806580281f73 100644 --- a/testdata/default/cheats/BroadcastRawTransaction.t.sol +++ b/testdata/default/cheats/BroadcastRawTransaction.t.sol @@ -13,7 +13,7 @@ contract BroadcastRawTransactionTest is DSTest { } function test_revert_missing_signature() public { - vm._expectCheatcodeRevert("failed to decode RLP-encoded transaction: input too short"); + vm._expectCheatcodeRevert("failed to decode RLP-encoded transaction: Unexpected type flag"); vm.broadcastRawTransaction(hex"dd806483030d40940993863c19b0defb183ca2b502db7d1b331ded757b80"); } From bfc53de69ca7a81d1cd8eb71f3a6035974f9ebea Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Wed, 18 Jun 2025 14:51:32 +0300 Subject: [PATCH 213/244] chore: pin nextest version in ci (#10800) --- .github/workflows/nextest.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/nextest.yml b/.github/workflows/nextest.yml index 855e5933c1b6d..f0502b9a71915 100644 --- a/.github/workflows/nextest.yml +++ b/.github/workflows/nextest.yml @@ -54,7 +54,9 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: target: ${{ matrix.target }} - - uses: taiki-e/install-action@nextest + - uses: taiki-e/install-action@v2 + with: + tool: nextest@0.9.98 # External tests dependencies - name: Setup Node.js From 6181d51a7c35b8356a3dc63e545f119339b4b653 Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Thu, 19 Jun 2025 09:43:22 +0200 Subject: [PATCH 214/244] chore: clean up unused EOF code (#10715) --- Cargo.lock | 14 +- Cargo.toml | 4 +- crates/anvil/src/eth/api.rs | 21 +- crates/cheatcodes/src/inspector.rs | 519 +++++++++++------------ crates/cheatcodes/src/inspector/utils.rs | 43 +- crates/debugger/src/op.rs | 78 ++-- crates/debugger/src/tui/context.rs | 18 +- crates/debugger/src/tui/draw.rs | 10 +- crates/evm/core/src/buffer.rs | 7 - crates/evm/evm/src/inspectors/stack.rs | 118 +----- 10 files changed, 307 insertions(+), 525 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe0c4dcc5d780..5b92cb3acb23a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -588,7 +588,7 @@ dependencies = [ "alloy-rlp", "alloy-serde", "alloy-sol-types", - "itertools 0.14.0", + "itertools 0.13.0", "serde", "serde_json", "thiserror 2.0.12", @@ -4265,7 +4265,7 @@ dependencies = [ "fs_extra", "futures-util", "home", - "itertools 0.14.0", + "itertools 0.13.0", "path-slash", "rand 0.8.5", "rayon", @@ -7162,7 +7162,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.14.0", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.103", @@ -8694,7 +8694,7 @@ dependencies = [ "derive_builder", "derive_more 2.0.1", "dunce", - "itertools 0.14.0", + "itertools 0.13.0", "itoa", "lasso", "match_cfg", @@ -8706,7 +8706,7 @@ dependencies = [ "solar-config", "solar-data-structures", "solar-macros", - "thiserror 2.0.12", + "thiserror 1.0.69", "tracing", "unicode-width 0.2.0", ] @@ -8731,7 +8731,7 @@ dependencies = [ "alloy-primitives", "bitflags 2.9.1", "bumpalo", - "itertools 0.14.0", + "itertools 0.13.0", "memchr", "num-bigint", "num-rational", @@ -9042,7 +9042,7 @@ dependencies = [ "serde_json", "sha2 0.10.9", "tempfile", - "thiserror 2.0.12", + "thiserror 1.0.69", "url", "zip", ] diff --git a/Cargo.toml b/Cargo.toml index 6a0eee283ddc0..30e2b3d0f1603 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -204,7 +204,7 @@ foundry-linking = { path = "crates/linking" } # solc & compilation utilities foundry-block-explorers = { version = "0.18.0", default-features = false } -foundry-compilers = { version = "0.17.1", default-features = false } +foundry-compilers = { version = "0.17.3", default-features = false } foundry-fork-db = "0.15" solang-parser = { version = "=0.3.9", package = "foundry-solang-parser" } solar-ast = { version = "=0.1.4", default-features = false } @@ -406,5 +406,5 @@ zip-extract = "=0.2.1" # revm-inspectors = { git = "https://github.com/paradigmxyz/revm-inspectors.git", rev = "a625c04" } ## foundry -# foundry-compilers = { git = "https://github.com/foundry-rs/compilers.git", rev = "855dee4" } +# foundry-compilers = { git = "https://github.com/foundry-rs/compilers.git", rev = "e4a9b04" } # foundry-fork-db = { git = "https://github.com/foundry-rs/foundry-fork-db", rev = "811a61a" } diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index fe5ea80838b1e..e4947472141d4 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -3414,6 +3414,8 @@ enum GasEstimationCallResult { } /// Converts the result of a call to revm EVM into a [`GasEstimationCallResult`]. +/// +/// Expected to stay up to date with: impl TryFrom, u128, State)>> for GasEstimationCallResult { type Error = BlockchainError; @@ -3427,8 +3429,15 @@ impl TryFrom, u128, State)>> for GasEs Ok((exit, output, gas, _)) => match exit { return_ok!() | InstructionResult::CallOrCreate => Ok(Self::Success(gas)), + // Revert opcodes: InstructionResult::Revert => Ok(Self::Revert(output.map(|o| o.into_data()))), + InstructionResult::CallTooDeep | + InstructionResult::OutOfFunds | + InstructionResult::CreateInitCodeStartingEF00 | + InstructionResult::InvalidEOFInitCode | + InstructionResult::InvalidExtDelegateCallTarget => Ok(Self::EvmError(exit)), + // Out of gas errors: InstructionResult::OutOfGas | InstructionResult::MemoryOOG | InstructionResult::MemoryLimitOOG | @@ -3436,11 +3445,10 @@ impl TryFrom, u128, State)>> for GasEs InstructionResult::InvalidOperandOOG | InstructionResult::ReentrancySentryOOG => Ok(Self::OutOfGas), + // Other errors: InstructionResult::OpcodeNotFound | InstructionResult::CallNotAllowedInsideStatic | InstructionResult::StateChangeDuringStaticCall | - InstructionResult::InvalidExtDelegateCallTarget | - InstructionResult::InvalidEXTCALLTarget | InstructionResult::InvalidFEOpcode | InstructionResult::InvalidJump | InstructionResult::NotActivated | @@ -3455,17 +3463,12 @@ impl TryFrom, u128, State)>> for GasEs InstructionResult::CreateContractStartingWithEF | InstructionResult::CreateInitCodeSizeLimit | InstructionResult::FatalExternalError | - InstructionResult::OutOfFunds | - InstructionResult::CallTooDeep => Ok(Self::EvmError(exit)), - - // Handle Revm EOF InstructionResults: not supported InstructionResult::ReturnContractInNotInitEOF | InstructionResult::EOFOpcodeDisabledInLegacy | InstructionResult::SubRoutineStackOverflow | - InstructionResult::CreateInitCodeStartingEF00 | - InstructionResult::InvalidEOFInitCode | InstructionResult::EofAuxDataOverflow | - InstructionResult::EofAuxDataTooSmall => Ok(Self::EvmError(exit)), + InstructionResult::EofAuxDataTooSmall | + InstructionResult::InvalidEXTCALLTarget => Ok(Self::EvmError(exit)), }, } } diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index c83f39bd59034..e2eb84ec522bf 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -661,271 +661,6 @@ impl Cheatcodes { } } - // common create functionality for both legacy and EOF. - fn create_common(&mut self, ecx: Ecx, mut input: Input) -> Option - where - Input: CommonCreateInput, - { - // Check if we should intercept this create - if self.intercept_next_create_call { - // Reset the flag - self.intercept_next_create_call = false; - - // Get initcode from the input - let output = input.init_code(); - - // Return a revert with the initcode as error data - return Some(CreateOutcome { - result: InterpreterResult { - result: InstructionResult::Revert, - output, - gas: Gas::new(input.gas_limit()), - }, - address: None, - }); - } - - let gas = Gas::new(input.gas_limit()); - let curr_depth = ecx.journaled_state.depth(); - - // Apply our prank - if let Some(prank) = &self.get_prank(curr_depth) { - if curr_depth >= prank.depth && input.caller() == prank.prank_caller { - let mut prank_applied = false; - - // At the target depth we set `msg.sender` - if curr_depth == prank.depth { - input.set_caller(prank.new_caller); - prank_applied = true; - } - - // At the target depth, or deeper, we set `tx.origin` - if let Some(new_origin) = prank.new_origin { - ecx.tx.caller = new_origin; - prank_applied = true; - } - - // If prank applied for first time, then update - if prank_applied { - if let Some(applied_prank) = prank.first_time_applied() { - self.pranks.insert(curr_depth, applied_prank); - } - } - } - } - - // Apply EIP-2930 access list - self.apply_accesslist(ecx); - - // Apply our broadcast - if let Some(broadcast) = &self.broadcast { - if curr_depth >= broadcast.depth && input.caller() == broadcast.original_caller { - if let Err(err) = ecx.journaled_state.load_account(broadcast.new_origin) { - return Some(CreateOutcome { - result: InterpreterResult { - result: InstructionResult::Revert, - output: Error::encode(err), - gas, - }, - address: None, - }); - } - - ecx.tx.caller = broadcast.new_origin; - - if curr_depth == broadcast.depth { - input.set_caller(broadcast.new_origin); - let is_fixed_gas_limit = check_if_fixed_gas_limit(&ecx, input.gas_limit()); - - let account = &ecx.journaled_state.inner.state()[&broadcast.new_origin]; - self.broadcastable_transactions.push_back(BroadcastableTransaction { - rpc: ecx.journaled_state.database.active_fork_url(), - transaction: TransactionRequest { - from: Some(broadcast.new_origin), - to: None, - value: Some(input.value()), - input: TransactionInput::new(input.init_code()), - nonce: Some(account.info.nonce), - gas: if is_fixed_gas_limit { Some(input.gas_limit()) } else { None }, - ..Default::default() - } - .into(), - }); - - input.log_debug(self, &input.scheme().unwrap_or(CreateScheme::Create)); - } - } - } - - // Allow cheatcodes from the address of the new contract - let address = input.allow_cheatcodes(self, ecx); - - // If `recordAccountAccesses` has been called, record the create - if let Some(recorded_account_diffs_stack) = &mut self.recorded_account_diffs_stack { - recorded_account_diffs_stack.push(vec![AccountAccess { - chainInfo: crate::Vm::ChainInfo { - forkId: ecx.journaled_state.db().active_fork_id().unwrap_or_default(), - chainId: U256::from(ecx.cfg.chain_id), - }, - accessor: input.caller(), - account: address, - kind: crate::Vm::AccountAccessKind::Create, - initialized: true, - oldBalance: U256::ZERO, // updated on (eof)create_end - newBalance: U256::ZERO, // updated on (eof)create_end - value: input.value(), - data: input.init_code(), - reverted: false, - deployedCode: Bytes::new(), // updated on (eof)create_end - storageAccesses: vec![], // updated on (eof)create_end - depth: curr_depth as u64, - }]); - } - - None - } - - // common create_end functionality for both legacy and EOF. - fn create_end_common( - &mut self, - ecx: Ecx, - call: Option<&CreateInputs>, - outcome: &mut CreateOutcome, - ) { - let curr_depth = ecx.journaled_state.depth(); - - // Clean up pranks - if let Some(prank) = &self.get_prank(curr_depth) { - if curr_depth == prank.depth { - ecx.tx.caller = prank.prank_origin; - - // Clean single-call prank once we have returned to the original depth - if prank.single_call { - std::mem::take(&mut self.pranks); - } - } - } - - // Clean up broadcasts - if let Some(broadcast) = &self.broadcast { - if curr_depth == broadcast.depth { - ecx.tx.caller = broadcast.original_origin; - - // Clean single-call broadcast once we have returned to the original depth - if broadcast.single_call { - std::mem::take(&mut self.broadcast); - } - } - } - - // Handle expected reverts - if let Some(expected_revert) = &self.expected_revert { - if curr_depth <= expected_revert.depth && - matches!(expected_revert.kind, ExpectedRevertKind::Default) - { - let mut expected_revert = std::mem::take(&mut self.expected_revert).unwrap(); - return match revert_handlers::handle_expect_revert( - false, - true, - self.config.internal_expect_revert, - &expected_revert, - outcome.result.result, - outcome.result.output.clone(), - &self.config.available_artifacts, - ) { - Ok((address, retdata)) => { - expected_revert.actual_count += 1; - if expected_revert.actual_count < expected_revert.count { - self.expected_revert = Some(expected_revert.clone()); - } - - outcome.result.result = InstructionResult::Return; - outcome.result.output = retdata; - outcome.address = address; - } - Err(err) => { - outcome.result.result = InstructionResult::Revert; - outcome.result.output = err.abi_encode().into(); - } - }; - } - } - - // If `startStateDiffRecording` has been called, update the `reverted` status of the - // previous call depth's recorded accesses, if any - if let Some(recorded_account_diffs_stack) = &mut self.recorded_account_diffs_stack { - // The root call cannot be recorded. - if curr_depth > 0 { - if let Some(last_depth) = &mut recorded_account_diffs_stack.pop() { - // Update the reverted status of all deeper calls if this call reverted, in - // accordance with EVM behavior - if outcome.result.is_revert() { - last_depth.iter_mut().for_each(|element| { - element.reverted = true; - element - .storageAccesses - .iter_mut() - .for_each(|storage_access| storage_access.reverted = true); - }) - } - - if let Some(create_access) = last_depth.first_mut() { - // Assert that we're at the correct depth before recording post-create state - // changes. Depending on what depth the cheat was called at, there - // may not be any pending calls to update if execution has - // percolated up to a higher depth. - let depth = ecx.journaled_state.depth(); - if create_access.depth == depth as u64 { - debug_assert_eq!( - create_access.kind as u8, - crate::Vm::AccountAccessKind::Create as u8 - ); - if let Some(address) = outcome.address { - if let Ok(created_acc) = ecx.journaled_state.load_account(address) { - create_access.newBalance = created_acc.info.balance; - create_access.deployedCode = created_acc - .info - .code - .clone() - .unwrap_or_default() - .original_bytes(); - } - } - } - // Merge the last depth's AccountAccesses into the AccountAccesses at the - // current depth, or push them back onto the pending - // vector if higher depths were not recorded. This - // preserves ordering of accesses. - if let Some(last) = recorded_account_diffs_stack.last_mut() { - last.append(last_depth); - } else { - recorded_account_diffs_stack.push(last_depth.clone()); - } - } - } - } - } - - // Match the create against expected_creates - if !self.expected_creates.is_empty() { - if let (Some(address), Some(call)) = (outcome.address, call) { - if let Ok(created_acc) = ecx.journaled_state.load_account(address) { - let bytecode = - created_acc.info.code.clone().unwrap_or_default().original_bytes(); - if let Some((index, _)) = - self.expected_creates.iter().find_position(|expected_create| { - expected_create.deployer == call.caller && - expected_create.create_scheme.eq(call.scheme.into()) && - expected_create.bytecode == bytecode - }) - { - self.expected_creates.swap_remove(index); - } - } - } - } - } - pub fn call_with_executor( &mut self, ecx: Ecx, @@ -1812,12 +1547,260 @@ impl Inspector> for Cheatcodes { } } - fn create(&mut self, ecx: Ecx, call: &mut CreateInputs) -> Option { - self.create_common(ecx, call) + fn create(&mut self, ecx: Ecx, mut input: &mut CreateInputs) -> Option { + // Check if we should intercept this create + if self.intercept_next_create_call { + // Reset the flag + self.intercept_next_create_call = false; + + // Get initcode from the input + let output = input.init_code(); + + // Return a revert with the initcode as error data + return Some(CreateOutcome { + result: InterpreterResult { + result: InstructionResult::Revert, + output, + gas: Gas::new(input.gas_limit()), + }, + address: None, + }); + } + + let gas = Gas::new(input.gas_limit()); + let curr_depth = ecx.journaled_state.depth(); + + // Apply our prank + if let Some(prank) = &self.get_prank(curr_depth) { + if curr_depth >= prank.depth && input.caller() == prank.prank_caller { + let mut prank_applied = false; + + // At the target depth we set `msg.sender` + if curr_depth == prank.depth { + input.set_caller(prank.new_caller); + prank_applied = true; + } + + // At the target depth, or deeper, we set `tx.origin` + if let Some(new_origin) = prank.new_origin { + ecx.tx.caller = new_origin; + prank_applied = true; + } + + // If prank applied for first time, then update + if prank_applied { + if let Some(applied_prank) = prank.first_time_applied() { + self.pranks.insert(curr_depth, applied_prank); + } + } + } + } + + // Apply EIP-2930 access list + self.apply_accesslist(ecx); + + // Apply our broadcast + if let Some(broadcast) = &self.broadcast { + if curr_depth >= broadcast.depth && input.caller() == broadcast.original_caller { + if let Err(err) = ecx.journaled_state.load_account(broadcast.new_origin) { + return Some(CreateOutcome { + result: InterpreterResult { + result: InstructionResult::Revert, + output: Error::encode(err), + gas, + }, + address: None, + }); + } + + ecx.tx.caller = broadcast.new_origin; + + if curr_depth == broadcast.depth { + input.set_caller(broadcast.new_origin); + let is_fixed_gas_limit = check_if_fixed_gas_limit(&ecx, input.gas_limit()); + + let account = &ecx.journaled_state.inner.state()[&broadcast.new_origin]; + self.broadcastable_transactions.push_back(BroadcastableTransaction { + rpc: ecx.journaled_state.database.active_fork_url(), + transaction: TransactionRequest { + from: Some(broadcast.new_origin), + to: None, + value: Some(input.value()), + input: TransactionInput::new(input.init_code()), + nonce: Some(account.info.nonce), + gas: if is_fixed_gas_limit { Some(input.gas_limit()) } else { None }, + ..Default::default() + } + .into(), + }); + + input.log_debug(self, &input.scheme().unwrap_or(CreateScheme::Create)); + } + } + } + + // Allow cheatcodes from the address of the new contract + let address = input.allow_cheatcodes(self, ecx); + + // If `recordAccountAccesses` has been called, record the create + if let Some(recorded_account_diffs_stack) = &mut self.recorded_account_diffs_stack { + recorded_account_diffs_stack.push(vec![AccountAccess { + chainInfo: crate::Vm::ChainInfo { + forkId: ecx.journaled_state.db().active_fork_id().unwrap_or_default(), + chainId: U256::from(ecx.cfg.chain_id), + }, + accessor: input.caller(), + account: address, + kind: crate::Vm::AccountAccessKind::Create, + initialized: true, + oldBalance: U256::ZERO, // updated on create_end + newBalance: U256::ZERO, // updated on create_end + value: input.value(), + data: input.init_code(), + reverted: false, + deployedCode: Bytes::new(), // updated on create_end + storageAccesses: vec![], // updated on create_end + depth: curr_depth as u64, + }]); + } + + None } fn create_end(&mut self, ecx: Ecx, call: &CreateInputs, outcome: &mut CreateOutcome) { - self.create_end_common(ecx, Some(call), outcome) + let call = Some(call); + let curr_depth = ecx.journaled_state.depth(); + + // Clean up pranks + if let Some(prank) = &self.get_prank(curr_depth) { + if curr_depth == prank.depth { + ecx.tx.caller = prank.prank_origin; + + // Clean single-call prank once we have returned to the original depth + if prank.single_call { + std::mem::take(&mut self.pranks); + } + } + } + + // Clean up broadcasts + if let Some(broadcast) = &self.broadcast { + if curr_depth == broadcast.depth { + ecx.tx.caller = broadcast.original_origin; + + // Clean single-call broadcast once we have returned to the original depth + if broadcast.single_call { + std::mem::take(&mut self.broadcast); + } + } + } + + // Handle expected reverts + if let Some(expected_revert) = &self.expected_revert { + if curr_depth <= expected_revert.depth && + matches!(expected_revert.kind, ExpectedRevertKind::Default) + { + let mut expected_revert = std::mem::take(&mut self.expected_revert).unwrap(); + return match revert_handlers::handle_expect_revert( + false, + true, + self.config.internal_expect_revert, + &expected_revert, + outcome.result.result, + outcome.result.output.clone(), + &self.config.available_artifacts, + ) { + Ok((address, retdata)) => { + expected_revert.actual_count += 1; + if expected_revert.actual_count < expected_revert.count { + self.expected_revert = Some(expected_revert.clone()); + } + + outcome.result.result = InstructionResult::Return; + outcome.result.output = retdata; + outcome.address = address; + } + Err(err) => { + outcome.result.result = InstructionResult::Revert; + outcome.result.output = err.abi_encode().into(); + } + }; + } + } + + // If `startStateDiffRecording` has been called, update the `reverted` status of the + // previous call depth's recorded accesses, if any + if let Some(recorded_account_diffs_stack) = &mut self.recorded_account_diffs_stack { + // The root call cannot be recorded. + if curr_depth > 0 { + if let Some(last_depth) = &mut recorded_account_diffs_stack.pop() { + // Update the reverted status of all deeper calls if this call reverted, in + // accordance with EVM behavior + if outcome.result.is_revert() { + last_depth.iter_mut().for_each(|element| { + element.reverted = true; + element + .storageAccesses + .iter_mut() + .for_each(|storage_access| storage_access.reverted = true); + }) + } + + if let Some(create_access) = last_depth.first_mut() { + // Assert that we're at the correct depth before recording post-create state + // changes. Depending on what depth the cheat was called at, there + // may not be any pending calls to update if execution has + // percolated up to a higher depth. + let depth = ecx.journaled_state.depth(); + if create_access.depth == depth as u64 { + debug_assert_eq!( + create_access.kind as u8, + crate::Vm::AccountAccessKind::Create as u8 + ); + if let Some(address) = outcome.address { + if let Ok(created_acc) = ecx.journaled_state.load_account(address) { + create_access.newBalance = created_acc.info.balance; + create_access.deployedCode = created_acc + .info + .code + .clone() + .unwrap_or_default() + .original_bytes(); + } + } + } + // Merge the last depth's AccountAccesses into the AccountAccesses at the + // current depth, or push them back onto the pending + // vector if higher depths were not recorded. This + // preserves ordering of accesses. + if let Some(last) = recorded_account_diffs_stack.last_mut() { + last.append(last_depth); + } else { + recorded_account_diffs_stack.push(last_depth.clone()); + } + } + } + } + } + + // Match the create against expected_creates + if !self.expected_creates.is_empty() { + if let (Some(address), Some(call)) = (outcome.address, call) { + if let Ok(created_acc) = ecx.journaled_state.load_account(address) { + let bytecode = + created_acc.info.code.clone().unwrap_or_default().original_bytes(); + if let Some((index, _)) = + self.expected_creates.iter().find_position(|expected_create| { + expected_create.deployer == call.caller && + expected_create.create_scheme.eq(call.scheme.into()) && + expected_create.bytecode == bytecode + }) + { + self.expected_creates.swap_remove(index); + } + } + } + } } } diff --git a/crates/cheatcodes/src/inspector/utils.rs b/crates/cheatcodes/src/inspector/utils.rs index c82f9023fafd4..58d1f2f90d7b7 100644 --- a/crates/cheatcodes/src/inspector/utils.rs +++ b/crates/cheatcodes/src/inspector/utils.rs @@ -1,7 +1,7 @@ use super::Ecx; use crate::inspector::Cheatcodes; use alloy_primitives::{Address, Bytes, U256}; -use revm::interpreter::{CreateInputs, CreateScheme, EOFCreateInputs, EOFCreateKind}; +use revm::interpreter::{CreateInputs, CreateScheme}; /// Common behaviour of legacy and EOF create inputs. pub(crate) trait CommonCreateInput { @@ -13,7 +13,6 @@ pub(crate) trait CommonCreateInput { fn set_caller(&mut self, caller: Address); fn log_debug(&self, cheatcode: &mut Cheatcodes, scheme: &CreateScheme); fn allow_cheatcodes(&self, cheatcodes: &mut Cheatcodes, ecx: Ecx) -> Address; - fn computed_created_address(&self) -> Option

; } impl CommonCreateInput for &mut CreateInputs { @@ -54,44 +53,4 @@ impl CommonCreateInput for &mut CreateInputs { cheatcodes.allow_cheatcodes_on_create(ecx, self.caller, created_address); created_address } - fn computed_created_address(&self) -> Option
{ - None - } -} - -impl CommonCreateInput for &mut EOFCreateInputs { - fn caller(&self) -> Address { - self.caller - } - fn gas_limit(&self) -> u64 { - self.gas_limit - } - fn value(&self) -> U256 { - self.value - } - fn init_code(&self) -> Bytes { - match &self.kind { - EOFCreateKind::Tx { initdata } => initdata.clone(), - EOFCreateKind::Opcode { initcode, .. } => initcode.raw.clone(), - } - } - fn scheme(&self) -> Option { - None - } - fn set_caller(&mut self, caller: Address) { - self.caller = caller; - } - fn log_debug(&self, cheatcode: &mut Cheatcodes, _scheme: &CreateScheme) { - debug!(target: "cheatcodes", tx=?cheatcode.broadcastable_transactions.back().unwrap(), "broadcastable eofcreate"); - } - fn allow_cheatcodes(&self, cheatcodes: &mut Cheatcodes, ecx: Ecx) -> Address { - let created_address = - <&mut EOFCreateInputs as CommonCreateInput>::computed_created_address(self) - .unwrap_or_default(); - cheatcodes.allow_cheatcodes_on_create(ecx, self.caller, created_address); - created_address - } - fn computed_created_address(&self) -> Option
{ - self.kind.created_address().copied() - } } diff --git a/crates/debugger/src/op.rs b/crates/debugger/src/op.rs index 8e2edce964ae9..8abf33d6f533d 100644 --- a/crates/debugger/src/op.rs +++ b/crates/debugger/src/op.rs @@ -1,6 +1,3 @@ -use alloy_primitives::Bytes; -use revm::bytecode::opcode; - /// Named parameter of an EVM opcode. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub(crate) struct OpcodeParam { @@ -14,32 +11,8 @@ impl OpcodeParam { /// Returns the list of named parameters for the given opcode, accounts for special opcodes /// requiring immediate bytes to determine stack items. #[inline] - pub(crate) fn of(op: u8, immediate: Option<&Bytes>) -> Option> { - match op { - // Handle special cases requiring immediate bytes - opcode::DUPN => immediate - .and_then(|i| i.first().copied()) - .map(|i| vec![Self { name: "dup_value", index: i as usize }]), - opcode::SWAPN => immediate.and_then(|i| { - i.first().map(|i| { - vec![ - Self { name: "a", index: 1 }, - Self { name: "swap_value", index: *i as usize }, - ] - }) - }), - opcode::EXCHANGE => immediate.and_then(|i| { - i.first().map(|imm| { - let n = (imm >> 4) + 1; - let m = (imm & 0xf) + 1; - vec![ - Self { name: "value1", index: n as usize }, - Self { name: "value2", index: m as usize }, - ] - }) - }), - _ => Some(MAP[op as usize].to_vec()), - } + pub(crate) fn of(op: u8) -> &'static [Self] { + MAP[op as usize] } } @@ -68,16 +41,21 @@ const fn map_opcode(op: u8) -> &'static [OpcodeParam] { } // https://www.evm.codes - // https://github.com/smlxl/evm.codes - // https://github.com/klkvr/evm.codes - // https://github.com/klkvr/evm.codes/blob/HEAD/opcodes.json - // jq -rf opcodes.jq opcodes.json - /* - def mkargs(input): - input | split(" | ") | to_entries | map("\(.key): \"\(.value)\"") | join(", "); - - to_entries[] | "0x\(.key)(\(mkargs(.value.input)))," - */ + // https://raw.githubusercontent.com/duneanalytics/evm.codes/refs/heads/main/opcodes.json + // + // jq -r ' + // def mkargs(input): + // input + // | split(" | ") + // | to_entries + // | map("\(.key): \"\(.value)\"") + // | join(", "); + // to_entries[] + // | "0x\(.key)(\(mkargs(.value.input)))," + // ' opcodes.json + // + // NOTE: the labels generated for `DUPN` and `SWAPN` have incorrect indices and have been + // manually adjusted in the `map!` macro below. map! { 0x00(), 0x01(0: "a", 1: "b"), @@ -152,7 +130,7 @@ const fn map_opcode(op: u8) -> &'static [OpcodeParam] { 0x46(), 0x47(), 0x48(), - 0x49(), + 0x49(0: "index"), 0x4a(), 0x4b(), 0x4c(), @@ -171,11 +149,9 @@ const fn map_opcode(op: u8) -> &'static [OpcodeParam] { 0x59(), 0x5a(), 0x5b(), - 0x5c(), - 0x5d(), - 0x5e(), - - // PUSHN + 0x5c(0: "key"), + 0x5d(0: "key", 1: "value"), + 0x5e(0: "destOffset", 1: "offset", 2: "size"), 0x5f(), 0x60(), 0x61(), @@ -297,7 +273,7 @@ const fn map_opcode(op: u8) -> &'static [OpcodeParam] { 0xd0(0: "offset"), 0xd1(), 0xd2(), - 0xd3(0: "memOffset", 1: "offset", 2: "size"), + 0xd3(0: "mem_offset", 1: "offset", 2: "size"), 0xd4(), 0xd5(), 0xd6(), @@ -322,9 +298,9 @@ const fn map_opcode(op: u8) -> &'static [OpcodeParam] { 0xe9(), 0xea(), 0xeb(), - 0xec(0: "value", 1: "salt", 2: "offset", 3: "size"), + 0xec(0: "value", 1: "salt", 2: "input_offset", 3: "input_size"), 0xed(), - 0xee(0: "offset", 1: "size"), + 0xee(0: "aux_data_offset", 1: "aux_data_size"), 0xef(), 0xf0(0: "value", 1: "offset", 2: "size"), 0xf1(0: "gas", 1: "address", 2: "value", 3: "argsOffset", 4: "argsSize", 5: "retOffset", 6: "retSize"), @@ -334,10 +310,10 @@ const fn map_opcode(op: u8) -> &'static [OpcodeParam] { 0xf5(0: "value", 1: "offset", 2: "size", 3: "salt"), 0xf6(), 0xf7(0: "offset"), - 0xf8(0: "address", 1: "argsOffset", 2: "argsSize", 3: "value"), - 0xf9(0: "address", 1: "argsOffset", 2: "argsSize"), + 0xf8(0: "target_address", 1: "input_offset", 2: "input_size", 3: "value"), + 0xf9(0: "target_address", 1: "input_offset", 2: "input_size"), 0xfa(0: "gas", 1: "address", 2: "argsOffset", 3: "argsSize", 4: "retOffset", 5: "retSize"), - 0xfb(0: "address", 1: "argsOffset", 2: "argsSize"), + 0xfb(0: "target_address", 1: "input_offset", 2: "input_size"), 0xfc(), 0xfd(0: "offset", 1: "size"), 0xfe(), diff --git a/crates/debugger/src/tui/context.rs b/crates/debugger/src/tui/context.rs index a2a4c987a78d6..cf4c6204b79bb 100644 --- a/crates/debugger/src/tui/context.rs +++ b/crates/debugger/src/tui/context.rs @@ -330,25 +330,11 @@ fn pretty_opcode(step: &CallTraceStep) -> String { } fn is_jump(step: &CallTraceStep, prev: &CallTraceStep) -> bool { - if !matches!( - prev.op, - OpCode::JUMP | - OpCode::JUMPI | - OpCode::JUMPF | - OpCode::RJUMP | - OpCode::RJUMPI | - OpCode::RJUMPV | - OpCode::CALLF | - OpCode::RETF - ) { + if !matches!(prev.op, OpCode::JUMP | OpCode::JUMPI) { return false } let immediate_len = prev.immediate_bytes.as_ref().map_or(0, |b| b.len()); - if step.pc != prev.pc + 1 + immediate_len { - true - } else { - step.code_section_idx != prev.code_section_idx - } + step.pc != prev.pc + 1 + immediate_len } diff --git a/crates/debugger/src/tui/draw.rs b/crates/debugger/src/tui/draw.rs index 580d6f958ac44..00f51c4c5654c 100644 --- a/crates/debugger/src/tui/draw.rs +++ b/crates/debugger/src/tui/draw.rs @@ -375,11 +375,10 @@ impl TUIContext<'_> { .collect::>(); let title = format!( - "Address: {} | PC: {} | Gas used in call: {} | Code section: {}", + "Address: {} | PC: {} | Gas used in call: {}", self.address(), self.current_step().pc, self.current_step().gas_used, - self.current_step().code_section_idx, ); let block = Block::default().title(title).borders(Borders::ALL); let list = List::new(items) @@ -398,7 +397,7 @@ impl TUIContext<'_> { let min_len = decimal_digits(stack_len).max(2); - let params = OpcodeParam::of(step.op.get(), step.immediate_bytes.as_ref()); + let params = OpcodeParam::of(step.op.get()); let text: Vec> = stack .map(|stack| { @@ -408,10 +407,7 @@ impl TUIContext<'_> { .enumerate() .skip(self.draw_memory.current_stack_startline) .map(|(i, stack_item)| { - let param = params - .as_ref() - .and_then(|params| params.iter().find(|param| param.index == i)); - + let param = params.iter().find(|param| param.index == i); let mut spans = Vec::with_capacity(1 + 32 * 2 + 3); // Stack index. diff --git a/crates/evm/core/src/buffer.rs b/crates/evm/core/src/buffer.rs index 5cce0a91ad97b..e600708f43173 100644 --- a/crates/evm/core/src/buffer.rs +++ b/crates/evm/core/src/buffer.rs @@ -75,13 +75,6 @@ pub fn get_buffer_accesses(op: u8, stack: &[U256]) -> Option { opcode::CALL | opcode::CALLCODE => (Some((BufferKind::Memory, 4, 5)), None), opcode::DELEGATECALL | opcode::STATICCALL => (Some((BufferKind::Memory, 3, 4)), None), opcode::MCOPY => (Some((BufferKind::Memory, 2, 3)), Some((1, 3))), - opcode::RETURNDATALOAD => (Some((BufferKind::Returndata, 1, -1)), None), - opcode::EOFCREATE => (Some((BufferKind::Memory, 3, 4)), None), - opcode::RETURNCONTRACT => (Some((BufferKind::Memory, 1, 2)), None), - opcode::DATACOPY => (None, Some((1, 3))), - opcode::EXTCALL | opcode::EXTSTATICCALL | opcode::EXTDELEGATECALL => { - (Some((BufferKind::Memory, 2, 3)), None) - } _ => Default::default(), }; diff --git a/crates/evm/evm/src/inspectors/stack.rs b/crates/evm/evm/src/inspectors/stack.rs index 520de5f45e2aa..f3c0fa3d13f4b 100644 --- a/crates/evm/evm/src/inspectors/stack.rs +++ b/crates/evm/evm/src/inspectors/stack.rs @@ -22,8 +22,8 @@ use revm::{ }, context_interface::CreateScheme, interpreter::{ - CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, EOFCreateInputs, - EOFCreateKind, Gas, InstructionResult, Interpreter, InterpreterResult, + CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, Gas, InstructionResult, + Interpreter, InterpreterResult, }, state::{Account, AccountStatus}, Inspector, @@ -578,32 +578,6 @@ impl InspectorStackRefMut<'_> { outcome.clone() } - fn do_eofcreate_end( - &mut self, - ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, - call: &EOFCreateInputs, - outcome: &mut CreateOutcome, - ) -> CreateOutcome { - let result = outcome.result.result; - call_inspectors!( - #[ret] - [&mut self.tracer, &mut self.cheatcodes, &mut self.printer], - |inspector| { - let previous_outcome = outcome.clone(); - inspector.eofcreate_end(ecx, call, outcome); - - // If the inspector returns a different status or a revert with a non-empty message, - // we assume it wants to tell us something - let different = outcome.result.result != result || - (outcome.result.result == InstructionResult::Revert && - outcome.output() != previous_outcome.output()); - different.then_some(outcome.clone()) - }, - ); - - outcome.clone() - } - fn transact_inner( &mut self, ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, @@ -1029,77 +1003,6 @@ impl Inspector> for InspectorStackRefMut<'_> self.top_level_frame_end(ecx, outcome.result.result); } } - - fn eofcreate( - &mut self, - ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, - create: &mut EOFCreateInputs, - ) -> Option { - if self.in_inner_context && ecx.journaled_state.depth == 1 { - self.adjust_evm_data_for_inner_context(ecx); - return None; - } - - if ecx.journaled_state.depth == 0 { - self.top_level_frame_start(ecx); - } - - call_inspectors!( - #[ret] - [&mut self.tracer, &mut self.coverage, &mut self.cheatcodes], - |inspector| inspector.eofcreate(ecx, create).map(Some), - ); - - if matches!(create.kind, EOFCreateKind::Tx { .. }) && - self.enable_isolation && - !self.in_inner_context && - ecx.journaled_state.depth == 1 - { - let init_code = match &mut create.kind { - EOFCreateKind::Tx { initdata } => initdata.clone(), - EOFCreateKind::Opcode { .. } => unreachable!(), - }; - - let (result, address) = self.transact_inner( - ecx, - TxKind::Create, - create.caller, - init_code, - create.gas_limit, - create.value, - ); - return Some(CreateOutcome { result, address }); - } - - None - } - - fn eofcreate_end( - &mut self, - ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, - call: &EOFCreateInputs, - outcome: &mut CreateOutcome, - ) { - // We are processing inner context outputs in the outer context, so need to avoid processing - // twice. - if self.in_inner_context && ecx.journaled_state.depth == 1 { - return; - } - - self.do_eofcreate_end(ecx, call, outcome); - - if ecx.journaled_state.depth == 0 { - self.top_level_frame_end(ecx, outcome.result.result); - } - } - - fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { - call_inspectors!([&mut self.tracer, &mut self.printer], |inspector| { - Inspector::>::selfdestruct( - inspector, contract, target, value, - ) - }); - } } impl InspectorExt for InspectorStackRefMut<'_> { @@ -1185,23 +1088,6 @@ impl Inspector> for InspectorStack { self.as_mut().create_end(context, call, outcome) } - fn eofcreate( - &mut self, - context: &mut EthEvmContext<&mut dyn DatabaseExt>, - create: &mut EOFCreateInputs, - ) -> Option { - self.as_mut().eofcreate(context, create) - } - - fn eofcreate_end( - &mut self, - context: &mut EthEvmContext<&mut dyn DatabaseExt>, - call: &EOFCreateInputs, - outcome: &mut CreateOutcome, - ) { - self.as_mut().eofcreate_end(context, call, outcome) - } - fn initialize_interp( &mut self, interpreter: &mut Interpreter, From 23e8841f9d4330eb381c4056872a0798ce50cf71 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Thu, 19 Jun 2025 11:23:19 +0300 Subject: [PATCH 215/244] fix(forge): vm.getChain use config for rpc and alias (#10806) --- crates/cheatcodes/src/test.rs | 23 ++++++++++++++--------- testdata/default/cheats/GetChain.t.sol | 17 +++++++++++++---- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/crates/cheatcodes/src/test.rs b/crates/cheatcodes/src/test.rs index bc36accccde12..683c5131bcddf 100644 --- a/crates/cheatcodes/src/test.rs +++ b/crates/cheatcodes/src/test.rs @@ -124,24 +124,29 @@ fn get_chain(state: &mut Cheatcodes, chain_alias: &str) -> Result { // Parse the chain alias - works for both chain names and IDs let alloy_chain = AlloyChain::from_str(chain_alias) .map_err(|_| fmt_err!("invalid chain alias: {chain_alias}"))?; + let chain_name = alloy_chain.to_string(); + let chain_id = alloy_chain.id(); // Check if this is an unknown chain ID by comparing the name to the chain ID // When a numeric ID is passed for an unknown chain, alloy_chain.to_string() will return the ID // So if they match, it's likely an unknown chain ID - if alloy_chain.to_string() == alloy_chain.id().to_string() { + if chain_name == chain_id.to_string() { return Err(fmt_err!("invalid chain alias: {chain_alias}")); } - // First, try to get RPC URL from the user's config in foundry.toml - let rpc_url = state.config.rpc_endpoint(chain_alias).ok().and_then(|e| e.url().ok()); - - // If we couldn't get a URL from config, return an empty string - let rpc_url = rpc_url.unwrap_or_default(); + // Try to retrieve RPC URL and chain alias from user's config in foundry.toml. + let (rpc_url, chain_alias) = if let Some(rpc_url) = + state.config.rpc_endpoint(&chain_name).ok().and_then(|e| e.url().ok()) + { + (rpc_url, chain_name.clone()) + } else { + (String::new(), chain_alias.to_string()) + }; let chain_struct = Chain { - name: alloy_chain.to_string(), - chainId: U256::from(alloy_chain.id()), - chainAlias: chain_alias.to_string(), + name: chain_name, + chainId: U256::from(chain_id), + chainAlias: chain_alias, rpcUrl: rpc_url, }; diff --git a/testdata/default/cheats/GetChain.t.sol b/testdata/default/cheats/GetChain.t.sol index 856a6b8a75712..15923612cfc60 100644 --- a/testdata/default/cheats/GetChain.t.sol +++ b/testdata/default/cheats/GetChain.t.sol @@ -56,7 +56,7 @@ contract GetChainTest is DSTest { Vm.Chain memory mainnet = vm.getChain(1); assertEq(mainnet.name, "mainnet"); assertEq(mainnet.chainId, 1); - assertEq(mainnet.chainAlias, "1"); + assertEq(mainnet.chainAlias, "mainnet"); } function testGetSepoliaById() public { @@ -64,7 +64,7 @@ contract GetChainTest is DSTest { Vm.Chain memory sepolia = vm.getChain(11155111); assertEq(sepolia.name, "sepolia"); assertEq(sepolia.chainId, 11155111); - assertEq(sepolia.chainAlias, "11155111"); + assertEq(sepolia.chainAlias, "sepolia"); } function testGetOptimismById() public { @@ -72,7 +72,16 @@ contract GetChainTest is DSTest { Vm.Chain memory optimism = vm.getChain(10); assertEq(optimism.name, "optimism"); assertEq(optimism.chainId, 10); - assertEq(optimism.chainAlias, "10"); + assertEq(optimism.chainAlias, "optimism"); + } + + function testGetBerachainById() public { + // Test Berachain using chain ID + Vm.Chain memory bera = vm.getChain(80094); + assertEq(bera.name, "berachain"); + assertEq(bera.chainId, 80094); + // No rpc url configured, chain alias is the chain id. + assertEq(bera.chainAlias, "80094"); } function testGetArbitrumById() public { @@ -80,7 +89,7 @@ contract GetChainTest is DSTest { Vm.Chain memory arbitrum = vm.getChain(42161); assertEq(arbitrum.name, "arbitrum"); assertEq(arbitrum.chainId, 42161); - assertEq(arbitrum.chainAlias, "42161"); + assertEq(arbitrum.chainAlias, "arbitrum"); } function testInvalidChainId() public { From 8e66fd12c6f1faee4c37bc0b1584c0e11cdaccae Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Thu, 19 Jun 2025 11:39:00 +0300 Subject: [PATCH 216/244] feat(forge): `--exclude-tests` option from coverage (#10807) feat: exclude tests option from coverage --- crates/forge/src/cmd/coverage.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/forge/src/cmd/coverage.rs b/crates/forge/src/cmd/coverage.rs index 3b2e04eb88b26..729f96e5a9838 100644 --- a/crates/forge/src/cmd/coverage.rs +++ b/crates/forge/src/cmd/coverage.rs @@ -75,6 +75,10 @@ pub struct CoverageArgs { #[arg(long)] include_libs: bool, + /// Whether to exclude tests from the coverage report. + #[arg(long)] + exclude_tests: bool, + /// The coverage reporters to use. Constructed from the other fields. #[arg(skip)] reporters: Vec>, @@ -194,8 +198,10 @@ impl CoverageArgs { for (path, source_file, version) in output.output().sources.sources_with_version() { report.add_source(version.clone(), source_file.id as usize, path.clone()); - // Filter out dependencies. - if !self.include_libs && project_paths.has_library_ancestor(path) { + // Filter out libs dependencies and tests. + if (!self.include_libs && project_paths.has_library_ancestor(path)) || + (self.exclude_tests && project_paths.is_test(path)) + { continue; } From 0c3dc32778229b74a3e9e3726bf9d5b99fe4b028 Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Thu, 19 Jun 2025 13:53:30 +0200 Subject: [PATCH 217/244] chore: bump vyper 0.4.3 and remove previous `prague` handling (#10808) * bump vyper to 0.4.3 * bump to 0.4.3, remove specific prague handling * update to latest commit w/ 0.4.3, remove workaround as it fails to build * make vyper and forge available in PATH * remove ignored ERC4626VaultTest, should now be able to be ran again --- .devcontainer/Dockerfile.dev | 2 +- .github/workflows/nextest.yml | 2 +- crates/config/src/lib.rs | 4 ++-- crates/config/src/vyper.rs | 12 +----------- crates/forge/src/cmd/compiler.rs | 9 ++------- crates/forge/tests/cli/compiler.rs | 10 +++++----- crates/forge/tests/cli/ext_integration.rs | 3 +-- crates/forge/tests/it/test_helpers.rs | 2 +- crates/test-utils/src/util.rs | 14 ++++++++++++++ 9 files changed, 28 insertions(+), 30 deletions(-) diff --git a/.devcontainer/Dockerfile.dev b/.devcontainer/Dockerfile.dev index 9017115744e89..c8e8935c91fda 100644 --- a/.devcontainer/Dockerfile.dev +++ b/.devcontainer/Dockerfile.dev @@ -5,7 +5,7 @@ ARG USER_UID=1000 ARG USER_GID=$USER_UID ARG PYTHON_VERSION=3.11 ARG NODE_MAJOR=20 -ARG VYPER_VERSION=0.4.0 +ARG VYPER_VERSION=0.4.3 ENV DEBIAN_FRONTEND=noninteractive ENV CARGO_TERM_COLOR=always \ diff --git a/.github/workflows/nextest.yml b/.github/workflows/nextest.yml index f0502b9a71915..acbe2fa5953c4 100644 --- a/.github/workflows/nextest.yml +++ b/.github/workflows/nextest.yml @@ -75,7 +75,7 @@ jobs: python-version: 3.11 - name: Install Vyper # Also update vyper version in .devcontainer/Dockerfile.dev - run: pip --version && pip install vyper==0.4.0 + run: pip --version && pip install vyper==0.4.3 - name: Forge RPC cache uses: actions/cache@v4 diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 1222b4703fa38..98fc97b227302 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -118,7 +118,7 @@ pub mod soldeer; use soldeer::{SoldeerConfig, SoldeerDependencyConfig}; mod vyper; -pub use vyper::{normalize_evm_version_vyper, VyperConfig}; +pub use vyper::VyperConfig; mod bind_json; use bind_json::BindJsonConfig; @@ -1548,7 +1548,7 @@ impl Config { /// - evm version pub fn vyper_settings(&self) -> Result { Ok(VyperSettings { - evm_version: Some(normalize_evm_version_vyper(self.evm_version)), + evm_version: Some(self.evm_version), optimize: self.vyper.optimize, bytecode_metadata: None, // TODO: We don't yet have a way to deserialize other outputs correctly, so request only diff --git a/crates/config/src/vyper.rs b/crates/config/src/vyper.rs index 12596e3bce401..dbd47faec208d 100644 --- a/crates/config/src/vyper.rs +++ b/crates/config/src/vyper.rs @@ -1,6 +1,6 @@ //! Vyper specific configuration types. -use foundry_compilers::artifacts::{vyper::VyperOptimizationMode, EvmVersion}; +use foundry_compilers::artifacts::vyper::VyperOptimizationMode; use serde::{Deserialize, Serialize}; use std::path::PathBuf; @@ -16,13 +16,3 @@ pub struct VyperConfig { #[serde(default, skip_serializing_if = "Option::is_none")] pub experimental_codegen: Option, } - -/// Vyper does not yet support the Prague EVM version, so we normalize it to Cancun. -/// This is a temporary workaround until Vyper supports Prague. -pub fn normalize_evm_version_vyper(evm_version: EvmVersion) -> EvmVersion { - if evm_version >= EvmVersion::Prague { - return EvmVersion::Cancun; - } - - evm_version -} diff --git a/crates/forge/src/cmd/compiler.rs b/crates/forge/src/cmd/compiler.rs index 82e9bf14ecee0..ded027dffc4aa 100644 --- a/crates/forge/src/cmd/compiler.rs +++ b/crates/forge/src/cmd/compiler.rs @@ -2,7 +2,7 @@ use clap::{Parser, Subcommand, ValueHint}; use eyre::Result; use foundry_common::shell; use foundry_compilers::{artifacts::EvmVersion, Graph}; -use foundry_config::{normalize_evm_version_vyper, Config}; +use foundry_config::Config; use semver::Version; use serde::Serialize; use std::{collections::BTreeMap, path::PathBuf}; @@ -97,12 +97,7 @@ impl ResolveArgs { .normalize_version_solc(version) .unwrap_or_default(); - // Vyper does not yet support Prague, so we normalize it to Cancun. - if language.is_vyper() { - Some(normalize_evm_version_vyper(evm)) - } else { - Some(evm) - } + Some(evm) } else { None }; diff --git a/crates/forge/tests/cli/compiler.rs b/crates/forge/tests/cli/compiler.rs index f58d5c3ef1511..20438dd2e8085 100644 --- a/crates/forge/tests/cli/compiler.rs +++ b/crates/forge/tests/cli/compiler.rs @@ -156,7 +156,7 @@ Solidity: - 0.8.30 Vyper: -- 0.4.0 +- 0.4.3 "#]]); @@ -174,7 +174,7 @@ forgetest!(can_list_resolved_multiple_compiler_versions_skipped, |prj, cmd| { r#" Vyper: -0.4.0: +0.4.3: ├── src/Counter.vy └── src/ICounter.vyi @@ -206,7 +206,7 @@ forgetest!(can_list_resolved_multiple_compiler_versions_skipped_json, |prj, cmd| ], "Vyper": [ { - "version": "0.4.0", + "version": "0.4.3", "paths": [ "src/Counter.vy", "src/ICounter.vyi" @@ -242,7 +242,7 @@ Solidity: Vyper: -0.4.0 (<= cancun): +0.4.3 (<= prague): ├── src/Counter.vy └── src/ICounter.vyi @@ -287,7 +287,7 @@ forgetest!(can_list_resolved_multiple_compiler_versions_verbose_json, |prj, cmd| ], "Vyper": [ { - "version": "0.4.0", + "version": "0.4.3", "evm_version": "[..]", "paths": [ "src/Counter.vy", diff --git a/crates/forge/tests/cli/ext_integration.rs b/crates/forge/tests/cli/ext_integration.rs index 5dcdf4be132b4..1783fb4b402d8 100644 --- a/crates/forge/tests/cli/ext_integration.rs +++ b/crates/forge/tests/cli/ext_integration.rs @@ -69,8 +69,7 @@ fn solady() { #[cfg_attr(windows, ignore = "Windows cannot find installed programs")] #[cfg(not(feature = "isolate-by-default"))] fn snekmate() { - ExtTester::new("pcaversaccio", "snekmate", "df226f4a45e86c8f8c3ff1f9fa3443d260002050") - .args(["--nmc", "ERC4626VaultTest"]) + ExtTester::new("pcaversaccio", "snekmate", "601031d244475b160a00f73053532528bf665cc3") .install_command(&["pnpm", "install", "--prefer-offline"]) // Try npm if pnpm fails / is not installed. .install_command(&["npm", "install", "--prefer-offline"]) diff --git a/crates/forge/tests/it/test_helpers.rs b/crates/forge/tests/it/test_helpers.rs index 877be09c1d016..06ea9de1f5743 100644 --- a/crates/forge/tests/it/test_helpers.rs +++ b/crates/forge/tests/it/test_helpers.rs @@ -274,7 +274,7 @@ pub fn get_vyper() -> Vyper { install it manually and add it to $PATH" ), }; - let url = format!("https://github.com/vyperlang/vyper/releases/download/v0.4.0/vyper.0.4.0+commit.e9db8d9f.{suffix}"); + let url = format!("https://github.com/vyperlang/vyper/releases/download/v0.4.3/vyper.0.4.3+commit.bff19ea2.{suffix}"); let res = reqwest::Client::builder().build().unwrap().get(url).send().await.unwrap(); diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index 9b59f50d1e848..d806c047492bd 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -148,6 +148,20 @@ impl ExtTester { let (prj, mut test_cmd) = setup_forge(self.name, self.style.clone()); + // Export vyper and forge in test command - workaround for snekmate venom tests. + if let Some(vyper) = &prj.inner.project().compiler.vyper { + let vyper_dir = vyper.path.parent().expect("vyper path should have a parent"); + let forge_bin = prj.exe_root.join(format!("../forge{}", env::consts::EXE_SUFFIX)); + let forge_dir = forge_bin.parent().expect("forge path should have a parent"); + + let existing_path = std::env::var_os("PATH").unwrap_or_default(); + let mut new_paths = vec![vyper_dir.to_path_buf(), forge_dir.to_path_buf()]; + new_paths.extend(std::env::split_paths(&existing_path)); + + let joined_path = std::env::join_paths(new_paths).expect("failed to join PATH"); + test_cmd.env("PATH", joined_path); + } + // Wipe the default structure. prj.wipe(); From f03869c47fde5c38fea22e976fe76561bdff2c8a Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Thu, 19 Jun 2025 18:54:38 +0300 Subject: [PATCH 218/244] chore: fix failing test (#10813) --- crates/cast/tests/cli/main.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index bf825cdd9f95f..a790d44f00ad1 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -2746,10 +2746,16 @@ Estimated data availability size for block 30558838 with 225 transactions: 52916 // casttest!(cast_call_return_array_of_tuples, |_prj, cmd| { - cmd.args(["call", "0x198FC70Dfe05E755C81e54bd67Bff3F729344B9b", "facets() returns ((address,bytes4[])[])", "--rpc-url", "https://rpc.viction.xyz"]) - .assert_success() - .stdout_eq(str![[r#" -[(0x9640977264aec6d4e9af381F548eee11b9e27aAe, [0x1f931c1c]), (0x395db83A04cC3d3F6C5eFc73896929Cf10D0F301, [0xcdffacc6, 0x52ef6b2c, 0xadfca15e, 0x7a0ed627, 0x01ffc9a7]), (0xC6F7b47F870024B0E2DF6DFd551E10c4A37A1cEa, [0x23452b9c, 0x7200b829, 0x8da5cb5b, 0xf2fde38b]), (0xc1f27c1f6c87e73e089Ffac23C236Fc4A9E3fccc, [0x1458d7ad, 0xd9caed12]), (0x70e272A93bc8344277a1f4390Ea6153A1D5fe450, [0x536db266, 0xfbb2d381, 0xfcd8e49e, 0x9afc19c7, 0x44e2b18c, 0x2d2506a9, 0x124f1ead, 0xc3a6a96b]), (0x662BCADB7A2CBb22367b2471d8A91E5b13FCe96B, [0x612ad9cb, 0xa4c3366e]), (0x190e03D49Ce76DDabC634a98629EDa6246aB5196, [0xa516f0f3, 0x5c2ed36a]), (0xAF69C0E3BBBf6AdE78f1466f86DfF86d64C8dA2A, [0x4630a0d8]), (0xD1317DA862AC5C145519E60D24372dc186EF7426, [0xd5bcb610, 0x5fd9ae2e, 0x2c57e884, 0x736eac0b, 0x4666fc80, 0x733214a3, 0xaf7060fd]), (0x176f558949e2a7C5217dD9C27Bf7A43c6783ee28, [0x7f99d7af, 0x103c5200, 0xc318eeda, 0xee0aa320, 0xdf1c3a5b, 0x070e81f1, 0xd53482cf, 0xf58ae2ce]), (0x531d69A3fAb6CB56A77B8402E6c217cB9cC902A9, [0xf86368ae, 0x5ad317a4, 0x0340e905, 0x2fc487ae])] + cmd.args([ + "call", + "0x198FC70Dfe05E755C81e54bd67Bff3F729344B9b", + "facets() returns ((address,bytes4[])[])", + "--rpc-url", + "https://rpc.viction.xyz", + ]) + .assert_success() + .stdout_eq(str![[r#" +[[..]] "#]]); }); From fa8d17e546027abb663856c8c4ac80ca10b28791 Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Thu, 19 Jun 2025 19:44:10 +0200 Subject: [PATCH 219/244] chore: unpin `rustfmt` nightly (#10815) unpin rustfmt nightly --- .github/workflows/test.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d5e21a495e6b0..8709cd7b07776 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -82,7 +82,6 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly with: - toolchain: nightly-2024-02-03 components: rustfmt - run: cargo fmt --all --check From 383429c75d81369c311a1c8b34c85973579859dc Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Thu, 19 Jun 2025 19:44:23 +0200 Subject: [PATCH 220/244] Revert "chore: pin nextest version in ci" (#10814) Revert "chore: pin nextest version in ci (#10800)" This reverts commit bfc53de69ca7a81d1cd8eb71f3a6035974f9ebea. --- .github/workflows/nextest.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/nextest.yml b/.github/workflows/nextest.yml index acbe2fa5953c4..ac8ed5898dd15 100644 --- a/.github/workflows/nextest.yml +++ b/.github/workflows/nextest.yml @@ -54,9 +54,7 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: target: ${{ matrix.target }} - - uses: taiki-e/install-action@v2 - with: - tool: nextest@0.9.98 + - uses: taiki-e/install-action@nextest # External tests dependencies - name: Setup Node.js From 7b1b5311b2d21c17492cbfa791735263b5b5b206 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 19 Jun 2025 23:49:24 +0200 Subject: [PATCH 221/244] chore: use native alloy functions for otterscan helpers (#10816) --- crates/anvil/src/eth/otterscan/api.rs | 84 ++++++--------------------- 1 file changed, 17 insertions(+), 67 deletions(-) diff --git a/crates/anvil/src/eth/otterscan/api.rs b/crates/anvil/src/eth/otterscan/api.rs index 66322bd21a392..451f2d268dee5 100644 --- a/crates/anvil/src/eth/otterscan/api.rs +++ b/crates/anvil/src/eth/otterscan/api.rs @@ -15,73 +15,12 @@ use alloy_rpc_types::{ BlockDetails, ContractCreator, InternalOperation, OtsBlock, OtsBlockTransactions, OtsReceipt, OtsSlimBlock, OtsTransactionReceipt, TraceEntry, TransactionsWithReceipts, }, - parity::{ - Action, CallAction, CallType, CreateAction, CreateOutput, LocalizedTransactionTrace, - RewardAction, TraceOutput, - }, + parity::{Action, CreateAction, CreateOutput, TraceOutput}, }, Block, BlockId, BlockNumberOrTag as BlockNumber, BlockTransactions, }; -use itertools::Itertools; - use futures::future::join_all; - -pub fn mentions_address(trace: LocalizedTransactionTrace, address: Address) -> Option { - match (trace.trace.action, trace.trace.result) { - (Action::Call(CallAction { from, to, .. }), _) if from == address || to == address => { - trace.transaction_hash - } - (_, Some(TraceOutput::Create(CreateOutput { address: created_address, .. }))) - if created_address == address => - { - trace.transaction_hash - } - (Action::Create(CreateAction { from, .. }), _) if from == address => trace.transaction_hash, - (Action::Reward(RewardAction { author, .. }), _) if author == address => { - trace.transaction_hash - } - _ => None, - } -} - -/// Converts the list of traces for a transaction into the expected Otterscan format. -/// -/// Follows format specified in the [`ots_traceTransaction`](https://docs.otterscan.io/api-docs/ots-api#ots_tracetransaction) spec. -pub fn batch_build_ots_traces(traces: Vec) -> Vec { - traces - .into_iter() - .filter_map(|trace| { - let output = trace - .trace - .result - .map(|r| match r { - TraceOutput::Call(output) => output.output, - TraceOutput::Create(output) => output.code, - }) - .unwrap_or_default(); - match trace.trace.action { - Action::Call(call) => Some(TraceEntry { - r#type: match call.call_type { - CallType::Call => "CALL", - CallType::CallCode => "CALLCODE", - CallType::DelegateCall => "DELEGATECALL", - CallType::StaticCall => "STATICCALL", - CallType::AuthCall => "AUTHCALL", - CallType::None => "NONE", - } - .to_string(), - depth: trace.trace.trace_address.len() as u32, - from: call.from, - to: call.to, - value: Some(call.value), - input: call.input, - output, - }), - Action::Create(_) | Action::Selfdestruct(_) | Action::Reward(_) => None, - } - }) - .collect() -} +use itertools::Itertools; impl EthApi { /// Otterscan currently requires this endpoint, even though it's not part of the `ots_*`. @@ -126,10 +65,19 @@ impl EthApi { } /// Trace a transaction and generate a trace call tree. + /// Converts the list of traces for a transaction into the expected Otterscan format. + /// + /// Follows format specified in the [`ots_traceTransaction`](https://docs.otterscan.io/api-docs/ots-api#ots_tracetransaction) spec. pub async fn ots_trace_transaction(&self, hash: B256) -> Result> { node_info!("ots_traceTransaction"); - - Ok(batch_build_ots_traces(self.backend.trace_transaction(hash).await?)) + let traces = self + .backend + .trace_transaction(hash) + .await? + .into_iter() + .filter_map(|trace| TraceEntry::from_transaction_trace(&trace.trace)) + .collect(); + Ok(traces) } /// Given a transaction hash, returns its raw revert reason. @@ -220,7 +168,8 @@ impl EthApi { let hashes = traces .into_iter() .rev() - .filter_map(|trace| mentions_address(trace, address)) + .filter(|trace| trace.contains_address(address)) + .filter_map(|trace| trace.transaction_hash) .unique(); if res.len() >= page_size { @@ -267,7 +216,8 @@ impl EthApi { let hashes = traces .into_iter() .rev() - .filter_map(|trace| mentions_address(trace, address)) + .filter(|trace| trace.contains_address(address)) + .filter_map(|trace| trace.transaction_hash) .unique(); if res.len() >= page_size { From 4fb811a03dd8ecbbbda8999e95a3e55b8cbfda0c Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 20 Jun 2025 00:02:13 +0200 Subject: [PATCH 222/244] chore: reuse alloy lenient blocknumber deserializer (#10817) * chore: reuse alloy lenient blocknumber deserializer * chore: reuse alloy lenient blocknumber type --- crates/anvil/core/src/eth/serde_helpers.rs | 47 ++-------------------- 1 file changed, 4 insertions(+), 43 deletions(-) diff --git a/crates/anvil/core/src/eth/serde_helpers.rs b/crates/anvil/core/src/eth/serde_helpers.rs index 05ec3b25fd04f..107914bd0ee5d 100644 --- a/crates/anvil/core/src/eth/serde_helpers.rs +++ b/crates/anvil/core/src/eth/serde_helpers.rs @@ -52,58 +52,19 @@ pub mod empty_params { /// A module that deserializes either a BlockNumberOrTag, or a simple number. pub mod lenient_block_number { + pub use alloy_eips::eip1898::LenientBlockNumberOrTag; use alloy_rpc_types::BlockNumberOrTag; use serde::{Deserialize, Deserializer}; - /// Following the spec the block parameter is either: - /// - /// > HEX String - an integer block number - /// > String "earliest" for the earliest/genesis block - /// > String "latest" - for the latest mined block - /// > String "pending" - for the pending state/transactions - /// - /// and with EIP-1898: - /// > blockNumber: QUANTITY - a block number - /// > blockHash: DATA - a block hash - /// - /// - /// - /// EIP-1898 does not all calls that use `BlockNumber` like `eth_getBlockByNumber` and doesn't - /// list raw integers as supported. - /// - /// However, there are dev node implementations that support integers, such as ganache: - /// - /// N.B.: geth does not support ints in `eth_getBlockByNumber` - pub fn lenient_block_number<'de, D>(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - LenientBlockNumber::deserialize(deserializer).map(Into::into) - } + /// deserializes either a BlockNumberOrTag, or a simple number. + pub use alloy_eips::eip1898::lenient_block_number_or_tag::deserialize as lenient_block_number; /// Same as `lenient_block_number` but requires to be `[num; 1]` pub fn lenient_block_number_seq<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { - let num = <[LenientBlockNumber; 1]>::deserialize(deserializer)?[0].into(); + let num = <[LenientBlockNumberOrTag; 1]>::deserialize(deserializer)?[0].into(); Ok(num) } - - /// Various block number representations, See [`lenient_block_number()`] - #[derive(Clone, Copy, Deserialize)] - #[serde(untagged)] - pub enum LenientBlockNumber { - BlockNumber(BlockNumberOrTag), - Num(u64), - } - - impl From for BlockNumberOrTag { - fn from(b: LenientBlockNumber) -> Self { - match b { - LenientBlockNumber::BlockNumber(b) => b, - LenientBlockNumber::Num(b) => b.into(), - } - } - } } From 6aa18605fafc088f2a6b94a481368d475e4fcb5b Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 20 Jun 2025 04:54:29 +0200 Subject: [PATCH 223/244] chore: remove HexDisplay util (#10819) --- crates/anvil/src/eth/util.rs | 48 ++++-------------------------------- 1 file changed, 5 insertions(+), 43 deletions(-) diff --git a/crates/anvil/src/eth/util.rs b/crates/anvil/src/eth/util.rs index beb73276c3b4d..fc7a64649e7b3 100644 --- a/crates/anvil/src/eth/util.rs +++ b/crates/anvil/src/eth/util.rs @@ -1,58 +1,20 @@ -use alloy_primitives::Address; +use alloy_primitives::{hex, Address}; +use itertools::Itertools; use revm::{ precompile::{PrecompileSpecId, Precompiles}, primitives::hardfork::SpecId, }; -use std::fmt; pub fn get_precompiles_for(spec_id: SpecId) -> Vec
{ Precompiles::new(PrecompileSpecId::from_spec_id(spec_id)).addresses().copied().collect() } -/// wrapper type that displays byte as hex -pub struct HexDisplay<'a>(&'a [u8]); - +/// Formats values as hex strings, separated by commas. pub fn hex_fmt_many(i: I) -> String where I: IntoIterator, T: AsRef<[u8]>, { - i.into_iter() - .map(|item| HexDisplay::from(item.as_ref()).to_string()) - .collect::>() - .join(", ") -} - -impl<'a> HexDisplay<'a> { - pub fn from(b: &'a [u8]) -> Self { - HexDisplay(b) - } -} - -impl fmt::Display for HexDisplay<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.0.len() < 1027 { - for byte in self.0 { - f.write_fmt(format_args!("{byte:02x}"))?; - } - } else { - for byte in &self.0[0..512] { - f.write_fmt(format_args!("{byte:02x}"))?; - } - f.write_str("...")?; - for byte in &self.0[self.0.len() - 512..] { - f.write_fmt(format_args!("{byte:02x}"))?; - } - } - Ok(()) - } -} - -impl fmt::Debug for HexDisplay<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for byte in self.0 { - f.write_fmt(format_args!("{byte:02x}"))?; - } - Ok(()) - } + let items = i.into_iter().map(|item| hex::encode(item.as_ref())).format(", "); + format!("{items}") } From 9d93694e682d0b04da7c6fe1eca28565ba299874 Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Fri, 20 Jun 2025 05:00:52 +0200 Subject: [PATCH 224/244] chore: update external integration tests (#10811) * update external integration tests * add note on last updated --- crates/forge/tests/cli/ext_integration.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/forge/tests/cli/ext_integration.rs b/crates/forge/tests/cli/ext_integration.rs index 1783fb4b402d8..1fe23ae0ff90e 100644 --- a/crates/forge/tests/cli/ext_integration.rs +++ b/crates/forge/tests/cli/ext_integration.rs @@ -1,11 +1,12 @@ use foundry_test_utils::util::ExtTester; // Actively maintained tests +// Last updated: June 19th 2025 // #[test] fn forge_std() { - ExtTester::new("foundry-rs", "forge-std", "464587138602dd194ed0eb5aab15b4721859d422") + ExtTester::new("foundry-rs", "forge-std", "60acb7aaadcce2d68e52986a0a66fe79f07d138f") // Skip fork tests. .args(["--nmc", "Fork"]) .run(); @@ -15,7 +16,7 @@ fn forge_std() { #[test] #[cfg_attr(windows, ignore = "Windows cannot find installed programs")] fn prb_math() { - ExtTester::new("PaulRBerg", "prb-math", "b03f814a03558ed5b62f89a57bcc8d720a393f67") + ExtTester::new("PaulRBerg", "prb-math", "aad73cfc6cdc2c9b660199b5b1e9db391ea48640") .install_command(&["bun", "install", "--prefer-offline"]) // Try npm if bun fails / is not installed. .install_command(&["npm", "install", "--prefer-offline"]) @@ -38,7 +39,7 @@ fn prb_proxy() { #[cfg_attr(windows, ignore = "Windows cannot find installed programs")] fn sablier_v2_core() { let mut tester = - ExtTester::new("sablier-labs", "v2-core", "43cf7c9d968e61a5a03e9237a71a27165b125414") + ExtTester::new("sablier-labs", "v2-core", "d85521f5615f6c19612ff250ee89c57b9afa6aa2") // Skip fork tests. .args(["--nmc", "Fork"]) // Increase the gas limit: https://github.com/sablier-labs/v2-core/issues/956 @@ -61,7 +62,7 @@ fn sablier_v2_core() { // #[test] fn solady() { - ExtTester::new("Vectorized", "solady", "66162801e022c268a2a0f621ac5eb0df4986f6eb").run(); + ExtTester::new("Vectorized", "solady", "701406e8126cfed931645727b274df303fbcd94d").run(); } // @@ -79,7 +80,7 @@ fn snekmate() { // #[test] fn mds1_multicall3() { - ExtTester::new("mds1", "multicall", "f534fbc9f98386a217eaaf9b29d3d4f6f920d5ec").run(); + ExtTester::new("mds1", "multicall", "5f90062160aedb7c807fadca469ac783a0557b57").run(); } // Legacy tests From edb9cc089065f1638cd9cd6e5511123c02b61a44 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 20 Jun 2025 08:24:14 +0200 Subject: [PATCH 225/244] chore: remove unused util (#10818) Co-authored-by: grandizzy --- crates/anvil/src/eth/backend/mem/mod.rs | 5 ----- crates/anvil/src/eth/util.rs | 10 +--------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index d0cc3b8795404..ea783ce7d0377 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -24,7 +24,6 @@ use crate::{ macros::node_info, pool::transactions::PoolTransaction, sign::build_typed_transaction, - util::get_precompiles_for, }, inject_precompiles, mem::{ @@ -516,10 +515,6 @@ impl Backend { self.fork.read().is_some() } - pub fn precompiles(&self) -> Vec
{ - get_precompiles_for(self.env.read().evm_env.cfg_env.spec) - } - /// Resets the fork to a fresh state pub async fn reset_fork(&self, forking: Forking) -> Result<(), BlockchainError> { if !self.is_fork() { diff --git a/crates/anvil/src/eth/util.rs b/crates/anvil/src/eth/util.rs index fc7a64649e7b3..36772dccd0982 100644 --- a/crates/anvil/src/eth/util.rs +++ b/crates/anvil/src/eth/util.rs @@ -1,13 +1,5 @@ -use alloy_primitives::{hex, Address}; +use alloy_primitives::hex; use itertools::Itertools; -use revm::{ - precompile::{PrecompileSpecId, Precompiles}, - primitives::hardfork::SpecId, -}; - -pub fn get_precompiles_for(spec_id: SpecId) -> Vec
{ - Precompiles::new(PrecompileSpecId::from_spec_id(spec_id)).addresses().copied().collect() -} /// Formats values as hex strings, separated by commas. pub fn hex_fmt_many(i: I) -> String From 2b3f9ff7d36dc2c19a1f5074053f68af3f74d276 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 20 Jun 2025 19:20:42 +0200 Subject: [PATCH 226/244] test(cast): add tests for EIP-712 type names with colons (#10772) * test(cast): add tests for EIP-712 type names with colons Add test cases to ensure cast can parse EIP-712 typed data when type names contain colons, which are valid according to the EIP-712 specification. Closes #10765 * chore: bump core * chore: rename test --- Cargo.lock | 50 +++++++++++----------- Cargo.toml | 12 +++--- crates/cast/tests/cli/main.rs | 78 +++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5b92cb3acb23a..65fab5199100f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -132,9 +132,9 @@ dependencies = [ [[package]] name = "alloy-dyn-abi" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9135eb501feccf7f4cb8a183afd406a65483fdad7bbd7332d0470e5d725c92f" +checksum = "7b95b3deca680efc7e9cba781f1a1db352fa1ea50e6384a514944dcf4419e652" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -268,9 +268,9 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b26fdd571915bafe857fccba4ee1a4f352965800e46a53e4a5f50187b7776fa" +checksum = "15516116086325c157c18261d768a20677f0f699348000ed391d4ad0dcb82530" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -361,9 +361,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a326d47106039f38b811057215a92139f46eef7983a4b77b10930a0ea5685b1e" +checksum = "6177ed26655d4e84e00b65cb494d4e0b8830e7cae7ef5d63087d445a2600fb55" dependencies = [ "alloy-rlp", "arbitrary", @@ -588,7 +588,7 @@ dependencies = [ "alloy-rlp", "alloy-serde", "alloy-sol-types", - "itertools 0.13.0", + "itertools 0.14.0", "serde", "serde_json", "thiserror 2.0.12", @@ -742,9 +742,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4be1ce1274ddd7fdfac86e5ece1b225e9bba1f2327e20fbb30ee6b9cc1423fe" +checksum = "a14f21d053aea4c6630687c2f4ad614bed4c81e14737a9b904798b24f30ea849" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -756,9 +756,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e92f3708ea4e0d9139001c86c051c538af0146944a2a9c7181753bd944bf57" +checksum = "34d99282e7c9ef14eb62727981a985a01869e586d1dec729d3bb33679094c100" dependencies = [ "alloy-json-abi", "alloy-sol-macro-input", @@ -775,9 +775,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afe1bd348a41f8c9b4b54dfb314886786d6201235b0b3f47198b9d910c86bb2" +checksum = "eda029f955b78e493360ee1d7bd11e1ab9f2a220a5715449babc79d6d0a01105" dependencies = [ "alloy-json-abi", "const-hex", @@ -793,9 +793,9 @@ dependencies = [ [[package]] name = "alloy-sol-type-parser" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6195df2acd42df92a380a8db6205a5c7b41282d0ce3f4c665ecf7911ac292f1" +checksum = "10db1bd7baa35bc8d4a1b07efbf734e73e5ba09f2580fb8cee3483a36087ceb2" dependencies = [ "serde", "winnow", @@ -803,9 +803,9 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6185e98a79cf19010722f48a74b5a65d153631d2f038cabd250f4b9e9813b8ad" +checksum = "58377025a47d8b8426b3e4846a251f2c1991033b27f517aade368146f6ab1dfe" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4265,7 +4265,7 @@ dependencies = [ "fs_extra", "futures-util", "home", - "itertools 0.13.0", + "itertools 0.14.0", "path-slash", "rand 0.8.5", "rayon", @@ -7162,7 +7162,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.13.0", + "itertools 0.14.0", "proc-macro2", "quote", "syn 2.0.103", @@ -8694,7 +8694,7 @@ dependencies = [ "derive_builder", "derive_more 2.0.1", "dunce", - "itertools 0.13.0", + "itertools 0.14.0", "itoa", "lasso", "match_cfg", @@ -8706,7 +8706,7 @@ dependencies = [ "solar-config", "solar-data-structures", "solar-macros", - "thiserror 1.0.69", + "thiserror 2.0.12", "tracing", "unicode-width 0.2.0", ] @@ -8731,7 +8731,7 @@ dependencies = [ "alloy-primitives", "bitflags 2.9.1", "bumpalo", - "itertools 0.13.0", + "itertools 0.14.0", "memchr", "num-bigint", "num-rational", @@ -9042,7 +9042,7 @@ dependencies = [ "serde_json", "sha2 0.10.9", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.12", "url", "zip", ] @@ -9083,9 +9083,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c8c8f496c33dc6343dac05b4be8d9e0bca180a4caa81d7b8416b10cc2273cd" +checksum = "b9ac494e7266fcdd2ad80bf4375d55d27a117ea5c866c26d0e97fe5b3caeeb75" dependencies = [ "paste", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 30e2b3d0f1603..a54e975ae1d13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -239,17 +239,17 @@ alloy-hardforks = { version = "0.2.6", default-features = false } alloy-op-hardforks = { version = "0.2.6", default-features = false } ## alloy-core -alloy-dyn-abi = "1.1" -alloy-json-abi = "1.1" -alloy-primitives = { version = "1.1", features = [ +alloy-dyn-abi = "1.2.1" +alloy-json-abi = "1.2.1" +alloy-primitives = { version = "1.2.1", features = [ "getrandom", "rand", "map-fxhash", "map-foldhash", ] } -alloy-sol-macro-expander = "1.1" -alloy-sol-macro-input = "1.1" -alloy-sol-types = "1.1" +alloy-sol-macro-expander = "1.2.1" +alloy-sol-macro-input = "1.2.1" +alloy-sol-types = "1.2.1" alloy-chains = "0.2" alloy-rlp = "0.3" diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index a790d44f00ad1..189a83ceec0f6 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -387,6 +387,84 @@ casttest!(wallet_sign_typed_data_file, |_prj, cmd| { "#]]); }); +// tests that `cast wallet sign typed-data` passes with type names containing colons +// +casttest!(wallet_sign_typed_data_with_colon_succeeds, |_prj, cmd| { + let typed_data_with_colon = r#"{ + "types": { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + {"name": "version", "type": "string"}, + {"name": "chainId", "type": "uint256"}, + {"name": "verifyingContract", "type": "address"} + ], + "Test:Message": [ + {"name": "content", "type": "string"} + ] + }, + "primaryType": "Test:Message", + "domain": { + "name": "TestDomain", + "version": "1", + "chainId": 1, + "verifyingContract": "0x0000000000000000000000000000000000000000" + }, + "message": { + "content": "Hello" + } + }"#; + + cmd.args([ + "wallet", + "sign", + "--private-key", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "--data", + typed_data_with_colon, + ]).assert_success().stdout_eq(str![[r#" +0xf91c67e845a4d468d1f876f457ffa01e65468641fc121453705242d21de39b266c278592b085814ab1e9adc938cc26b1d64bb61f80b437df077777c4283612291b + +"#]]); +}); + +// tests that the same data without colon works correctly +// +casttest!(wallet_sign_typed_data_without_colon_works, |_prj, cmd| { + let typed_data_without_colon = r#"{ + "types": { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + {"name": "version", "type": "string"}, + {"name": "chainId", "type": "uint256"}, + {"name": "verifyingContract", "type": "address"} + ], + "TestMessage": [ + {"name": "content", "type": "string"} + ] + }, + "primaryType": "TestMessage", + "domain": { + "name": "TestDomain", + "version": "1", + "chainId": 1, + "verifyingContract": "0x0000000000000000000000000000000000000000" + }, + "message": { + "content": "Hello" + } + }"#; + + cmd.args([ + "wallet", + "sign", + "--private-key", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "--data", + typed_data_without_colon, + ]) + .assert_success(); +}); + // tests that `cast wallet sign-auth message` outputs the expected signature casttest!(wallet_sign_auth, |_prj, cmd| { cmd.args([ From e6de72c999bf8b72c166c5c37fbf71f5a7893cef Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Fri, 20 Jun 2025 12:44:14 -0500 Subject: [PATCH 227/244] feat(forge): coverage guided fuzzing & time based campaigns for invariant mode (#10190) * rename coverage to line coverage for clarity * WIP: coverage guided fuzzing * wip persist invariant corpus * add binning and history map * rm proptest runner, add corpus mutations * fix: splice mutation, add some notes * Clippy and more tests * save * use libafl_bolt's SIMD hitmap * fix eyre issues * add comments and psuedocode * Revert libafl * Typo * Fix win config test * cleanup, save corpus at the end of run, if new coverage * consolidate corpus manager * Consolidate tx manager corpus logic * Review changes: do not stop fuzzing if corpus replay failures, report number of failures, uuids for corpus file * Default gzip corpus and config to toggle json/gzip * Evict oldest corpus with more than x mutations * Add min corpus size config, bump max mutations to default depth run * Simplify corpus manager and corpus struct, enable prefix / suffix mutation, manager to handle generate from strategy * Fuzz arg from ABI * Corpus max mutations default 5 * Save metadata on disk at eviction time * Remove more than 2 branches branch, make sure we always have one * Load gz and json seeds, ignore metadata files * ABI mutation replaces subset of arguments sometimes * prevent empty range but perform at least 1 round * trim selector when using abi_decode_input * Nit, remove clippy allow * retain corpus items that are highly likely to produce new finds * rename corpus_max_mutations to corpus_min_mutations * update cli test expectations * Stateless fuzz corpus config revert, add invariant time based campaigns * Changes after review - revert cache dir configs, invariant corpus can be external of cache - save and load as json.gz - comment update - introduce mutation type enum * Remove outdated comment * Update crates/evm/evm/src/executors/mod.rs Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> * Changes after review: comment, update merge_edge_coverage, use rng.gen * Fix docs * Keep test assert, found faster than without guidance * Fix * Do not use in memory mutated corpus if coverage guided is disabled. --------- Co-authored-by: grandizzy Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> --- Cargo.lock | 2 + Cargo.toml | 2 + crates/anvil/Cargo.toml | 2 +- crates/common/Cargo.toml | 2 + crates/common/src/fs.rs | 26 +- crates/config/src/invariant.rs | 17 + crates/config/src/lib.rs | 2 + crates/evm/coverage/src/inspector.rs | 12 +- crates/evm/coverage/src/lib.rs | 2 +- crates/evm/evm/Cargo.toml | 1 + crates/evm/evm/src/executors/fuzz/mod.rs | 4 +- .../evm/evm/src/executors/invariant/corpus.rs | 513 ++++++++++++++++++ crates/evm/evm/src/executors/invariant/mod.rs | 138 +++-- .../evm/evm/src/executors/invariant/replay.rs | 8 +- .../evm/evm/src/executors/invariant/result.rs | 4 +- crates/evm/evm/src/executors/mod.rs | 60 +- crates/evm/evm/src/inspectors/mod.rs | 2 +- crates/evm/evm/src/inspectors/stack.rs | 63 ++- crates/evm/fuzz/src/invariant/mod.rs | 13 +- crates/evm/fuzz/src/lib.rs | 4 +- crates/forge/src/cmd/coverage.rs | 4 +- crates/forge/src/cmd/snapshot.rs | 7 +- crates/forge/src/multi_runner.rs | 18 +- crates/forge/src/progress.rs | 20 +- crates/forge/src/result.rs | 96 +++- crates/forge/src/runner.rs | 36 +- crates/forge/tests/cli/config.rs | 8 + crates/forge/tests/it/invariant.rs | 18 +- crates/forge/tests/it/test_helpers.rs | 4 + 29 files changed, 919 insertions(+), 169 deletions(-) create mode 100644 crates/evm/evm/src/executors/invariant/corpus.rs diff --git a/Cargo.lock b/Cargo.lock index 65fab5199100f..65cb9689ebe43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4204,6 +4204,7 @@ dependencies = [ "comfy-table", "dunce", "eyre", + "flate2", "foundry-block-explorers", "foundry-common-fmt", "foundry-compilers", @@ -4438,6 +4439,7 @@ dependencies = [ "serde", "thiserror 2.0.12", "tracing", + "uuid 1.17.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a54e975ae1d13..e2fbc4a9f9bd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -349,6 +349,8 @@ yansi = { version = "1.0", features = ["detect-tty", "detect-env"] } path-slash = "0.2" jiff = "0.2" heck = "0.5" +uuid = "1.17.0" +flate2 = "1.1" ## Pinned dependencies. Enabled for the workspace in crates/test-utils. diff --git a/crates/anvil/Cargo.toml b/crates/anvil/Cargo.toml index 24abbca6feeb6..3ad68fe3b4fb7 100644 --- a/crates/anvil/Cargo.toml +++ b/crates/anvil/Cargo.toml @@ -84,7 +84,7 @@ futures.workspace = true async-trait.workspace = true # misc -flate2 = "1.1" +flate2.workspace = true serde_json.workspace = true serde.workspace = true thiserror.workspace = true diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index ecfc9279ac39a..b440a5f7cdb84 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -73,6 +73,8 @@ anstyle.workspace = true terminal_size.workspace = true ciborium.workspace = true +flate2.workspace = true + [build-dependencies] chrono.workspace = true vergen = { workspace = true, features = ["build", "git", "gitcl"] } diff --git a/crates/common/src/fs.rs b/crates/common/src/fs.rs index 19675e425a4ce..4853eeed5a886 100644 --- a/crates/common/src/fs.rs +++ b/crates/common/src/fs.rs @@ -1,10 +1,11 @@ //! Contains various `std::fs` wrapper functions that also contain the target path in their errors. use crate::errors::FsPathError; +use flate2::{read::GzDecoder, write::GzEncoder, Compression}; use serde::{de::DeserializeOwned, Serialize}; use std::{ fs::{self, File}, - io::{BufWriter, Write}, + io::{BufReader, BufWriter, Write}, path::{Component, Path, PathBuf}, }; @@ -49,6 +50,15 @@ pub fn read_json_file(path: &Path) -> Result { serde_json::from_str(&s).map_err(|source| FsPathError::ReadJson { source, path: path.into() }) } +/// Reads and decodes the json gzip file, then deserialize it into the provided type. +pub fn read_json_gzip_file(path: &Path) -> Result { + let file = open(path)?; + let reader = BufReader::new(file); + let decoder = GzDecoder::new(reader); + serde_json::from_reader(decoder) + .map_err(|source| FsPathError::ReadJson { source, path: path.into() }) +} + /// Writes the object as a JSON object. pub fn write_json_file(path: &Path, obj: &T) -> Result<()> { let file = create_file(path)?; @@ -67,6 +77,20 @@ pub fn write_pretty_json_file(path: &Path, obj: &T) -> Result<()> writer.flush().map_err(|e| FsPathError::write(e, path)) } +/// Writes the object as a gzip compressed file. +pub fn write_json_gzip_file(path: &Path, obj: &T) -> Result<()> { + let file = create_file(path)?; + let writer = BufWriter::new(file); + let mut encoder = GzEncoder::new(writer, Compression::default()); + serde_json::to_writer(&mut encoder, obj) + .map_err(|source| FsPathError::WriteJson { source, path: path.into() })?; + encoder + .finish() + .map_err(serde_json::Error::io) + .map_err(|source| FsPathError::WriteJson { source, path: path.into() })?; + Ok(()) +} + /// Wrapper for `std::fs::write` pub fn write(path: impl AsRef, contents: impl AsRef<[u8]>) -> Result<()> { let path = path.as_ref(); diff --git a/crates/config/src/invariant.rs b/crates/config/src/invariant.rs index b5939ad6f5f1d..be775dcd146e2 100644 --- a/crates/config/src/invariant.rs +++ b/crates/config/src/invariant.rs @@ -26,6 +26,15 @@ pub struct InvariantConfig { pub max_assume_rejects: u32, /// Number of runs to execute and include in the gas report. pub gas_report_samples: u32, + /// Path where invariant corpus is stored. If not configured then coverage guided fuzzing is + /// disabled. + pub corpus_dir: Option, + /// Whether corpus to use gzip file compression and decompression. + pub corpus_gzip: bool, + // Number of corpus mutations until marked as eligible to be flushed from memory. + pub corpus_min_mutations: usize, + // Number of corpus that won't be evicted from memory. + pub corpus_min_size: usize, /// Path where invariant failures are recorded and replayed. pub failure_persist_dir: Option, /// Whether to collect and display fuzzed selectors metrics. @@ -47,6 +56,10 @@ impl Default for InvariantConfig { shrink_run_limit: 5000, max_assume_rejects: 65536, gas_report_samples: 256, + corpus_dir: None, + corpus_gzip: true, + corpus_min_mutations: 5, + corpus_min_size: 0, failure_persist_dir: None, show_metrics: true, timeout: None, @@ -67,6 +80,10 @@ impl InvariantConfig { shrink_run_limit: 5000, max_assume_rejects: 65536, gas_report_samples: 256, + corpus_dir: None, + corpus_gzip: true, + corpus_min_mutations: 5, + corpus_min_size: 0, failure_persist_dir: Some(cache_dir), show_metrics: true, timeout: None, diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 98fc97b227302..1d4a056969a30 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -1059,6 +1059,7 @@ impl Config { } }; remove_test_dir(&self.fuzz.failure_persist_dir); + remove_test_dir(&self.invariant.corpus_dir); remove_test_dir(&self.invariant.failure_persist_dir); Ok(()) @@ -4537,6 +4538,7 @@ mod tests { runs: 512, depth: 10, failure_persist_dir: Some(PathBuf::from("cache/invariant")), + corpus_dir: None, ..Default::default() } ); diff --git a/crates/evm/coverage/src/inspector.rs b/crates/evm/coverage/src/inspector.rs index dfed9589e55fc..d01b4325a0296 100644 --- a/crates/evm/coverage/src/inspector.rs +++ b/crates/evm/coverage/src/inspector.rs @@ -10,7 +10,7 @@ use std::ptr::NonNull; /// Inspector implementation for collecting coverage information. #[derive(Clone, Debug)] -pub struct CoverageCollector { +pub struct LineCoverageCollector { // NOTE: `current_map` is always a valid reference into `maps`. // It is accessed only through `get_or_insert_map` which guarantees that it's valid. // Both of these fields are unsafe to access directly outside of `*insert_map`. @@ -21,10 +21,10 @@ pub struct CoverageCollector { } // SAFETY: See comments on `current_map`. -unsafe impl Send for CoverageCollector {} -unsafe impl Sync for CoverageCollector {} +unsafe impl Send for LineCoverageCollector {} +unsafe impl Sync for LineCoverageCollector {} -impl Default for CoverageCollector { +impl Default for LineCoverageCollector { fn default() -> Self { Self { current_map: NonNull::dangling(), @@ -34,7 +34,7 @@ impl Default for CoverageCollector { } } -impl Inspector for CoverageCollector +impl Inspector for LineCoverageCollector where CTX: ContextTr, { @@ -50,7 +50,7 @@ where } } -impl CoverageCollector { +impl LineCoverageCollector { /// Finish collecting coverage information and return the [`HitMaps`]. pub fn finish(self) -> HitMaps { self.maps diff --git a/crates/evm/coverage/src/lib.rs b/crates/evm/coverage/src/lib.rs index 793e0ee56670c..14af71c0a1c5d 100644 --- a/crates/evm/coverage/src/lib.rs +++ b/crates/evm/coverage/src/lib.rs @@ -29,7 +29,7 @@ pub mod analysis; pub mod anchors; mod inspector; -pub use inspector::CoverageCollector; +pub use inspector::LineCoverageCollector; /// A coverage report. /// diff --git a/crates/evm/evm/Cargo.toml b/crates/evm/evm/Cargo.toml index 06074e305b630..c77f0192f67a5 100644 --- a/crates/evm/evm/Cargo.toml +++ b/crates/evm/evm/Cargo.toml @@ -52,3 +52,4 @@ thiserror.workspace = true tracing.workspace = true indicatif.workspace = true serde.workspace = true +uuid.workspace = true diff --git a/crates/evm/evm/src/executors/fuzz/mod.rs b/crates/evm/evm/src/executors/fuzz/mod.rs index a64b072193587..24c0a71107713 100644 --- a/crates/evm/evm/src/executors/fuzz/mod.rs +++ b/crates/evm/evm/src/executors/fuzz/mod.rs @@ -181,7 +181,7 @@ impl FuzzedExecutor { traces: last_run_traces, breakpoints: last_run_breakpoints, gas_report_traces: traces.into_iter().map(|a| a.arena).collect(), - coverage: fuzz_result.coverage, + line_coverage: fuzz_result.coverage, deprecated_cheatcodes: fuzz_result.deprecated_cheatcodes, }; @@ -258,7 +258,7 @@ impl FuzzedExecutor { Ok(FuzzOutcome::Case(CaseOutcome { case: FuzzCase { calldata, gas: call.gas_used, stipend: call.stipend }, traces: call.traces, - coverage: call.coverage, + coverage: call.line_coverage, breakpoints, logs: call.logs, deprecated_cheatcodes, diff --git a/crates/evm/evm/src/executors/invariant/corpus.rs b/crates/evm/evm/src/executors/invariant/corpus.rs new file mode 100644 index 0000000000000..8c8d07c72dc08 --- /dev/null +++ b/crates/evm/evm/src/executors/invariant/corpus.rs @@ -0,0 +1,513 @@ +use crate::executors::{ + invariant::{InvariantTest, InvariantTestRun}, + Executor, +}; +use alloy_dyn_abi::JsonAbiExt; +use alloy_primitives::U256; +use eyre::eyre; +use foundry_config::InvariantConfig; +use foundry_evm_fuzz::{ + invariant::{BasicTxDetails, FuzzRunIdentifiedContracts}, + strategies::fuzz_param_from_state, +}; +use proptest::{ + prelude::{Just, Rng, Strategy}, + prop_oneof, + strategy::{BoxedStrategy, ValueTree}, + test_runner::TestRunner, +}; +use serde::Serialize; +use std::{ + path::PathBuf, + time::{SystemTime, UNIX_EPOCH}, +}; +use uuid::Uuid; + +const METADATA_SUFFIX: &str = "metadata.json"; +const JSON_EXTENSION: &str = ".json"; + +/// Possible mutation strategies to apply on a call sequence. +#[derive(Debug, Clone)] +enum MutationType { + /// Splice original call sequence. + Splice, + /// Repeat selected call several times. + Repeat, + /// Interleave calls from two random call sequences. + Interleave, + /// Replace prefix of the original call sequence with new calls. + Prefix, + /// Replace suffix of the original call sequence with new calls. + Suffix, + /// ABI mutate random args of selected call in sequence. + Abi, +} + +/// Holds Corpus information. +#[derive(Serialize)] +struct Corpus { + // Unique corpus identifier. + uuid: Uuid, + // Total mutations of corpus as primary source. + total_mutations: usize, + // New coverage found as a result of mutating this corpus. + new_finds_produced: usize, + // Corpus call sequence. + #[serde(skip_serializing)] + tx_seq: Vec, +} + +impl Corpus { + /// New corpus from given call sequence and corpus path to read uuid. + pub fn new(tx_seq: Vec, path: PathBuf) -> eyre::Result { + let uuid = if let Some(stem) = path.file_stem().and_then(|s| s.to_str()) { + Uuid::try_from(stem.strip_suffix(JSON_EXTENSION).unwrap_or(stem).to_string())? + } else { + Uuid::new_v4() + }; + Ok(Self { uuid, total_mutations: 0, new_finds_produced: 0, tx_seq }) + } + + /// New corpus with given call sequence and new uuid. + pub fn from_tx_seq(tx_seq: Vec) -> Self { + Self { uuid: Uuid::new_v4(), total_mutations: 0, new_finds_produced: 0, tx_seq } + } +} + +/// Invariant corpus manager. +pub struct TxCorpusManager { + // Fuzzed calls generator. + tx_generator: BoxedStrategy, + // Call sequence mutation strategy type generator. + mutation_generator: BoxedStrategy, + // Path to invariant corpus directory. If None, sequences with new coverage are not persisted. + corpus_dir: Option, + // Whether corpus to use gzip file compression and decompression. + corpus_gzip: bool, + // Number of mutations until entry marked as eligible to be flushed from in-memory corpus. + // Mutations will be perfored at least `corpus_min_mutations` times. + corpus_min_mutations: usize, + // Number of corpus that won't be evicted from memory. + corpus_min_size: usize, + // In-memory corpus, populated from persisted files and current runs. + // Mutation is performed on these. + in_memory_corpus: Vec, + // Identifier of current mutated entry. + current_mutated: Option, + // Number of failed replays from persisted corpus. + failed_replays: usize, +} + +impl TxCorpusManager { + pub fn new( + invariant_config: &InvariantConfig, + test_name: &String, + fuzzed_contracts: &FuzzRunIdentifiedContracts, + tx_generator: BoxedStrategy, + executor: &Executor, + history_map: &mut [u8], + ) -> eyre::Result { + let mutation_generator = prop_oneof![ + Just(MutationType::Splice), + Just(MutationType::Repeat), + Just(MutationType::Interleave), + Just(MutationType::Prefix), + Just(MutationType::Suffix), + Just(MutationType::Abi), + ] + .boxed(); + let mut in_memory_corpus = vec![]; + let corpus_gzip = invariant_config.corpus_gzip; + let corpus_min_mutations = invariant_config.corpus_min_mutations; + let corpus_min_size = invariant_config.corpus_min_size; + let mut failed_replays = 0; + + // Early return if corpus dir / coverage guided fuzzing not configured. + let Some(corpus_dir) = &invariant_config.corpus_dir else { + return Ok(Self { + tx_generator, + mutation_generator, + corpus_dir: None, + corpus_gzip, + corpus_min_mutations, + corpus_min_size, + in_memory_corpus, + current_mutated: None, + failed_replays, + }) + }; + + // Ensure corpus dir for invariant function is created. + let corpus_dir = corpus_dir.join(test_name); + if !corpus_dir.is_dir() { + foundry_common::fs::create_dir_all(&corpus_dir)?; + } + + let fuzzed_contracts = fuzzed_contracts.targets.lock(); + + for entry in std::fs::read_dir(&corpus_dir)? { + let path = entry?.path(); + if path.is_file() { + if let Some(name) = path.file_name().and_then(|s| s.to_str()) { + // Ignore metadata files + if name.contains(METADATA_SUFFIX) { + continue + } + } + } + + let read_corpus_result = match path.extension().and_then(|ext| ext.to_str()) { + Some("gz") => foundry_common::fs::read_json_gzip_file::>(&path), + _ => foundry_common::fs::read_json_file::>(&path), + }; + + let Ok(tx_seq) = read_corpus_result else { + trace!(target: "corpus", "failed to load corpus from {}", path.display()); + continue + }; + + if !tx_seq.is_empty() { + // Warm up history map from loaded sequences. + let mut executor = executor.clone(); + for tx in &tx_seq { + let mut call_result = executor + .call_raw( + tx.sender, + tx.call_details.target, + tx.call_details.calldata.clone(), + U256::ZERO, + ) + .map_err(|e| eyre!(format!("Could not make raw evm call: {e}")))?; + + if fuzzed_contracts.can_replay(tx) { + call_result.merge_edge_coverage(history_map); + executor.commit(&mut call_result); + } else { + failed_replays += 1; + } + } + + trace!( + target: "corpus", + "load sequence with len {} from corpus file {}", + tx_seq.len(), + path.display() + ); + + // Populate in memory corpus with sequence from corpus file. + in_memory_corpus.push(Corpus::new(tx_seq, path)?); + } + } + + Ok(Self { + tx_generator, + mutation_generator, + corpus_dir: Some(corpus_dir), + corpus_gzip, + corpus_min_mutations, + corpus_min_size, + in_memory_corpus, + current_mutated: None, + failed_replays, + }) + } + + /// Collects inputs from given invariant run, if new coverage produced. + /// Persists call sequence (if corpus directory is configured) and updates in-memory corpus. + pub fn collect_inputs(&mut self, test_run: &InvariantTestRun) { + // Early return if corpus dir / coverage guided fuzzing is not configured. + let Some(corpus_dir) = &self.corpus_dir else { + return; + }; + + // Update stats of current mutated primary corpus. + if let Some(uuid) = &self.current_mutated { + if let Some(corpus) = + self.in_memory_corpus.iter_mut().find(|corpus| corpus.uuid.eq(uuid)) + { + corpus.total_mutations += 1; + if test_run.new_coverage { + corpus.new_finds_produced += 1 + } + + trace!( + target: "corpus", + "updated corpus {}, total mutations: {}, new finds: {}", + corpus.uuid, corpus.total_mutations, corpus.new_finds_produced + ); + } + + self.current_mutated = None; + } + + // Collect inputs only if current run produced new coverage. + if !test_run.new_coverage { + return; + } + + let corpus = Corpus::from_tx_seq(test_run.inputs.clone()); + let corpus_uuid = corpus.uuid; + + // Persist to disk if corpus dir is configured. + let write_result = if self.corpus_gzip { + foundry_common::fs::write_json_gzip_file( + corpus_dir.join(format!("{corpus_uuid}{JSON_EXTENSION}.gz")).as_path(), + &corpus.tx_seq, + ) + } else { + foundry_common::fs::write_json_file( + corpus_dir.join(format!("{corpus_uuid}{JSON_EXTENSION}")).as_path(), + &corpus.tx_seq, + ) + }; + + if let Err(err) = write_result { + debug!(target: "corpus", %err, "Failed to record call sequence {:?}", &corpus.tx_seq); + } else { + trace!( + target: "corpus", + "persisted {} inputs for new coverage in {corpus_uuid} corpus", + &corpus.tx_seq.len() + ); + } + + // This includes reverting txs in the corpus and `can_continue` removes + // them. We want this as it is new coverage and may help reach the other branch. + self.in_memory_corpus.push(corpus); + } + + /// Generates new call sequence from in memory corpus. Evicts oldest corpus mutated more than + /// configured max mutations value. + pub fn new_sequence(&mut self, test: &InvariantTest) -> eyre::Result> { + let mut new_seq = vec![]; + let test_runner = &mut test.execution_data.borrow_mut().branch_runner; + + // Early return with first_input only if corpus dir / coverage guided fuzzing not + // configured. + let Some(corpus_dir) = &self.corpus_dir else { + new_seq.push(self.new_tx(test_runner)?); + return Ok(new_seq); + }; + + if !self.in_memory_corpus.is_empty() { + // Flush oldest corpus mutated more than configured max mutations unless they are + // producing new finds more than 1/3 of the time. + let should_evict = self.in_memory_corpus.len() > self.corpus_min_size.max(1); + if should_evict { + if let Some(index) = self.in_memory_corpus.iter().position(|corpus| { + corpus.total_mutations > self.corpus_min_mutations && + (corpus.new_finds_produced as f64 / corpus.total_mutations as f64) < 0.3 + }) { + let corpus = self.in_memory_corpus.get(index).unwrap(); + let uuid = corpus.uuid; + debug!(target: "corpus", "evict corpus {uuid}"); + + // Flush to disk the seed metadata at the time of eviction. + let eviction_time = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_secs(); + foundry_common::fs::write_json_file( + corpus_dir + .join(format!("{uuid}-{eviction_time}-{METADATA_SUFFIX}")) + .as_path(), + &corpus, + )?; + // Remove corpus from memory. + self.in_memory_corpus.remove(index); + } + } + + let mutation_type = self + .mutation_generator + .new_tree(test_runner) + .expect("Could not generate mutation type") + .current(); + let rng = test_runner.rng(); + let corpus_len = self.in_memory_corpus.len(); + let primary = &self.in_memory_corpus[rng.random_range(0..corpus_len)]; + let secondary = &self.in_memory_corpus[rng.random_range(0..corpus_len)]; + + match mutation_type { + MutationType::Splice => { + trace!(target: "corpus", "splice {} and {}", primary.uuid, secondary.uuid); + if should_evict { + self.current_mutated = Some(primary.uuid); + } + let start1 = rng.random_range(0..primary.tx_seq.len()); + let end1 = rng.random_range(start1..primary.tx_seq.len()); + + let start2 = rng.random_range(0..secondary.tx_seq.len()); + let end2 = rng.random_range(start2..secondary.tx_seq.len()); + + for tx in primary.tx_seq.iter().take(end1).skip(start1) { + new_seq.push(tx.clone()); + } + for tx in secondary.tx_seq.iter().take(end2).skip(start2) { + new_seq.push(tx.clone()); + } + } + MutationType::Repeat => { + let corpus = if rng.random::() { primary } else { secondary }; + trace!(target: "corpus", "repeat {}", corpus.uuid); + if should_evict { + self.current_mutated = Some(corpus.uuid); + } + new_seq = corpus.tx_seq.clone(); + let start = rng.random_range(0..corpus.tx_seq.len()); + let end = rng.random_range(start..corpus.tx_seq.len()); + let item_idx = rng.random_range(0..corpus.tx_seq.len()); + let repeated = vec![new_seq[item_idx].clone(); end - start]; + new_seq.splice(start..end, repeated); + } + MutationType::Interleave => { + trace!(target: "corpus", "interleave {} with {}", primary.uuid, secondary.uuid); + if should_evict { + self.current_mutated = Some(primary.uuid); + } + for (tx1, tx2) in primary.tx_seq.iter().zip(secondary.tx_seq.iter()) { + // chunks? + let tx = if rng.random::() { tx1.clone() } else { tx2.clone() }; + new_seq.push(tx); + } + } + MutationType::Prefix => { + let corpus = if rng.random::() { primary } else { secondary }; + trace!(target: "corpus", "overwrite prefix of {}", corpus.uuid); + if should_evict { + self.current_mutated = Some(corpus.uuid); + } + new_seq = corpus.tx_seq.clone(); + for i in 0..rng.random_range(0..=new_seq.len()) { + new_seq[i] = self.new_tx(test_runner)?; + } + } + MutationType::Suffix => { + let corpus = if rng.random::() { primary } else { secondary }; + trace!(target: "corpus", "overwrite suffix of {}", corpus.uuid); + if should_evict { + self.current_mutated = Some(corpus.uuid); + } + new_seq = corpus.tx_seq.clone(); + for i in new_seq.len() - rng.random_range(0..new_seq.len())..corpus.tx_seq.len() + { + new_seq[i] = self.new_tx(test_runner)?; + } + } + MutationType::Abi => { + let targets = test.targeted_contracts.targets.lock(); + let corpus = if rng.random::() { primary } else { secondary }; + trace!(target: "corpus", "ABI mutate args of {}", corpus.uuid); + if should_evict { + self.current_mutated = Some(corpus.uuid); + } + new_seq = corpus.tx_seq.clone(); + + let idx = rng.random_range(0..new_seq.len()); + let tx = new_seq.get_mut(idx).unwrap(); + if let (_, Some(function)) = targets.fuzzed_artifacts(tx) { + // TODO add call_value to call details and mutate it as well as sender some + // of the time + if !function.inputs.is_empty() { + let mut new_function = function.clone(); + let mut arg_mutation_rounds = + rng.random_range(0..=function.inputs.len()).max(1); + let round_arg_idx: Vec = if function.inputs.len() <= 1 { + vec![0] + } else { + (0..arg_mutation_rounds) + .map(|_| { + test_runner.rng().random_range(0..function.inputs.len()) + }) + .collect() + }; + // TODO mutation strategy for individual ABI types + let mut prev_inputs = function + .abi_decode_input(&tx.call_details.calldata[4..]) + .expect("fuzzed_artifacts returned wrong sig"); + // For now, only new inputs are generated, no existing inputs are + // mutated. + let mut gen_input = |input: &alloy_json_abi::Param| { + fuzz_param_from_state( + &input.selector_type().parse().unwrap(), + &test.fuzz_state, + ) + .new_tree(test_runner) + .expect("Could not generate case") + .current() + }; + + while arg_mutation_rounds > 0 { + let idx = round_arg_idx[arg_mutation_rounds - 1]; + let input = new_function + .inputs + .get_mut(idx) + .expect("Could not get input to mutate"); + let new_input = gen_input(input); + prev_inputs[idx] = new_input; + arg_mutation_rounds -= 1; + } + + tx.call_details.calldata = new_function + .abi_encode_input(&prev_inputs) + .map_err(|e| eyre!(e.to_string()))? + .into(); + } + } + } + } + } + + // Make sure sequence contains at least one tx to start fuzzing from. + if new_seq.is_empty() { + new_seq.push(self.new_tx(test_runner)?); + } + trace!(target: "corpus", "new sequence of {} calls generated", new_seq.len()); + + Ok(new_seq) + } + + /// Returns the next call to be used in call sequence. + /// If coverage guided fuzzing is not configured or if previous input was discarded then this is + /// a new tx from strategy. + /// If running with coverage guided fuzzing it returns a new call only when sequence + /// does not have enough entries, or randomly. Otherwise, returns the next call from initial + /// sequence. + pub fn generate_next_input( + &mut self, + test: &InvariantTest, + sequence: &[BasicTxDetails], + discarded: bool, + depth: usize, + ) -> eyre::Result { + let test_runner = &mut test.execution_data.borrow_mut().branch_runner; + + // Early return with new input if corpus dir / coverage guided fuzzing not configured or if + // call was discarded. + if self.corpus_dir.is_none() || discarded { + return self.new_tx(test_runner) + } + + // When running with coverage guided fuzzing enabled then generate new sequence if initial + // sequence's length is less than depth or randomly, to occasionally intermix new txs. + if depth > sequence.len().saturating_sub(1) || test_runner.rng().random_ratio(1, 10) { + return self.new_tx(test_runner) + } + + // Continue with the next call initial sequence + Ok(sequence[depth].clone()) + } + + /// Generates single call from invariant strategy. + pub fn new_tx(&mut self, test_runner: &mut TestRunner) -> eyre::Result { + Ok(self + .tx_generator + .new_tree(test_runner) + .map_err(|_| eyre!("Could not generate case"))? + .current()) + } + + pub fn failed_replays(self) -> usize { + self.failed_replays + } +} diff --git a/crates/evm/evm/src/executors/invariant/mod.rs b/crates/evm/evm/src/executors/invariant/mod.rs index 4e2914ae79e04..29ad0154bc250 100644 --- a/crates/evm/evm/src/executors/invariant/mod.rs +++ b/crates/evm/evm/src/executors/invariant/mod.rs @@ -10,7 +10,6 @@ use foundry_config::InvariantConfig; use foundry_evm_core::{ constants::{ CALLER, CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, HARDHAT_CONSOLE_ADDRESS, MAGIC_ASSUME, - TEST_TIMEOUT, }, precompiles::PRECOMPILES, }; @@ -25,10 +24,7 @@ use foundry_evm_fuzz::{ use foundry_evm_traces::{CallTraceArena, SparsedTraceArena}; use indicatif::ProgressBar; use parking_lot::RwLock; -use proptest::{ - strategy::{Strategy, ValueTree}, - test_runner::{TestCaseError, TestRunner}, -}; +use proptest::{strategy::Strategy, test_runner::TestRunner}; use result::{assert_after_invariant, assert_invariants, can_continue}; use revm::state::Account; use shrink::shrink_sequence; @@ -49,8 +45,10 @@ mod result; pub use result::InvariantFuzzTestResult; use serde::{Deserialize, Serialize}; +mod corpus; + mod shrink; -use crate::executors::{EvmError, FuzzTestTimer}; +use crate::executors::{invariant::corpus::TxCorpusManager, EvmError, FuzzTestTimer}; pub use shrink::check_sequence; sol! { @@ -130,8 +128,8 @@ pub struct InvariantTestData { pub gas_report_traces: Vec>, // Last call results of the invariant test. pub last_call_results: Option, - // Coverage information collected from all fuzzed calls. - pub coverage: Option, + // Line coverage information collected from all fuzzed calls. + pub line_coverage: Option, // Metrics for each fuzzed selector. pub metrics: Map, @@ -171,7 +169,7 @@ impl InvariantTest { last_run_inputs: vec![], gas_report_traces: vec![], last_call_results, - coverage: None, + line_coverage: None, metrics: Map::default(), branch_runner, }); @@ -203,9 +201,9 @@ impl InvariantTest { self.execution_data.borrow_mut().last_run_inputs.clone_from(inputs); } - /// Merge current collected coverage with the new coverage from last fuzzed call. + /// Merge current collected line coverage with the new coverage from last fuzzed call. pub fn merge_coverage(&self, new_coverage: Option) { - HitMaps::merge_opt(&mut self.execution_data.borrow_mut().coverage, new_coverage); + HitMaps::merge_opt(&mut self.execution_data.borrow_mut().line_coverage, new_coverage); } /// Update metrics for a fuzzed selector, extracted from tx details. @@ -261,6 +259,8 @@ pub struct InvariantTestRun { pub depth: u32, // Current assume rejects of the invariant run. pub assume_rejects_counter: u32, + // Whether new coverage was discovered during this run. + pub new_coverage: bool, } impl InvariantTestRun { @@ -274,6 +274,7 @@ impl InvariantTestRun { run_traces: vec![], depth: 0, assume_rejects_counter: 0, + new_coverage: false, } } } @@ -297,7 +298,10 @@ pub struct InvariantExecutor<'a> { project_contracts: &'a ContractsByArtifact, /// Filters contracts to be fuzzed through their artifact identifiers. artifact_filters: ArtifactFilters, + /// History of binned hitcount of edges seen during fuzzing. + history_map: Vec, } +const COVERAGE_MAP_SIZE: usize = 65536; impl<'a> InvariantExecutor<'a> { /// Instantiates a fuzzed executor EVM given a testrunner @@ -315,6 +319,7 @@ impl<'a> InvariantExecutor<'a> { setup_contracts, project_contracts, artifact_filters: ArtifactFilters::default(), + history_map: vec![0u8; COVERAGE_MAP_SIZE], } } @@ -328,19 +333,30 @@ impl<'a> InvariantExecutor<'a> { ) -> Result { // Throw an error to abort test run if the invariant function accepts input params if !invariant_contract.invariant_function.inputs.is_empty() { - return Err(eyre!("Invariant test function should have no inputs")) + return Err(eyre!("Invariant test function should have no inputs")); } - let (invariant_test, invariant_strategy) = + let (invariant_test, mut corpus_manager) = self.prepare_test(&invariant_contract, fuzz_fixtures, deployed_libs)?; // Start timer for this invariant test. + let mut runs = 0; let timer = FuzzTestTimer::new(self.config.timeout); + let continue_campaign = |runs: u32| { + // If timeout is configured, then perform invariant runs until expires. + if self.config.timeout.is_some() { + return !timer.is_timed_out() + } + // If no timeout configured then loop until configured runs. + runs < self.config.runs + }; + + 'stop: while continue_campaign(runs) { + let initial_seq = corpus_manager.new_sequence(&invariant_test)?; - let _ = self.runner.run(&invariant_strategy, |first_input| { // Create current invariant run data. let mut current_run = InvariantTestRun::new( - first_input, + initial_seq[0].clone(), // Before each run, we must reset the backend state. self.executor.clone(), self.config.depth as usize, @@ -348,7 +364,7 @@ impl<'a> InvariantExecutor<'a> { // We stop the run immediately if we have reverted, and `fail_on_revert` is set. if self.config.fail_on_revert && invariant_test.reverts() > 0 { - return Err(TestCaseError::fail("call reverted")) + return Err(eyre!("call reverted")) } while current_run.depth < self.config.depth { @@ -358,12 +374,13 @@ impl<'a> InvariantExecutor<'a> { // successful even though it timed out. We *want* // this behavior for now, so that's ok, but // future developers should be aware of this. - return Err(TestCaseError::fail(TEST_TIMEOUT)); + break 'stop; } - let tx = current_run.inputs.last().ok_or_else(|| { - TestCaseError::fail("no input generated to called fuzz target") - })?; + let tx = current_run + .inputs + .last() + .ok_or_else(|| eyre!("no input generated to call fuzzed target."))?; // Execute call from the randomly generated sequence without committing state. // State is committed only if call is not a magic assume. @@ -375,15 +392,22 @@ impl<'a> InvariantExecutor<'a> { tx.call_details.calldata.clone(), U256::ZERO, ) - .map_err(|e| TestCaseError::fail(e.to_string()))?; + .map_err(|e| eyre!(format!("Could not make raw evm call: {e}")))?; let discarded = call_result.result.as_ref() == MAGIC_ASSUME; if self.config.show_metrics { invariant_test.record_metrics(tx, call_result.reverted, discarded); } - // Collect coverage from last fuzzed call. - invariant_test.merge_coverage(call_result.coverage.clone()); + // Collect line coverage from last fuzzed call. + invariant_test.merge_coverage(call_result.line_coverage.clone()); + // If coverage guided fuzzing is enabled then merge edge count with current history + // map and set new coverage in current run. + if self.config.corpus_dir.is_some() && + call_result.merge_edge_coverage(&mut self.history_map) + { + current_run.new_coverage = true; + } if discarded { current_run.inputs.pop(); @@ -392,9 +416,7 @@ impl<'a> InvariantExecutor<'a> { invariant_test.set_error(InvariantFuzzError::MaxAssumeRejects( self.config.max_assume_rejects, )); - return Err(TestCaseError::fail( - "reached maximum number of `vm.assume` rejects", - )); + break 'stop; } } else { // Commit executed call result. @@ -446,29 +468,30 @@ impl<'a> InvariantExecutor<'a> { call_result, &state_changeset, ) - .map_err(|e| TestCaseError::fail(e.to_string()))?; + .map_err(|e| eyre!(e.to_string()))?; if !result.can_continue || current_run.depth == self.config.depth - 1 { invariant_test.set_last_run_inputs(¤t_run.inputs); } // If test cannot continue then stop current run and exit test suite. if !result.can_continue { - return Err(TestCaseError::fail("test cannot continue")) + break 'stop; } invariant_test.set_last_call_results(result.call_result); current_run.depth += 1; } - // Generates the next call from the run using the recently updated - // dictionary. - current_run.inputs.push( - invariant_strategy - .new_tree(&mut invariant_test.execution_data.borrow_mut().branch_runner) - .map_err(|_| TestCaseError::Fail("Could not generate case".into()))? - .current(), - ); + current_run.inputs.push(corpus_manager.generate_next_input( + &invariant_test, + &initial_seq, + discarded, + current_run.depth as usize, + )?); } + // Extend corpus with current run data. + corpus_manager.collect_inputs(¤t_run); + // Call `afterInvariant` only if it is declared and test didn't fail already. if invariant_contract.call_after_invariant && !invariant_test.has_errors() { assert_after_invariant( @@ -477,7 +500,7 @@ impl<'a> InvariantExecutor<'a> { ¤t_run, &self.config, ) - .map_err(|_| TestCaseError::Fail("Failed to call afterInvariant".into()))?; + .map_err(|_| eyre!("Failed to call afterInvariant"))?; } // End current invariant test run. @@ -488,8 +511,8 @@ impl<'a> InvariantExecutor<'a> { progress.inc(1); } - Ok(()) - }); + runs += 1; + } trace!(?fuzz_fixtures); invariant_test.fuzz_state.log_stats(); @@ -501,20 +524,21 @@ impl<'a> InvariantExecutor<'a> { reverts: result.failures.reverts, last_run_inputs: result.last_run_inputs, gas_report_traces: result.gas_report_traces, - coverage: result.coverage, + line_coverage: result.line_coverage, metrics: result.metrics, + failed_corpus_replays: corpus_manager.failed_replays(), }) } /// Prepares certain structures to execute the invariant tests: /// * Invariant Fuzz Test. - /// * Invariant Strategy + /// * Invariant Corpus Manager. fn prepare_test( &mut self, invariant_contract: &InvariantContract<'_>, fuzz_fixtures: &FuzzFixtures, deployed_libs: &[Address], - ) -> Result<(InvariantTest, impl Strategy)> { + ) -> Result<(InvariantTest, TxCorpusManager)> { // Finds out the chosen deployed contracts and/or senders. self.select_contract_artifacts(invariant_contract.address)?; let (targeted_senders, targeted_contracts) = @@ -576,16 +600,24 @@ impl<'a> InvariantExecutor<'a> { return Err(eyre!(error.revert_reason().unwrap_or_default())) } - Ok(( - InvariantTest::new( - fuzz_state, - targeted_contracts, - failures, - last_call_results, - self.runner.clone(), - ), - strategy, - )) + let corpus_manager = TxCorpusManager::new( + &self.config, + &invariant_contract.invariant_function.name, + &targeted_contracts, + strategy.boxed(), + &self.executor, + &mut self.history_map, + )?; + + let invariant_test = InvariantTest::new( + fuzz_state, + targeted_contracts, + failures, + last_call_results, + self.runner.clone(), + ); + + Ok((invariant_test, corpus_manager)) } /// Fills the `InvariantExecutor` with the artifact identifier filters (in `path:name` string @@ -895,7 +927,7 @@ fn collect_data( pub(crate) fn call_after_invariant_function( executor: &Executor, to: Address, -) -> std::result::Result<(RawCallResult, bool), EvmError> { +) -> Result<(RawCallResult, bool), EvmError> { let calldata = Bytes::from_static(&IInvariantTest::afterInvariantCall::SELECTOR); let mut call_result = executor.call_raw(CALLER, to, calldata, U256::ZERO)?; let success = executor.is_raw_call_mut_success(to, &mut call_result, false); diff --git a/crates/evm/evm/src/executors/invariant/replay.rs b/crates/evm/evm/src/executors/invariant/replay.rs index ab11f3728ae99..f14d3e3d1c3fb 100644 --- a/crates/evm/evm/src/executors/invariant/replay.rs +++ b/crates/evm/evm/src/executors/invariant/replay.rs @@ -28,7 +28,7 @@ pub fn replay_run( mut ided_contracts: ContractsByAddress, logs: &mut Vec, traces: &mut Traces, - coverage: &mut Option, + line_coverage: &mut Option, deprecated_cheatcodes: &mut HashMap<&'static str, Option<&'static str>>, inputs: &[BasicTxDetails], show_solidity: bool, @@ -51,7 +51,7 @@ pub fn replay_run( logs.extend(call_result.logs); traces.push((TraceKind::Execution, call_result.traces.clone().unwrap())); - HitMaps::merge_opt(coverage, call_result.coverage); + HitMaps::merge_opt(line_coverage, call_result.line_coverage); // Identify newly generated contracts, if they exist. ided_contracts @@ -108,7 +108,7 @@ pub fn replay_error( ided_contracts: ContractsByAddress, logs: &mut Vec, traces: &mut Traces, - coverage: &mut Option, + line_coverage: &mut Option, deprecated_cheatcodes: &mut HashMap<&'static str, Option<&'static str>>, progress: Option<&ProgressBar>, show_solidity: bool, @@ -136,7 +136,7 @@ pub fn replay_error( ided_contracts, logs, traces, - coverage, + line_coverage, deprecated_cheatcodes, &calls, show_solidity, diff --git a/crates/evm/evm/src/executors/invariant/result.rs b/crates/evm/evm/src/executors/invariant/result.rs index 8920a1209342a..bbc97db760af4 100644 --- a/crates/evm/evm/src/executors/invariant/result.rs +++ b/crates/evm/evm/src/executors/invariant/result.rs @@ -29,9 +29,11 @@ pub struct InvariantFuzzTestResult { /// Additional traces used for gas report construction. pub gas_report_traces: Vec>, /// The coverage info collected during the invariant test runs. - pub coverage: Option, + pub line_coverage: Option, /// Fuzzed selectors metrics collected during the invariant test runs. pub metrics: HashMap, + /// NUmber of failed replays from persisted corpus. + pub failed_corpus_replays: usize, } /// Enriched results of an invariant run check. diff --git a/crates/evm/evm/src/executors/mod.rs b/crates/evm/evm/src/executors/mod.rs index bfd57a4a0ccee..95d6328098210 100644 --- a/crates/evm/evm/src/executors/mod.rs +++ b/crates/evm/evm/src/executors/mod.rs @@ -802,8 +802,10 @@ pub struct RawCallResult { pub labels: AddressHashMap, /// The traces of the call pub traces: Option, - /// The coverage info collected during the call - pub coverage: Option, + /// The line coverage info collected during the call + pub line_coverage: Option, + /// The edge coverage info collected during the call + pub edge_coverage: Option>, /// Scripted transactions generated from this call pub transactions: Option, /// The changeset of the state. @@ -831,7 +833,8 @@ impl Default for RawCallResult { logs: Vec::new(), labels: HashMap::default(), traces: None, - coverage: None, + line_coverage: None, + edge_coverage: None, transactions: None, state_changeset: HashMap::default(), env: Env::default(), @@ -904,6 +907,43 @@ impl RawCallResult { pub fn transactions(&self) -> Option<&BroadcastableTransactions> { self.cheatcodes.as_ref().map(|c| &c.broadcastable_transactions) } + + /// Update provided history map with edge coverage info collected during this call. + /// Uses AFL binning algo + pub fn merge_edge_coverage(&mut self, history_map: &mut [u8]) -> bool { + let mut new_coverage = false; + if let Some(x) = &mut self.edge_coverage { + // Iterate over the current map and the history map together and update + // the history map, if we discover some new coverage, report true + for (curr, hist) in std::iter::zip(x, history_map) { + // If we got a hitcount of at least 1 + if *curr > 0 { + // Convert hitcount into bucket count + let bucket = match *curr { + 0 => 0, + 1 => 1, + 2 => 2, + 3 => 4, + 4..=7 => 8, + 8..=15 => 16, + 16..=31 => 32, + 32..=127 => 64, + 128..=255 => 128, + }; + + // If the old record for this edge pair is lower, update + if *hist < bucket { + *hist = bucket; + new_coverage = true; + } + + // Zero out the current map for next iteration. + *curr = 0; + } + } + } + new_coverage + } } /// The result of a call. @@ -963,8 +1003,15 @@ fn convert_executed_result( _ => Bytes::new(), }; - let InspectorData { mut logs, labels, traces, coverage, cheatcodes, chisel_state } = - inspector.collect(); + let InspectorData { + mut logs, + labels, + traces, + line_coverage, + edge_coverage, + cheatcodes, + chisel_state, + } = inspector.collect(); if logs.is_empty() { logs = exec_logs; @@ -986,7 +1033,8 @@ fn convert_executed_result( logs, labels, traces, - coverage, + line_coverage, + edge_coverage, transactions, state_changeset, env, diff --git a/crates/evm/evm/src/inspectors/mod.rs b/crates/evm/evm/src/inspectors/mod.rs index 85ed1354ea11a..31ff3f2603605 100644 --- a/crates/evm/evm/src/inspectors/mod.rs +++ b/crates/evm/evm/src/inspectors/mod.rs @@ -1,7 +1,7 @@ //! EVM inspectors. pub use foundry_cheatcodes::{self as cheatcodes, Cheatcodes, CheatsConfig}; -pub use foundry_evm_coverage::CoverageCollector; +pub use foundry_evm_coverage::LineCoverageCollector; pub use foundry_evm_fuzz::Fuzzer; pub use foundry_evm_traces::{StackSnapshotType, TracingInspector, TracingInspectorConfig}; diff --git a/crates/evm/evm/src/inspectors/stack.rs b/crates/evm/evm/src/inspectors/stack.rs index f3c0fa3d13f4b..4b7cde5bef3cc 100644 --- a/crates/evm/evm/src/inspectors/stack.rs +++ b/crates/evm/evm/src/inspectors/stack.rs @@ -1,5 +1,5 @@ use super::{ - Cheatcodes, CheatsConfig, ChiselState, CoverageCollector, CustomPrintTracer, Fuzzer, + Cheatcodes, CheatsConfig, ChiselState, CustomPrintTracer, Fuzzer, LineCoverageCollector, LogCollector, RevertDiagnostic, ScriptExecutionInspector, TracingInspector, }; use alloy_evm::{eth::EthEvmContext, Evm}; @@ -28,6 +28,7 @@ use revm::{ state::{Account, AccountStatus}, Inspector, }; +use revm_inspectors::edge_cov::EdgeCovInspector; use std::{ ops::{Deref, DerefMut}, sync::Arc, @@ -54,8 +55,8 @@ pub struct InspectorStackBuilder { pub trace_mode: TraceMode, /// Whether logs should be collected. pub logs: Option, - /// Whether coverage info should be collected. - pub coverage: Option, + /// Whether line coverage info should be collected. + pub line_coverage: Option, /// Whether to print all opcode traces into the console. Useful for debugging the EVM. pub print: Option, /// The chisel state inspector. @@ -128,10 +129,10 @@ impl InspectorStackBuilder { self } - /// Set whether to collect coverage information. + /// Set whether to collect line coverage information. #[inline] - pub fn coverage(mut self, yes: bool) -> Self { - self.coverage = Some(yes); + pub fn line_coverage(mut self, yes: bool) -> Self { + self.line_coverage = Some(yes); self } @@ -183,7 +184,7 @@ impl InspectorStackBuilder { fuzzer, trace_mode, logs, - coverage, + line_coverage, print, chisel_state, enable_isolation, @@ -209,8 +210,8 @@ impl InspectorStackBuilder { if let Some(chisel_state) = chisel_state { stack.set_chisel(chisel_state); } - - stack.collect_coverage(coverage.unwrap_or(false)); + stack.collect_line_coverage(line_coverage.unwrap_or(false)); + stack.collect_edge_coverage(true); stack.collect_logs(logs.unwrap_or(true)); stack.print(print.unwrap_or(false)); stack.tracing(trace_mode); @@ -258,7 +259,8 @@ pub struct InspectorData { pub logs: Vec, pub labels: AddressHashMap, pub traces: Option, - pub coverage: Option, + pub line_coverage: Option, + pub edge_coverage: Option>, pub cheatcodes: Option, pub chisel_state: Option<(Vec, Vec, InstructionResult)>, } @@ -296,7 +298,8 @@ pub struct InspectorStack { #[derive(Default, Clone, Debug)] pub struct InspectorStackInner { pub chisel_state: Option, - pub coverage: Option, + pub line_coverage: Option, + pub edge_coverage: Option, pub fuzzer: Option, pub log_collector: Option, pub printer: Option, @@ -355,7 +358,7 @@ impl InspectorStack { )* }; } - push!(cheatcodes, chisel_state, coverage, fuzzer, log_collector, printer, tracer); + push!(cheatcodes, chisel_state, line_coverage, fuzzer, log_collector, printer, tracer); if self.enable_isolation { enabled.push("isolation"); } @@ -404,10 +407,16 @@ impl InspectorStack { self.chisel_state = Some(ChiselState::new(final_pc)); } - /// Set whether to enable the coverage collector. + /// Set whether to enable the line coverage collector. + #[inline] + pub fn collect_line_coverage(&mut self, yes: bool) { + self.line_coverage = yes.then(Default::default); + } + + /// Set whether to enable the edge coverage collector. #[inline] - pub fn collect_coverage(&mut self, yes: bool) { - self.coverage = yes.then(Default::default); + pub fn collect_edge_coverage(&mut self, yes: bool) { + self.edge_coverage = yes.then(EdgeCovInspector::new); // TODO configurable edge size? } /// Set whether to enable call isolation. @@ -469,7 +478,15 @@ impl InspectorStack { pub fn collect(self) -> InspectorData { let Self { mut cheatcodes, - inner: InspectorStackInner { chisel_state, coverage, log_collector, tracer, .. }, + inner: + InspectorStackInner { + chisel_state, + line_coverage, + edge_coverage, + log_collector, + tracer, + .. + }, } = self; let traces = tracer.map(|tracer| tracer.into_traces()).map(|arena| { @@ -497,7 +514,8 @@ impl InspectorStack { .map(|cheatcodes| cheatcodes.labels.clone()) .unwrap_or_default(), traces, - coverage: coverage.map(|coverage| coverage.finish()), + line_coverage: line_coverage.map(|line_coverage| line_coverage.finish()), + edge_coverage: edge_coverage.map(|edge_coverage| edge_coverage.into_hitcount()), cheatcodes, chisel_state: chisel_state.and_then(|state| state.state), } @@ -661,7 +679,7 @@ impl InspectorStackRefMut<'_> { for (addr, mut acc) in res.state { let Some(acc_mut) = ecx.journaled_state.state.get_mut(&addr) else { ecx.journaled_state.state.insert(addr, acc); - continue + continue; }; // make sure accounts that were warmed earlier do not become cold @@ -676,7 +694,7 @@ impl InspectorStackRefMut<'_> { for (key, val) in acc.storage { let Some(slot_mut) = acc_mut.storage.get_mut(&key) else { acc_mut.storage.insert(key, val); - continue + continue; }; slot_mut.present_value = val.present_value; slot_mut.is_cold &= val.is_cold; @@ -769,7 +787,7 @@ impl Inspector> for InspectorStackRefMut<'_> ) { call_inspectors!( [ - &mut self.coverage, + &mut self.line_coverage, &mut self.tracer, &mut self.cheatcodes, &mut self.script_execution_inspector, @@ -788,7 +806,8 @@ impl Inspector> for InspectorStackRefMut<'_> [ &mut self.fuzzer, &mut self.tracer, - &mut self.coverage, + &mut self.line_coverage, + &mut self.edge_coverage, &mut self.cheatcodes, &mut self.script_execution_inspector, &mut self.printer, @@ -962,7 +981,7 @@ impl Inspector> for InspectorStackRefMut<'_> call_inspectors!( #[ret] - [&mut self.tracer, &mut self.coverage, &mut self.cheatcodes], + [&mut self.tracer, &mut self.line_coverage, &mut self.cheatcodes], |inspector| inspector.create(ecx, create).map(Some), ); diff --git a/crates/evm/fuzz/src/invariant/mod.rs b/crates/evm/fuzz/src/invariant/mod.rs index c681512de1e60..7d7fc98db1432 100644 --- a/crates/evm/fuzz/src/invariant/mod.rs +++ b/crates/evm/fuzz/src/invariant/mod.rs @@ -2,6 +2,7 @@ use alloy_json_abi::{Function, JsonAbi}; use alloy_primitives::{Address, Bytes, Selector}; use itertools::Either; use parking_lot::Mutex; +use serde::{Deserialize, Serialize}; use std::{collections::BTreeMap, sync::Arc}; mod call_override; @@ -126,6 +127,14 @@ impl TargetedContracts { .flat_map(|(contract, c)| c.abi_fuzzed_functions().map(move |f| (contract, f))) } + /// Returns whether the given transaction can be replayed or not with known contracts. + pub fn can_replay(&self, tx: &BasicTxDetails) -> bool { + match self.inner.get(&tx.call_details.target) { + Some(c) => c.abi.functions().any(|f| f.selector() == tx.call_details.calldata[..4]), + None => false, + } + } + /// Identifies fuzzed contract and function based on given tx details and returns unique metric /// key composed from contract identifier and function name. pub fn fuzzed_metric_key(&self, tx: &BasicTxDetails) -> Option { @@ -211,7 +220,7 @@ impl TargetedContract { } /// Details of a transaction generated by invariant strategy for fuzzing a target. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct BasicTxDetails { // Transaction sender address. pub sender: Address, @@ -220,7 +229,7 @@ pub struct BasicTxDetails { } /// Call details of a transaction generated to fuzz invariant target. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct CallDetails { // Address of target contract. pub target: Address, diff --git a/crates/evm/fuzz/src/lib.rs b/crates/evm/fuzz/src/lib.rs index bce67dfe320fa..9c458903e6187 100644 --- a/crates/evm/fuzz/src/lib.rs +++ b/crates/evm/fuzz/src/lib.rs @@ -221,8 +221,8 @@ pub struct FuzzTestResult { /// Those traces should not be displayed. pub gas_report_traces: Vec, - /// Raw coverage info - pub coverage: Option, + /// Raw line coverage info + pub line_coverage: Option, /// Breakpoints for debugger. Correspond to the same fuzz case as `traces`. pub breakpoints: Option, diff --git a/crates/forge/src/cmd/coverage.rs b/crates/forge/src/cmd/coverage.rs index 729f96e5a9838..6a32b223936ae 100644 --- a/crates/forge/src/cmd/coverage.rs +++ b/crates/forge/src/cmd/coverage.rs @@ -289,7 +289,7 @@ impl CoverageArgs { let data = outcome.results.iter().flat_map(|(_, suite)| { let mut hits = Vec::new(); for result in suite.test_results.values() { - let Some(hit_maps) = result.coverage.as_ref() else { continue }; + let Some(hit_maps) = result.line_coverage.as_ref() else { continue }; for map in hit_maps.0.values() { if let Some((id, _)) = known_contracts.find_by_deployed_code(map.bytecode()) { hits.push((id, map, true)); @@ -415,7 +415,7 @@ pub struct BytecodeData { /// The source maps are indexed by *instruction counters*, which are the indexes of /// instructions in the bytecode *minus any push bytes*. /// - /// Since our coverage inspector collects hit data using program counters, the anchors + /// Since our line coverage inspector collects hit data using program counters, the anchors /// also need to be based on program counters. ic_pc_map: IcPcMap, } diff --git a/crates/forge/src/cmd/snapshot.rs b/crates/forge/src/cmd/snapshot.rs index da642bd1241be..fe2cc7588ab2d 100644 --- a/crates/forge/src/cmd/snapshot.rs +++ b/crates/forge/src/cmd/snapshot.rs @@ -242,6 +242,7 @@ impl FromStr for GasSnapshotEntry { calls: calls.as_str().parse().unwrap(), reverts: reverts.as_str().parse().unwrap(), metrics: HashMap::default(), + failed_corpus_replays: 0, }, }) } @@ -488,7 +489,8 @@ mod tests { runs: 256, calls: 100, reverts: 200, - metrics: HashMap::default() + metrics: HashMap::default(), + failed_corpus_replays: 0, } } ); @@ -507,7 +509,8 @@ mod tests { runs: 256, calls: 3840, reverts: 2388, - metrics: HashMap::default() + metrics: HashMap::default(), + failed_corpus_replays: 0, } } ); diff --git a/crates/forge/src/multi_runner.rs b/crates/forge/src/multi_runner.rs index 7b10328d5908e..7d967a479b365 100644 --- a/crates/forge/src/multi_runner.rs +++ b/crates/forge/src/multi_runner.rs @@ -286,8 +286,8 @@ pub struct TestRunnerConfig { /// The address which will be used to deploy the initial contracts and send all transactions. pub sender: Address, - /// Whether to collect coverage info - pub coverage: bool, + /// Whether to collect line coverage info + pub line_coverage: bool, /// Whether to collect debug info pub debug: bool, /// Whether to enable steps tracking in the tracer. @@ -330,7 +330,7 @@ impl TestRunnerConfig { Arc::new(cheatcodes.config.clone_with(&self.config, self.evm_opts.clone())); } inspector.tracing(self.trace_mode()); - inspector.collect_coverage(self.coverage); + inspector.collect_line_coverage(self.line_coverage); inspector.enable_isolation(self.isolation); inspector.odyssey(self.odyssey); // inspector.set_create2_deployer(self.evm_opts.create2_deployer); @@ -359,7 +359,7 @@ impl TestRunnerConfig { stack .cheatcodes(cheats_config) .trace_mode(self.trace_mode()) - .coverage(self.coverage) + .line_coverage(self.line_coverage) .enable_isolation(self.isolation) .odyssey(self.odyssey) .create2_deployer(self.evm_opts.create2_deployer) @@ -394,8 +394,8 @@ pub struct MultiContractRunnerBuilder { pub fork: Option, /// Project config. pub config: Arc, - /// Whether or not to collect coverage info - pub coverage: bool, + /// Whether or not to collect line coverage info + pub line_coverage: bool, /// Whether or not to collect debug info pub debug: bool, /// Whether to enable steps tracking in the tracer. @@ -414,7 +414,7 @@ impl MultiContractRunnerBuilder { initial_balance: Default::default(), evm_spec: Default::default(), fork: Default::default(), - coverage: Default::default(), + line_coverage: Default::default(), debug: Default::default(), isolation: Default::default(), decode_internal: Default::default(), @@ -443,7 +443,7 @@ impl MultiContractRunnerBuilder { } pub fn set_coverage(mut self, enable: bool) -> Self { - self.coverage = enable; + self.line_coverage = enable; self } @@ -536,7 +536,7 @@ impl MultiContractRunnerBuilder { spec_id: self.evm_spec.unwrap_or_else(|| self.config.evm_spec_id()), sender: self.sender.unwrap_or(self.config.sender), - coverage: self.coverage, + line_coverage: self.line_coverage, debug: self.debug, decode_internal: self.decode_internal, inline_config: Arc::new(InlineConfig::new_parsed(output, &self.config)?), diff --git a/crates/forge/src/progress.rs b/crates/forge/src/progress.rs index 9ca182f769d50..5c5e3c65082a0 100644 --- a/crates/forge/src/progress.rs +++ b/crates/forge/src/progress.rs @@ -1,7 +1,9 @@ use alloy_primitives::map::HashMap; +use chrono::Utc; use indicatif::{MultiProgress, ProgressBar}; use parking_lot::Mutex; use std::{sync::Arc, time::Duration}; + /// State of [ProgressBar]s displayed for the given test run. /// Shows progress of all test suites matching filter. /// For each test within the test suite an individual progress bar is displayed. @@ -64,17 +66,22 @@ impl TestsProgressState { &mut self, suite_name: &str, test_name: &String, + timeout: Option, runs: u32, ) -> Option { if let Some(suite_progress) = self.suites_progress.get(suite_name) { let fuzz_progress = self.multi.insert_after(suite_progress, ProgressBar::new(runs as u64)); + let template = if let Some(timeout) = timeout { + let ends_at = (Utc::now() + chrono::Duration::seconds(timeout.into())) + .format("%H:%M:%S %Y-%m-%d") + .to_string(); + format!(" ↪ {{prefix:.bold.dim}}: [{{pos}}]{{msg}} Runs, ends at {ends_at} UTC") + } else { + " ↪ {prefix:.bold.dim}: [{pos}/{len}]{msg} Runs".to_string() + }; fuzz_progress.set_style( - indicatif::ProgressStyle::with_template( - " ↪ {prefix:.bold.dim}: [{pos}/{len}]{msg} Runs", - ) - .unwrap() - .tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ "), + indicatif::ProgressStyle::with_template(&template).unwrap().tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ "), ); fuzz_progress.set_prefix(test_name.to_string()); Some(fuzz_progress) @@ -106,10 +113,11 @@ pub fn start_fuzz_progress( tests_progress: Option<&TestsProgress>, suite_name: &str, test_name: &String, + timeout: Option, runs: u32, ) -> Option { if let Some(progress) = tests_progress { - progress.inner.lock().start_fuzz_progress(suite_name, test_name, runs) + progress.inner.lock().start_fuzz_progress(suite_name, test_name, timeout, runs) } else { None } diff --git a/crates/forge/src/result.rs b/crates/forge/src/result.rs index 90447fc26bfa0..3a6b5bf53fed4 100644 --- a/crates/forge/src/result.rs +++ b/crates/forge/src/result.rs @@ -402,9 +402,9 @@ pub struct TestResult { #[serde(skip)] pub gas_report_traces: Vec>, - /// Raw coverage info + /// Raw line coverage info #[serde(skip)] - pub coverage: Option, + pub line_coverage: Option, /// Labeled addresses pub labeled_addresses: AddressHashMap, @@ -479,7 +479,7 @@ impl TestResult { labeled_addresses: setup.labels.clone(), logs: setup.logs.clone(), traces: setup.traces.clone(), - coverage: setup.coverage.clone(), + line_coverage: setup.coverage.clone(), ..Default::default() } } @@ -496,7 +496,7 @@ impl TestResult { reason: setup.reason, logs: setup.logs, traces: setup.traces, - coverage: setup.coverage, + line_coverage: setup.coverage, labeled_addresses: setup.labels, ..Default::default() } @@ -529,7 +529,7 @@ impl TestResult { self.logs.extend(raw_call_result.logs); self.labeled_addresses.extend(raw_call_result.labels); self.traces.extend(raw_call_result.traces.map(|traces| (TraceKind::Execution, traces))); - self.merge_coverages(raw_call_result.coverage); + self.merge_coverages(raw_call_result.line_coverage); self.status = match success { true => TestStatus::Success, @@ -560,7 +560,7 @@ impl TestResult { self.logs.extend(result.logs); self.labeled_addresses.extend(result.labeled_addresses); self.traces.extend(result.traces.map(|traces| (TraceKind::Execution, traces))); - self.merge_coverages(result.coverage); + self.merge_coverages(result.line_coverage); self.status = if result.skipped { TestStatus::Skipped @@ -579,8 +579,13 @@ impl TestResult { /// Returns the skipped result for invariant test. pub fn invariant_skip(&mut self, reason: SkipReason) { - self.kind = - TestKind::Invariant { runs: 1, calls: 1, reverts: 1, metrics: HashMap::default() }; + self.kind = TestKind::Invariant { + runs: 1, + calls: 1, + reverts: 1, + metrics: HashMap::default(), + failed_corpus_replays: 0, + }; self.status = TestStatus::Skipped; self.reason = reason.0; } @@ -592,8 +597,13 @@ impl TestResult { invariant_name: &String, call_sequence: Vec, ) { - self.kind = - TestKind::Invariant { runs: 1, calls: 1, reverts: 1, metrics: HashMap::default() }; + self.kind = TestKind::Invariant { + runs: 1, + calls: 1, + reverts: 1, + metrics: HashMap::default(), + failed_corpus_replays: 0, + }; self.status = TestStatus::Failure; self.reason = if replayed_entirely { Some(format!("{invariant_name} replay failure")) @@ -605,8 +615,13 @@ impl TestResult { /// Returns the fail result for invariant test setup. pub fn invariant_setup_fail(&mut self, e: Report) { - self.kind = - TestKind::Invariant { runs: 0, calls: 0, reverts: 0, metrics: HashMap::default() }; + self.kind = TestKind::Invariant { + runs: 0, + calls: 0, + reverts: 0, + metrics: HashMap::default(), + failed_corpus_replays: 0, + }; self.status = TestStatus::Failure; self.reason = Some(format!("failed to set up invariant testing environment: {e}")); } @@ -622,12 +637,14 @@ impl TestResult { cases: Vec, reverts: usize, metrics: Map, + failed_corpus_replays: usize, ) { self.kind = TestKind::Invariant { runs: cases.len(), calls: cases.iter().map(|sequence| sequence.cases().len()).sum(), reverts, metrics, + failed_corpus_replays, }; self.status = match success { true => TestStatus::Success, @@ -653,21 +670,33 @@ impl TestResult { self.logs.extend(call_result.logs); self.labeled_addresses.extend(call_result.labels); self.traces.extend(call_result.traces.map(|traces| (TraceKind::Execution, traces))); - self.merge_coverages(call_result.coverage); + self.merge_coverages(call_result.line_coverage); } /// Merges the given coverage result into `self`. pub fn merge_coverages(&mut self, other_coverage: Option) { - HitMaps::merge_opt(&mut self.coverage, other_coverage); + HitMaps::merge_opt(&mut self.line_coverage, other_coverage); } } /// Data report by a test. #[derive(Clone, Debug, PartialEq, Eq)] pub enum TestKindReport { - Unit { gas: u64 }, - Fuzz { runs: usize, mean_gas: u64, median_gas: u64 }, - Invariant { runs: usize, calls: usize, reverts: usize, metrics: Map }, + Unit { + gas: u64, + }, + Fuzz { + runs: usize, + mean_gas: u64, + median_gas: u64, + }, + Invariant { + runs: usize, + calls: usize, + reverts: usize, + metrics: Map, + failed_corpus_replays: usize, + }, } impl fmt::Display for TestKindReport { @@ -679,8 +708,12 @@ impl fmt::Display for TestKindReport { Self::Fuzz { runs, mean_gas, median_gas } => { write!(f, "(runs: {runs}, μ: {mean_gas}, ~: {median_gas})") } - Self::Invariant { runs, calls, reverts, metrics: _ } => { - write!(f, "(runs: {runs}, calls: {calls}, reverts: {reverts})") + Self::Invariant { runs, calls, reverts, metrics: _, failed_corpus_replays } => { + if *failed_corpus_replays != 0 { + write!(f, "(runs: {runs}, calls: {calls}, reverts: {reverts}, failed corpus replays: {failed_corpus_replays})") + } else { + write!(f, "(runs: {runs}, calls: {calls}, reverts: {reverts})") + } } } } @@ -713,7 +746,13 @@ pub enum TestKind { median_gas: u64, }, /// An invariant test. - Invariant { runs: usize, calls: usize, reverts: usize, metrics: Map }, + Invariant { + runs: usize, + calls: usize, + reverts: usize, + metrics: Map, + failed_corpus_replays: usize, + }, } impl Default for TestKind { @@ -730,12 +769,15 @@ impl TestKind { Self::Fuzz { first_case: _, runs, mean_gas, median_gas } => { TestKindReport::Fuzz { runs: *runs, mean_gas: *mean_gas, median_gas: *median_gas } } - Self::Invariant { runs, calls, reverts, metrics: _ } => TestKindReport::Invariant { - runs: *runs, - calls: *calls, - reverts: *reverts, - metrics: HashMap::default(), - }, + Self::Invariant { runs, calls, reverts, metrics: _, failed_corpus_replays } => { + TestKindReport::Invariant { + runs: *runs, + calls: *calls, + reverts: *reverts, + metrics: HashMap::default(), + failed_corpus_replays: *failed_corpus_replays, + } + } } } } @@ -783,6 +825,6 @@ impl TestSetup { self.logs.extend(raw.logs); self.labels.extend(raw.labels); self.traces.extend(raw.traces.map(|traces| (trace_kind, traces))); - HitMaps::merge_opt(&mut self.coverage, raw.coverage); + HitMaps::merge_opt(&mut self.coverage, raw.line_coverage); } } diff --git a/crates/forge/src/runner.rs b/crates/forge/src/runner.rs index 5384df363729f..64f921050b161 100644 --- a/crates/forge/src/runner.rs +++ b/crates/forge/src/runner.rs @@ -623,8 +623,13 @@ impl<'a> FunctionRunner<'a> { table_fixtures.push(&fixtures[..]); } - let progress = - start_fuzz_progress(self.cr.progress, self.cr.name, &func.name, fixtures_len as u32); + let progress = start_fuzz_progress( + self.cr.progress, + self.cr.name, + &func.name, + None, + fixtures_len as u32, + ); for i in 0..fixtures_len { // Increment progress bar. @@ -764,7 +769,7 @@ impl<'a> FunctionRunner<'a> { identified_contracts.clone(), &mut self.result.logs, &mut self.result.traces, - &mut self.result.coverage, + &mut self.result.line_coverage, &mut self.result.deprecated_cheatcodes, &txes, show_solidity, @@ -779,8 +784,13 @@ impl<'a> FunctionRunner<'a> { } } - let progress = - start_fuzz_progress(self.cr.progress, self.cr.name, &func.name, invariant_config.runs); + let progress = start_fuzz_progress( + self.cr.progress, + self.cr.name, + &func.name, + invariant_config.timeout, + invariant_config.runs, + ); let invariant_result = match evm.invariant_fuzz( invariant_contract.clone(), &self.setup.fuzz_fixtures, @@ -794,7 +804,7 @@ impl<'a> FunctionRunner<'a> { } }; // Merge coverage collected during invariant run with test setup coverage. - self.result.merge_coverages(invariant_result.coverage); + self.result.merge_coverages(invariant_result.line_coverage); let mut counterexample = None; let success = invariant_result.error.is_none(); @@ -815,7 +825,7 @@ impl<'a> FunctionRunner<'a> { identified_contracts.clone(), &mut self.result.logs, &mut self.result.traces, - &mut self.result.coverage, + &mut self.result.line_coverage, &mut self.result.deprecated_cheatcodes, progress.as_ref(), show_solidity, @@ -864,7 +874,7 @@ impl<'a> FunctionRunner<'a> { identified_contracts.clone(), &mut self.result.logs, &mut self.result.traces, - &mut self.result.coverage, + &mut self.result.line_coverage, &mut self.result.deprecated_cheatcodes, &invariant_result.last_run_inputs, show_solidity, @@ -882,6 +892,7 @@ impl<'a> FunctionRunner<'a> { invariant_result.cases, invariant_result.reverts, invariant_result.metrics, + invariant_result.failed_corpus_replays, ); self.result } @@ -904,8 +915,13 @@ impl<'a> FunctionRunner<'a> { let runner = self.fuzz_runner(); let fuzz_config = self.config.fuzz.clone(); - let progress = - start_fuzz_progress(self.cr.progress, self.cr.name, &func.name, fuzz_config.runs); + let progress = start_fuzz_progress( + self.cr.progress, + self.cr.name, + &func.name, + fuzz_config.timeout, + fuzz_config.runs, + ); // Run fuzz test. let fuzzed_executor = diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index 3cea4fca0d31a..8b9b7a452ee55 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -91,6 +91,7 @@ forgetest!(can_extract_config_values, |prj, cmd| { invariant: InvariantConfig { runs: 256, failure_persist_dir: Some("test-cache/fuzz".into()), + corpus_dir: Some("cache/invariant/corpus".into()), ..Default::default() }, ffi: true, @@ -1106,6 +1107,9 @@ max_fuzz_dictionary_values = 6553600 shrink_run_limit = 5000 max_assume_rejects = 65536 gas_report_samples = 256 +corpus_gzip = true +corpus_min_mutations = 5 +corpus_min_size = 0 failure_persist_dir = "cache/invariant" show_metrics = true show_solidity = false @@ -1213,6 +1217,10 @@ exclude = [] "shrink_run_limit": 5000, "max_assume_rejects": 65536, "gas_report_samples": 256, + "corpus_dir": null, + "corpus_gzip": true, + "corpus_min_mutations": 5, + "corpus_min_size": 0, "failure_persist_dir": "cache/invariant", "show_metrics": true, "timeout": null, diff --git a/crates/forge/tests/it/invariant.rs b/crates/forge/tests/it/invariant.rs index f947a4d0d6497..f63b1ad918cbe 100644 --- a/crates/forge/tests/it/invariant.rs +++ b/crates/forge/tests/it/invariant.rs @@ -815,7 +815,7 @@ contract BalanceAssumeTest is Test { cmd.args(["test", "--mt", "invariant_balance"]).assert_failure().stdout_eq(str![[r#" ... -[FAIL: `vm.assume` rejected too many inputs (10 allowed)] invariant_balance() (runs: 5, calls: 2500, reverts: 0) +[FAIL: `vm.assume` rejected too many inputs (10 allowed)] invariant_balance() (runs: 10, calls: 5000, reverts: 0) ... "#]]); }); @@ -1058,9 +1058,9 @@ contract InvariantSelectorsWeightTest is Test { function afterInvariant() public { assertEq(handlerOne.hit1(), 2); assertEq(handlerTwo.hit2(), 2); - assertEq(handlerTwo.hit3(), 3); + assertEq(handlerTwo.hit3(), 2); assertEq(handlerTwo.hit4(), 1); - assertEq(handlerTwo.hit5(), 2); + assertEq(handlerTwo.hit5(), 3); } function invariant_selectors_weight() public view {} @@ -1104,7 +1104,7 @@ contract InvariantSequenceLenTest is Test { cmd.args(["test", "--mt", "invariant_increment"]).assert_failure().stdout_eq(str![[r#" ... [FAIL: invariant increment failure] - [Sequence] (original: 4, shrunk: 1) + [Sequence] (original: 3, shrunk: 1) ... "#]]); @@ -1119,8 +1119,7 @@ contract InvariantSequenceLenTest is Test { Failing tests: Encountered 1 failing test in test/InvariantSequenceLenTest.t.sol:InvariantSequenceLenTest [FAIL: invariant increment failure] - [Sequence] (original: 4, shrunk: 4) - sender=0x000000000000000000000000000000001ed7831C addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] + [Sequence] (original: 3, shrunk: 3) sender=0x00000000000000000000000000000000000014ba addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] sender=0x8ef7F804bAd9183981A366EA618d9D47D3124649 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] sender=0x00000000000000000000000000000000000016b9 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[284406551521730736391345481857560031052359183671404042152984097777 [2.844e65]] @@ -1142,9 +1141,7 @@ Encountered a total of 1 failing tests, 0 tests succeeded Failing tests: Encountered 1 failing test in test/InvariantSequenceLenTest.t.sol:InvariantSequenceLenTest [FAIL: invariant increment failure] - [Sequence] (original: 4, shrunk: 4) - vm.prank(0x000000000000000000000000000000001ed7831C); - Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).increment(); + [Sequence] (original: 3, shrunk: 3) vm.prank(0x00000000000000000000000000000000000014ba); Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).increment(); vm.prank(0x8ef7F804bAd9183981A366EA618d9D47D3124649); @@ -1168,8 +1165,7 @@ Encountered a total of 1 failing tests, 0 tests succeeded Failing tests: Encountered 1 failing test in test/InvariantSequenceLenTest.t.sol:InvariantSequenceLenTest [FAIL: invariant_increment replay failure] - [Sequence] (original: 4, shrunk: 4) - sender=0x000000000000000000000000000000001ed7831C addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] + [Sequence] (original: 3, shrunk: 3) sender=0x00000000000000000000000000000000000014ba addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] sender=0x8ef7F804bAd9183981A366EA618d9D47D3124649 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[] sender=0x00000000000000000000000000000000000016b9 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[284406551521730736391345481857560031052359183671404042152984097777 [2.844e65]] diff --git a/crates/forge/tests/it/test_helpers.rs b/crates/forge/tests/it/test_helpers.rs index 06ea9de1f5743..22e6df8724ed7 100644 --- a/crates/forge/tests/it/test_helpers.rs +++ b/crates/forge/tests/it/test_helpers.rs @@ -145,6 +145,10 @@ impl ForgeTestProfile { shrink_run_limit: 5000, max_assume_rejects: 65536, gas_report_samples: 256, + corpus_dir: None, + corpus_gzip: true, + corpus_min_mutations: 5, + corpus_min_size: 0, failure_persist_dir: Some( tempfile::Builder::new() .prefix(&format!("foundry-{self}")) From ed86c645f037f1cc4e5c1583f074a7b2142c4f66 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Sat, 21 Jun 2025 13:37:06 +0200 Subject: [PATCH 228/244] chore: use existing minimal_tx_type fn (#10826) --- crates/anvil/src/eth/backend/mem/mod.rs | 27 +++---------------------- 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index ea783ce7d0377..beeb6087777aa 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -39,14 +39,7 @@ use alloy_consensus::{ Account, BlockHeader, EnvKzgSettings, Header, Receipt, ReceiptWithBloom, Signed, Transaction as TransactionTrait, TxEnvelope, }; -use alloy_eips::{ - eip1559::BaseFeeParams, - eip2718::{ - EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID, - LEGACY_TX_TYPE_ID, - }, - eip7840::BlobParams, -}; +use alloy_eips::{eip1559::BaseFeeParams, eip7840::BlobParams}; use alloy_evm::{eth::EthEvmContext, precompiles::PrecompilesMap, Database, Evm}; use alloy_network::{ AnyHeader, AnyRpcBlock, AnyRpcHeader, AnyRpcTransaction, AnyTxEnvelope, AnyTxType, @@ -1443,6 +1436,8 @@ impl Backend { fee_details: FeeDetails, block_env: BlockEnv, ) -> Env { + let tx_type = request.minimal_tx_type() as u8; + let WithOtherFields:: { inner: TransactionRequest { @@ -1458,27 +1453,11 @@ impl Backend { sidecar: _, chain_id, transaction_type, - max_fee_per_gas, - max_priority_fee_per_gas, .. // Rest of the gas fees related fields are taken from `fee_details` }, other, } = request; - let tx_type = transaction_type.unwrap_or_else(|| { - if authorization_list.is_some() { - EIP7702_TX_TYPE_ID - } else if blob_versioned_hashes.is_some() { - EIP4844_TX_TYPE_ID - } else if max_fee_per_gas.is_some() || max_priority_fee_per_gas.is_some() { - EIP1559_TX_TYPE_ID - } else if access_list.is_some() { - EIP2930_TX_TYPE_ID - } else { - LEGACY_TX_TYPE_ID - } - }); - let FeeDetails { gas_price, max_fee_per_gas, From ca9f4201441706107dbf6db5f4f49a20e4c825fd Mon Sep 17 00:00:00 2001 From: o-az Date: Sat, 21 Jun 2025 09:26:48 -0700 Subject: [PATCH 229/244] feat(fmt): dprint for toml, json, md, dockerfile, ts, & yml (#10824) * feat(fmt): dprint for toml, json, md, dockerfile, ts, & yml * chore: fmt --- .gitattributes | 3 ++ .github/PULL_REQUEST_TEMPLATE.md | 2 +- .github/workflows/dependencies.yml | 2 +- .github/workflows/docker-publish.yml | 32 ++++++------ .github/workflows/nix.yml | 2 +- .github/workflows/release.yml | 2 +- .gitignore | 5 ++ CONTRIBUTING.md | 2 +- Dockerfile | 5 +- FUNDING.json | 2 +- Makefile | 19 ++++++- README.md | 2 +- crates/cheatcodes/README.md | 1 + crates/doc/README.md | 4 +- crates/fmt/README.md | 32 ++++++------ crates/forge/assets/README.md | 8 +-- crates/lint/README.md | 46 ++++++++--------- deny.toml | 2 +- docs/dev/lintrules.md | 75 ++++++++++++++-------------- docs/dev/scripting.md | 2 - dprint.json | 62 +++++++++++++++++++++++ flake.nix | 1 + 22 files changed, 198 insertions(+), 113 deletions(-) create mode 100644 dprint.json diff --git a/.gitattributes b/.gitattributes index a1451e6b491a5..c3c54b1cfce95 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,3 +4,6 @@ testdata/cheats/Vm.sol linguist-generated # See *.rs diff=rust crates/lint/testdata/* text eol=lf + +dprint.json linguist-language=JSON-with-Comments +.devcontainer/devcontainer.json linguist-language=JSON-with-Comments \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 16e0182b117ac..393554ad7ebeb 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -31,4 +31,4 @@ the code change. - [ ] Added Tests - [ ] Added Documentation -- [ ] Breaking changes \ No newline at end of file +- [ ] Breaking changes diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index d22bbffcab714..e452a68c80967 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -7,7 +7,7 @@ on: # Run weekly - cron: "0 0 * * SUN" workflow_dispatch: - # Needed so we can run it manually +# Needed so we can run it manually permissions: contents: write diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index fdd069cf2e7ef..25a96b82b06fe 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -40,9 +40,9 @@ jobs: if: github.event_name != 'pull_request' uses: docker/login-action@v2 with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} # Extract metadata (tags, labels) for Docker # https://github.com/docker/metadata-action @@ -50,7 +50,7 @@ jobs: id: meta uses: docker/metadata-action@v4 with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # Creates an additional 'latest' or 'nightly' tag # If the job is triggered via cron schedule, tag nightly and nightly-{SHA} @@ -59,22 +59,22 @@ jobs: - name: Finalize Docker Metadata id: docker_tagging run: | - if [[ "${{ github.event_name }}" == 'schedule' ]]; then - echo "cron trigger, assigning nightly tag" - echo "docker_tags=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:nightly,${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:nightly-${GITHUB_SHA}" >> $GITHUB_OUTPUT - elif [[ "${GITHUB_REF##*/}" == "main" ]] || [[ ${GITHUB_REF##*/} == "master" ]]; then - echo "manual trigger from master/main branch, assigning latest tag" - echo "docker_tags=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${GITHUB_REF##*/},${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" >> $GITHUB_OUTPUT - else - echo "Neither scheduled nor manual release from main branch. Just tagging as branch name" - echo "docker_tags=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${GITHUB_REF##*/}" >> $GITHUB_OUTPUT - fi + if [[ "${{ github.event_name }}" == 'schedule' ]]; then + echo "cron trigger, assigning nightly tag" + echo "docker_tags=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:nightly,${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:nightly-${GITHUB_SHA}" >> $GITHUB_OUTPUT + elif [[ "${GITHUB_REF##*/}" == "main" ]] || [[ ${GITHUB_REF##*/} == "master" ]]; then + echo "manual trigger from master/main branch, assigning latest tag" + echo "docker_tags=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${GITHUB_REF##*/},${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" >> $GITHUB_OUTPUT + else + echo "Neither scheduled nor manual release from main branch. Just tagging as branch name" + echo "docker_tags=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${GITHUB_REF##*/}" >> $GITHUB_OUTPUT + fi # Log docker metadata to explicitly know what is being pushed - name: Inspect Docker Metadata run: | - echo "TAGS -> ${{ steps.docker_tagging.outputs.docker_tags }}" - echo "LABELS -> ${{ steps.meta.outputs.labels }}" + echo "TAGS -> ${{ steps.docker_tagging.outputs.docker_tags }}" + echo "LABELS -> ${{ steps.meta.outputs.labels }}" - name: Build and push foundry image run: make DOCKER_IMAGE_NAME=${{ steps.docker_tagging.outputs.docker_tags }} CARGO_TAG_NAME=${{ inputs.tag_name }} PROFILE=maxperf docker-build-push diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index e1091ec923ef7..168f378f9673b 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -5,7 +5,7 @@ on: # Run weekly - cron: "0 0 * * SUN" workflow_dispatch: - # Needed so we can run it manually +# Needed so we can run it manually concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b94b219cdc312..2faf123e4741e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -158,7 +158,7 @@ jobs: shell: bash run: | set -eo pipefail - flags=(--target $TARGET --profile $PROFILE --bins + flags=(--target $TARGET --profile $PROFILE --bins --no-default-features --features aws-kms,gcp-kms,cli,asm-keccak) # `jemalloc` is not fully supported on MSVC or aarch64 Linux. diff --git a/.gitignore b/.gitignore index 12d56ed3c7d97..64af508ada43c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,8 @@ out.json .vscode .claude CLAUDE.md +.env +node_modules +dist +bin +_ \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4b85713d56cdf..23e1ed07f888c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -186,7 +186,7 @@ Be aware that _how_ you communicate requests and reviews in your feedback can ha ##### Abandoned or stale pull requests -If a pull request appears to be abandoned or stalled, it is polite to first check with the contributor to see if they intend to continue the work before checking if they would mind if you took it over (especially if it just has nits left). When doing so, it is courteous to give the original contributor credit for the work they started, either by preserving their name and e-mail address in the commit log, or by using the `Author: ` or `Co-authored-by: ` metadata tag in the commits. +If a pull request appears to be abandoned or stalled, it is polite to first check with the contributor to see if they intend to continue the work before checking if they would mind if you took it over (especially if it just has nits left). When doing so, it is courteous to give the original contributor credit for the work they started, either by preserving their name and e-mail address in the commit log, or by using the `Author:` or `Co-authored-by:` metadata tag in the commits. _Adapted from the [ethers-rs contributing guide](https://github.com/gakonst/ethers-rs/blob/master/CONTRIBUTING.md)_. diff --git a/Dockerfile b/Dockerfile index 57983fe283b4d..b3d2fa31f732c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1.4 -FROM alpine:3.21 as build-environment +FROM alpine:3.21 AS build-environment ARG TARGETARCH WORKDIR /opt @@ -30,7 +30,7 @@ RUN --mount=type=cache,target=/root/.cargo/registry --mount=type=cache,target=/r && strip out/chisel \ && strip out/anvil; -FROM alpine:3.21 as foundry-client +FROM alpine:3.21 AS foundry-client RUN apk add --no-cache linux-headers git gcompat libstdc++ @@ -43,7 +43,6 @@ RUN adduser -Du 1000 foundry ENTRYPOINT ["/bin/sh", "-c"] - LABEL org.label-schema.build-date=$BUILD_DATE \ org.label-schema.name="Foundry" \ org.label-schema.description="Foundry" \ diff --git a/FUNDING.json b/FUNDING.json index 8f127f0f4e008..99e9e5c51a20f 100644 --- a/FUNDING.json +++ b/FUNDING.json @@ -7,4 +7,4 @@ "opRetro": { "projectId": "0x4562c0630907577f433cad78c7e2cc03349d918b6c14ef982f11a2678f5999ad" } -} \ No newline at end of file +} diff --git a/Makefile b/Makefile index 0e98b93d9f48f..0fa6df9bd581d 100644 --- a/Makefile +++ b/Makefile @@ -133,4 +133,21 @@ deny: ## Perform a `cargo` deny check. pr: ## Run all checks and tests. make deny && \ make lint && \ - make test \ No newline at end of file + make test + +# dprint formatting commands +.PHONY: dprint-fmt +dprint-fmt: ## Format code with dprint + @if ! command -v dprint > /dev/null; then \ + echo "Installing dprint..."; \ + cargo install dprint; \ + fi + dprint fmt + +.PHONY: dprint-check +dprint-check: ## Check formatting with dprint + @if ! command -v dprint > /dev/null; then \ + echo "Installing dprint..."; \ + cargo install dprint; \ + fi + dprint check \ No newline at end of file diff --git a/README.md b/README.md index 3d8a1f35f098f..efbd48205c443 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ _In the above benchmarks, compilation was always skipped_ - + diff --git a/crates/cheatcodes/README.md b/crates/cheatcodes/README.md index 7f776392eb744..5be3bc9614d98 100644 --- a/crates/cheatcodes/README.md +++ b/crates/cheatcodes/README.md @@ -26,6 +26,7 @@ The JSON interface is guaranteed to be stable, and can be used by third-party to the Foundry cheatcodes externally. For example, here are some tools that make use of the JSON interface: + - Internally, this is used to generate [a simple Solidity interface](../../testdata/cheats/Vm.sol) for testing - Used by [`forge-std`](https://github.com/foundry-rs/forge-std) to generate [user-friendly Solidity interfaces](https://github.com/foundry-rs/forge-std/blob/master/src/Vm.sol) - (WIP) Used by [the Foundry book](https://github.com/foundry-rs/book) to generate [the cheatcodes reference](https://book.getfoundry.sh/cheatcodes) diff --git a/crates/doc/README.md b/crates/doc/README.md index 9e9c638aadd9f..0d7bb2d24b733 100644 --- a/crates/doc/README.md +++ b/crates/doc/README.md @@ -14,14 +14,12 @@ In this phase, builder invokes 2 parsers: [solang parser](https://github.com/hyp Then, builder takes the output of the internal `Parser` and creates documents with additional information: the path of the original item, display identity, the target path where this document will be written. - 2. Preprocess The builder accepts an array of preprocessors which can be applied to documents produced in the `Parse` phase. The preprocessors can rearrange and/or change the array as well as modify the separate documents. At the end of this phase, the builder maintains a possibly modified collection of documents. - 3. Write -At this point, builder has all necessary information to generate documentation for the source code. It takes every document, formats the source file contents and writes/copies additional files that are required for building documentation. \ No newline at end of file +At this point, builder has all necessary information to generate documentation for the source code. It takes every document, formats the source file contents and writes/copies additional files that are required for building documentation. diff --git a/crates/fmt/README.md b/crates/fmt/README.md index f38eed245eaf9..3cd4331738b73 100644 --- a/crates/fmt/README.md +++ b/crates/fmt/README.md @@ -115,7 +115,7 @@ event Greet(string indexed name); The formatter supports multiple configuration options defined in `FormatterConfig`. | Option | Default | Description | -|------------------------------|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ---------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | line_length | 120 | Maximum line length where formatter will try to wrap the line | | tab_width | 4 | Number of spaces per indentation level | | bracket_spacing | false | Print spaces between brackets | @@ -177,7 +177,7 @@ following process: 1. Preparse comments with config values 2. Parse and compare the AST for source & expected files. - - The `AstEq` trait defines the comparison rules for the AST nodes + - The `AstEq` trait defines the comparison rules for the AST nodes 3. Format the source file and assert the equality of the output with the expected file. 4. Format the expected files and assert the idempotency of the formatting operation. @@ -190,17 +190,17 @@ Guidelines for contributing to `forge fmt`: ### Opening an issue 1. Create a short concise title describing an issue. - - Bad Title Examples - ```text - Forge fmt does not work - Forge fmt breaks - Forge fmt unexpected behavior - ``` - - Good Title Examples - ```text - Forge fmt postfix comment misplaced - Forge fmt does not inline short yul blocks - ``` + - Bad Title Examples + ```text + Forge fmt does not work + Forge fmt breaks + Forge fmt unexpected behavior + ``` + - Good Title Examples + ```text + Forge fmt postfix comment misplaced + Forge fmt does not inline short yul blocks + ``` 2. Fill in the issue template fields that include foundry version, platform & component info. 3. Provide the code snippets showing the current & expected behaviors. 4. If it's a feature request, specify why this feature is needed. @@ -217,6 +217,6 @@ Guidelines for contributing to `forge fmt`: 1. Specify an issue that is being addressed in the PR description. 2. Add a note on the solution in the PR description. 3. Provide the test coverage for the new feature. These should include: - - Adding malformatted & expected solidity code under `fmt/testdata/$dir/` - - Testing the behavior of pre and postfix comments - - If it's a new config value, tests covering **all** available options \ No newline at end of file + - Adding malformatted & expected solidity code under `fmt/testdata/$dir/` + - Testing the behavior of pre and postfix comments + - If it's a new config value, tests covering **all** available options diff --git a/crates/forge/assets/README.md b/crates/forge/assets/README.md index 9265b4558406a..8817d6ab7b2a9 100644 --- a/crates/forge/assets/README.md +++ b/crates/forge/assets/README.md @@ -4,10 +4,10 @@ Foundry consists of: -- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). -- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. -- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. -- **Chisel**: Fast, utilitarian, and verbose solidity REPL. +- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). +- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. +- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. +- **Chisel**: Fast, utilitarian, and verbose solidity REPL. ## Documentation diff --git a/crates/lint/README.md b/crates/lint/README.md index aae8ae0e2ab5c..bbb282cb16b78 100644 --- a/crates/lint/README.md +++ b/crates/lint/README.md @@ -7,25 +7,25 @@ It helps enforce best practices and improve code quality within Foundry projects `forge-lint` includes rules across several categories: -* **High Severity:** - * `incorrect-shift`: Warns against shift operations where operands might be in the wrong order. -* **Medium Severity:** - * `divide-before-multiply`: Warns against performing division before multiplication in the same expression, which can cause precision loss. -* **Informational / Style Guide:** - * `pascal-case-struct`: Flags for struct names not adhering to `PascalCase`. - * `mixed-case-function`: Flags for function names not adhering to `mixedCase`. - * `mixed-case-variable`: Flags for mutable variable names not adhering to `mixedCase`. - * `screaming-snake-case-const`: Flags for `constant` variable names not adhering to `SCREAMING_SNAKE_CASE`. - * `screaming-snake-case-immutable`: Flags for `immutable` variable names not adhering to `SCREAMING_SNAKE_CASE`. -* **Gas Optimizations:** - * `asm-keccak256`: Recommends using inline assembly for `keccak256` for potential gas savings. +- **High Severity:** + - `incorrect-shift`: Warns against shift operations where operands might be in the wrong order. +- **Medium Severity:** + - `divide-before-multiply`: Warns against performing division before multiplication in the same expression, which can cause precision loss. +- **Informational / Style Guide:** + - `pascal-case-struct`: Flags for struct names not adhering to `PascalCase`. + - `mixed-case-function`: Flags for function names not adhering to `mixedCase`. + - `mixed-case-variable`: Flags for mutable variable names not adhering to `mixedCase`. + - `screaming-snake-case-const`: Flags for `constant` variable names not adhering to `SCREAMING_SNAKE_CASE`. + - `screaming-snake-case-immutable`: Flags for `immutable` variable names not adhering to `SCREAMING_SNAKE_CASE`. +- **Gas Optimizations:** + - `asm-keccak256`: Recommends using inline assembly for `keccak256` for potential gas savings. ## Configuration The behavior of the `SolidityLinter` can be customized with the following options: | Option | Default | Description | -|---------------------|---------|------------------------------------------------------------------------------------------------------------| +| ------------------- | ------- | ---------------------------------------------------------------------------------------------------------- | | `with_severity` | `None` | Filters active lints by their severity (`High`, `Med`, `Low`, `Info`, `Gas`). `None` means all severities. | | `with_lints` | `None` | Specifies a list of `SolLint` instances to include. Overrides severity filter if a lint matches. | | `without_lints` | `None` | Specifies a list of `SolLint` instances to exclude, even if they match other criteria. | @@ -41,16 +41,16 @@ Guidelines for contributing to `forge lint`: ### Opening an issue 1. Create a short concise title describing an issue. - - Bad Title Examples - ```text - Forge lint does not work - Forge lint breaks - Forge lint unexpected behavior - ``` - - Good Title Examples - ```text - Forge lint does not flag incorrect shift operations - ``` + - Bad Title Examples + ```text + Forge lint does not work + Forge lint breaks + Forge lint unexpected behavior + ``` + - Good Title Examples + ```text + Forge lint does not flag incorrect shift operations + ``` 2. Fill in the issue template fields that include foundry version, platform & component info. 3. Provide the code snippets showing the current & expected behaviors. 4. If it's a feature request, specify why this feature is needed. diff --git a/deny.toml b/deny.toml index b1f10b3a4a852..e10c06ec8f3f5 100644 --- a/deny.toml +++ b/deny.toml @@ -71,7 +71,7 @@ exceptions = [ { allow = ["CC0-1.0"], name = "dunce" }, { allow = ["CC0-1.0"], name = "aurora-engine-modexp" }, ] -#copyleft = "deny" +# copyleft = "deny" # See note in unicode-ident's readme! [[licenses.clarify]] diff --git a/docs/dev/lintrules.md b/docs/dev/lintrules.md index 450934ab6f477..5dc7513736040 100644 --- a/docs/dev/lintrules.md +++ b/docs/dev/lintrules.md @@ -7,58 +7,59 @@ It helps enforce best practices and improve code quality within Foundry projects The `forge-lint` system operates by analyzing Solidity source code: -1. **Parsing**: Solidity source files are parsed into an Abstract Syntax Tree (AST) using `solar-parse`. This AST represents the structure of the code. -2. **AST Traversal**: The generated AST is then traversed using a Visitor pattern. The `EarlyLintVisitor` is responsible for walking through the AST nodes. -3. **Applying Lint Passes**: As the visitor encounters different AST nodes (like functions, expressions, variable definitions), it invokes registered "lint passes" (`EarlyLintPass` implementations). Each pass is designed to check for a specific code pattern. -4. **Emitting Diagnostics**: If a lint pass identifies a violation of its rule, it uses the `LintContext` to emit a diagnostic (either `warning` or `note`) that pinpoints the issue in the source code. +1. **Parsing**: Solidity source files are parsed into an Abstract Syntax Tree (AST) using `solar-parse`. This AST represents the structure of the code. +2. **AST Traversal**: The generated AST is then traversed using a Visitor pattern. The `EarlyLintVisitor` is responsible for walking through the AST nodes. +3. **Applying Lint Passes**: As the visitor encounters different AST nodes (like functions, expressions, variable definitions), it invokes registered "lint passes" (`EarlyLintPass` implementations). Each pass is designed to check for a specific code pattern. +4. **Emitting Diagnostics**: If a lint pass identifies a violation of its rule, it uses the `LintContext` to emit a diagnostic (either `warning` or `note`) that pinpoints the issue in the source code. ### Key Components -* **`Linter` Trait**: Defines a generic interface for linters. `SolidityLinter` is the concrete implementation tailored for Solidity. -* **`Lint` Trait & `SolLint` Struct**: - * `Lint`: A trait that defines the essential properties of a lint rule, such as its unique ID, severity, description, and an optional help message/URL. - * `SolLint`: A struct implementing the `Lint` trait, used to hold the metadata for each specific Solidity lint rule. -* **`EarlyLintPass<'ast>` Trait**: Lints that operate directly on AST nodes implement this trait. It contains methods (like `check_expr`, `check_item_function`, etc.) called by the visitor. -* **`LintContext<'s>`**: Provides contextual information to lint passes during execution, such as access to the session for emitting diagnostics. -* **`EarlyLintVisitor<'a, 's, 'ast>`**: The core visitor that traverses the AST and dispatches checks to the registered `EarlyLintPass` instances. +- **`Linter` Trait**: Defines a generic interface for linters. `SolidityLinter` is the concrete implementation tailored for Solidity. +- **`Lint` Trait & `SolLint` Struct**: + - `Lint`: A trait that defines the essential properties of a lint rule, such as its unique ID, severity, description, and an optional help message/URL. + - `SolLint`: A struct implementing the `Lint` trait, used to hold the metadata for each specific Solidity lint rule. +- **`EarlyLintPass<'ast>` Trait**: Lints that operate directly on AST nodes implement this trait. It contains methods (like `check_expr`, `check_item_function`, etc.) called by the visitor. +- **`LintContext<'s>`**: Provides contextual information to lint passes during execution, such as access to the session for emitting diagnostics. +- **`EarlyLintVisitor<'a, 's, 'ast>`**: The core visitor that traverses the AST and dispatches checks to the registered `EarlyLintPass` instances. ## Developing a new lint rule 1. Specify an issue that is being addressed in the PR description. 2. In your PR: - * Create a static `SolLint` instance using the `declare_forge_lint!` to define its metadata. - ```rust - declare_forge_lint!( - MIXED_CASE_FUNCTION, // The Rust identifier for this SolLint static - Severity::Info, // The default severity of the lint - "mixed-case-function", // A unique string ID for configuration/CLI - "function names should use mixedCase", // A brief description - "https://docs.soliditylang.org/en/latest/style-guide.html#function-names" // Optional help link - ); - ``` - - * Register the pass struct and the lint using `register_lints!` in the `mod.rs` of its corresponding severity category. This macro generates the necessary boilerplate to make them discoverable by the linter, and creates helper functions to instantiate them. - ```rust - register_lints!( - (PascalCaseStruct, (PASCAL_CASE_STRUCT)), - (MixedCaseVariable, (MIXED_CASE_VARIABLE)), - (MixedCaseFunction, (MIXED_CASE_FUNCTION)) - ); - // The structs `PascalCaseStruct`, `MixedCaseVariable`, etc., would have to manually implement `EarlyLintPass`. - ``` - - * Implement the `EarlyLintPass` trait logic for the pass struct. Do it in a new file within the relevant severity module (e.g., `src/sol/med/my_new_lint.rs`). + +- Create a static `SolLint` instance using the `declare_forge_lint!` to define its metadata. + ```rust + declare_forge_lint!( + MIXED_CASE_FUNCTION, // The Rust identifier for this SolLint static + Severity::Info, // The default severity of the lint + "mixed-case-function", // A unique string ID for configuration/CLI + "function names should use mixedCase", // A brief description + "https://docs.soliditylang.org/en/latest/style-guide.html#function-names" // Optional help link + ); + ``` + +- Register the pass struct and the lint using `register_lints!` in the `mod.rs` of its corresponding severity category. This macro generates the necessary boilerplate to make them discoverable by the linter, and creates helper functions to instantiate them. + ```rust + register_lints!( + (PascalCaseStruct, (PASCAL_CASE_STRUCT)), + (MixedCaseVariable, (MIXED_CASE_VARIABLE)), + (MixedCaseFunction, (MIXED_CASE_FUNCTION)) + ); + // The structs `PascalCaseStruct`, `MixedCaseVariable`, etc., would have to manually implement `EarlyLintPass`. + ``` + +- Implement the `EarlyLintPass` trait logic for the pass struct. Do it in a new file within the relevant severity module (e.g., `src/sol/med/my_new_lint.rs`). 3. Add comprehensive tests in `lint/testdata/`: - * Create `MyNewLint.sol` with various examples (triggering and non-triggering cases, edge cases). - * Generate the corresponding blessed file with the expected output. + - Create `MyNewLint.sol` with various examples (triggering and non-triggering cases, edge cases). + - Generate the corresponding blessed file with the expected output. ### Testing a lint rule Tests are located in the `lint/testdata/` directory. A test for a lint rule involves: - - A Solidity source file with various code snippets, some of which are expected to trigger the lint. Expected diagnostics must be indicated with either `//~WARN: description` or `//~NOTE: description` on the relevant line. - - corresponding `.stderr` (blessed) file which contains the exact diagnostic output the linter is expected to produce for that source file. +- A Solidity source file with various code snippets, some of which are expected to trigger the lint. Expected diagnostics must be indicated with either `//~WARN: description` or `//~NOTE: description` on the relevant line. +- corresponding `.stderr` (blessed) file which contains the exact diagnostic output the linter is expected to produce for that source file. The testing framework runs the linter on the `.sol` file and compares its standard error output against the content of the `.stderr` file to ensure correctness. diff --git a/docs/dev/scripting.md b/docs/dev/scripting.md index cdface73a28e5..92b65a03ab561 100644 --- a/docs/dev/scripting.md +++ b/docs/dev/scripting.md @@ -44,7 +44,6 @@ graph TD; MultiChainSequence::new-->ScriptArgs::multi_chain_deployment ScriptSequence::new-->ScriptArgs::single_deployment ScriptArgs::single_deployment-->ScriptArgs::send_transactions - ``` ### Notes @@ -83,7 +82,6 @@ ScriptRunner::script--"run()"-->Executor::call; end end Executor::call-. BroadcastableTransactions .->ScriptArgs::handle_broadcastable_transactions; - ``` ## Nonce Management diff --git a/dprint.json b/dprint.json new file mode 100644 index 0000000000000..c534f9106fd29 --- /dev/null +++ b/dprint.json @@ -0,0 +1,62 @@ +{ + "$schema": "https://raw.githubusercontent.com/dprint/dprint/refs/heads/main/website/src/assets/schemas/v0.json", + "incremental": true, + "indentWidth": 2, + "useTabs": false, + "includes": [ + "*.md", + "*.{toml}", + "Dockerfile", + "*.{yml,yaml}", + "*.{json,jsonc}", + "*.{js,cjs,mjs,d.ts,d.cts,d.mts,ts,tsx,jsx}" + ], + "excludes": [ + "**/build", + "**/abi/**", + "**/target", + "**/test/**", + "**/*.min.*", + "**/dist/**", + "testdata/**", + "**/tests/**", + "changelog.json", + "**/test-data/**", + "**/node_modules", + "**/cheatcodes/**", + ".github/scripts/**", + ".github/ISSUE_TEMPLATE/**" + ], + "plugins": [ + "https://plugins.dprint.dev/toml-0.7.0.wasm", + "https://plugins.dprint.dev/json-0.20.0.wasm", + "https://plugins.dprint.dev/markdown-0.18.0.wasm", + "https://plugins.dprint.dev/dockerfile-0.3.3.wasm", + "https://plugins.dprint.dev/typescript-0.95.7.wasm", + "https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.1.wasm" + ], + "markdown": { + "lineWidth": 100, + "textWrap": "maintain" + }, + "toml": { + "columnWidth": 100 + }, + "json": { + "useTabs": false, + "indentWidth": 2, + "trailingCommas": "never", + "array.preferSingleLine": true + }, + "typescript": { + "useTabs": false, + "semiColons": "asi", + "quoteProps": "asNeeded", + "useBraces": "preferNone", + "trailingCommas": "never", + "quoteStyle": "alwaysSingle", + "arrowFunction.useParentheses": "preferNone", + "exportDeclaration.sortTypeOnlyExports": "none", + "importDeclaration.sortTypeOnlyImports": "none" + } +} diff --git a/flake.nix b/flake.nix index 8cf41ed16d3a3..759b9291f642e 100644 --- a/flake.nix +++ b/flake.nix @@ -28,6 +28,7 @@ # test dependencies solc vyper + dprint nodejs ]; buildInputs = lib.optionals pkgs.stdenv.isDarwin From a4780092092fa6d0dd22f2f59968254148b87a91 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 22 Jun 2025 10:01:25 +0200 Subject: [PATCH 230/244] Update flake.lock (#10830) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit flake.lock: Update Flake lock file updates: • Updated input 'fenix': 'github:nix-community/fenix/a804172f150bcf81262655324e583bb0cd0f28dd?narHash=sha256-RlcGw3vAnbI3cfZn8aFaovNUd7312VZh%2B/FDWkqdA7E%3D' (2025-06-14) → 'github:nix-community/fenix/933bc78d45abaf764dbfe0fd117be981631f3e9a?narHash=sha256-79O83W9osY3wyvxZHqL0gw85tcACSX0TU5en3%2Bdky/0%3D' (2025-06-21) • Updated input 'fenix/rust-analyzer-src': 'github:rust-lang/rust-analyzer/a497f4114ccf24978accb56190e60d1e1659e0c7?narHash=sha256-t6x6/PKg8Shnkd3htrxf3WMgycfRLRWvN9JHAmGWf%2Bs%3D' (2025-06-13) → 'github:rust-lang/rust-analyzer/b0552d779f7137c76f109666ce0ad28395c0e582?narHash=sha256-EMFKnO%2BJ3dZOa9J%2BuiKZgHYgzALv9dqxY7NHV0DbO/U%3D' (2025-06-20) • Updated input 'nixpkgs': 'github:NixOS/nixpkgs/6afe187897bef7933475e6af374c893f4c84a293?narHash=sha256-K9yBph93OLTNw02Q6e9CYFGrUhvEXnh45vrZqIRWfvQ%3D' (2025-06-14) → 'github:NixOS/nixpkgs/076e8c6678d8c54204abcb4b1b14c366835a58bb?narHash=sha256-1ovgdmuDYVo5OUC5NzdF%2BV4zx2uT8RtsgZahxidBTyw%3D' (2025-06-20) Co-authored-by: github-actions[bot] --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index dcf4bb4f625f0..1acebbb2bdee2 100644 --- a/flake.lock +++ b/flake.lock @@ -8,11 +8,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1749883145, - "narHash": "sha256-RlcGw3vAnbI3cfZn8aFaovNUd7312VZh+/FDWkqdA7E=", + "lastModified": 1750487788, + "narHash": "sha256-79O83W9osY3wyvxZHqL0gw85tcACSX0TU5en3+dky/0=", "owner": "nix-community", "repo": "fenix", - "rev": "a804172f150bcf81262655324e583bb0cd0f28dd", + "rev": "933bc78d45abaf764dbfe0fd117be981631f3e9a", "type": "github" }, "original": { @@ -23,11 +23,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1749871736, - "narHash": "sha256-K9yBph93OLTNw02Q6e9CYFGrUhvEXnh45vrZqIRWfvQ=", + "lastModified": 1750386251, + "narHash": "sha256-1ovgdmuDYVo5OUC5NzdF+V4zx2uT8RtsgZahxidBTyw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "6afe187897bef7933475e6af374c893f4c84a293", + "rev": "076e8c6678d8c54204abcb4b1b14c366835a58bb", "type": "github" }, "original": { @@ -46,11 +46,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1749829309, - "narHash": "sha256-t6x6/PKg8Shnkd3htrxf3WMgycfRLRWvN9JHAmGWf+s=", + "lastModified": 1750405264, + "narHash": "sha256-EMFKnO+J3dZOa9J+uiKZgHYgzALv9dqxY7NHV0DbO/U=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "a497f4114ccf24978accb56190e60d1e1659e0c7", + "rev": "b0552d779f7137c76f109666ce0ad28395c0e582", "type": "github" }, "original": { From e44249aa21dfb7d724676d5cd82d219851a2ba99 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 22 Jun 2025 11:32:18 +0200 Subject: [PATCH 231/244] chore(deps): weekly `cargo update` (#10831) Locking 45 packages to latest compatible versions Updating alloy-consensus v1.0.11 -> v1.0.12 Updating alloy-consensus-any v1.0.11 -> v1.0.12 Updating alloy-contract v1.0.11 -> v1.0.12 Updating alloy-eips v1.0.11 -> v1.0.12 Updating alloy-ens v1.0.11 -> v1.0.12 Unchanged alloy-evm v0.10.0 (available: v0.12.1) Updating alloy-genesis v1.0.11 -> v1.0.12 Updating alloy-json-rpc v1.0.11 -> v1.0.12 Updating alloy-network v1.0.11 -> v1.0.12 Updating alloy-network-primitives v1.0.11 -> v1.0.12 Unchanged alloy-op-evm v0.10.0 (available: v0.12.1) Updating alloy-provider v1.0.11 -> v1.0.12 Updating alloy-pubsub v1.0.11 -> v1.0.12 Updating alloy-rpc-client v1.0.11 -> v1.0.12 Updating alloy-rpc-types v1.0.11 -> v1.0.12 Updating alloy-rpc-types-anvil v1.0.11 -> v1.0.12 Updating alloy-rpc-types-any v1.0.11 -> v1.0.12 Updating alloy-rpc-types-debug v1.0.11 -> v1.0.12 Updating alloy-rpc-types-engine v1.0.11 -> v1.0.12 Updating alloy-rpc-types-eth v1.0.11 -> v1.0.12 Updating alloy-rpc-types-trace v1.0.11 -> v1.0.12 Updating alloy-rpc-types-txpool v1.0.11 -> v1.0.12 Updating alloy-serde v1.0.11 -> v1.0.12 Updating alloy-signer v1.0.11 -> v1.0.12 Updating alloy-signer-aws v1.0.11 -> v1.0.12 Updating alloy-signer-gcp v1.0.11 -> v1.0.12 Updating alloy-signer-ledger v1.0.11 -> v1.0.12 Updating alloy-signer-local v1.0.11 -> v1.0.12 Updating alloy-signer-trezor v1.0.11 -> v1.0.12 Updating alloy-transport v1.0.11 -> v1.0.12 Updating alloy-transport-http v1.0.11 -> v1.0.12 Updating alloy-transport-ipc v1.0.11 -> v1.0.12 Updating alloy-transport-ws v1.0.11 -> v1.0.12 Unchanged alloy-trie v0.8.1 (available: v0.9.0) Updating alloy-tx-macros v1.0.11 -> v1.0.12 Updating atomic v0.6.0 -> v0.6.1 Updating autocfg v1.4.0 -> v1.5.0 Updating aws-sdk-sts v1.74.0 -> v1.75.0 Unchanged crossterm v0.28.1 (available: v0.29.0) Updating errno v0.3.12 -> v0.3.13 Unchanged idna_adapter v1.1.0 (available: v1.2.1) Updating libc v0.2.173 -> v0.2.174 Updating markup5ever v0.16.1 -> v0.16.2 Unchanged matchit v0.8.4 (available: v0.8.6) Updating newtype-uuid v1.2.3 -> v1.2.4 Unchanged op-alloy-consensus v0.17.2 (available: v0.18.6) Unchanged op-alloy-rpc-types v0.17.2 (available: v0.18.6) Unchanged op-revm v5.0.1 (available: v7.0.1) Unchanged opener v0.7.2 (available: v0.8.2) Updating prettyplease v0.2.34 -> v0.2.35 Unchanged protobuf v3.3.0 (available: v3.7.2) Unchanged protobuf-support v3.3.0 (available: v3.7.2) Updating quinn-udp v0.5.12 -> v0.5.13 Unchanged rand v0.8.5 (available: v0.9.1) Unchanged revm v24.0.1 (available: v26.0.1) Unchanged revm-inspectors v0.23.0 (available: v0.25.0) Unchanged rustyline v15.0.0 (available: v16.0.0) Unchanged schemars v0.8.22 (available: v0.9.0) Updating syn v2.0.103 -> v2.0.104 Unchanged ui_test v0.29.2 (available: v0.30.1) Unchanged unicode-width v0.2.0 (available: v0.2.1) Unchanged vergen v8.3.2 (available: v9.0.6) Updating webpki-roots v1.0.0 -> v1.0.1 Updating zerocopy v0.8.25 -> v0.8.26 Updating zerocopy-derive v0.8.25 -> v0.8.26 Unchanged zip-extract v0.2.1 (available: v0.2.3) note: to see how you depend on a package, run `cargo tree --invert --package @` Co-authored-by: mattsse <19890894+mattsse@users.noreply.github.com> --- Cargo.lock | 320 ++++++++++++++++++++++++++--------------------------- 1 file changed, 160 insertions(+), 160 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 65cb9689ebe43..69bee29216009 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,9 +70,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "659c33e85c4a9f8bb1b9a2400f4f3d0dd52fbc4bd3650e08d22df1e17d5d92ee" +checksum = "2bcb57295c4b632b6b3941a089ee82d00ff31ff9eb3eac801bf605ffddc81041" dependencies = [ "alloy-eips", "alloy-primitives", @@ -95,9 +95,9 @@ dependencies = [ [[package]] name = "alloy-consensus-any" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48fdc146414932cec2114f749f5f65a8960ee7547b1638a97bb0d04160d09e4" +checksum = "3ab669be40024565acb719daf1b2a050e6dc065fc0bec6050d97a81cdb860bd7" dependencies = [ "alloy-consensus", "alloy-eips", @@ -109,9 +109,9 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c711bfed1579611565ab831166c7bbaf123baea785ea945f02ed3620950f6fe1" +checksum = "8ba5d28e15c14226f243d6e329611840135e1b0fa31feaea57c461e0b03b4c7b" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -189,9 +189,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8390cb5c872d53560635dabc02d616c1bb626dd0f7d6893f8725edb822573fed" +checksum = "4f853de9ca1819f54de80de5d03bfc1bb7c9fafcf092b480a654447141bc354d" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -209,9 +209,9 @@ dependencies = [ [[package]] name = "alloy-ens" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc0a11ddee117c05e7c614d6cb6fcf87d6aed6a449a4ccca656e5bbfbd0cc8c" +checksum = "7cba413e1baa2a5a765f48d30cb0244d0c6b3cf911c5e66105361744b277da8d" dependencies = [ "alloy-contract", "alloy-primitives", @@ -242,9 +242,9 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18ce1538291d8409d4a7d826176d461a6f9eb28632d7185f801bda43a138260" +checksum = "8500bcc1037901953771c25cb77e0d4ec0bffd938d93a04715390230d21a612d" dependencies = [ "alloy-eips", "alloy-primitives", @@ -280,9 +280,9 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b91481d12dcd964f4a838271d6abffac2d4082695fc3f73a15429166ea1692d" +checksum = "f4997a9873c8639d079490f218e50e5fa07e70f957e9fc187c0a0535977f482f" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -295,9 +295,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8b245fa9d76cc9fc58cf78844f2d4e481333449ba679b2044f09b983fc96f85" +checksum = "a0306e8d148b7b94d988615d367443c1b9d6d2e9fecd2e1f187ac5153dce56f5" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -321,9 +321,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cecb975fc2f2e1eb09c513428c34e0d8c13e28b5ff1dbdf68e0f64a1a92c5f3" +checksum = "3eef189583f4c53d231dd1297b28a675ff842b551fb34715f562868a1937431a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -392,9 +392,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecac2cbea1cb3da53b4e68a078e57f9da8d12d86e2017db1240df222e2498397" +checksum = "ea624ddcdad357c33652b86aa7df9bd21afd2080973389d3facf1a221c573948" dependencies = [ "alloy-chains", "alloy-consensus", @@ -438,9 +438,9 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db1d3c2316590910ba697485aa75cdafef89735010d338d197f8af5baa79df92" +checksum = "1ea3227fa5f627d22b7781e88bc2fe79ba1792d5535b4161bc8fc99cdcd8bedd" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -476,14 +476,14 @@ checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] name = "alloy-rpc-client" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0bed8157038003c702dd1861a6b72d4b1a8f46aeffad35e81580223642170fa" +checksum = "e43d00b4de38432304c4e4b01ae6a3601490fd9824c852329d158763ec18663c" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -509,9 +509,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82fed036edc62cd79476fe0340277a1c47b07c173f6ac0244f24193e1183b8e4" +checksum = "3bf22ddb69a436f28bbdda7daf34fe011ee9926fa13bfce89fa023aca9ce2b2f" dependencies = [ "alloy-primitives", "alloy-rpc-types-anvil", @@ -525,9 +525,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f2e3dc925ec6722524f8d7412b9a6845a3350c7037f8a37892ada00c9018125" +checksum = "1ecd1c60085d8cbc3562e16e264a3cd68f42e54dc16b0d40645e5e42841bc042" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -537,9 +537,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf6702dd7eb929068ab075869679e745d68c4eb611c5a0cf72617688b85b5f4" +checksum = "5958f2310d69f4806e6f6b90ceb4f2b781cc5a843517a7afe2e7cfec6de3cfb9" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -548,9 +548,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-debug" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e982f72ff47c0f754cb6aa579e456220d768e1ec07675e66cfce970dad70292" +checksum = "c293df0c58d15330e65599f776e30945ea078c93b1594e5c4ba0efaad3f0a739" dependencies = [ "alloy-primitives", "serde", @@ -558,9 +558,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "505224e162e239980c6df7632c99f0bc5abbcf630017502810979e9e01f3c86e" +checksum = "2e5b09d86d0c015cb8400c5d1d0483425670bef4fc1260336aea9ef6d4b9540c" dependencies = [ "alloy-consensus", "alloy-eips", @@ -576,9 +576,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20ff509ca40537042b7cc9bede6b415ef807c9c5c48024e9fe10b8c8ad0757ef" +checksum = "1826285e4ffc2372a8c061d5cc145858e67a0be3309b768c5b77ddb6b9e6cbc7" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -596,9 +596,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51dc49d5865f2227c810a416c8d14141db7716a0174bfa6cff1c1a984b678b5e" +checksum = "d1e8f7fa774a1d6f7b3654686f68955631e55f687e03da39c0bd77a9418d57a1" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -610,9 +610,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c962ec5193084873353ad7a65568056b4e704203302e6ba81374e95a22deba4d" +checksum = "d39d9218a0fd802dbccd7e0ce601a6bdefb61190386e97a437d97a31661cd358" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -622,9 +622,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9873512b1e99505f4a65e1d3a3105cb689f112f8e3cab3c632b20a97a46adae" +checksum = "906ce0190afeded19cb2e963cb8507c975a7862216b9e74f39bf91ddee6ae74b" dependencies = [ "alloy-primitives", "serde", @@ -633,9 +633,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2d4d95d8431a11e0daee724c3b7635dc8e9d3d60d0b803023a8125c74a77899" +checksum = "c89baab06195c4be9c5d66f15c55e948013d1aff3ec1cfb0ed469e1423313fce" dependencies = [ "alloy-dyn-abi", "alloy-primitives", @@ -650,9 +650,9 @@ dependencies = [ [[package]] name = "alloy-signer-aws" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a7daec95526f0e005b38ff9dbdcb74ed1a2ea28ea01b84d61b930880fe83f3" +checksum = "3d6a8589f1186ffb01e0086d515c657bf1bfb3bb456cfc7c6f51dbb29e154a5f" dependencies = [ "alloy-consensus", "alloy-network", @@ -668,9 +668,9 @@ dependencies = [ [[package]] name = "alloy-signer-gcp" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7afc41138d41871c554f678c26ea8d1c7796d714996d66d2c618f4ac26cf7aba" +checksum = "4080f77195f44eeb806aa1dcdb55c1c14ac16a4f85e8f0ca769b14709cf3fc3c" dependencies = [ "alloy-consensus", "alloy-network", @@ -686,9 +686,9 @@ dependencies = [ [[package]] name = "alloy-signer-ledger" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3546b3d813008ddf90f90f711d30d3fb5d0804ea42400d59bca1460d2ffb83f1" +checksum = "ccaa089aa033669ed92f05e365e3a12d7a29b0cc5ee415917f3bf381fa1f346d" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -706,9 +706,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb03eca937485b258d8e791d143e95b50dbfae0e18f92e1b1271c38959cd00fb" +checksum = "8a249a923e302ac6db932567c43945392f0b6832518aab3c4274858f58756774" dependencies = [ "alloy-consensus", "alloy-network", @@ -725,9 +725,9 @@ dependencies = [ [[package]] name = "alloy-signer-trezor" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a28e40ca39d4c4a93165a951aa45554b6496f1439a882e96d9fed849c15ec2" +checksum = "9a087d62a5c2b109c2f7521da31d72ba914025141f2aa1c0be122ddc3f0ce31b" dependencies = [ "alloy-consensus", "alloy-network", @@ -751,7 +751,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -768,7 +768,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", "syn-solidity", "tiny-keccak", ] @@ -787,7 +787,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.103", + "syn 2.0.104", "syn-solidity", ] @@ -815,9 +815,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "468a871d7ea52e31ef3abf5ccde612cb3723794f484d26dca6a04a3a776db739" +checksum = "6d1ae10b1bc77fde38161e242749e41e65e34000d05da0a3d3f631e03bfcb19e" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -838,9 +838,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e969c254b189f7da95f07bab53673dd418f8595abfe3397b2cf8d7ba7955487" +checksum = "b234272ee449e32c9f1afbbe4ee08ea7c4b52f14479518f95c844ab66163c545" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -853,9 +853,9 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb134aaa80c2e1e03eebc101e7c513f08a529726738506d8c306ec9f3c9a7f3b" +checksum = "061672d736144eb5aae13ca67cfec8e5e69a65bef818cb1a2ab2345d55c50ab4" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -873,9 +873,9 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e57f13346af9441cafa99d5b80d95c2480870dd18bd274464f7131df01ad692a" +checksum = "40b01f10382c2aea797d710279b24687a1e9e09a09ecd145f84f636f2a8a3fcc" dependencies = [ "alloy-pubsub", "alloy-transport", @@ -907,15 +907,15 @@ dependencies = [ [[package]] name = "alloy-tx-macros" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d642ba58c32547ad9742c613f9849a2aedc47914b02948224326e4cb62b91040" +checksum = "b75ef8609ea2b31c799b0a56c724dca4c73105c5ccc205d9dfeb1d038df6a1da" dependencies = [ "alloy-primitives", "darling", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -1303,7 +1303,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -1341,7 +1341,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -1430,7 +1430,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -1528,7 +1528,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -1539,7 +1539,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -1555,9 +1555,9 @@ dependencies = [ [[package]] name = "atomic" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" +checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" dependencies = [ "bytemuck", ] @@ -1592,14 +1592,14 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-config" @@ -1758,9 +1758,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.74.0" +version = "1.75.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d440e1d368759bd10df0dbdddbfff6473d7cd73e9d9ef2363dc9995ac2d711" +checksum = "e3258fa707f2f585ee3049d9550954b959002abd59176975150a01d5cf38ae3f" dependencies = [ "aws-credential-types", "aws-runtime", @@ -2107,7 +2107,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.103", + "syn 2.0.104", "which 4.4.2", ] @@ -2222,7 +2222,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -2619,7 +2619,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3073,7 +3073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3116,7 +3116,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3127,7 +3127,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3207,7 +3207,7 @@ checksum = "510c292c8cf384b1a340b816a9a6cf2599eb8f566a44949024af88418000c50b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3218,7 +3218,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3239,7 +3239,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3249,7 +3249,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3278,7 +3278,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", "unicode-xid", ] @@ -3291,7 +3291,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", "unicode-xid", ] @@ -3358,7 +3358,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3430,7 +3430,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3535,7 +3535,7 @@ checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3585,12 +3585,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -4001,7 +4001,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -4597,7 +4597,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -4774,7 +4774,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -5193,7 +5193,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.0", + "webpki-roots 1.0.1", ] [[package]] @@ -5329,7 +5329,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -5447,7 +5447,7 @@ dependencies = [ "indoc", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -5563,7 +5563,7 @@ checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -5742,9 +5742,9 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] name = "libc" -version = "0.2.173" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libdbus-sys" @@ -5954,7 +5954,7 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -5965,9 +5965,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "markup5ever" -version = "0.16.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a8096766c229e8c88a3900c9b44b7e06aa7f7343cc229158c3e58ef8f9973a" +checksum = "2e4cd8c02f18a011991a039855480c64d74291c5792fcc160d55d77dc4de4a39" dependencies = [ "log", "tendril", @@ -5988,7 +5988,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -6080,7 +6080,7 @@ checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -6158,7 +6158,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -6169,9 +6169,9 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "newtype-uuid" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5825f69cf354438a53f85b959f0baa6a7ada1f4bd923f63e42c34090bf288fb" +checksum = "a17d82edb1c8a6c20c238747ae7aae9181133e766bc92cd2556fdd764407d0d1" dependencies = [ "uuid 1.17.0", ] @@ -6421,7 +6421,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -6651,7 +6651,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -6734,7 +6734,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -6793,7 +6793,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -6867,7 +6867,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -6916,7 +6916,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -7021,12 +7021,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.34" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6837b9e10d61f45f987d50808f83d1ee3d206c66acf650c3e4ae2e1f6ddedf55" +checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" dependencies = [ "proc-macro2", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -7077,7 +7077,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -7097,7 +7097,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", "version_check", "yansi", ] @@ -7144,7 +7144,7 @@ checksum = "4ee1c9ac207483d5e7db4940700de86a9aae46ef90c48b57f99fe7edb8345e49" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -7167,7 +7167,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -7299,9 +7299,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" +checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970" dependencies = [ "cfg_aliases", "libc", @@ -7497,7 +7497,7 @@ checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -7595,7 +7595,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 1.0.0", + "webpki-roots 1.0.1", ] [[package]] @@ -8166,7 +8166,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -8315,7 +8315,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -8326,7 +8326,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -8410,7 +8410,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -8721,7 +8721,7 @@ checksum = "e17f8b99f28f358b41acb6efe4d7b8f326541b3c58a15dd1931d6fe581feefef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -8929,7 +8929,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -8942,7 +8942,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -9074,9 +9074,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.103" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -9092,7 +9092,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -9230,7 +9230,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -9241,7 +9241,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -9365,7 +9365,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -9598,7 +9598,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -10109,7 +10109,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", "wasm-bindgen-shared", ] @@ -10144,7 +10144,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -10278,14 +10278,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.0", + "webpki-roots 1.0.1", ] [[package]] name = "webpki-roots" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" +checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502" dependencies = [ "rustls-pki-types", ] @@ -10405,7 +10405,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -10416,7 +10416,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -10712,22 +10712,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -10747,7 +10747,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] From 8bd3d64a999e9e87a936c71a5cc928cbf7676830 Mon Sep 17 00:00:00 2001 From: Delweng Date: Tue, 24 Jun 2025 21:25:47 +0800 Subject: [PATCH 232/244] feat(cast): add recover-authority for EIP7702 Authorization (#10839) * cast: add subcommand recover-authority Signed-off-by: jsvisa * cargo: add alloy-eips Signed-off-by: jsvisa * cargo Signed-off-by: jsvisa * add testcase Signed-off-by: jsvisa * fmt Signed-off-by: jsvisa --------- Signed-off-by: jsvisa --- Cargo.lock | 1 + crates/cast/Cargo.toml | 3 ++- crates/cast/src/args.rs | 5 +++++ crates/cast/src/opts.rs | 4 ++++ crates/cast/tests/cli/main.rs | 15 +++++++++++++++ 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 69bee29216009..527b93eb2adf5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2369,6 +2369,7 @@ dependencies = [ "alloy-consensus", "alloy-contract", "alloy-dyn-abi", + "alloy-eips", "alloy-ens", "alloy-hardforks", "alloy-json-abi", diff --git a/crates/cast/Cargo.toml b/crates/cast/Cargo.toml index d08d10fc6fce9..6d7b22e214b5d 100644 --- a/crates/cast/Cargo.toml +++ b/crates/cast/Cargo.toml @@ -53,6 +53,7 @@ alloy-signer.workspace = true alloy-sol-types.workspace = true alloy-transport.workspace = true alloy-ens = { workspace = true, features = ["provider"] } +alloy-eips.workspace = true op-alloy-flz.workspace = true op-alloy-consensus = { workspace = true, features = ["alloy-compat"] } @@ -98,4 +99,4 @@ mimalloc = ["foundry-cli/mimalloc"] tracy-allocator = ["foundry-cli/tracy-allocator"] aws-kms = ["foundry-wallets/aws-kms"] gcp-kms = ["foundry-wallets/gcp-kms"] -isolate-by-default = ["foundry-config/isolate-by-default"] \ No newline at end of file +isolate-by-default = ["foundry-config/isolate-by-default"] diff --git a/crates/cast/src/args.rs b/crates/cast/src/args.rs index 6b75b45927f64..cb5cbb15ab03f 100644 --- a/crates/cast/src/args.rs +++ b/crates/cast/src/args.rs @@ -5,6 +5,7 @@ use crate::{ }; use alloy_consensus::transaction::{Recovered, SignerRecoverable}; use alloy_dyn_abi::{DynSolValue, ErrorExt, EventExt}; +use alloy_eips::eip7702::SignedAuthorization; use alloy_ens::{namehash, ProviderEnsExt}; use alloy_primitives::{eip191_hash_message, hex, keccak256, Address, B256}; use alloy_provider::Provider; @@ -723,6 +724,10 @@ pub async fn run_command(args: CastArgs) -> Result<()> { sh_println!("{}", serde_json::to_string_pretty(&tx)?)?; } } + CastSubcommand::RecoverAuthority { auth } => { + let auth: SignedAuthorization = serde_json::from_str(&auth).unwrap(); + sh_println!("{}", auth.recover_authority()?)?; + } CastSubcommand::TxPool { command } => command.run().await?, CastSubcommand::DAEstimate(cmd) => { cmd.run().await?; diff --git a/crates/cast/src/opts.rs b/crates/cast/src/opts.rs index f712f43bf0114..ccc045bad7bd0 100644 --- a/crates/cast/src/opts.rs +++ b/crates/cast/src/opts.rs @@ -1070,6 +1070,10 @@ pub enum CastSubcommand { #[command(visible_aliases = &["dt", "decode-tx"])] DecodeTransaction { tx: Option }, + /// Recovery an EIP-7702 authority from a Authorization JSON string. + #[command(visible_aliases = &["decode-auth"])] + RecoverAuthority { auth: String }, + /// Extracts function selectors and arguments from bytecode #[command(visible_alias = "sel")] Selectors { diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 189a83ceec0f6..c954e2b11dd7e 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -2852,3 +2852,18 @@ casttest!(tx_raw_opstack_deposit, |_prj, cmd| { "#]]); }); + +casttest!(recover_authority, |_prj, cmd| { + let auth = r#"{ + "chainId": "0x1", + "address": "0xb684710e6d5914ad6e64493de2a3c424cc43e970", + "nonce": "0x3dc1", + "yParity": "0x1", + "r": "0x2f15ba55009fcd3682cd0f9c9645dd94e616f9a969ba3f1a5a2d871f9fe0f2b4", + "s": "0x53c332a83312d0b17dd4c16eeb15b1ff5223398b14e0a55c70762e8f3972b7a5" + }"#; + cmd.args(["recover-authority", auth]).assert_success().stdout_eq(str![[r#" +0x17816E9A858b161c3E37016D139cf618056CaCD4 + +"#]]); +}); From 12ff25d6bcb76b62d91b2d0c24b4790d1776ce24 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 24 Jun 2025 16:58:41 +0300 Subject: [PATCH 233/244] fix(forge): filter selectors if test contract is target (#10798) --- crates/common/src/traits.rs | 9 ++ crates/evm/evm/src/executors/invariant/mod.rs | 23 ++++ crates/forge/tests/it/invariant.rs | 110 ++++++++++++++++++ 3 files changed, 142 insertions(+) diff --git a/crates/common/src/traits.rs b/crates/common/src/traits.rs index a3344c57b6dc7..52843aa440328 100644 --- a/crates/common/src/traits.rs +++ b/crates/common/src/traits.rs @@ -69,6 +69,15 @@ pub trait TestFunctionExt { self.test_function_kind().is_fixture() } + /// Returns `true` if this function is test reserved function. + fn is_reserved(&self) -> bool { + self.is_any_test() || + self.is_setup() || + self.is_before_test_setup() || + self.is_after_invariant() || + self.is_fixture() + } + #[doc(hidden)] fn tfe_as_str(&self) -> &str; #[doc(hidden)] diff --git a/crates/evm/evm/src/executors/invariant/mod.rs b/crates/evm/evm/src/executors/invariant/mod.rs index 29ad0154bc250..4e506c60f28d5 100644 --- a/crates/evm/evm/src/executors/invariant/mod.rs +++ b/crates/evm/evm/src/executors/invariant/mod.rs @@ -42,6 +42,7 @@ mod replay; pub use replay::{replay_error, replay_run}; mod result; +use foundry_common::TestFunctionExt; pub use result::InvariantFuzzTestResult; use serde::{Deserialize, Serialize}; @@ -827,6 +828,28 @@ impl<'a> InvariantExecutor<'a> { address: Address, targeted_contracts: &mut TargetedContracts, ) -> Result<()> { + if let Some(target) = targeted_contracts.get(&address) { + // If test contract is a target, then include only state-changing functions + // that are not reserved. + let selectors: Vec<_> = target + .abi + .functions() + .filter_map(|func| { + if matches!( + func.state_mutability, + alloy_json_abi::StateMutability::Pure | + alloy_json_abi::StateMutability::View + ) || func.is_reserved() + { + None + } else { + Some(func.selector()) + } + }) + .collect(); + self.add_address_with_functions(address, &selectors, false, targeted_contracts)?; + } + for (address, (identifier, _)) in self.setup_contracts { if let Some(selectors) = self.artifact_filters.targeted.get(identifier) { self.add_address_with_functions(*address, selectors, false, targeted_contracts)?; diff --git a/crates/forge/tests/it/invariant.rs b/crates/forge/tests/it/invariant.rs index f63b1ad918cbe..19c62f9c8731a 100644 --- a/crates/forge/tests/it/invariant.rs +++ b/crates/forge/tests/it/invariant.rs @@ -1336,3 +1336,113 @@ contract InvariantTest is Test { "#]], ); }); + +// Tests that reserved test functions are not fuzzed when test is set as target. +// +forgetest_init!(invariant_target_test_contract_selectors, |prj, cmd| { + prj.update_config(|config| { + config.invariant.runs = 10; + config.invariant.depth = 100; + }); + prj.add_test( + "InvariantTargetTest.t.sol", + r#" +import {Test} from "forge-std/Test.sol"; + +contract InvariantTargetTest is Test { + bool fooCalled; + bool testSanityCalled; + bool testTableCalled; + uint256 invariantCalledNum; + uint256 setUpCalledNum; + + function setUp() public { + targetContract(address(this)); + } + + function beforeTestSetup() public { + } + + // Only this selector should be targeted. + function foo() public { + fooCalled = true; + } + + function fixtureCalled() public returns (bool[] memory) { + } + + function table_sanity(bool called) public { + testTableCalled = called; + } + + function test_sanity() public { + testSanityCalled = true; + } + + function afterInvariant() public { + } + + function invariant_foo_called() public view { + } + + function invariant_testSanity_considered_target() public { + } + + function invariant_setUp_considered_target() public { + setUpCalledNum++; + } + + function invariant_considered_target() public { + invariantCalledNum++; + } +} + "#, + ) + .unwrap(); + + cmd.args(["test", "--mc", "InvariantTargetTest", "--mt", "invariant"]) + .assert_success() + .stdout_eq(str![[r#" +[COMPILING_FILES] with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 4 tests for test/InvariantTargetTest.t.sol:InvariantTargetTest +[PASS] invariant_considered_target() (runs: 10, calls: 1000, reverts: 0) + +╭---------------------+----------+-------+---------+----------╮ +| Contract | Selector | Calls | Reverts | Discards | ++=============================================================+ +| InvariantTargetTest | foo | 1000 | 0 | 0 | +╰---------------------+----------+-------+---------+----------╯ + +[PASS] invariant_foo_called() (runs: 10, calls: 1000, reverts: 0) + +╭---------------------+----------+-------+---------+----------╮ +| Contract | Selector | Calls | Reverts | Discards | ++=============================================================+ +| InvariantTargetTest | foo | 1000 | 0 | 0 | +╰---------------------+----------+-------+---------+----------╯ + +[PASS] invariant_setUp_considered_target() (runs: 10, calls: 1000, reverts: 0) + +╭---------------------+----------+-------+---------+----------╮ +| Contract | Selector | Calls | Reverts | Discards | ++=============================================================+ +| InvariantTargetTest | foo | 1000 | 0 | 0 | +╰---------------------+----------+-------+---------+----------╯ + +[PASS] invariant_testSanity_considered_target() (runs: 10, calls: 1000, reverts: 0) + +╭---------------------+----------+-------+---------+----------╮ +| Contract | Selector | Calls | Reverts | Discards | ++=============================================================+ +| InvariantTargetTest | foo | 1000 | 0 | 0 | +╰---------------------+----------+-------+---------+----------╯ + +Suite result: ok. 4 passed; 0 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 4 tests passed, 0 failed, 0 skipped (4 total tests) + +"#]]); +}); From a3b6b33bd3bd8e2c66758c17918641531b3e55fd Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Tue, 24 Jun 2025 17:04:47 +0200 Subject: [PATCH 234/244] refactor: flatten bind_json.rs to one pass without state structs (#10791) --- crates/forge/src/cmd/bind_json.rs | 424 ++++++++++++++---------------- 1 file changed, 203 insertions(+), 221 deletions(-) diff --git a/crates/forge/src/cmd/bind_json.rs b/crates/forge/src/cmd/bind_json.rs index fc5ca28bccdf7..4860fb7afa6d4 100644 --- a/crates/forge/src/cmd/bind_json.rs +++ b/crates/forge/src/cmd/bind_json.rs @@ -25,9 +25,9 @@ use solar_parse::{ use solar_sema::thread_local::ThreadLocal; use std::{ collections::{BTreeMap, BTreeSet, HashSet}, - fmt::{self, Write}, + fmt::Write, ops::ControlFlow, - path::PathBuf, + path::{Path, PathBuf}, sync::Arc, }; @@ -48,32 +48,11 @@ pub struct BindJsonArgs { impl BindJsonArgs { pub fn run(self) -> Result<()> { - self.preprocess()?.find_structs()?.resolve_imports_and_aliases().write()?; - - Ok(()) - } - - /// In cases when user moves/renames/deletes structs, compiler will start failing because - /// generated bindings will be referencing non-existing structs or importing non-existing - /// files. - /// - /// Because of that, we need a little bit of preprocessing to make sure that bindings will still - /// be valid. - /// - /// The strategy is: - /// 1. Replace bindings file with an empty one to get rid of potentially invalid imports. - /// 2. Remove all function bodies to get rid of `serialize`/`deserialize` invocations. - /// 3. Remove all `immutable` attributes to avoid errors because of erased constructors - /// initializing them. - /// - /// After that we'll still have enough information for bindings but compilation should succeed - /// in most of the cases. - fn preprocess(self) -> Result { let config = self.load_config()?; let project = config.ephemeral_project()?; - let target_path = config.root.join(self.out.as_ref().unwrap_or(&config.bind_json.out)); + // Step 1: Read and preprocess sources let sources = project.paths.read_input_files()?; let graph = Graph::::resolve_sources(&project.paths, sources)?; @@ -92,6 +71,38 @@ impl BindJsonArgs { .max_by(|(v1, _, _), (v2, _, _)| v1.cmp(v2)) .unwrap(); + // Step 2: Preprocess sources to handle potentially invalid bindings + self.preprocess_sources(&mut sources)?; + + // Insert empty bindings file. + sources.insert(target_path.clone(), Source::new(JSON_BINDINGS_PLACEHOLDER)); + + // Step 3: Find structs and generate bindings + let structs_to_write = + self.find_and_resolve_structs(&config, &project, version, sources, &target_path)?; + + // Step 4: Write bindings + self.write_bindings(&structs_to_write, &target_path)?; + + Ok(()) + } + + /// In cases when user moves/renames/deletes structs, compiler will start failing because + /// generated bindings will be referencing non-existing structs or importing non-existing + /// files. + /// + /// Because of that, we need a little bit of preprocessing to make sure that bindings will still + /// be valid. + /// + /// The strategy is: + /// 1. Replace bindings file with an empty one to get rid of potentially invalid imports. + /// 2. Remove all function bodies to get rid of `serialize`/`deserialize` invocations. + /// 3. Remove all `immutable` attributes to avoid errors because of erased constructors + /// initializing them. + /// + /// After that we'll still have enough information for bindings but compilation should succeed + /// in most of the cases. + fn preprocess_sources(&self, sources: &mut Sources) -> Result<()> { let sess = Session::builder().with_stderr_emitter().build(); let result = sess.enter_parallel(|| -> solar_parse::interface::Result<()> { sources.0.par_iter_mut().try_for_each(|(path, source)| { @@ -115,157 +126,33 @@ impl BindJsonArgs { }) }); eyre::ensure!(result.is_ok(), "failed parsing"); - - // Insert empty bindings file. - sources.insert(target_path.clone(), Source::new(JSON_BINDINGS_PLACEHOLDER)); - - Ok(PreprocessedState { version, sources, target_path, project, config }) - } -} - -struct PreprocessorVisitor { - updates: Vec<(Span, &'static str)>, -} - -impl PreprocessorVisitor { - fn new() -> Self { - Self { updates: Vec::new() } - } - - fn update(mut self, sess: &Session, content: &mut String) { - if self.updates.is_empty() { - return; - } - - let sf = sess.source_map().lookup_source_file(self.updates[0].0.lo()); - let base = sf.start_pos.0; - - self.updates.sort_by_key(|(span, _)| span.lo()); - let mut shift = 0_i64; - for (span, new) in self.updates { - let lo = span.lo() - base; - let hi = span.hi() - base; - let start = ((lo.0 as i64) - shift) as usize; - let end = ((hi.0 as i64) - shift) as usize; - - content.replace_range(start..end, new); - shift += (end - start) as i64; - shift -= new.len() as i64; - } - } -} - -impl<'ast> Visit<'ast> for PreprocessorVisitor { - type BreakValue = solar_parse::interface::data_structures::Never; - - fn visit_item_function( - &mut self, - func: &'ast ast::ItemFunction<'ast>, - ) -> ControlFlow { - // Replace function bodies with a noop statement. - if let Some(block) = &func.body { - if !block.is_empty() { - let span = block.first().unwrap().span.to(block.last().unwrap().span); - let new_body = match func.kind { - FunctionKind::Modifier => "_;", - _ => "revert();", - }; - self.updates.push((span, new_body)); - } - } - - self.walk_item_function(func) - } - - fn visit_variable_definition( - &mut self, - var: &'ast ast::VariableDefinition<'ast>, - ) -> ControlFlow { - // Remove `immutable` attributes. - if let Some(VarMut::Immutable) = var.mutability { - self.updates.push((var.span, "")); - } - - self.walk_variable_definition(var) - } -} - -/// A single struct definition for which we need to generate bindings. -#[derive(Debug, Clone)] -struct StructToWrite { - /// Name of the struct definition. - name: String, - /// Name of the contract containing the struct definition. None if the struct is defined at the - /// file level. - contract_name: Option, - /// Import alias for the contract or struct, depending on whether the struct is imported - /// directly, or via a contract. - import_alias: Option, - /// Path to the file containing the struct definition. - path: PathBuf, - /// EIP712 schema for the struct. - schema: String, - /// Name of the struct definition used in function names and schema_* variables. - name_in_fns: String, -} - -impl StructToWrite { - /// Returns the name of the imported item. If struct is defined at the file level, returns the - /// struct name, otherwise returns the parent contract name. - fn struct_or_contract_name(&self) -> &str { - self.contract_name.as_deref().unwrap_or(&self.name) - } - - /// Same as [StructToWrite::struct_or_contract_name] but with alias applied. - fn struct_or_contract_name_with_alias(&self) -> &str { - self.import_alias.as_deref().unwrap_or(self.struct_or_contract_name()) - } - - /// Path which can be used to reference this struct in input/output parameters. Either - /// StructName or ParantName.StructName - fn full_path(&self) -> String { - if self.contract_name.is_some() { - format!("{}.{}", self.struct_or_contract_name_with_alias(), self.name) - } else { - self.struct_or_contract_name_with_alias().to_string() - } - } - - fn import_item(&self) -> String { - if let Some(alias) = &self.import_alias { - format!("{} as {}", self.struct_or_contract_name(), alias) - } else { - self.struct_or_contract_name().to_string() - } + Ok(()) } -} - -struct PreprocessedState { - version: Version, - sources: Sources, - target_path: PathBuf, - project: Project, - config: Config, -} - -impl PreprocessedState { - fn find_structs(self) -> Result { - let mut structs_to_write = Vec::new(); - let Self { version, sources, target_path, config, project } = self; + /// Find structs, resolve conflicts, and prepare them for writing + fn find_and_resolve_structs( + &self, + config: &Config, + project: &Project, + version: Version, + sources: Sources, + _target_path: &Path, + ) -> Result> { let settings = config.solc_settings()?; - let include = config.bind_json.include; - let exclude = config.bind_json.exclude; - let root = config.root; + let include = &config.bind_json.include; + let exclude = &config.bind_json.exclude; + let root = &config.root; let input = SolcVersionedInput::build(sources, settings, SolcLanguage::Solidity, version); let mut sess = Session::builder().with_stderr_emitter().build(); sess.dcx = sess.dcx.set_flags(|flags| flags.track_diagnostics = false); + let mut structs_to_write = Vec::new(); + sess.enter_parallel(|| -> Result<()> { // Set up the parsing context with the project paths, without adding the source files - let mut parsing_context = solar_pcx_from_solc_project(&sess, &project, &input, false); + let mut parsing_context = solar_pcx_from_solc_project(&sess, project, &input, false); let mut target_files = HashSet::new(); for (path, source) in &input.input.sources { @@ -313,11 +200,10 @@ impl PreprocessedState { .contract .map(|id| hir.contract(id).name.as_str().into()), path: path - .strip_prefix(&root) + .strip_prefix(root) .unwrap_or_else(|_| path) .to_path_buf(), schema, - // will be filled later import_alias: None, name_in_fns: String::new(), @@ -331,31 +217,24 @@ impl PreprocessedState { eyre::ensure!(sess.dcx.has_errors().is_ok(), "errors occurred"); - Ok(StructsState { structs_to_write, target_path }) - } -} + // Resolve import aliases and function names + self.resolve_conflicts(&mut structs_to_write); -#[derive(Debug)] -struct StructsState { - structs_to_write: Vec, - target_path: PathBuf, -} + Ok(structs_to_write) + } -impl StructsState { - /// We manage 2 namespsaces for JSON bindings: + /// We manage 2 namespaces for JSON bindings: /// - Namespace of imported items. This includes imports of contracts containing structs and /// structs defined at the file level. /// - Namespace of struct names used in function names and schema_* variables. /// /// Both of those might contain conflicts, so we need to resolve them. - fn resolve_imports_and_aliases(self) -> ResolvedState { - let Self { mut structs_to_write, target_path } = self; - + fn resolve_conflicts(&self, structs_to_write: &mut [StructToWrite]) { // firstly, we resolve imported names conflicts // construct mapping name -> paths from which items with such name are imported let mut names_to_paths = BTreeMap::new(); - for s in &structs_to_write { + for s in structs_to_write.iter() { names_to_paths .entry(s.struct_or_contract_name()) .or_insert_with(BTreeSet::new) @@ -367,8 +246,7 @@ impl StructsState { for (name, paths) in names_to_paths { if paths.len() <= 1 { - // no alias needed - continue + continue; // no alias needed } for (i, path) in paths.into_iter().enumerate() { @@ -379,7 +257,7 @@ impl StructsState { } } - for s in &mut structs_to_write { + for s in structs_to_write.iter_mut() { let name = s.struct_or_contract_name(); if aliases.contains_key(name) { s.import_alias = Some(aliases[name][&s.path].clone()); @@ -410,37 +288,19 @@ impl StructsState { for (s, fn_name) in structs_to_write.iter_mut().zip(fn_names.into_iter()) { s.name_in_fns = fn_name.unwrap_or(s.name.clone()); } - - ResolvedState { structs_to_write, target_path } } -} - -struct ResolvedState { - structs_to_write: Vec, - target_path: PathBuf, -} -impl ResolvedState { - fn write(self) -> Result { + /// Write the final bindings file + fn write_bindings( + &self, + structs_to_write: &[StructToWrite], + target_path: &PathBuf, + ) -> Result<()> { let mut result = String::new(); - self.write_imports(&mut result)?; - self.write_vm(&mut result); - self.write_library(&mut result)?; - - if let Some(parent) = self.target_path.parent() { - fs::create_dir_all(parent)?; - } - fs::write(&self.target_path, &result)?; - - sh_println!("Bindings written to {}", self.target_path.display())?; - - Ok(result) - } - fn write_imports(&self, result: &mut String) -> fmt::Result { + // Write imports let mut grouped_imports = BTreeMap::new(); - - for struct_to_write in &self.structs_to_write { + for struct_to_write in structs_to_write { let item = struct_to_write.import_item(); grouped_imports .entry(struct_to_write.path.as_path()) @@ -452,18 +312,15 @@ impl ResolvedState { for (path, names) in grouped_imports { writeln!( - result, + &mut result, "import {{{}}} from \"{}\";", names.iter().join(", "), path.to_slash_lossy() )?; } - Ok(()) - } - - /// Writes minimal VM interface to not depend on forge-std version - fn write_vm(&self, result: &mut String) { + // Write VM interface + // Writes minimal VM interface to not depend on forge-std version result.push_str(r#" interface Vm { function parseJsonTypeArray(string calldata json, string calldata key, string calldata typeDescription) external pure returns (bytes memory); @@ -473,9 +330,8 @@ interface Vm { function serializeJsonType(string calldata objectKey, string calldata valueKey, string calldata typeDescription, bytes memory value) external returns (string memory json); } "#); - } - fn write_library(&self, result: &mut String) -> fmt::Result { + // Write library result.push_str( r#" library JsonBindings { @@ -483,19 +339,20 @@ library JsonBindings { "#, ); + // write schema constants - for struct_to_write in &self.structs_to_write { + for struct_to_write in structs_to_write { writeln!( - result, + &mut result, " {}{} = \"{}\";", TYPE_BINDING_PREFIX, struct_to_write.name_in_fns, struct_to_write.schema )?; } // write serialization functions - for struct_to_write in &self.structs_to_write { + for struct_to_write in structs_to_write { write!( - result, + &mut result, r#" function serialize({path} memory value) internal pure returns (string memory) {{ return vm.serializeJsonType(schema_{name_in_fns}, abi.encode(value)); @@ -524,6 +381,131 @@ library JsonBindings { result.push_str("}\n"); + // Write to file + if let Some(parent) = target_path.parent() { + fs::create_dir_all(parent)?; + } + fs::write(target_path, &result)?; + + sh_println!("Bindings written to {}", target_path.display())?; + Ok(()) } } + +struct PreprocessorVisitor { + updates: Vec<(Span, &'static str)>, +} + +impl PreprocessorVisitor { + fn new() -> Self { + Self { updates: Vec::new() } + } + + fn update(mut self, sess: &Session, content: &mut String) { + if self.updates.is_empty() { + return; + } + + let sf = sess.source_map().lookup_source_file(self.updates[0].0.lo()); + let base = sf.start_pos.0; + + self.updates.sort_by_key(|(span, _)| span.lo()); + let mut shift = 0_i64; + for (span, new) in self.updates { + let lo = span.lo() - base; + let hi = span.hi() - base; + let start = ((lo.0 as i64) - shift) as usize; + let end = ((hi.0 as i64) - shift) as usize; + + content.replace_range(start..end, new); + shift += (end - start) as i64; + shift -= new.len() as i64; + } + } +} + +impl<'ast> Visit<'ast> for PreprocessorVisitor { + type BreakValue = solar_parse::interface::data_structures::Never; + + fn visit_item_function( + &mut self, + func: &'ast ast::ItemFunction<'ast>, + ) -> ControlFlow { + // Replace function bodies with a noop statement. + if let Some(block) = &func.body { + if !block.is_empty() { + let span = block.first().unwrap().span.to(block.last().unwrap().span); + let new_body = match func.kind { + FunctionKind::Modifier => "_;", + _ => "revert();", + }; + self.updates.push((span, new_body)); + } + } + + self.walk_item_function(func) + } + + fn visit_variable_definition( + &mut self, + var: &'ast ast::VariableDefinition<'ast>, + ) -> ControlFlow { + // Remove `immutable` attributes. + if let Some(VarMut::Immutable) = var.mutability { + self.updates.push((var.span, "")); + } + + self.walk_variable_definition(var) + } +} + +/// A single struct definition for which we need to generate bindings. +#[derive(Debug, Clone)] +struct StructToWrite { + /// Name of the struct definition. + name: String, + /// Name of the contract containing the struct definition. None if the struct is defined at the + /// file level. + contract_name: Option, + /// Import alias for the contract or struct, depending on whether the struct is imported + /// directly, or via a contract. + import_alias: Option, + /// Path to the file containing the struct definition. + path: PathBuf, + /// EIP712 schema for the struct. + schema: String, + /// Name of the struct definition used in function names and schema_* variables. + name_in_fns: String, +} + +impl StructToWrite { + /// Returns the name of the imported item. If struct is defined at the file level, returns the + /// struct name, otherwise returns the parent contract name. + fn struct_or_contract_name(&self) -> &str { + self.contract_name.as_deref().unwrap_or(&self.name) + } + + /// Same as [StructToWrite::struct_or_contract_name] but with alias applied. + fn struct_or_contract_name_with_alias(&self) -> &str { + self.import_alias.as_deref().unwrap_or(self.struct_or_contract_name()) + } + + /// Path which can be used to reference this struct in input/output parameters. Either + /// StructName or ParantName.StructName + fn full_path(&self) -> String { + if self.contract_name.is_some() { + format!("{}.{}", self.struct_or_contract_name_with_alias(), self.name) + } else { + self.struct_or_contract_name_with_alias().to_string() + } + } + + fn import_item(&self) -> String { + if let Some(alias) = &self.import_alias { + format!("{} as {}", self.struct_or_contract_name(), alias) + } else { + self.struct_or_contract_name().to_string() + } + } +} From d0fc9774d7f1a7420462c8e9b6ddca8a7fb4349e Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 25 Jun 2025 15:40:40 +0200 Subject: [PATCH 235/244] cast: Improve debugger when tracing on-chain transactions/calls (#10596) * cast: Fetch bytecodes in `run/call` to better match contracts Without fetching the bytecodes from the current chain, matching the contracts with `--with-local-artifacts` option only works if the matching contracts have been deployed in the trace. This is very limiting when trying to `--debug` an on-chain transaction. By fetching the contracts' bytecodes, we can increase the matching of address to source file, by thus providing the runtime bytecode. * cast: Strip placeholder from bytecode-object for source-map and matching If a contract contains some libraries, and thus has an "unlinked" bytecode object, it will never be matched against a deployed instance, and the source map will never be set. This fixes this issue by striping from the unlinked bytecode all placeholders, replacing them with the `0x00..00` address. It doesn't change anything regarding source-maps, but could change the matching of the runtime bytecode. The changes are usually minimal in this case, though. --- Cargo.lock | 1 + crates/cast/src/cmd/call.rs | 4 ++ crates/cast/src/cmd/run.rs | 51 ++++++++++++++++++++++- crates/cli/src/utils/cmd.rs | 6 ++- crates/common/Cargo.toml | 1 + crates/common/src/contracts.rs | 12 +++++- crates/common/src/utils.rs | 25 ++++++++++- crates/evm/traces/src/debug/sources.rs | 8 ++-- crates/evm/traces/src/identifier/local.rs | 29 ++++++++++--- crates/evm/traces/src/identifier/mod.rs | 13 +++++- 10 files changed, 134 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 527b93eb2adf5..683b7a0882a41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4214,6 +4214,7 @@ dependencies = [ "jiff", "num-format", "path-slash", + "regex", "reqwest", "semver 1.0.26", "serde", diff --git a/crates/cast/src/cmd/call.rs b/crates/cast/src/cmd/call.rs index c329dbe3cc717..65dc59c465833 100644 --- a/crates/cast/src/cmd/call.rs +++ b/crates/cast/src/cmd/call.rs @@ -34,6 +34,8 @@ use regex::Regex; use revm::context::TransactionType; use std::{str::FromStr, sync::LazyLock}; +use super::run::fetch_contracts_bytecode_from_trace; + // matches override pattern
:: // e.g. 0x123:0x1:0x1234 static OVERRIDE_PATTERN: LazyLock = @@ -301,10 +303,12 @@ impl CallArgs { ), }; + let contracts_bytecode = fetch_contracts_bytecode_from_trace(&provider, &trace).await?; handle_traces( trace, &config, chain, + &contracts_bytecode, labels, with_local_artifacts, debug, diff --git a/crates/cast/src/cmd/run.rs b/crates/cast/src/cmd/run.rs index 04f52957ef668..1af816ad5b40b 100644 --- a/crates/cast/src/cmd/run.rs +++ b/crates/cast/src/cmd/run.rs @@ -1,6 +1,10 @@ use alloy_consensus::Transaction; use alloy_network::{AnyNetwork, TransactionResponse}; -use alloy_provider::Provider; +use alloy_primitives::{ + map::{HashMap, HashSet}, + Address, Bytes, +}; +use alloy_provider::{Provider, RootProvider}; use alloy_rpc_types::BlockTransactions; use clap::Parser; use eyre::{Result, WrapErr}; @@ -21,7 +25,7 @@ use foundry_config::{ use foundry_evm::{ executors::{EvmError, TracingExecutor}, opts::EvmOpts, - traces::{InternalTraceMode, TraceMode}, + traces::{InternalTraceMode, TraceMode, Traces}, utils::configure_tx_env, Env, }; @@ -272,10 +276,12 @@ impl RunArgs { } }; + let contracts_bytecode = fetch_contracts_bytecode_from_trace(&provider, &result).await?; handle_traces( result, &config, chain, + &contracts_bytecode, self.label, self.with_local_artifacts, self.debug, @@ -287,6 +293,47 @@ impl RunArgs { } } +pub async fn fetch_contracts_bytecode_from_trace( + provider: &RootProvider, + result: &TraceResult, +) -> Result> { + let mut contracts_bytecode = HashMap::default(); + if let Some(ref traces) = result.traces { + let addresses = gather_trace_addresses(traces); + let results = futures::future::join_all(addresses.into_iter().map(async |a| { + ( + a, + provider.get_code_at(a).await.unwrap_or_else(|e| { + sh_warn!("Failed to fetch code for {a:?}: {e:?}").ok(); + Bytes::new() + }), + ) + })) + .await; + for (address, code) in results { + if !code.is_empty() { + contracts_bytecode.insert(address, code); + } + } + } + Ok(contracts_bytecode) +} + +fn gather_trace_addresses(traces: &Traces) -> HashSet
{ + let mut addresses = HashSet::default(); + for (_, trace) in traces { + for node in trace.arena.nodes() { + if !node.trace.address.is_zero() { + addresses.insert(node.trace.address); + } + if !node.trace.caller.is_zero() { + addresses.insert(node.trace.caller); + } + } + } + addresses +} + impl figment::Provider for RunArgs { fn metadata(&self) -> Metadata { Metadata::named("RunArgs") diff --git a/crates/cli/src/utils/cmd.rs b/crates/cli/src/utils/cmd.rs index 21f411d446235..e3e6a166fdeac 100644 --- a/crates/cli/src/utils/cmd.rs +++ b/crates/cli/src/utils/cmd.rs @@ -1,5 +1,5 @@ use alloy_json_abi::JsonAbi; -use alloy_primitives::Address; +use alloy_primitives::{map::HashMap, Address, Bytes}; use eyre::{Result, WrapErr}; use foundry_common::{ compile::ProjectCompiler, fs, selectors::SelectorKind, shell, ContractsByArtifact, @@ -330,10 +330,12 @@ impl TryFrom> for TraceResult { } /// labels the traces, conditionally prints them or opens the debugger +#[expect(clippy::too_many_arguments)] pub async fn handle_traces( mut result: TraceResult, config: &Config, chain: Option, + contracts_bytecode: &HashMap, labels: Vec, with_local_artifacts: bool, debug: bool, @@ -372,7 +374,7 @@ pub async fn handle_traces( let mut identifier = TraceIdentifiers::new().with_etherscan(config, chain)?; if let Some(contracts) = &known_contracts { builder = builder.with_known_contracts(contracts); - identifier = identifier.with_local(contracts); + identifier = identifier.with_local_and_bytecodes(contracts, contracts_bytecode); } let mut decoder = builder.build(); diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index b440a5f7cdb84..76f42de2f0f6b 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -57,6 +57,7 @@ itertools.workspace = true jiff.workspace = true num-format.workspace = true path-slash.workspace = true +regex.workspace = true reqwest.workspace = true semver.workspace = true serde = { workspace = true, features = ["derive"] } diff --git a/crates/common/src/contracts.rs b/crates/common/src/contracts.rs index 789491d074dbf..1ebb284e4133a 100644 --- a/crates/common/src/contracts.rs +++ b/crates/common/src/contracts.rs @@ -1,6 +1,6 @@ //! Commonly used contract types and functions. -use crate::compile::PathOrContractInfo; +use crate::{compile::PathOrContractInfo, strip_bytecode_placeholders}; use alloy_dyn_abi::JsonAbiExt; use alloy_json_abi::{Event, Function, JsonAbi}; use alloy_primitives::{hex, Address, Bytes, Selector, B256}; @@ -87,6 +87,16 @@ impl ContractData { pub fn deployed_bytecode(&self) -> Option<&Bytes> { self.deployed_bytecode.as_ref()?.bytes().filter(|b| !b.is_empty()) } + + /// Returns the bytecode without placeholders, if present. + pub fn bytecode_without_placeholders(&self) -> Option { + strip_bytecode_placeholders(self.bytecode.as_ref()?.object.as_ref()?) + } + + /// Returns the deployed bytecode without placeholders, if present. + pub fn deployed_bytecode_without_placeholders(&self) -> Option { + strip_bytecode_placeholders(self.deployed_bytecode.as_ref()?.object.as_ref()?) + } } type ArtifactWithContractRef<'a> = (&'a ArtifactId, &'a ContractData); diff --git a/crates/common/src/utils.rs b/crates/common/src/utils.rs index a655d1e3d713f..3a9294c1b40cc 100644 --- a/crates/common/src/utils.rs +++ b/crates/common/src/utils.rs @@ -1,6 +1,13 @@ //! Uncategorised utilities. -use alloy_primitives::{keccak256, B256, U256}; +use alloy_primitives::{hex, keccak256, Bytes, B256, U256}; +use foundry_compilers::artifacts::BytecodeObject; +use regex::Regex; +use std::sync::LazyLock; + +static BYTECODE_PLACEHOLDER_RE: LazyLock = + LazyLock::new(|| Regex::new(r"__\$.{34}\$__").expect("invalid regex")); + /// Block on a future using the current tokio runtime on the current thread. pub fn block_on(future: F) -> F::Output { block_on_handle(&tokio::runtime::Handle::current(), future) @@ -54,3 +61,19 @@ pub fn ignore_metadata_hash(bytecode: &[u8]) -> &[u8] { bytecode } } + +/// Strips all __$xxx$__ placeholders from the bytecode if it's an unlinked bytecode. +/// by replacing them with 20 zero bytes. +/// This is useful for matching bytecodes to a contract source, and for the source map, +/// in which the actual address of the placeholder isn't important. +pub fn strip_bytecode_placeholders(bytecode: &BytecodeObject) -> Option { + match &bytecode { + BytecodeObject::Bytecode(bytes) => Some(bytes.clone()), + BytecodeObject::Unlinked(s) => { + // Replace all __$xxx$__ placeholders with 32 zero bytes + let s = (*BYTECODE_PLACEHOLDER_RE).replace_all(s, "00".repeat(40)); + let bytes = hex::decode(s.as_bytes()); + Some(bytes.ok()?.into()) + } + } +} diff --git a/crates/evm/traces/src/debug/sources.rs b/crates/evm/traces/src/debug/sources.rs index cfd7056e5a8b6..12aaafb29ad5a 100644 --- a/crates/evm/traces/src/debug/sources.rs +++ b/crates/evm/traces/src/debug/sources.rs @@ -1,5 +1,5 @@ use eyre::{Context, Result}; -use foundry_common::compact_to_contract; +use foundry_common::{compact_to_contract, strip_bytecode_placeholders}; use foundry_compilers::{ artifacts::{ sourcemap::{SourceElement, SourceMap}, @@ -94,9 +94,9 @@ impl ArtifactData { }) }; - // Only parse bytecode if it's not empty. - let pc_ic_map = if let Some(bytes) = b.bytes() { - (!bytes.is_empty()).then(|| PcIcMap::new(bytes)) + // Only parse bytecode if it's not empty, stripping placeholders if necessary. + let pc_ic_map = if let Some(bytes) = strip_bytecode_placeholders(&b.object) { + (!bytes.is_empty()).then(|| PcIcMap::new(bytes.as_ref())) } else { None }; diff --git a/crates/evm/traces/src/identifier/local.rs b/crates/evm/traces/src/identifier/local.rs index f0bb8cd9d7d76..94b24c341a493 100644 --- a/crates/evm/traces/src/identifier/local.rs +++ b/crates/evm/traces/src/identifier/local.rs @@ -1,6 +1,7 @@ use super::{IdentifiedAddress, TraceIdentifier}; use alloy_dyn_abi::JsonAbiExt; use alloy_json_abi::JsonAbi; +use alloy_primitives::{map::HashMap, Address, Bytes}; use foundry_common::contracts::{bytecode_diff_score, ContractsByArtifact}; use foundry_compilers::ArtifactId; use revm_inspectors::tracing::types::CallTraceNode; @@ -12,6 +13,8 @@ pub struct LocalTraceIdentifier<'a> { known_contracts: &'a ContractsByArtifact, /// Vector of pairs of artifact ID and the runtime code length of the given artifact. ordered_ids: Vec<(&'a ArtifactId, usize)>, + /// The contracts bytecode. + contracts_bytecode: Option<&'a HashMap>, } impl<'a> LocalTraceIdentifier<'a> { @@ -24,7 +27,12 @@ impl<'a> LocalTraceIdentifier<'a> { .map(|(id, bytecode)| (id, bytecode.len())) .collect::>(); ordered_ids.sort_by_key(|(_, len)| *len); - Self { known_contracts, ordered_ids } + Self { known_contracts, ordered_ids, contracts_bytecode: None } + } + + pub fn with_bytecodes(mut self, contracts_bytecode: &'a HashMap) -> Self { + self.contracts_bytecode = Some(contracts_bytecode); + self } /// Returns the known contracts. @@ -48,9 +56,9 @@ impl<'a> LocalTraceIdentifier<'a> { let contract = self.known_contracts.get(id)?; // Select bytecodes to compare based on `is_creation` flag. let (contract_bytecode, current_bytecode) = if is_creation { - (contract.bytecode(), creation_code) + (contract.bytecode_without_placeholders(), creation_code) } else { - (contract.deployed_bytecode(), runtime_code) + (contract.deployed_bytecode_without_placeholders(), runtime_code) }; if let Some(bytecode) = contract_bytecode { @@ -67,7 +75,7 @@ impl<'a> LocalTraceIdentifier<'a> { } } - let score = bytecode_diff_score(bytecode, current_bytecode); + let score = bytecode_diff_score(&bytecode, current_bytecode); if score == 0.0 { trace!(target: "evm::traces::local", "found exact match"); return Some((id, &contract.abi)); @@ -161,7 +169,18 @@ impl TraceIdentifier for LocalTraceIdentifier<'_> { let _span = trace_span!(target: "evm::traces::local", "identify", %address).entered(); - let (id, abi) = self.identify_code(runtime_code?, creation_code?)?; + // In order to identify the addresses, we need at least the runtime code. It can be + // obtained from the trace itself (if it's a CREATE* call), or from the fetched + // bytecodes. + let (runtime_code, creation_code) = match (runtime_code, creation_code) { + (Some(runtime_code), Some(creation_code)) => (runtime_code, creation_code), + (Some(runtime_code), _) => (runtime_code, &[] as &[u8]), + _ => { + let code = self.contracts_bytecode?.get(&address)?; + (code.as_ref(), &[] as &[u8]) + } + }; + let (id, abi) = self.identify_code(runtime_code, creation_code)?; trace!(target: "evm::traces::local", id=%id.identifier(), "identified"); Some(IdentifiedAddress { diff --git a/crates/evm/traces/src/identifier/mod.rs b/crates/evm/traces/src/identifier/mod.rs index 0654b5087764f..00045863847a8 100644 --- a/crates/evm/traces/src/identifier/mod.rs +++ b/crates/evm/traces/src/identifier/mod.rs @@ -1,5 +1,5 @@ use alloy_json_abi::JsonAbi; -use alloy_primitives::Address; +use alloy_primitives::{map::HashMap, Address, Bytes}; use foundry_common::ContractsByArtifact; use foundry_compilers::ArtifactId; use foundry_config::{Chain, Config}; @@ -79,6 +79,17 @@ impl<'a> TraceIdentifiers<'a> { self } + /// Sets the local identifier. + pub fn with_local_and_bytecodes( + mut self, + known_contracts: &'a ContractsByArtifact, + contracts_bytecode: &'a HashMap, + ) -> Self { + self.local = + Some(LocalTraceIdentifier::new(known_contracts).with_bytecodes(contracts_bytecode)); + self + } + /// Sets the etherscan identifier. pub fn with_etherscan(mut self, config: &Config, chain: Option) -> eyre::Result { self.etherscan = EtherscanIdentifier::new(config, chain)?; From 6de8703c15858fc46d6b923f525c5c5c4613cc2b Mon Sep 17 00:00:00 2001 From: 0xrusowsky <90208954+0xrusowsky@users.noreply.github.com> Date: Wed, 25 Jun 2025 16:32:34 +0200 Subject: [PATCH 236/244] chore(forge-lint): clickable links + housekeeping (#10847) --- Cargo.lock | 6 +++--- crates/lint/src/sol/gas/keccak.rs | 1 - crates/lint/src/sol/gas/mod.rs | 5 +---- crates/lint/src/sol/high/incorrect_shift.rs | 1 - crates/lint/src/sol/high/mod.rs | 5 +---- crates/lint/src/sol/info/mixed_case.rs | 1 - crates/lint/src/sol/info/mod.rs | 5 +---- crates/lint/src/sol/info/pascal_case.rs | 1 - crates/lint/src/sol/info/screaming_snake_case.rs | 1 - crates/lint/src/sol/macros.rs | 9 ++++++++- crates/lint/src/sol/med/div_mul.rs | 1 - crates/lint/src/sol/med/mod.rs | 5 +---- crates/lint/src/sol/mod.rs | 1 + 13 files changed, 16 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 683b7a0882a41..7097beb85322a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8698,7 +8698,7 @@ dependencies = [ "derive_builder", "derive_more 2.0.1", "dunce", - "itertools 0.14.0", + "itertools 0.10.5", "itoa", "lasso", "match_cfg", @@ -8710,7 +8710,7 @@ dependencies = [ "solar-config", "solar-data-structures", "solar-macros", - "thiserror 2.0.12", + "thiserror 1.0.69", "tracing", "unicode-width 0.2.0", ] @@ -8735,7 +8735,7 @@ dependencies = [ "alloy-primitives", "bitflags 2.9.1", "bumpalo", - "itertools 0.14.0", + "itertools 0.10.5", "memchr", "num-bigint", "num-rational", diff --git a/crates/lint/src/sol/gas/keccak.rs b/crates/lint/src/sol/gas/keccak.rs index d6df396f27779..341859b71ffeb 100644 --- a/crates/lint/src/sol/gas/keccak.rs +++ b/crates/lint/src/sol/gas/keccak.rs @@ -1,6 +1,5 @@ use super::AsmKeccak256; use crate::{ - declare_forge_lint, linter::EarlyLintPass, sol::{Severity, SolLint}, }; diff --git a/crates/lint/src/sol/gas/mod.rs b/crates/lint/src/sol/gas/mod.rs index 1949cc9df63f3..69bc9422f57f3 100644 --- a/crates/lint/src/sol/gas/mod.rs +++ b/crates/lint/src/sol/gas/mod.rs @@ -1,7 +1,4 @@ -use crate::{ - register_lints, - sol::{EarlyLintPass, SolLint}, -}; +use crate::sol::{EarlyLintPass, SolLint}; mod keccak; use keccak::ASM_KECCAK256; diff --git a/crates/lint/src/sol/high/incorrect_shift.rs b/crates/lint/src/sol/high/incorrect_shift.rs index 8d2326c5cc9f9..f2a7b95dad2ab 100644 --- a/crates/lint/src/sol/high/incorrect_shift.rs +++ b/crates/lint/src/sol/high/incorrect_shift.rs @@ -1,6 +1,5 @@ use super::IncorrectShift; use crate::{ - declare_forge_lint, linter::{EarlyLintPass, LintContext}, sol::{Severity, SolLint}, }; diff --git a/crates/lint/src/sol/high/mod.rs b/crates/lint/src/sol/high/mod.rs index 720f172420e66..30d3dc8a02d4e 100644 --- a/crates/lint/src/sol/high/mod.rs +++ b/crates/lint/src/sol/high/mod.rs @@ -1,7 +1,4 @@ -use crate::{ - register_lints, - sol::{EarlyLintPass, SolLint}, -}; +use crate::sol::{EarlyLintPass, SolLint}; mod incorrect_shift; use incorrect_shift::INCORRECT_SHIFT; diff --git a/crates/lint/src/sol/info/mixed_case.rs b/crates/lint/src/sol/info/mixed_case.rs index 5e839e9f313cf..c3b3ba4938811 100644 --- a/crates/lint/src/sol/info/mixed_case.rs +++ b/crates/lint/src/sol/info/mixed_case.rs @@ -1,6 +1,5 @@ use super::{MixedCaseFunction, MixedCaseVariable}; use crate::{ - declare_forge_lint, linter::{EarlyLintPass, LintContext}, sol::{Severity, SolLint}, }; diff --git a/crates/lint/src/sol/info/mod.rs b/crates/lint/src/sol/info/mod.rs index 6c414864f9688..df458bacef992 100644 --- a/crates/lint/src/sol/info/mod.rs +++ b/crates/lint/src/sol/info/mod.rs @@ -1,7 +1,4 @@ -use crate::{ - register_lints, - sol::{EarlyLintPass, SolLint}, -}; +use crate::sol::{EarlyLintPass, SolLint}; mod mixed_case; use mixed_case::{MIXED_CASE_FUNCTION, MIXED_CASE_VARIABLE}; diff --git a/crates/lint/src/sol/info/pascal_case.rs b/crates/lint/src/sol/info/pascal_case.rs index 60cafbc8365a3..b8e719aa0d762 100644 --- a/crates/lint/src/sol/info/pascal_case.rs +++ b/crates/lint/src/sol/info/pascal_case.rs @@ -1,6 +1,5 @@ use super::PascalCaseStruct; use crate::{ - declare_forge_lint, linter::{EarlyLintPass, LintContext}, sol::{Severity, SolLint}, }; diff --git a/crates/lint/src/sol/info/screaming_snake_case.rs b/crates/lint/src/sol/info/screaming_snake_case.rs index ccc978029b8a4..28ca4c54c7b26 100644 --- a/crates/lint/src/sol/info/screaming_snake_case.rs +++ b/crates/lint/src/sol/info/screaming_snake_case.rs @@ -1,6 +1,5 @@ use super::ScreamingSnakeCase; use crate::{ - declare_forge_lint, linter::{EarlyLintPass, LintContext}, sol::{Severity, SolLint}, }; diff --git a/crates/lint/src/sol/macros.rs b/crates/lint/src/sol/macros.rs index 357f742aa297c..9fa944164c616 100644 --- a/crates/lint/src/sol/macros.rs +++ b/crates/lint/src/sol/macros.rs @@ -1,3 +1,10 @@ +#[macro_export] +macro_rules! link { + ($url:expr) => { + concat!("\x1b]8;;", $url, "\x1b\\", $url, "\x1b]8;;\x1b\\") + }; +} + /// Macro for defining lints and relevant metadata for the Solidity linter. /// /// # Parameters @@ -20,7 +27,7 @@ macro_rules! declare_forge_lint { id: $str_id, severity: $severity, description: $desc, - help: concat!("https://book.getfoundry.sh/reference/forge/forge-lint#", $str_id), + help: link!(concat!("https://book.getfoundry.sh/reference/forge/forge-lint#", $str_id)), }; }; diff --git a/crates/lint/src/sol/med/div_mul.rs b/crates/lint/src/sol/med/div_mul.rs index b154971e55434..3d31956d0406f 100644 --- a/crates/lint/src/sol/med/div_mul.rs +++ b/crates/lint/src/sol/med/div_mul.rs @@ -1,6 +1,5 @@ use super::DivideBeforeMultiply; use crate::{ - declare_forge_lint, linter::{EarlyLintPass, LintContext}, sol::{Severity, SolLint}, }; diff --git a/crates/lint/src/sol/med/mod.rs b/crates/lint/src/sol/med/mod.rs index d315ff5405e51..5afc21772ca06 100644 --- a/crates/lint/src/sol/med/mod.rs +++ b/crates/lint/src/sol/med/mod.rs @@ -1,7 +1,4 @@ -use crate::{ - register_lints, - sol::{EarlyLintPass, SolLint}, -}; +use crate::sol::{EarlyLintPass, SolLint}; mod div_mul; use div_mul::DIVIDE_BEFORE_MULTIPLY; diff --git a/crates/lint/src/sol/mod.rs b/crates/lint/src/sol/mod.rs index 47e08296c1eee..6dee5314becfc 100644 --- a/crates/lint/src/sol/mod.rs +++ b/crates/lint/src/sol/mod.rs @@ -13,6 +13,7 @@ use std::{ }; use thiserror::Error; +#[macro_use] pub mod macros; pub mod gas; From 75df4f56ff5a4bb6b3ac97ee0c0a7969645b77d5 Mon Sep 17 00:00:00 2001 From: GregTheDev Date: Wed, 2 Jul 2025 16:13:07 -0500 Subject: [PATCH 237/244] chore: fix contracts --- Cargo.lock | 1 - crates/cheatcodes/src/credible.rs | 43 ++++++++++++++++--------------- crates/cli/src/opts/global.rs | 5 +--- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d217709a72f7e..606b4f63a5cb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1584,7 +1584,6 @@ dependencies = [ "alloy-network", "alloy-network-primitives", "alloy-node-bindings", - "alloy-op-evm", "alloy-primitives", "alloy-provider", "alloy-pubsub", diff --git a/crates/cheatcodes/src/credible.rs b/crates/cheatcodes/src/credible.rs index 67f8c38d09ab9..96280f85e8b5b 100644 --- a/crates/cheatcodes/src/credible.rs +++ b/crates/cheatcodes/src/credible.rs @@ -7,10 +7,11 @@ use assertion_executor::{ ExecutorConfig, }; use foundry_evm_core::backend::{DatabaseError, DatabaseExt}; -use revm::{ +use assertion_executor::{ primitives::{AccountInfo, Address, Bytecode, ExecutionResult, TxEnv, B256, U256}, - DatabaseCommit, DatabaseRef, + db::{DatabaseCommit, DatabaseRef}, }; +use revm::context_interface::ContextTr; use std::{ collections::HashMap, sync::{Arc, Mutex}, @@ -40,19 +41,19 @@ impl<'a> ThreadSafeDb<'a> { impl<'a> DatabaseRef for ThreadSafeDb<'a> { type Error = DatabaseError; - fn basic_ref(&self, address: Address) -> Result, Self::Error> { + fn basic_ref(&self, address: Address) -> Result, ::Error> { self.db.lock().unwrap().basic(address) } - fn code_by_hash_ref(&self, code_hash: B256) -> Result { + fn code_by_hash_ref(&self, code_hash: B256) -> Result::Error> { self.db.lock().unwrap().code_by_hash(code_hash) } - fn storage_ref(&self, address: Address, index: U256) -> Result { + fn storage_ref(&self, address: Address, index: U256) -> Result::Error> { self.db.lock().unwrap().storage(address, index) } - fn block_hash_ref(&self, number: u64) -> Result { + fn block_hash_ref(&self, number: u64) -> Result::Error> { self.db.lock().unwrap().block_hash(number) } } @@ -66,16 +67,16 @@ impl Cheatcode for assertionExCall { assertionContractLabel, } = self; - let spec_id = ccx.ecx.spec_id(); - let block = ccx.ecx.env.block.clone(); + let spec_id = ccx.ecx.cfg.spec; + let block = ccx.ecx.block.clone(); let state = ccx.ecx.journaled_state.state.clone(); - let chain_id = ccx.ecx.env.cfg.chain_id; + let chain_id = ccx.ecx.cfg.chain_id; // Setup assertion database - let db = ThreadSafeDb::new(ccx.ecx.db); + let db = ThreadSafeDb::new(ccx.ecx.db()); // Prepare assertion store - let assertion_contract_bytecode = Bytecode::LegacyRaw(assertionContract.to_vec().into()); + let assertion_contract_bytecode = Bytecode::new_legacy(assertionContract.to_vec().into()); let config = ExecutorConfig { spec_id, chain_id, assertion_gas_limit: 100_000 }; @@ -87,30 +88,30 @@ impl Cheatcode for assertionExCall { store.insert(*assertion_adopter, assertion_state).expect("Failed to store assertions"); - let decoded_tx = AssertionExTransaction::abi_decode(tx, true)?; + let decoded_tx = AssertionExTransaction::abi_decode(tx)?; let tx_env = TxEnv { caller: decoded_tx.from, - gas_limit: ccx.ecx.env.block.gas_limit.try_into().unwrap_or(u64::MAX), - transact_to: TxKind::Call(decoded_tx.to), + gas_limit: block.gas_limit.try_into().unwrap_or(u64::MAX), + kind: TxKind::Call(decoded_tx.to), value: decoded_tx.value, data: decoded_tx.data, chain_id: Some(chain_id), ..Default::default() }; - let mut assertion_executor = config.build(db, store); + let mut assertion_executor = config.build(store); // Commit current journal state so that it is available for assertions and // triggering tx - let mut fork_db = ForkDb::new(assertion_executor.db.clone()); + let mut fork_db = ForkDb::new(db.clone()); fork_db.commit(state); // Odysseas: This is a hack to use the new unified codepath for validate_transaction_ext_db // Effectively, we are applying the transaction in a clone of the currently running database // which is then used by the fork_db. // TODO: Remove this once we have a proper way to handle this. - let mut ext_db = revm::db::WrapDatabaseRef(fork_db.clone()); + let mut ext_db = revm::database::WrapDatabaseRef(fork_db.clone()); // Store assertions let tx_validation = assertion_executor @@ -187,7 +188,7 @@ fn decode_invalidated_assertion(execution_result: &ExecutionResult) -> Revert { reason: "Tried to decode invalidated assertion, but result was success. This is a bug in phoundry. Please report to the Phylax team.".to_string(), }, ExecutionResult::Revert{output, ..} => { - Revert::abi_decode(output, true) + Revert::abi_decode(output) .unwrap_or(Revert::new(("Unknown Revert Reason".to_string(),))) }, ExecutionResult::Halt{reason, ..} => Revert { @@ -200,7 +201,7 @@ fn decode_invalidated_assertion(execution_result: &ExecutionResult) -> Revert { mod tests { use super::*; use alloy_primitives::Bytes; - use revm::primitives::{HaltReason, Output, SuccessReason}; + use assertion_executor::primitives::{HaltReason, ExecutionResult}; #[test] fn test_decode_revert_error_success() { @@ -209,8 +210,8 @@ mod tests { gas_used: 0, gas_refunded: 0, logs: vec![], - output: Output::Call(Bytes::new()), - reason: SuccessReason::Return, + output: revm::context::result::Output::Call(Bytes::new()), + reason: revm::context::result::SuccessReason::Return, }; let revert = decode_invalidated_assertion(&result); assert_eq!(revert.reason(), "Tried to decode invalidated assertion, but result was success. This is a bug in phoundry. Please report to the Phylax team."); diff --git a/crates/cli/src/opts/global.rs b/crates/cli/src/opts/global.rs index a3a59014deb87..6dc34067f6198 100644 --- a/crates/cli/src/opts/global.rs +++ b/crates/cli/src/opts/global.rs @@ -1,8 +1,5 @@ use clap::{ArgAction, Parser}; -use foundry_common::{ - shell::{ColorChoice, OutputFormat, OutputMode, Shell, Verbosity}, - version::{IS_NIGHTLY_VERSION, NIGHTLY_VERSION_WARNING_MESSAGE}, -}; +use foundry_common::shell::{ColorChoice, OutputFormat, OutputMode, Shell, Verbosity}; use serde::{Deserialize, Serialize}; /// Global arguments for the CLI. From 7e1ed875fb620e3315c9189c3340f322bb98d152 Mon Sep 17 00:00:00 2001 From: GregTheDev Date: Wed, 2 Jul 2025 16:16:54 -0500 Subject: [PATCH 238/244] chore: use git assex --- Cargo.lock | 11 +++++++---- crates/cheatcodes/Cargo.toml | 5 +++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 606b4f63a5cb2..fc3fe312d37ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,9 +58,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy" -version = "1.0.12" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a66e45d962abb2e1e8a505d97af34d92137b82f6cabbfb373406a9220dc7dca" +checksum = "4e0d1aecf3cab3d0e7383064ce488616434b4ade10d8904dff422e74203c712f" dependencies = [ "alloy-consensus", "alloy-contract", @@ -374,9 +374,9 @@ dependencies = [ [[package]] name = "alloy-node-bindings" -version = "1.0.12" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e712c068ebe9f690d7d06610ed2e52639cb9570c81420d7a5fb0c9780625086" +checksum = "0d4f3ab81744547ab8283aa94c9670d3880ac826642e52739e3c4ecbfa84857a" dependencies = [ "alloy-genesis", "alloy-hardforks", @@ -1553,6 +1553,7 @@ dependencies = [ [[package]] name = "assertion-da-client" version = "0.2.0" +source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=968372e#968372e153a53dfb6bf7a3b136b046ce7d0a2cfb" dependencies = [ "alloy", "assertion-da-core", @@ -1569,6 +1570,7 @@ dependencies = [ [[package]] name = "assertion-da-core" version = "0.2.0" +source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=968372e#968372e153a53dfb6bf7a3b136b046ce7d0a2cfb" dependencies = [ "alloy", "serde", @@ -1577,6 +1579,7 @@ dependencies = [ [[package]] name = "assertion-executor" version = "0.2.0" +source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=968372e#968372e153a53dfb6bf7a3b136b046ce7d0a2cfb" dependencies = [ "alloy", "alloy-consensus", diff --git a/crates/cheatcodes/Cargo.toml b/crates/cheatcodes/Cargo.toml index 9349638830f29..af6b9f13c288d 100644 --- a/crates/cheatcodes/Cargo.toml +++ b/crates/cheatcodes/Cargo.toml @@ -22,8 +22,9 @@ vergen = { workspace = true, default-features = false, features = [ ] } [dependencies] -#assertion-executor = { git = "https://github.com/phylaxsystems/.git", tag = "0.1.6", default-features = false } -assertion-executor = { path = "../../../credible-sdk/crates/assertion-executor", default-features = false } +assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", rev = "968372e", default-features = false } +#assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", tag = "0.1.6", default-features = false } +#assertion-executor = { path = "../../../credible-sdk/crates/assertion-executor", default-features = false } foundry-cheatcodes-spec.workspace = true foundry-common.workspace = true From 0971d2ac7dafbf940a3b0e80a7ca7d1850c2a71a Mon Sep 17 00:00:00 2001 From: GregTheDev Date: Wed, 2 Jul 2025 16:32:20 -0500 Subject: [PATCH 239/244] chore: fix rebase issue --- crates/cheatcodes/src/credible.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/crates/cheatcodes/src/credible.rs b/crates/cheatcodes/src/credible.rs index df43dc5aa6b78..c67e4cafe1fcc 100644 --- a/crates/cheatcodes/src/credible.rs +++ b/crates/cheatcodes/src/credible.rs @@ -2,15 +2,12 @@ use crate::{Cheatcode, CheatcodesExecutor, CheatsCtxt, Result, Vm::*}; use alloy_primitives::TxKind; use alloy_sol_types::{Revert, SolError, SolValue}; use assertion_executor::{ - db::fork_db::ForkDb, + db::{fork_db::ForkDb, DatabaseCommit, DatabaseRef}, + primitives::{AccountInfo, Address, Bytecode, ExecutionResult, TxEnv, B256, U256}, store::{AssertionState, AssertionStore}, ExecutorConfig, }; use foundry_evm_core::backend::{DatabaseError, DatabaseExt}; -use assertion_executor::{ - primitives::{AccountInfo, Address, Bytecode, ExecutionResult, TxEnv, B256, U256}, - db::{DatabaseCommit, DatabaseRef}, -}; use revm::context_interface::ContextTr; use std::{ collections::HashMap, @@ -41,7 +38,10 @@ impl<'a> ThreadSafeDb<'a> { impl<'a> DatabaseRef for ThreadSafeDb<'a> { type Error = DatabaseError; - fn basic_ref(&self, address: Address) -> Result, ::Error> { + fn basic_ref( + &self, + address: Address, + ) -> Result, ::Error> { self.db.lock().unwrap().basic(address) } @@ -49,7 +49,11 @@ impl<'a> DatabaseRef for ThreadSafeDb<'a> { self.db.lock().unwrap().code_by_hash(code_hash) } - fn storage_ref(&self, address: Address, index: U256) -> Result::Error> { + fn storage_ref( + &self, + address: Address, + index: U256, + ) -> Result::Error> { self.db.lock().unwrap().storage(address, index) } @@ -97,7 +101,7 @@ impl Cheatcode for assertionExCall { value: decoded_tx.value, data: decoded_tx.data, chain_id: Some(chain_id), - gas_price: ccx.ecx.env.block.basefee, + gas_price: block.basefee.into(), ..Default::default() }; @@ -202,7 +206,7 @@ fn decode_invalidated_assertion(execution_result: &ExecutionResult) -> Revert { mod tests { use super::*; use alloy_primitives::Bytes; - use assertion_executor::primitives::{HaltReason, ExecutionResult}; + use assertion_executor::primitives::HaltReason; #[test] fn test_decode_revert_error_success() { From 01993e48f899872b728a4190bcbcc44b216368c2 Mon Sep 17 00:00:00 2001 From: GregTheDev Date: Thu, 3 Jul 2025 12:23:59 -0500 Subject: [PATCH 240/244] chore: bump assex --- Cargo.lock | 6 +++--- crates/cheatcodes/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc3fe312d37ad..7a7fdb7df1fc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1553,7 +1553,7 @@ dependencies = [ [[package]] name = "assertion-da-client" version = "0.2.0" -source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=968372e#968372e153a53dfb6bf7a3b136b046ce7d0a2cfb" +source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=70fe36e#70fe36ef7dbb7853eae2fec6cca16a27ef3e5b7f" dependencies = [ "alloy", "assertion-da-core", @@ -1570,7 +1570,7 @@ dependencies = [ [[package]] name = "assertion-da-core" version = "0.2.0" -source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=968372e#968372e153a53dfb6bf7a3b136b046ce7d0a2cfb" +source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=70fe36e#70fe36ef7dbb7853eae2fec6cca16a27ef3e5b7f" dependencies = [ "alloy", "serde", @@ -1579,7 +1579,7 @@ dependencies = [ [[package]] name = "assertion-executor" version = "0.2.0" -source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=968372e#968372e153a53dfb6bf7a3b136b046ce7d0a2cfb" +source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=70fe36e#70fe36ef7dbb7853eae2fec6cca16a27ef3e5b7f" dependencies = [ "alloy", "alloy-consensus", diff --git a/crates/cheatcodes/Cargo.toml b/crates/cheatcodes/Cargo.toml index af6b9f13c288d..ded3b30259ad9 100644 --- a/crates/cheatcodes/Cargo.toml +++ b/crates/cheatcodes/Cargo.toml @@ -22,7 +22,7 @@ vergen = { workspace = true, default-features = false, features = [ ] } [dependencies] -assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", rev = "968372e", default-features = false } +assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", rev = "fbc5578", default-features = false } #assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", tag = "0.1.6", default-features = false } #assertion-executor = { path = "../../../credible-sdk/crates/assertion-executor", default-features = false } From 46650927ede08c739f12bcfc15316f6ba10dc214 Mon Sep 17 00:00:00 2001 From: GregTheDev Date: Wed, 9 Jul 2025 15:49:40 +0700 Subject: [PATCH 241/244] chore: bump assex --- Cargo.lock | 22 +++++++++++++++++++--- crates/cheatcodes/Cargo.toml | 3 ++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7a7fdb7df1fc6..aeab03d8db56f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1553,7 +1553,7 @@ dependencies = [ [[package]] name = "assertion-da-client" version = "0.2.0" -source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=70fe36e#70fe36ef7dbb7853eae2fec6cca16a27ef3e5b7f" +source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=6e4131d#6e4131d0e22a4a0ef913c497171749193ac55e1f" dependencies = [ "alloy", "assertion-da-core", @@ -1570,7 +1570,7 @@ dependencies = [ [[package]] name = "assertion-da-core" version = "0.2.0" -source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=70fe36e#70fe36ef7dbb7853eae2fec6cca16a27ef3e5b7f" +source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=6e4131d#6e4131d0e22a4a0ef913c497171749193ac55e1f" dependencies = [ "alloy", "serde", @@ -1579,7 +1579,7 @@ dependencies = [ [[package]] name = "assertion-executor" version = "0.2.0" -source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=70fe36e#70fe36ef7dbb7853eae2fec6cca16a27ef3e5b7f" +source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=6e4131d#6e4131d0e22a4a0ef913c497171749193ac55e1f" dependencies = [ "alloy", "alloy-consensus", @@ -1602,6 +1602,7 @@ dependencies = [ "bincode", "clap", "enum-as-inner", + "evm-glue", "moka", "op-revm", "parking_lot", @@ -3834,6 +3835,15 @@ dependencies = [ "hex", ] +[[package]] +name = "evm-glue" +version = "0.1.0" +source = "git+https://git@github.com/Philogy/evm-glue.git?rev=6be3e8c89a7d193b591ca0415ec2a48b1540c01e#6be3e8c89a7d193b591ca0415ec2a48b1540c01e" +dependencies = [ + "hex", + "hex-literal", +] + [[package]] name = "evmole" version = "0.8.0" @@ -5264,6 +5274,12 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + [[package]] name = "hidapi-rusb" version = "1.3.3" diff --git a/crates/cheatcodes/Cargo.toml b/crates/cheatcodes/Cargo.toml index ded3b30259ad9..45a4c1c5cd899 100644 --- a/crates/cheatcodes/Cargo.toml +++ b/crates/cheatcodes/Cargo.toml @@ -22,7 +22,8 @@ vergen = { workspace = true, default-features = false, features = [ ] } [dependencies] -assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", rev = "fbc5578", default-features = false } +#assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", rev = "fbc5578", default-features = false } +assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", rev = "6e4131d", default-features = false } #assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", tag = "0.1.6", default-features = false } #assertion-executor = { path = "../../../credible-sdk/crates/assertion-executor", default-features = false } From 8ee8e6db1c093e28b81de5836a3657667c23aa23 Mon Sep 17 00:00:00 2001 From: GregTheDev Date: Wed, 9 Jul 2025 16:03:21 +0700 Subject: [PATCH 242/244] chore: bump assex --- crates/cheatcodes/Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/cheatcodes/Cargo.toml b/crates/cheatcodes/Cargo.toml index 45a4c1c5cd899..e0856de305ea2 100644 --- a/crates/cheatcodes/Cargo.toml +++ b/crates/cheatcodes/Cargo.toml @@ -22,9 +22,7 @@ vergen = { workspace = true, default-features = false, features = [ ] } [dependencies] -#assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", rev = "fbc5578", default-features = false } assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", rev = "6e4131d", default-features = false } -#assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", tag = "0.1.6", default-features = false } #assertion-executor = { path = "../../../credible-sdk/crates/assertion-executor", default-features = false } foundry-cheatcodes-spec.workspace = true From a3ffa1fffd28d94f7744e6fcafab1964c028224b Mon Sep 17 00:00:00 2001 From: GregTheDev Date: Wed, 9 Jul 2025 20:22:07 +0700 Subject: [PATCH 243/244] chore: bump assex --- Cargo.lock | 6 +++--- crates/cheatcodes/Cargo.toml | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aeab03d8db56f..ce2195fa90f01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1553,7 +1553,7 @@ dependencies = [ [[package]] name = "assertion-da-client" version = "0.2.0" -source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=6e4131d#6e4131d0e22a4a0ef913c497171749193ac55e1f" +source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=2e62531#2e625312536d187a6216b56bdd69fef8bc772fae" dependencies = [ "alloy", "assertion-da-core", @@ -1570,7 +1570,7 @@ dependencies = [ [[package]] name = "assertion-da-core" version = "0.2.0" -source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=6e4131d#6e4131d0e22a4a0ef913c497171749193ac55e1f" +source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=2e62531#2e625312536d187a6216b56bdd69fef8bc772fae" dependencies = [ "alloy", "serde", @@ -1579,7 +1579,7 @@ dependencies = [ [[package]] name = "assertion-executor" version = "0.2.0" -source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=6e4131d#6e4131d0e22a4a0ef913c497171749193ac55e1f" +source = "git+https://github.com/phylaxsystems/credible-sdk.git?rev=2e62531#2e625312536d187a6216b56bdd69fef8bc772fae" dependencies = [ "alloy", "alloy-consensus", diff --git a/crates/cheatcodes/Cargo.toml b/crates/cheatcodes/Cargo.toml index e0856de305ea2..0672110ddc282 100644 --- a/crates/cheatcodes/Cargo.toml +++ b/crates/cheatcodes/Cargo.toml @@ -22,8 +22,7 @@ vergen = { workspace = true, default-features = false, features = [ ] } [dependencies] -assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", rev = "6e4131d", default-features = false } -#assertion-executor = { path = "../../../credible-sdk/crates/assertion-executor", default-features = false } +assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", rev = "2e62531", default-features = false } foundry-cheatcodes-spec.workspace = true foundry-common.workspace = true From 645c85dc375abbf90f74c53b8823d6417e7f084e Mon Sep 17 00:00:00 2001 From: GregTheDev Date: Wed, 9 Jul 2025 20:41:37 +0700 Subject: [PATCH 244/244] chore: bump assex --- crates/cheatcodes/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cheatcodes/Cargo.toml b/crates/cheatcodes/Cargo.toml index 0672110ddc282..37b3471e8fdfb 100644 --- a/crates/cheatcodes/Cargo.toml +++ b/crates/cheatcodes/Cargo.toml @@ -22,7 +22,7 @@ vergen = { workspace = true, default-features = false, features = [ ] } [dependencies] -assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", rev = "2e62531", default-features = false } +assertion-executor = { git = "https://github.com/phylaxsystems/credible-sdk.git", rev = "8145495", default-features = false } foundry-cheatcodes-spec.workspace = true foundry-common.workspace = true