From ce74f6be81f3164c4c874896ada8b155e1161243 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Sat, 26 Oct 2024 07:48:17 +0200 Subject: [PATCH 01/35] chore: silence logger if silent (#9199) --- crates/anvil/src/lib.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/anvil/src/lib.rs b/crates/anvil/src/lib.rs index 11cb4473fad7..123faa1e9a5a 100644 --- a/crates/anvil/src/lib.rs +++ b/crates/anvil/src/lib.rs @@ -20,10 +20,7 @@ use crate::{ use alloy_primitives::{Address, U256}; use alloy_signer_local::PrivateKeySigner; use eth::backend::fork::ClientFork; -use foundry_common::{ - provider::{ProviderBuilder, RetryProvider}, - shell, -}; +use foundry_common::provider::{ProviderBuilder, RetryProvider}; use foundry_evm::revm; use futures::{FutureExt, TryFutureExt}; use parking_lot::Mutex; @@ -131,7 +128,7 @@ pub async fn spawn(config: NodeConfig) -> (EthApi, NodeHandle) { /// ``` pub async fn try_spawn(mut config: NodeConfig) -> io::Result<(EthApi, NodeHandle)> { let logger = if config.enable_tracing { init_tracing() } else { Default::default() }; - logger.set_enabled(!shell::is_quiet()); + logger.set_enabled(!config.silent); let backend = Arc::new(config.setup().await); From 6913a3d2a27cd2c44d38e8492d6bb20f7eef1163 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Sat, 26 Oct 2024 08:34:40 +0200 Subject: [PATCH 02/35] test: add test for rlp data (#9200) --- crates/cast/src/rlp_converter.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/crates/cast/src/rlp_converter.rs b/crates/cast/src/rlp_converter.rs index faa5cfd0569e..3f24aa563c1e 100644 --- a/crates/cast/src/rlp_converter.rs +++ b/crates/cast/src/rlp_converter.rs @@ -95,7 +95,8 @@ impl fmt::Display for Item { #[cfg(test)] mod test { use crate::rlp_converter::Item; - use alloy_rlp::Decodable; + use alloy_primitives::hex; + use alloy_rlp::{Bytes, Decodable}; use serde_json::Result as JsonResult; // https://en.wikipedia.org/wiki/Set-theoretic_definition_of_natural_numbers @@ -179,4 +180,24 @@ mod test { Ok(()) } + + #[test] + fn rlp_data() { + // + let hex_val_rlp = hex!("820002"); + let item = Item::decode(&mut &hex_val_rlp[..]).unwrap(); + + let data = hex!("0002"); + let encoded = alloy_rlp::encode(&data[..]); + let decoded: Bytes = alloy_rlp::decode_exact(&encoded[..]).unwrap(); + assert_eq!(Item::Data(decoded.to_vec()), item); + + let hex_val_rlp = hex!("00"); + let item = Item::decode(&mut &hex_val_rlp[..]).unwrap(); + + let data = hex!("00"); + let encoded = alloy_rlp::encode(&data[..]); + let decoded: Bytes = alloy_rlp::decode_exact(&encoded[..]).unwrap(); + assert_eq!(Item::Data(decoded.to_vec()), item); + } } From 12292787208c626ed6b2791eeed55ef7ab3578b0 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Sun, 27 Oct 2024 00:22:16 +0400 Subject: [PATCH 03/35] fix(anvil): correctly set hardfork-specific block fields (#9202) * fix(anvil): correctly set hardfork-specific block fields * fmt --- crates/anvil/core/src/eth/block.rs | 24 +++++++++------------ crates/anvil/src/eth/backend/executor.rs | 13 ++++++----- crates/anvil/src/eth/backend/mem/storage.rs | 9 +++----- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/crates/anvil/core/src/eth/block.rs b/crates/anvil/core/src/eth/block.rs index 0dc386b01b1d..c9f9048b8199 100644 --- a/crates/anvil/core/src/eth/block.rs +++ b/crates/anvil/core/src/eth/block.rs @@ -2,7 +2,7 @@ use super::{ transaction::{TransactionInfo, TypedReceipt}, trie, }; -use alloy_consensus::Header; +use alloy_consensus::{Header, EMPTY_OMMER_ROOT_HASH}; use alloy_eips::eip2718::Encodable2718; use alloy_primitives::{Address, Bloom, Bytes, B256, B64, U256}; use alloy_rlp::{RlpDecodable, RlpEncodable}; @@ -34,19 +34,11 @@ impl Block { /// /// Note: if the `impersonate-tx` feature is enabled this will also accept /// `MaybeImpersonatedTransaction`. - pub fn new( - partial_header: PartialHeader, - transactions: impl IntoIterator, - ommers: Vec
, - ) -> Self + pub fn new(partial_header: PartialHeader, transactions: impl IntoIterator) -> Self where T: Into, { let transactions: Vec<_> = transactions.into_iter().map(Into::into).collect(); - let mut encoded_ommers: Vec = Vec::new(); - alloy_rlp::encode_list(&ommers, &mut encoded_ommers); - let ommers_hash = - B256::from_slice(alloy_primitives::utils::keccak256(encoded_ommers).as_slice()); let transactions_root = trie::ordered_trie_root(transactions.iter().map(|r| r.encoded_2718())); @@ -54,7 +46,7 @@ impl Block { header: Header { parent_hash: partial_header.parent_hash, beneficiary: partial_header.beneficiary, - ommers_hash, + ommers_hash: EMPTY_OMMER_ROOT_HASH, state_root: partial_header.state_root, transactions_root, receipts_root: partial_header.receipts_root, @@ -66,16 +58,16 @@ impl Block { timestamp: partial_header.timestamp, extra_data: partial_header.extra_data, mix_hash: partial_header.mix_hash, - withdrawals_root: None, + withdrawals_root: partial_header.withdrawals_root, blob_gas_used: partial_header.blob_gas_used, excess_blob_gas: partial_header.excess_blob_gas, parent_beacon_block_root: partial_header.parent_beacon_block_root, nonce: partial_header.nonce, base_fee_per_gas: partial_header.base_fee, - requests_hash: None, + requests_hash: partial_header.requests_hash, }, transactions, - ommers, + ommers: vec![], } } } @@ -100,6 +92,8 @@ pub struct PartialHeader { pub parent_beacon_block_root: Option, pub nonce: B64, pub base_fee: Option, + pub withdrawals_root: Option, + pub requests_hash: Option, } impl From
for PartialHeader { @@ -122,6 +116,8 @@ impl From
for PartialHeader { blob_gas_used: value.blob_gas_used, excess_blob_gas: value.excess_blob_gas, parent_beacon_block_root: value.parent_beacon_block_root, + requests_hash: value.requests_hash, + withdrawals_root: value.withdrawals_root, } } } diff --git a/crates/anvil/src/eth/backend/executor.rs b/crates/anvil/src/eth/backend/executor.rs index 3ceee8b04e94..a00afd962878 100644 --- a/crates/anvil/src/eth/backend/executor.rs +++ b/crates/anvil/src/eth/backend/executor.rs @@ -8,8 +8,8 @@ use crate::{ mem::inspector::Inspector, PrecompileFactory, }; -use alloy_consensus::{Header, Receipt, ReceiptWithBloom}; -use alloy_eips::eip2718::Encodable2718; +use alloy_consensus::{constants::EMPTY_WITHDRAWALS, Receipt, ReceiptWithBloom}; +use alloy_eips::{eip2718::Encodable2718, eip7685::EMPTY_REQUESTS_HASH}; use alloy_primitives::{Bloom, BloomInput, Log, B256}; use anvil_core::eth::{ block::{Block, BlockInfo, PartialHeader}, @@ -134,7 +134,9 @@ impl TransactionExecutor<'_, DB, V> { 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 mut cumulative_blob_gas_used = if is_cancun { Some(0u64) } else { None }; @@ -208,7 +210,6 @@ impl TransactionExecutor<'_, DB, V> { transactions.push(transaction.pending_transaction.transaction.clone()); } - let ommers: Vec
= Vec::new(); let receipts_root = trie::ordered_trie_root(receipts.iter().map(Encodable2718::encoded_2718)); @@ -227,12 +228,14 @@ impl TransactionExecutor<'_, DB, V> { mix_hash: Default::default(), nonce: Default::default(), base_fee, - parent_beacon_block_root: Default::default(), + parent_beacon_block_root: is_cancun.then_some(Default::default()), blob_gas_used: cumulative_blob_gas_used, excess_blob_gas, + withdrawals_root: is_shanghai.then_some(EMPTY_WITHDRAWALS), + requests_hash: is_prague.then_some(EMPTY_REQUESTS_HASH), }; - let block = Block::new(partial_header, transactions.clone(), ommers); + let block = Block::new(partial_header, transactions.clone()); let block = BlockInfo { block, transactions: transaction_infos, receipts }; ExecutedTransactions { block, included, invalid } } diff --git a/crates/anvil/src/eth/backend/mem/storage.rs b/crates/anvil/src/eth/backend/mem/storage.rs index 942ce5a9d23c..2105666a4e91 100644 --- a/crates/anvil/src/eth/backend/mem/storage.rs +++ b/crates/anvil/src/eth/backend/mem/storage.rs @@ -274,7 +274,7 @@ impl BlockchainStorage { excess_blob_gas: env.block.get_blob_excess_gas(), ..Default::default() }; - let block = Block::new::(partial_header, vec![], vec![]); + 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(0u64); @@ -693,11 +693,8 @@ mod tests { let bytes_first = &mut &hex::decode("f86b02843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba00eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5aea03a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18").unwrap()[..]; let tx: MaybeImpersonatedTransaction = TypedTransaction::decode(&mut &bytes_first[..]).unwrap().into(); - let block = Block::new::( - partial_header.clone(), - vec![tx.clone()], - vec![], - ); + let block = + Block::new::(partial_header.clone(), vec![tx.clone()]); let block_hash = block.header.hash_slow(); dump_storage.blocks.insert(block_hash, block); From 484a5de4be707cd94d5f9bf128d997b0205e4880 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 27 Oct 2024 02:53:32 +0100 Subject: [PATCH 04/35] chore(deps): weekly `cargo update` (#9206) Locking 26 packages to latest compatible versions Updating alloy-chains v0.1.40 -> v0.1.42 Updating anstream v0.6.15 -> v0.6.17 Updating anstyle v1.0.8 -> v1.0.9 Updating anstyle-parse v0.2.5 -> v0.2.6 Updating anstyle-query v1.1.1 -> v1.1.2 Updating anstyle-wincon v3.0.4 -> v3.0.6 Updating aws-config v1.5.8 -> v1.5.9 Updating aws-sdk-kms v1.47.0 -> v1.48.0 Updating aws-sdk-sso v1.46.0 -> v1.47.0 Updating aws-sdk-ssooidc v1.47.0 -> v1.48.0 Updating aws-sdk-sts v1.46.0 -> v1.47.0 Updating aws-sigv4 v1.2.4 -> v1.2.5 Updating aws-smithy-runtime v1.7.2 -> v1.7.3 Updating aws-smithy-types v1.2.7 -> v1.2.8 Updating colorchoice v1.0.2 -> v1.0.3 Updating libm v0.2.8 -> v0.2.9 Updating op-alloy-consensus v0.5.0 -> v0.5.1 Updating op-alloy-rpc-types v0.5.0 -> v0.5.1 Updating pin-project v1.1.6 -> v1.1.7 Updating pin-project-internal v1.1.6 -> v1.1.7 Updating pin-project-lite v0.2.14 -> v0.2.15 Updating regex v1.11.0 -> v1.11.1 Updating scale-info v2.11.4 -> v2.11.5 Updating scale-info-derive v2.11.4 -> v2.11.5 Updating scc v2.2.2 -> v2.2.4 Updating wasm-streams v0.4.1 -> v0.4.2 note: pass `--verbose` to see 13 unchanged dependencies behind latest Co-authored-by: mattsse <19890894+mattsse@users.noreply.github.com> --- Cargo.lock | 124 ++++++++++++++++++++++++++--------------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f5d17a156de3..6d730b949b62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,9 +74,9 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alloy-chains" -version = "0.1.40" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4932d790c723181807738cf1ac68198ab581cd699545b155601332541ee47bd" +checksum = "dca4a1469a3e572e9ba362920ff145f5d0a00a3e71a64ddcb4a3659cf64c76a7" dependencies = [ "alloy-primitives", "num_enum", @@ -321,7 +321,7 @@ dependencies = [ "futures-utils-wasm", "lru", "parking_lot", - "pin-project 1.1.6", + "pin-project 1.1.7", "reqwest", "schnellru", "serde", @@ -388,7 +388,7 @@ dependencies = [ "alloy-transport-ipc", "alloy-transport-ws", "futures", - "pin-project 1.1.6", + "pin-project 1.1.7", "reqwest", "serde", "serde_json", @@ -729,7 +729,7 @@ dependencies = [ "bytes", "futures", "interprocess", - "pin-project 1.1.6", + "pin-project 1.1.7", "serde", "serde_json", "tempfile", @@ -801,9 +801,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" dependencies = [ "anstyle", "anstyle-parse", @@ -816,36 +816,36 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -961,7 +961,7 @@ dependencies = [ "futures", "interprocess", "parking_lot", - "pin-project 1.1.6", + "pin-project 1.1.7", "serde", "serde_json", "thiserror", @@ -1261,9 +1261,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-config" -version = "1.5.8" +version = "1.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7198e6f03240fdceba36656d8be440297b6b82270325908c7381f37d826a74f6" +checksum = "2d6448cfb224dd6a9b9ac734f58622dd0d4751f3589f3b777345745f46b2eb14" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1328,9 +1328,9 @@ dependencies = [ [[package]] name = "aws-sdk-kms" -version = "1.47.0" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "564a597a3c71a957d60a2e4c62c93d78ee5a0d636531e15b760acad983a5c18e" +checksum = "2afbd208dabc6785946d4ef2444eb1f54fe0aaf0f62f2a4f9a9e9c303aeff0be" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1350,9 +1350,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.46.0" +version = "1.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc2faec3205d496c7e57eff685dd944203df7ce16a4116d0281c44021788a7b" +checksum = "a8776850becacbd3a82a4737a9375ddb5c6832a51379f24443a98e61513f852c" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1372,9 +1372,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.47.0" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c93c241f52bc5e0476e259c953234dab7e2a35ee207ee202e86c0095ec4951dc" +checksum = "0007b5b8004547133319b6c4e87193eee2a0bcb3e4c18c75d09febe9dab7b383" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1394,9 +1394,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.46.0" +version = "1.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b259429be94a3459fa1b00c5684faee118d74f9577cc50aebadc36e507c63b5f" +checksum = "9fffaa356e7f1c725908b75136d53207fa714e348f365671df14e95a60530ad3" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1417,9 +1417,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.2.4" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc8db6904450bafe7473c6ca9123f88cc11089e41a025408f992db4e22d3be68" +checksum = "5619742a0d8f253be760bfbb8e8e8368c69e3587e4637af5754e488a611499b1" dependencies = [ "aws-credential-types", "aws-smithy-http", @@ -1490,9 +1490,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.7.2" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a065c0fe6fdbdf9f11817eb68582b2ab4aff9e9c39e986ae48f7ec576c6322db" +checksum = "be28bd063fa91fd871d131fc8b68d7cd4c5fa0869bea68daca50dcb1cbd76be2" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -1534,9 +1534,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.2.7" +version = "1.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147100a7bea70fa20ef224a6bad700358305f5dc0f84649c53769761395b355b" +checksum = "07c9cdc179e6afbf5d391ab08c85eac817b51c87e1892a5edb5f7bbdc64314b4" dependencies = [ "base64-simd", "bytes", @@ -2311,9 +2311,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "comfy-table" @@ -5474,9 +5474,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "3bda4c6077b0b08da2c48b172195795498381a7c8988c9e6212a6c55c5b9bd70" [[package]] name = "libredox" @@ -6083,9 +6083,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "op-alloy-consensus" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d49163f952491820088dd0e66f3a35d63337c3066eceff0a931bf83a8e2101" +checksum = "ba7c98055fd048073738df0cc6d6537e992a0d8828f39d99a469e870db126dbd" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6099,9 +6099,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9556293835232b019ec9c6fd84e4265a3151111af60ea09b5b513e3dbed41c" +checksum = "919e9b69212d61f3c8932bfb717c7ad458ea3fc52072b3433d99994f8223d555" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6512,11 +6512,11 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ - "pin-project-internal 1.1.6", + "pin-project-internal 1.1.7", ] [[package]] @@ -6532,9 +6532,9 @@ dependencies = [ [[package]] name = "pin-project-internal" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", @@ -6543,9 +6543,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -7094,9 +7094,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -7629,9 +7629,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.11.4" +version = "2.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22760a375f81a31817aeaf6f5081e9ccb7ffd7f2da1809a6e3fc82b6656f10d5" +checksum = "1aa7ffc1c0ef49b0452c6e2986abf2b07743320641ffd5fc63d552458e3b779b" dependencies = [ "cfg-if", "derive_more", @@ -7641,21 +7641,21 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.11.4" +version = "2.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abc61ebe25a5c410c0e245028fc9934bf8fa4817199ef5a24a68092edfd34614" +checksum = "46385cc24172cf615450267463f937c10072516359b3ff1cb24228a4a08bf951" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.85", ] [[package]] name = "scc" -version = "2.2.2" +version = "2.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c1f7fc6deb21665a9060dfc7d271be784669295a31babdcd4dd2c79ae8cbfb" +checksum = "d8d25269dd3a12467afe2e510f69fb0b46b698e5afb296b59f2145259deaf8e8" dependencies = [ "sdd", ] @@ -8803,7 +8803,7 @@ dependencies = [ "hyper-timeout", "hyper-util", "percent-encoding", - "pin-project 1.1.6", + "pin-project 1.1.7", "prost", "rustls-native-certs 0.8.0", "rustls-pemfile 2.2.0", @@ -8832,7 +8832,7 @@ dependencies = [ "futures-core", "futures-util", "indexmap 1.9.3", - "pin-project 1.1.6", + "pin-project 1.1.7", "pin-project-lite", "rand", "slab", @@ -9378,9 +9378,9 @@ checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-streams" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ "futures-util", "js-sys", From 3b0c75d5edd01e7be921b48b2e16271a467c2ffd Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Sun, 27 Oct 2024 15:12:07 +0100 Subject: [PATCH 05/35] fix: include withdrawals root in response (#9208) --- crates/anvil/src/eth/backend/mem/mod.rs | 6 ++--- crates/anvil/tests/it/anvil.rs | 29 ++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 34d37d666d44..73adaa97f3fd 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -1880,7 +1880,7 @@ impl Backend { mix_hash, nonce, base_fee_per_gas, - withdrawals_root: _, + withdrawals_root, blob_gas_used, excess_blob_gas, parent_beacon_block_root, @@ -1906,7 +1906,7 @@ impl Backend { mix_hash: Some(mix_hash), nonce: Some(nonce), base_fee_per_gas, - withdrawals_root: None, + withdrawals_root, blob_gas_used, excess_blob_gas, parent_beacon_block_root, @@ -1917,7 +1917,7 @@ impl Backend { transactions.into_iter().map(|tx| tx.hash()).collect(), ), uncles: vec![], - withdrawals: None, + withdrawals: withdrawals_root.map(|_| Default::default()), }; let mut block = WithOtherFields::new(block); diff --git a/crates/anvil/tests/it/anvil.rs b/crates/anvil/tests/it/anvil.rs index 50e27c57aa57..5a952da6b2b4 100644 --- a/crates/anvil/tests/it/anvil.rs +++ b/crates/anvil/tests/it/anvil.rs @@ -1,9 +1,10 @@ //! tests for anvil specific logic +use alloy_consensus::EMPTY_ROOT_HASH; use alloy_eips::BlockNumberOrTag; use alloy_primitives::Address; use alloy_provider::Provider; -use anvil::{spawn, NodeConfig}; +use anvil::{spawn, EthereumHardfork, NodeConfig}; #[tokio::test(flavor = "multi_thread")] async fn test_can_change_mining_mode() { @@ -88,3 +89,29 @@ async fn test_can_handle_large_timestamp() { let block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap(); assert_eq!(block.header.timestamp, num); } + +#[tokio::test(flavor = "multi_thread")] +async fn test_shanghai_fields() { + let (api, _handle) = + spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Shanghai.into()))).await; + api.mine_one().await; + + let block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap(); + assert_eq!(block.header.withdrawals_root, Some(EMPTY_ROOT_HASH)); + assert_eq!(block.withdrawals, Some(Default::default())); + assert!(block.header.blob_gas_used.is_none()); + assert!(block.header.excess_blob_gas.is_none()); +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_cancun_fields() { + let (api, _handle) = + spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()))).await; + api.mine_one().await; + + let block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap(); + assert_eq!(block.header.withdrawals_root, Some(EMPTY_ROOT_HASH)); + assert_eq!(block.withdrawals, Some(Default::default())); + assert!(block.header.blob_gas_used.is_some()); + assert!(block.header.excess_blob_gas.is_some()); +} From 513ed69f79cbc24cfc08d5ef39e9f8bb5fe7eff7 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Sun, 27 Oct 2024 18:14:02 +0400 Subject: [PATCH 06/35] fix(script): correctly detect additional contracts (#9207) * add test * fix(script): correctly detect additional contracts * fix --- Cargo.lock | 1 + crates/forge/Cargo.toml | 1 + crates/forge/tests/cli/script.rs | 48 ++++++++++++++++++++++++++++++++ crates/script/src/transaction.rs | 2 ++ 4 files changed, 52 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 6d730b949b62..014b458f9642 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3360,6 +3360,7 @@ dependencies = [ "forge-doc", "forge-fmt", "forge-script", + "forge-script-sequence", "forge-sol-macro-gen", "forge-verify", "foundry-block-explorers", diff --git a/crates/forge/Cargo.toml b/crates/forge/Cargo.toml index 1b716497a45e..f85a08d69f27 100644 --- a/crates/forge/Cargo.toml +++ b/crates/forge/Cargo.toml @@ -33,6 +33,7 @@ foundry-config.workspace = true foundry-evm.workspace = true foundry-wallets.workspace = true foundry-linking.workspace = true +forge-script-sequence.workspace = true ethers-contract-abigen = { workspace = true, features = ["providers"] } diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index c4a69223d521..88b75ad50114 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -3,6 +3,7 @@ use crate::constants::TEMPLATE_CONTRACT; use alloy_primitives::{hex, Address, Bytes}; use anvil::{spawn, NodeConfig}; +use forge_script_sequence::ScriptSequence; use foundry_test_utils::{ rpc, util::{OTHER_SOLC_VERSION, SOLC_VERSION}, @@ -2269,3 +2270,50 @@ backend: failed while inspecting; header validation error: `prevrandao` not set; "#]]); }); + +forgetest_async!(should_detect_additional_contracts, |prj, cmd| { + let (_api, handle) = spawn(NodeConfig::test()).await; + + foundry_test_utils::util::initialize(prj.root()); + prj.add_source( + "Foo", + r#" +import "forge-std/Script.sol"; + +contract Simple {} + +contract Deployer { + function deploy() public { + new Simple(); + } +} + +contract ContractScript is Script { + function run() public { + vm.startBroadcast(); + Deployer deployer = new Deployer(); + deployer.deploy(); + } +} + "#, + ) + .unwrap(); + cmd.arg("script") + .args([ + "ContractScript", + "--private-key", + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + "--rpc-url", + &handle.http_endpoint(), + ]) + .assert_success(); + + let run_latest = foundry_common::fs::json_files(&prj.root().join("broadcast")) + .find(|file| file.ends_with("run-latest.json")) + .expect("No broadcast artifacts"); + + let sequence: ScriptSequence = foundry_common::fs::read_json_file(&run_latest).unwrap(); + + assert_eq!(sequence.transactions.len(), 2); + assert_eq!(sequence.transactions[1].additional_contracts.len(), 1); +}); diff --git a/crates/script/src/transaction.rs b/crates/script/src/transaction.rs index 39bf0490ea42..fcd4eefc36d4 100644 --- a/crates/script/src/transaction.rs +++ b/crates/script/src/transaction.rs @@ -155,6 +155,8 @@ impl ScriptTransactionBuilder { self.transaction.contract_address.map_or(true, |addr| addr != contract.address) }); + self.transaction.additional_contracts = created_contracts; + if !self.transaction.is_fixed_gas_limit { if let Some(unsigned) = self.transaction.transaction.as_unsigned_mut() { // We inflate the gas used by the user specified percentage From 5c69a9d9fd4e2ec07fc398ab5ef9d706c33890c2 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Sun, 27 Oct 2024 18:37:01 +0400 Subject: [PATCH 07/35] fix(`cast block`): ensure to print all fields (#9209) fix(cast block): ensure to print all fields --- crates/cast/tests/cli/main.rs | 3 ++ crates/common/fmt/src/ui.rs | 89 +++++++++++++++++++++++++---------- 2 files changed, 68 insertions(+), 24 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index f307a6cfef11..6d5a6fd6a821 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -81,6 +81,9 @@ stateRoot [..] timestamp [..] withdrawalsRoot [..] totalDifficulty [..] +blobGasUsed [..] +excessBlobGas [..] +requestsHash [..] transactions: [ ... ] diff --git a/crates/common/fmt/src/ui.rs b/crates/common/fmt/src/ui.rs index 4789c381da0a..5534e72d8355 100644 --- a/crates/common/fmt/src/ui.rs +++ b/crates/common/fmt/src/ui.rs @@ -4,7 +4,7 @@ use alloy_consensus::{AnyReceiptEnvelope, Eip658Value, Receipt, ReceiptWithBloom use alloy_network::ReceiptResponse; use alloy_primitives::{hex, Address, Bloom, Bytes, FixedBytes, Uint, B256, I256, U256, U64}; use alloy_rpc_types::{ - AccessListItem, AnyNetworkBlock, AnyTransactionReceipt, Block, BlockTransactions, Log, + AccessListItem, AnyNetworkBlock, AnyTransactionReceipt, Block, BlockTransactions, Header, Log, Transaction, TransactionReceipt, }; use alloy_serde::{OtherFields, WithOtherFields}; @@ -597,6 +597,9 @@ pub fn get_pretty_block_attr(block: &AnyNetworkBlock, attr: &str) -> Option Some(block.header.state_root.pretty()), "timestamp" => Some(block.header.timestamp.pretty()), "totalDifficulty" | "total_difficult" => Some(block.header.total_difficulty.pretty()), + "blobGasUsed" | "blob_gas_used" => Some(block.header.blob_gas_used.pretty()), + "excessBlobGas" | "excess_blob_gas" => Some(block.header.excess_blob_gas.pretty()), + "requestsHash" | "requests_hash" => Some(block.header.requests_hash.pretty()), other => { if let Some(value) = block.other.get(other) { let val = EthValue::from(value.clone()); @@ -608,6 +611,38 @@ pub fn get_pretty_block_attr(block: &AnyNetworkBlock, attr: &str) -> Option(block: &Block) -> String { + let Block { + header: + Header { + hash, + parent_hash, + uncles_hash, + miner, + state_root, + transactions_root, + receipts_root, + logs_bloom, + difficulty, + number, + gas_limit, + gas_used, + timestamp, + total_difficulty, + extra_data, + mix_hash, + nonce, + base_fee_per_gas, + withdrawals_root, + blob_gas_used, + excess_blob_gas, + parent_beacon_block_root, + requests_hash, + }, + uncles: _, + transactions: _, + size, + withdrawals: _, + } = block; format!( " baseFeePerGas {} @@ -630,31 +665,37 @@ size {} stateRoot {} timestamp {} ({}) withdrawalsRoot {} -totalDifficulty {}", - block.header.base_fee_per_gas.pretty(), - block.header.difficulty.pretty(), - block.header.extra_data.pretty(), - block.header.gas_limit.pretty(), - block.header.gas_used.pretty(), - block.header.hash.pretty(), - block.header.logs_bloom.pretty(), - block.header.miner.pretty(), - block.header.mix_hash.pretty(), - block.header.nonce.pretty(), - block.header.number.pretty(), - block.header.parent_hash.pretty(), - block.header.parent_beacon_block_root.pretty(), - block.header.transactions_root.pretty(), - block.header.receipts_root.pretty(), - block.header.uncles_hash.pretty(), - block.size.pretty(), - block.header.state_root.pretty(), - block.header.timestamp.pretty(), - chrono::DateTime::from_timestamp(block.header.timestamp as i64, 0) +totalDifficulty {} +blobGasUsed {} +excessBlobGas {} +requestsHash {}", + base_fee_per_gas.pretty(), + difficulty.pretty(), + extra_data.pretty(), + gas_limit.pretty(), + gas_used.pretty(), + hash.pretty(), + logs_bloom.pretty(), + miner.pretty(), + mix_hash.pretty(), + nonce.pretty(), + number.pretty(), + parent_hash.pretty(), + parent_beacon_block_root.pretty(), + transactions_root.pretty(), + receipts_root.pretty(), + uncles_hash.pretty(), + size.pretty(), + state_root.pretty(), + timestamp.pretty(), + chrono::DateTime::from_timestamp(*timestamp as i64, 0) .expect("block timestamp in range") .to_rfc2822(), - block.header.withdrawals_root.pretty(), - block.header.total_difficulty.pretty(), + withdrawals_root.pretty(), + total_difficulty.pretty(), + blob_gas_used.pretty(), + excess_blob_gas.pretty(), + requests_hash.pretty(), ) } From 00415bbb0653c429c1e21dcd0405be3005a36cc6 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Mon, 28 Oct 2024 18:24:37 +0700 Subject: [PATCH 08/35] feat(cast): add --int flag to from-rlp (#9210) * bet * fmt * bet * bet * remove unneccessary validation --- crates/cast/bin/args.rs | 4 ++++ crates/cast/bin/main.rs | 4 ++-- crates/cast/src/lib.rs | 28 ++++++++++++++++++---------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/crates/cast/bin/args.rs b/crates/cast/bin/args.rs index 6cbfd73f7988..386201e5b0ee 100644 --- a/crates/cast/bin/args.rs +++ b/crates/cast/bin/args.rs @@ -317,6 +317,10 @@ pub enum CastSubcommand { FromRlp { /// The RLP hex-encoded data. value: Option, + + /// Decode the RLP data as int + #[arg(id = "int", long = "as_int", alias = "int")] + as_int: bool, }, /// Converts a number of one base to another diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index 90367d106e8a..0338d9ff26f0 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -149,9 +149,9 @@ async fn main_args(args: CastArgs) -> Result<()> { let value = stdin::unwrap_line(value)?; sh_println!("{}", SimpleCast::to_wei(&value, &unit)?)? } - CastSubcommand::FromRlp { value } => { + CastSubcommand::FromRlp { value, as_int } => { let value = stdin::unwrap_line(value)?; - sh_println!("{}", SimpleCast::from_rlp(value)?)? + sh_println!("{}", SimpleCast::from_rlp(value, as_int)?)? } CastSubcommand::ToRlp { value } => { let value = stdin::unwrap_line(value)?; diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index d40a4a5954aa..97624c12ab64 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -1448,23 +1448,31 @@ impl SimpleCast { Ok(ParseUnits::parse_units(value, unit)?.to_string()) } - /// Decodes rlp encoded list with hex data - /// - /// # Example + // Decodes RLP encoded data with validation for canonical integer representation /// + /// # Examples /// ``` /// use cast::SimpleCast as Cast; /// - /// assert_eq!(Cast::from_rlp("0xc0").unwrap(), "[]"); - /// assert_eq!(Cast::from_rlp("0x0f").unwrap(), "\"0x0f\""); - /// assert_eq!(Cast::from_rlp("0x33").unwrap(), "\"0x33\""); - /// assert_eq!(Cast::from_rlp("0xc161").unwrap(), "[\"0x61\"]"); - /// assert_eq!(Cast::from_rlp("0xc26162").unwrap(), "[\"0x61\",\"0x62\"]"); + /// assert_eq!(Cast::from_rlp("0xc0", false).unwrap(), "[]"); + /// assert_eq!(Cast::from_rlp("0x0f", false).unwrap(), "\"0x0f\""); + /// assert_eq!(Cast::from_rlp("0x33", false).unwrap(), "\"0x33\""); + /// assert_eq!(Cast::from_rlp("0xc161", false).unwrap(), "[\"0x61\"]"); + /// assert_eq!(Cast::from_rlp("820002", true).is_err(), true); + /// assert_eq!(Cast::from_rlp("820002", false).unwrap(), "\"0x0002\""); + /// assert_eq!(Cast::from_rlp("00", true).is_err(), true); + /// assert_eq!(Cast::from_rlp("00", false).unwrap(), "\"0x00\""); /// # Ok::<_, eyre::Report>(()) /// ``` - pub fn from_rlp(value: impl AsRef) -> Result { + pub fn from_rlp(value: impl AsRef, as_int: bool) -> Result { let bytes = hex::decode(value.as_ref()).wrap_err("Could not decode hex")?; + + if as_int { + return Ok(U256::decode(&mut &bytes[..])?.to_string()); + } + let item = Item::decode(&mut &bytes[..]).wrap_err("Could not decode rlp")?; + Ok(item.to_string()) } @@ -2288,7 +2296,7 @@ mod tests { #[test] fn from_rlp() { let rlp = "0xf8b1a02b5df5f0757397573e8ff34a8b987b21680357de1f6c8d10273aa528a851eaca8080a02838ac1d2d2721ba883169179b48480b2ba4f43d70fcf806956746bd9e83f90380a0e46fff283b0ab96a32a7cc375cecc3ed7b6303a43d64e0a12eceb0bc6bd8754980a01d818c1c414c665a9c9a0e0c0ef1ef87cacb380b8c1f6223cb2a68a4b2d023f5808080a0236e8f61ecde6abfebc6c529441f782f62469d8a2cc47b7aace2c136bd3b1ff08080808080"; - let item = Cast::from_rlp(rlp).unwrap(); + let item = Cast::from_rlp(rlp, false).unwrap(); assert_eq!( item, r#"["0x2b5df5f0757397573e8ff34a8b987b21680357de1f6c8d10273aa528a851eaca","0x","0x","0x2838ac1d2d2721ba883169179b48480b2ba4f43d70fcf806956746bd9e83f903","0x","0xe46fff283b0ab96a32a7cc375cecc3ed7b6303a43d64e0a12eceb0bc6bd87549","0x","0x1d818c1c414c665a9c9a0e0c0ef1ef87cacb380b8c1f6223cb2a68a4b2d023f5","0x","0x","0x","0x236e8f61ecde6abfebc6c529441f782f62469d8a2cc47b7aace2c136bd3b1ff0","0x","0x","0x","0x","0x"]"# From 0191e176acec1acffd94e671eb0a46b0894767e5 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Mon, 28 Oct 2024 15:21:30 +0200 Subject: [PATCH 09/35] chore: try from eyre:Result for TraceResult (display chained error) (#9212) --- crates/cast/bin/cmd/run.rs | 4 ++-- crates/cli/src/utils/cmd.rs | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/crates/cast/bin/cmd/run.rs b/crates/cast/bin/cmd/run.rs index bc06547044d4..11c7b507e355 100644 --- a/crates/cast/bin/cmd/run.rs +++ b/crates/cast/bin/cmd/run.rs @@ -1,7 +1,7 @@ use alloy_primitives::U256; use alloy_provider::Provider; use alloy_rpc_types::BlockTransactions; -use cast::{revm::primitives::EnvWithHandlerCfg, traces::TraceKind}; +use cast::revm::primitives::EnvWithHandlerCfg; use clap::Parser; use eyre::{Result, WrapErr}; use foundry_cli::{ @@ -235,7 +235,7 @@ impl RunArgs { if let Some(to) = tx.to { trace!(tx=?tx.hash, to=?to, "executing call transaction"); - TraceResult::from_raw(executor.transact_with_env(env)?, TraceKind::Execution) + TraceResult::try_from(executor.transact_with_env(env))? } else { trace!(tx=?tx.hash, "executing create transaction"); TraceResult::try_from(executor.deploy_with_env(env, None))? diff --git a/crates/cli/src/utils/cmd.rs b/crates/cli/src/utils/cmd.rs index e4d0a5114627..9852f53f1d44 100644 --- a/crates/cli/src/utils/cmd.rs +++ b/crates/cli/src/utils/cmd.rs @@ -362,6 +362,23 @@ impl TryFrom> for TraceResult { } } +impl From for TraceResult { + fn from(result: RawCallResult) -> Self { + Self::from_raw(result, TraceKind::Execution) + } +} + +impl TryFrom> for TraceResult { + type Error = EvmError; + + fn try_from(value: Result) -> Result { + match value { + Ok(result) => Ok(Self::from(result)), + Err(err) => Err(EvmError::from(err)), + } + } +} + /// labels the traces, conditionally prints them or opens the debugger pub async fn handle_traces( mut result: TraceResult, From a428ba6ad8856611339a6319290aade3347d25d9 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Mon, 28 Oct 2024 20:35:30 +0200 Subject: [PATCH 10/35] feat(`forge install`): add `@tag=` `@branch=` `@rev=` specific refs (#9214) * fix(`forge install`): add @tag= @branch= @commit= for refs * Consistent @rev= --- crates/cli/src/opts/dependency.rs | 46 ++++++++++++++++++++++++++----- crates/forge/bin/cmd/install.rs | 2 ++ 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/crates/cli/src/opts/dependency.rs b/crates/cli/src/opts/dependency.rs index 6fa33a53f8a1..6783e32d25ce 100644 --- a/crates/cli/src/opts/dependency.rs +++ b/crates/cli/src/opts/dependency.rs @@ -12,6 +12,9 @@ pub static GH_REPO_PREFIX_REGEX: LazyLock = LazyLock::new(|| { .unwrap() }); +static VERSION_PREFIX_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r#"@(tag|branch|rev)="#).unwrap()); + const GITHUB: &str = "github.com"; const VERSION_SEPARATOR: char = '@'; const ALIAS_SEPARATOR: char = '='; @@ -49,6 +52,12 @@ pub struct Dependency { impl FromStr for Dependency { type Err = eyre::Error; fn from_str(dependency: &str) -> Result { + // Handle dependency exact ref type (`@tag=`, `@branch=` or `@rev=`)`. + // Only extract version for first tag/branch/commit specified. + let url_and_version: Vec<&str> = VERSION_PREFIX_REGEX.split(dependency).collect(); + let dependency = url_and_version[0]; + let mut tag_or_branch = url_and_version.get(1).map(|version| version.to_string()); + // everything before "=" should be considered the alias let (mut alias, dependency) = if let Some(split) = dependency.split_once(ALIAS_SEPARATOR) { (Some(String::from(split.0)), split.1.to_string()) @@ -96,14 +105,15 @@ impl FromStr for Dependency { // `tag` does not contain a slash let mut split = url_with_version.rsplit(VERSION_SEPARATOR); - let mut tag = None; let mut url = url_with_version.as_str(); - let maybe_tag = split.next().unwrap(); - if let Some(actual_url) = split.next() { - if !maybe_tag.contains('/') { - tag = Some(maybe_tag.to_string()); - url = actual_url; + if tag_or_branch.is_none() { + let maybe_tag_or_branch = split.next().unwrap(); + if let Some(actual_url) = split.next() { + if !maybe_tag_or_branch.contains('/') { + tag_or_branch = Some(maybe_tag_or_branch.to_string()); + url = actual_url; + } } } @@ -114,7 +124,7 @@ impl FromStr for Dependency { .ok_or_else(|| eyre::eyre!("no dependency name found"))? .to_string(); - (Some(url), Some(name), tag) + (Some(url), Some(name), tag_or_branch) } else { (None, None, None) }; @@ -360,4 +370,26 @@ mod tests { let dep: Dependency = "org-git12345678@github.com:my-org/my-repo.git".parse().unwrap(); assert_eq!(dep.url.unwrap(), "https://github.com/my-org/my-repo"); } + + #[test] + fn can_parse_with_explicit_ref_type() { + let dep = Dependency::from_str("smartcontractkit/ccip@tag=contracts-ccip/v1.2.1").unwrap(); + assert_eq!(dep.name, "ccip"); + assert_eq!(dep.url, Some("https://github.com/smartcontractkit/ccip".to_string())); + assert_eq!(dep.tag, Some("contracts-ccip/v1.2.1".to_string())); + assert_eq!(dep.alias, None); + + let dep = + Dependency::from_str("smartcontractkit/ccip@branch=contracts-ccip/v1.2.1").unwrap(); + assert_eq!(dep.name, "ccip"); + assert_eq!(dep.url, Some("https://github.com/smartcontractkit/ccip".to_string())); + assert_eq!(dep.tag, Some("contracts-ccip/v1.2.1".to_string())); + assert_eq!(dep.alias, None); + + let dep = Dependency::from_str("smartcontractkit/ccip@rev=80eb41b").unwrap(); + assert_eq!(dep.name, "ccip"); + assert_eq!(dep.url, Some("https://github.com/smartcontractkit/ccip".to_string())); + assert_eq!(dep.tag, Some("80eb41b".to_string())); + assert_eq!(dep.alias, None); + } } diff --git a/crates/forge/bin/cmd/install.rs b/crates/forge/bin/cmd/install.rs index 2567825d45a1..1485bc440942 100644 --- a/crates/forge/bin/cmd/install.rs +++ b/crates/forge/bin/cmd/install.rs @@ -37,6 +37,8 @@ pub struct InstallArgs { /// - A tag: v1.2.3 /// - A commit: 8e8128 /// + /// For exact match, a ref can be provided with `@tag=`, `@branch=` or `@rev=` prefix. + /// /// Target installation directory can be added via `=` suffix. /// The dependency will installed to `lib/`. dependencies: Vec, From 48930a68c583e8c56abd09e8b5af1cdb85367348 Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Tue, 29 Oct 2024 11:02:27 +0100 Subject: [PATCH 11/35] feat: make `--gas-report` w/ `--json` output one JSON blob and add `contract_path` to output (#9216) * show resolved contract name * split out helpers * add basic test for multiple selectors resolve to same name w/ different args * collect JSON gas reports and render it as one blob * update tests * avoid unnecessary nesting of non-overloaded function names --- crates/forge/src/gas_report.rs | 170 ++++++--- crates/forge/tests/cli/cmd.rs | 630 ++++++++++++++++++++++++++++----- 2 files changed, 669 insertions(+), 131 deletions(-) diff --git a/crates/forge/src/gas_report.rs b/crates/forge/src/gas_report.rs index 59c417b97097..6c53bd9e6e75 100644 --- a/crates/forge/src/gas_report.rs +++ b/crates/forge/src/gas_report.rs @@ -9,6 +9,7 @@ use comfy_table::{presets::ASCII_MARKDOWN, *}; use foundry_common::{calc, TestFunctionExt}; use foundry_evm::traces::CallKind; use serde::{Deserialize, Serialize}; +use serde_json::json; use std::{collections::BTreeMap, fmt::Display}; use yansi::Paint; @@ -156,59 +157,136 @@ impl GasReport { impl Display for GasReport { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - for (name, contract) in &self.contracts { - if contract.functions.is_empty() { - trace!(name, "gas report contract without functions"); - continue; - } + match self.report_type { + GasReportKind::Markdown => { + for (name, contract) in &self.contracts { + if contract.functions.is_empty() { + trace!(name, "gas report contract without functions"); + continue; + } - if self.report_type == GasReportKind::JSON { - writeln!(f, "{}", serde_json::to_string(&contract).unwrap())?; - continue; + let table = self.format_table_output(contract, name); + writeln!(f, "{table}")?; + writeln!(f, "\n")?; + } + } + GasReportKind::JSON => { + writeln!(f, "{}", &self.format_json_output())?; } - - let mut table = Table::new(); - table.load_preset(ASCII_MARKDOWN); - table.set_header([Cell::new(format!("{name} contract")) - .add_attribute(Attribute::Bold) - .fg(Color::Green)]); - table.add_row([ - Cell::new("Deployment Cost").add_attribute(Attribute::Bold).fg(Color::Cyan), - Cell::new("Deployment Size").add_attribute(Attribute::Bold).fg(Color::Cyan), - ]); - table.add_row([contract.gas.to_string(), contract.size.to_string()]); - - table.add_row([ - Cell::new("Function Name").add_attribute(Attribute::Bold).fg(Color::Magenta), - Cell::new("min").add_attribute(Attribute::Bold).fg(Color::Green), - Cell::new("avg").add_attribute(Attribute::Bold).fg(Color::Yellow), - Cell::new("median").add_attribute(Attribute::Bold).fg(Color::Yellow), - Cell::new("max").add_attribute(Attribute::Bold).fg(Color::Red), - Cell::new("# calls").add_attribute(Attribute::Bold), - ]); - contract.functions.iter().for_each(|(fname, sigs)| { - sigs.iter().for_each(|(sig, gas_info)| { - // show function signature if overloaded else name - let fn_display = - if sigs.len() == 1 { fname.clone() } else { sig.replace(':', "") }; - - table.add_row([ - Cell::new(fn_display).add_attribute(Attribute::Bold), - Cell::new(gas_info.min.to_string()).fg(Color::Green), - Cell::new(gas_info.mean.to_string()).fg(Color::Yellow), - Cell::new(gas_info.median.to_string()).fg(Color::Yellow), - Cell::new(gas_info.max.to_string()).fg(Color::Red), - Cell::new(gas_info.calls.to_string()), - ]); - }) - }); - writeln!(f, "{table}")?; - writeln!(f, "\n")?; } + Ok(()) } } +impl GasReport { + fn format_json_output(&self) -> String { + #[inline] + fn format_gas_info(gas_info: &GasInfo) -> serde_json::Value { + json!({ + "calls": gas_info.calls, + "min": gas_info.min, + "mean": gas_info.mean, + "median": gas_info.median, + "max": gas_info.max, + }) + } + + serde_json::to_string( + &self + .contracts + .iter() + .filter_map(|(name, contract)| { + if contract.functions.is_empty() { + trace!(name, "gas report contract without functions"); + return None; + } + + let functions = contract + .functions + .iter() + .map(|(fname, sigs)| { + // If there is only one signature, display the gas info directly. + let function_value = if sigs.len() == 1 { + format_gas_info(sigs.values().next().unwrap()) + } else { + // If there are multiple signatures, e.g. overloads like: + // - `foo(uint256)` + // - `foo(int256)` + // display the gas info as a map with the signature as the key. + let signatures = sigs + .iter() + .map(|(sig, gas_info)| { + let display_name = sig.replace(':', ""); + (display_name, format_gas_info(gas_info)) + }) + .collect::>(); + + json!(signatures) + }; + + (fname.to_string(), function_value) + }) + .collect::>(); + + Some(json!({ + "contract": name, + "deployment": { + "gas": contract.gas, + "size": contract.size, + }, + "functions": functions, + })) + }) + .collect::>(), + ) + .unwrap() + } + + // Helper function to format the table output + fn format_table_output(&self, contract: &ContractInfo, name: &str) -> Table { + let mut table = Table::new(); + table.load_preset(ASCII_MARKDOWN); + table.set_header([Cell::new(format!("{name} contract")) + .add_attribute(Attribute::Bold) + .fg(Color::Green)]); + + table.add_row([ + Cell::new("Deployment Cost").add_attribute(Attribute::Bold).fg(Color::Cyan), + Cell::new("Deployment Size").add_attribute(Attribute::Bold).fg(Color::Cyan), + ]); + table.add_row([contract.gas.to_string(), contract.size.to_string()]); + + table.add_row([ + Cell::new("Function Name").add_attribute(Attribute::Bold).fg(Color::Magenta), + Cell::new("min").add_attribute(Attribute::Bold).fg(Color::Green), + Cell::new("avg").add_attribute(Attribute::Bold).fg(Color::Yellow), + Cell::new("median").add_attribute(Attribute::Bold).fg(Color::Yellow), + Cell::new("max").add_attribute(Attribute::Bold).fg(Color::Red), + Cell::new("# calls").add_attribute(Attribute::Bold), + ]); + + contract.functions.iter().for_each(|(fname, sigs)| { + sigs.iter().for_each(|(sig, gas_info)| { + // Show function signature if overloaded else display function name. + let display_name = + if sigs.len() == 1 { fname.to_string() } else { sig.replace(':', "") }; + + table.add_row([ + Cell::new(display_name).add_attribute(Attribute::Bold), + Cell::new(gas_info.min.to_string()).fg(Color::Green), + Cell::new(gas_info.mean.to_string()).fg(Color::Yellow), + Cell::new(gas_info.median.to_string()).fg(Color::Yellow), + Cell::new(gas_info.max.to_string()).fg(Color::Red), + Cell::new(gas_info.calls.to_string()), + ]); + }) + }); + + table + } +} + #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct ContractInfo { pub gas: u64, diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 6177e973dce6..48b73ac626ec 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -1591,16 +1591,61 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ); prj.write_config(Config { gas_reports: (vec![]), ..Default::default() }); cmd.forge_fuse().arg("test").arg("--gas-report").assert_success().stdout_eq(str![[r#" @@ -1630,16 +1675,61 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ); prj.write_config(Config { gas_reports: (vec!["*".to_string()]), ..Default::default() }); cmd.forge_fuse().arg("test").arg("--gas-report").assert_success().stdout_eq(str![[r#" @@ -1669,16 +1759,61 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ); prj.write_config(Config { gas_reports: (vec![ @@ -1715,16 +1850,61 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ); }); forgetest!(gas_report_some_contracts, |prj, cmd| { @@ -1745,14 +1925,29 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + } +] +"#]] + .is_json(), + ); // report for Two prj.write_config(Config { gas_reports: vec!["ContractTwo".to_string()], ..Default::default() }); @@ -1770,8 +1965,26 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { "#]]); cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( str![[r#" -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines(), +[ + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), ); // report for Three @@ -1791,17 +2004,32 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + } +] +"#]] + .is_json(), + ); }); -forgetest!(gas_ignore_some_contracts, |prj, cmd| { +forgetest!(gas_report_ignore_some_contracts, |prj, cmd| { prj.insert_ds_test(); prj.add_source("Contracts.sol", GAS_REPORT_CONTRACTS).unwrap(); @@ -1831,15 +2059,45 @@ forgetest!(gas_ignore_some_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ); // ignore ContractTwo cmd.forge_fuse(); @@ -1868,17 +2126,51 @@ forgetest!(gas_ignore_some_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + } +] +"#]] + .is_json(), + ); - // ignore ContractThree + // If the user listed the contract in 'gas_reports' (the foundry.toml field) a + // report for the contract is generated even if it's listed in the ignore + // list. This is addressed this way because getting a report you don't expect is + // preferable than not getting one you expect. A warning is printed to stderr + // indicating the "double listing". cmd.forge_fuse(); prj.write_config(Config { gas_reports: (vec![ @@ -1890,7 +2182,10 @@ forgetest!(gas_ignore_some_contracts, |prj, cmd| { ..Default::default() }); cmd.forge_fuse(); - cmd.arg("test").arg("--gas-report").assert_success().stdout_eq(str![[r#" + cmd.arg("test") + .arg("--gas-report") + .assert_success() + .stdout_eq(str![[r#" ... | src/Contracts.sol:ContractOne contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| @@ -1915,18 +2210,183 @@ forgetest!(gas_ignore_some_contracts, |prj, cmd| { | Function Name | min | avg | median | max | # calls | | bar | 64984 | 64984 | 64984 | 64984 | 1 | ... - +"#]]) + .stderr_eq(str![[r#" +... +warning: ContractThree is listed in both 'gas_reports' and 'gas_reports_ignore'. +... "#]]); cmd.forge_fuse() .arg("test") .arg("--gas-report") .arg("--json") .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + .stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ) + .stderr_eq(str![[r#" +... +warning: ContractThree is listed in both 'gas_reports' and 'gas_reports_ignore'. +... +"#]]); +}); + +forgetest!(gas_report_multiple_selectors, |prj, cmd| { + prj.insert_ds_test(); + prj.add_source( + "Counter.sol", + r#" +contract Counter { + uint256 public a; + int256 public b; + + function setNumber(uint256 x) public { + a = x; + } + + function setNumber(int256 x) public { + b = x; + } +} +"#, + ) + .unwrap(); + + prj.add_source( + "CounterTest.t.sol", + r#" +import "./test.sol"; +import {Counter} from "./Counter.sol"; + +contract CounterTest is DSTest { + Counter public counter; + + function setUp() public { + counter = new Counter(); + counter.setNumber(uint256(0)); + counter.setNumber(int256(0)); + } + + function test_Increment() public { + counter.setNumber(uint256(counter.a() + 1)); + counter.setNumber(int256(counter.b() + 1)); + } +} +"#, + ) + .unwrap(); + + cmd.arg("test").arg("--gas-report").assert_success().stdout_eq(str![[r#" +... +| src/Counter.sol:Counter contract | | | | | | +|----------------------------------|-----------------|-------|--------|-------|---------| +| Deployment Cost | Deployment Size | | | | | +| 101137 | 250 | | | | | +| Function Name | min | avg | median | max | # calls | +| a | 2261 | 2261 | 2261 | 2261 | 1 | +| b | 2305 | 2305 | 2305 | 2305 | 1 | +| setNumber(int256) | 23648 | 33604 | 33604 | 43560 | 2 | +| setNumber(uint256) | 23604 | 33560 | 33560 | 43516 | 2 | +... +"#]]); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Counter.sol:Counter", + "deployment": { + "gas": 101137, + "size": 250 + }, + "functions": { + "a": { + "calls": 1, + "min": 2261, + "mean": 2261, + "median": 2261, + "max": 2261 + }, + "b": { + "calls": 1, + "min": 2305, + "mean": 2305, + "median": 2305, + "max": 2305 + }, + "setNumber": { + "setNumber(int256)": { + "calls": 2, + "min": 23648, + "mean": 33604, + "median": 33604, + "max": 43560 + }, + "setNumber(uint256)": { + "calls": 2, + "min": 23604, + "mean": 33560, + "median": 33560, + "max": 43516 + } + } + } + } +] +"#]] + .is_json(), + ); }); forgetest_init!(can_use_absolute_imports, |prj, cmd| { From dd443c6c0b017718a97a2302328e61f5c01582c2 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:56:51 +0200 Subject: [PATCH 12/35] fix(forge create): set skip_is_verified_check: true (#9222) fix(verify): set skip_is_verified_check: true for deploy (similar to broadcast) --- crates/forge/bin/cmd/create.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/forge/bin/cmd/create.rs b/crates/forge/bin/cmd/create.rs index 1962f41f6d0c..0cbc389c2ffd 100644 --- a/crates/forge/bin/cmd/create.rs +++ b/crates/forge/bin/cmd/create.rs @@ -350,7 +350,7 @@ impl CreateArgs { rpc: Default::default(), flatten: false, force: false, - skip_is_verified_check: false, + skip_is_verified_check: true, watch: true, retry: self.retry, libraries: self.opts.libraries.clone(), From 3e901afcdc5dd22755ebe8ebdb288a6af756c8eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Urbanek?= Date: Tue, 29 Oct 2024 15:45:26 +0100 Subject: [PATCH 13/35] feat(cast) add creation-code method [#8973] (#9029) * feat(cast) add creation-code method [#8973] * Fix typo * Fix CI * Code review fixes * Add creation-code flags and creation-args * Update comments * eyre style fixes * typo * use r#".."# for snapbox * Apply suggestions from code review * fix test regression * tag arguments as mutually exclusive * use unreachable! * Rename and add abi_path param * Decode constructor args * Update crates/cast/bin/cmd/constructor_args.rs * fix test * Update crates/cast/bin/args.rs Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> * Update crates/cast/bin/cmd/creation_code.rs Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> * Update crates/cast/bin/cmd/creation_code.rs Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> * Fix formatting * Code review fixes --------- Co-authored-by: zerosnacks Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- crates/cast/Cargo.toml | 9 +- crates/cast/bin/args.rs | 11 +- crates/cast/bin/cmd/constructor_args.rs | 100 ++++++++++++++ crates/cast/bin/cmd/creation_code.rs | 167 ++++++++++++++++++++++++ crates/cast/bin/cmd/interface.rs | 4 +- crates/cast/bin/cmd/mod.rs | 2 + crates/cast/bin/main.rs | 2 + crates/cast/tests/cli/main.rs | 58 ++++++++ 8 files changed, 348 insertions(+), 5 deletions(-) create mode 100644 crates/cast/bin/cmd/constructor_args.rs create mode 100644 crates/cast/bin/cmd/creation_code.rs diff --git a/crates/cast/Cargo.toml b/crates/cast/Cargo.toml index 5fadb49675ce..4e6b001ecfaf 100644 --- a/crates/cast/Cargo.toml +++ b/crates/cast/Cargo.toml @@ -44,9 +44,14 @@ alloy-json-abi.workspace = true alloy-json-rpc.workspace = true alloy-network.workspace = true alloy-primitives.workspace = true -alloy-provider = { workspace = true, features = ["reqwest", "ws", "ipc"] } +alloy-provider = { workspace = true, features = [ + "reqwest", + "ws", + "ipc", + "trace-api", +] } alloy-rlp.workspace = true -alloy-rpc-types = { workspace = true, features = ["eth"] } +alloy-rpc-types = { workspace = true, features = ["eth", "trace"] } alloy-serde.workspace = true alloy-signer-local = { workspace = true, features = ["mnemonic", "keystore"] } alloy-signer.workspace = true diff --git a/crates/cast/bin/args.rs b/crates/cast/bin/args.rs index 386201e5b0ee..7552c3bd5f03 100644 --- a/crates/cast/bin/args.rs +++ b/crates/cast/bin/args.rs @@ -1,5 +1,6 @@ use crate::cmd::{ - access_list::AccessListArgs, bind::BindArgs, call::CallArgs, create2::Create2Args, + access_list::AccessListArgs, bind::BindArgs, call::CallArgs, + constructor_args::ConstructorArgsArgs, create2::Create2Args, creation_code::CreationCodeArgs, estimate::EstimateArgs, find_block::FindBlockArgs, interface::InterfaceArgs, logs::LogsArgs, mktx::MakeTxArgs, rpc::RpcArgs, run::RunArgs, send::SendTxArgs, storage::StorageArgs, wallet::WalletSubcommands, @@ -937,6 +938,14 @@ pub enum CastSubcommand { command: WalletSubcommands, }, + /// Download a contract creation code from Etherscan and RPC. + #[command(visible_alias = "cc")] + CreationCode(CreationCodeArgs), + + /// Display constructor arguments used for the contract initialization. + #[command(visible_alias = "cra")] + ConstructorArgs(ConstructorArgsArgs), + /// Generate a Solidity interface from a given ABI. /// /// Currently does not support ABI encoder v2. diff --git a/crates/cast/bin/cmd/constructor_args.rs b/crates/cast/bin/cmd/constructor_args.rs new file mode 100644 index 000000000000..b0a08704fb3c --- /dev/null +++ b/crates/cast/bin/cmd/constructor_args.rs @@ -0,0 +1,100 @@ +use alloy_dyn_abi::DynSolType; +use alloy_primitives::{Address, Bytes}; +use clap::{command, Parser}; +use eyre::{eyre, OptionExt, Result}; +use foundry_block_explorers::Client; +use foundry_cli::{ + opts::{EtherscanOpts, RpcOpts}, + utils, +}; +use foundry_config::Config; + +use super::{ + creation_code::fetch_creation_code, + interface::{fetch_abi_from_etherscan, load_abi_from_file}, +}; + +/// CLI arguments for `cast creation-args`. +#[derive(Parser)] +pub struct ConstructorArgsArgs { + /// An Ethereum address, for which the bytecode will be fetched. + contract: Address, + + /// Path to file containing the contract's JSON ABI. It's necessary if the target contract is + /// not verified on Etherscan + #[arg(long)] + abi_path: Option, + + #[command(flatten)] + etherscan: EtherscanOpts, + + #[command(flatten)] + rpc: RpcOpts, +} + +impl ConstructorArgsArgs { + pub async fn run(self) -> Result<()> { + let Self { contract, etherscan, rpc, abi_path } = self; + + let config = Config::from(ðerscan); + let chain = config.chain.unwrap_or_default(); + let api_key = config.get_etherscan_api_key(Some(chain)).unwrap_or_default(); + let client = Client::new(chain, api_key)?; + + let config = Config::from(&rpc); + let provider = utils::get_provider(&config)?; + + let bytecode = fetch_creation_code(contract, client, provider).await?; + + let args_arr = parse_constructor_args(bytecode, contract, ðerscan, abi_path).await?; + for arg in args_arr { + let _ = sh_println!("{arg}"); + } + + Ok(()) + } +} + +/// Fetches the constructor arguments values and types from the creation bytecode and ABI. +async fn parse_constructor_args( + bytecode: Bytes, + contract: Address, + etherscan: &EtherscanOpts, + abi_path: Option, +) -> Result> { + let abi = if let Some(abi_path) = abi_path { + load_abi_from_file(&abi_path, None)? + } else { + fetch_abi_from_etherscan(contract, etherscan).await? + }; + + let abi = abi.into_iter().next().ok_or_eyre("No ABI found.")?; + let (abi, _) = abi; + + let constructor = abi.constructor.ok_or_else(|| eyre!("No constructor found."))?; + + if constructor.inputs.is_empty() { + return Err(eyre!("No constructor arguments found.")); + } + + let args_size = constructor.inputs.len() * 32; + let args_bytes = Bytes::from(bytecode[bytecode.len() - args_size..].to_vec()); + + let display_args: Vec = args_bytes + .chunks(32) + .enumerate() + .map(|(i, arg)| { + format_arg(&constructor.inputs[i].ty, arg).expect("Failed to format argument.") + }) + .collect(); + + Ok(display_args) +} + +fn format_arg(ty: &str, arg: &[u8]) -> Result { + let arg_type: DynSolType = ty.parse().expect("Invalid ABI type."); + let decoded = arg_type.abi_decode(arg)?; + let bytes = Bytes::from(arg.to_vec()); + + Ok(format!("{bytes} → {decoded:?}")) +} diff --git a/crates/cast/bin/cmd/creation_code.rs b/crates/cast/bin/cmd/creation_code.rs new file mode 100644 index 000000000000..bcafeac9488a --- /dev/null +++ b/crates/cast/bin/cmd/creation_code.rs @@ -0,0 +1,167 @@ +use alloy_primitives::{Address, Bytes}; +use alloy_provider::{ext::TraceApi, Provider}; +use alloy_rpc_types::trace::parity::{Action, CreateAction, CreateOutput, TraceOutput}; +use cast::SimpleCast; +use clap::{command, Parser}; +use eyre::{eyre, OptionExt, Result}; +use foundry_block_explorers::Client; +use foundry_cli::{ + opts::{EtherscanOpts, RpcOpts}, + utils, +}; +use foundry_common::provider::RetryProvider; +use foundry_config::Config; + +use super::interface::{fetch_abi_from_etherscan, load_abi_from_file}; + +/// CLI arguments for `cast creation-code`. +#[derive(Parser)] +pub struct CreationCodeArgs { + /// An Ethereum address, for which the bytecode will be fetched. + contract: Address, + + /// Path to file containing the contract's JSON ABI. It's necessary if the target contract is + /// not verified on Etherscan. + #[arg(long)] + abi_path: Option, + + /// Disassemble bytecodes into individual opcodes. + #[arg(long)] + disassemble: bool, + + /// Return creation bytecode without constructor arguments appended. + #[arg(long, conflicts_with = "only_args")] + without_args: bool, + + /// Return only constructor arguments. + #[arg(long)] + only_args: bool, + + #[command(flatten)] + etherscan: EtherscanOpts, + + #[command(flatten)] + rpc: RpcOpts, +} + +impl CreationCodeArgs { + pub async fn run(self) -> Result<()> { + let Self { contract, etherscan, rpc, disassemble, without_args, only_args, abi_path } = + self; + + let config = Config::from(ðerscan); + let chain = config.chain.unwrap_or_default(); + let api_key = config.get_etherscan_api_key(Some(chain)).unwrap_or_default(); + let client = Client::new(chain, api_key)?; + + let config = Config::from(&rpc); + let provider = utils::get_provider(&config)?; + + let bytecode = fetch_creation_code(contract, client, provider).await?; + + let bytecode = + parse_code_output(bytecode, contract, ðerscan, abi_path, without_args, only_args) + .await?; + + if disassemble { + let _ = sh_println!("{}", SimpleCast::disassemble(&bytecode)?); + } else { + let _ = sh_println!("{bytecode}"); + } + + Ok(()) + } +} + +/// Parses the creation bytecode and returns one of the following: +/// - The complete bytecode +/// - The bytecode without constructor arguments +/// - Only the constructor arguments +async fn parse_code_output( + bytecode: Bytes, + contract: Address, + etherscan: &EtherscanOpts, + abi_path: Option, + without_args: bool, + only_args: bool, +) -> Result { + if !without_args && !only_args { + return Ok(bytecode); + } + + let abi = if let Some(abi_path) = abi_path { + load_abi_from_file(&abi_path, None)? + } else { + fetch_abi_from_etherscan(contract, etherscan).await? + }; + + let abi = abi.into_iter().next().ok_or_eyre("No ABI found.")?; + let (abi, _) = abi; + + if abi.constructor.is_none() { + if only_args { + return Err(eyre!("No constructor found.")); + } + return Ok(bytecode); + } + + let constructor = abi.constructor.unwrap(); + if constructor.inputs.is_empty() { + if only_args { + return Err(eyre!("No constructor arguments found.")); + } + return Ok(bytecode); + } + + let args_size = constructor.inputs.len() * 32; + + let bytecode = if without_args { + Bytes::from(bytecode[..bytecode.len() - args_size].to_vec()) + } else if only_args { + Bytes::from(bytecode[bytecode.len() - args_size..].to_vec()) + } else { + unreachable!(); + }; + + Ok(bytecode) +} + +/// Fetches the creation code of a contract from Etherscan and RPC. +pub async fn fetch_creation_code( + contract: Address, + client: Client, + provider: RetryProvider, +) -> Result { + 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?; + let tx_data = tx_data.ok_or_eyre("Could not find creation tx data.")?; + + let bytecode = if tx_data.inner.to.is_none() { + // Contract was created using a standard transaction + tx_data.inner.input + } else { + // Contract was created using a factory pattern or create2 + // Extract creation code from tx traces + let mut creation_bytecode = None; + + let traces = provider.trace_transaction(creation_tx_hash).await.map_err(|e| { + eyre!("Could not fetch traces for transaction {}: {}", creation_tx_hash, e) + })?; + + for trace in traces { + if let Some(TraceOutput::Create(CreateOutput { address, .. })) = trace.trace.result { + if address == contract { + creation_bytecode = match trace.trace.action { + Action::Create(CreateAction { init, .. }) => Some(init), + _ => None, + }; + } + } + } + + creation_bytecode.ok_or_else(|| eyre!("Could not find contract creation trace."))? + }; + + Ok(bytecode) +} diff --git a/crates/cast/bin/cmd/interface.rs b/crates/cast/bin/cmd/interface.rs index 1d9b392964b5..45df4983e4f0 100644 --- a/crates/cast/bin/cmd/interface.rs +++ b/crates/cast/bin/cmd/interface.rs @@ -108,7 +108,7 @@ struct InterfaceSource { } /// Load the ABI from a file. -fn load_abi_from_file(path: &str, name: Option) -> Result> { +pub fn load_abi_from_file(path: &str, name: Option) -> Result> { let file = std::fs::read_to_string(path).wrap_err("unable to read abi file")?; let obj: ContractObject = serde_json::from_str(&file)?; let abi = obj.abi.ok_or_else(|| eyre::eyre!("could not find ABI in file {path}"))?; @@ -139,7 +139,7 @@ fn load_abi_from_artifact(path_or_contract: &str) -> Result Result> { diff --git a/crates/cast/bin/cmd/mod.rs b/crates/cast/bin/cmd/mod.rs index 6c904417407c..49e3ed2efe96 100644 --- a/crates/cast/bin/cmd/mod.rs +++ b/crates/cast/bin/cmd/mod.rs @@ -8,7 +8,9 @@ pub mod access_list; pub mod bind; pub mod call; +pub mod constructor_args; pub mod create2; +pub mod creation_code; pub mod estimate; pub mod find_block; pub mod interface; diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index 0338d9ff26f0..a7cd013c8b2f 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -206,6 +206,8 @@ async fn main_args(args: CastArgs) -> Result<()> { sh_println!("{}", SimpleCast::calldata_encode(sig, &args)?)?; } CastSubcommand::Interface(cmd) => cmd.run().await?, + CastSubcommand::CreationCode(cmd) => cmd.run().await?, + CastSubcommand::ConstructorArgs(cmd) => cmd.run().await?, CastSubcommand::Bind(cmd) => cmd.run().await?, CastSubcommand::PrettyCalldata { calldata, offline } => { let calldata = stdin::unwrap_line(calldata)?; diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 6d5a6fd6a821..9ff8a6d49c6d 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -1435,3 +1435,61 @@ casttest!(format_units, |_prj, cmd| { "#]]); }); + +// tests that fetches a sample contract creation code +// +casttest!(fetch_creation_code_from_etherscan, |_prj, cmd| { + let eth_rpc_url = next_http_rpc_endpoint(); + cmd.args([ + "creation-code", + "--etherscan-api-key", + &next_mainnet_etherscan_api_key(), + "0x0923cad07f06b2d0e5e49e63b8b35738d4156b95", + "--rpc-url", + eth_rpc_url.as_str(), + ]) + .assert_success() + .stdout_eq(str![[r#" +0x60566050600b82828239805160001a6073146043577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122074c61e8e4eefd410ca92eec26e8112ec6e831d0a4bf35718fdd78b45d68220d064736f6c63430008070033 + +"#]]); +}); + +// tests that fetches a sample contract creation args bytes +// +casttest!(fetch_creation_code_only_args_from_etherscan, |_prj, cmd| { + let eth_rpc_url = next_http_rpc_endpoint(); + cmd.args([ + "creation-code", + "--etherscan-api-key", + &next_mainnet_etherscan_api_key(), + "0x6982508145454ce325ddbe47a25d4ec3d2311933", + "--rpc-url", + eth_rpc_url.as_str(), + "--only-args", + ]) + .assert_success() + .stdout_eq(str![[r#" +0x00000000000000000000000000000000000014bddab3e51a57cff87a50000000 + +"#]]); +}); + +// tests that displays a sample contract creation args +// +casttest!(fetch_constructor_args_from_etherscan, |_prj, cmd| { + let eth_rpc_url = next_http_rpc_endpoint(); + cmd.args([ + "constructor-args", + "--etherscan-api-key", + &next_mainnet_etherscan_api_key(), + "0x6982508145454ce325ddbe47a25d4ec3d2311933", + "--rpc-url", + eth_rpc_url.as_str(), + ]) + .assert_success() + .stdout_eq(str![[r#" +0x00000000000000000000000000000000000014bddab3e51a57cff87a50000000 → Uint(420690000000000000000000000000000, 256) + +"#]]); +}); From 4389cbc0146e2f1a5fc663d6ceaa80ec722871ca Mon Sep 17 00:00:00 2001 From: Karrq Date: Tue, 29 Oct 2024 15:49:35 +0100 Subject: [PATCH 14/35] refactor: simplify `merge_db_account_data` (#9223) * refactor: simplify `merge_db_account_data` * chore: fmt --- crates/evm/core/src/backend/mod.rs | 42 +++++++++++++++++------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index b08d5fd44b60..e0b35f0bd07b 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -1877,25 +1877,31 @@ fn merge_db_account_data( ) { trace!(?addr, "merging database data"); - let mut acc = if let Some(acc) = active.accounts.get(&addr).cloned() { - acc - } else { - // Account does not exist - return; - }; - - if let Some(code) = active.contracts.get(&acc.info.code_hash).cloned() { - fork_db.contracts.insert(acc.info.code_hash, code); - } - - if let Some(fork_account) = fork_db.accounts.get_mut(&addr) { - // This will merge the fork's tracked storage with active storage and update values - fork_account.storage.extend(std::mem::take(&mut acc.storage)); - // swap them so we can insert the account as whole in the next step - std::mem::swap(&mut fork_account.storage, &mut acc.storage); + let Some(acc) = active.accounts.get(&addr) else { return }; + + // port contract cache over + if let Some(code) = active.contracts.get(&acc.info.code_hash) { + trace!("merging contract cache"); + fork_db.contracts.insert(acc.info.code_hash, code.clone()); + } + + // port account storage over + use std::collections::hash_map::Entry; + match fork_db.accounts.entry(addr) { + Entry::Vacant(vacant) => { + trace!("target account not present - inserting from active"); + // if the fork_db doesn't have the target account + // insert the entire thing + vacant.insert(acc.clone()); + } + Entry::Occupied(mut occupied) => { + trace!("target account present - merging storage slots"); + // if the fork_db does have the system, + // extend the existing storage (overriding) + let fork_account = occupied.get_mut(); + fork_account.storage.extend(&acc.storage); + } } - - fork_db.accounts.insert(addr, acc); } /// Returns true of the address is a contract From 0c703053fd272b505f40b62962dbd682cacd0adb Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 29 Oct 2024 20:15:42 +0100 Subject: [PATCH 15/35] test: update test (#9226) --- crates/forge/tests/cli/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index f492de01d1f3..d7860381cb19 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -261,7 +261,7 @@ forgetest_init!(can_parse_remappings_correctly, |prj, cmd| { cmd.forge_fuse().args(["install", dep, "--no-commit"]).assert_success().stdout_eq(str![[ r#" Installing solmate in [..] (url: Some("https://github.com/transmissions11/solmate"), tag: None) - Installed solmate + Installed solmate[..] "# ]]); From 95015894110734539c53ffad97cd64ca116fce5e Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 29 Oct 2024 20:25:37 +0100 Subject: [PATCH 16/35] style: smol refactor (#9224) --- crates/forge/bin/cmd/create.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/crates/forge/bin/cmd/create.rs b/crates/forge/bin/cmd/create.rs index 0cbc389c2ffd..23fb0922ec35 100644 --- a/crates/forge/bin/cmd/create.rs +++ b/crates/forge/bin/cmd/create.rs @@ -128,20 +128,19 @@ impl CreateArgs { }; // Add arguments to constructor - let provider = utils::get_provider(&config)?; - let params = match abi.constructor { - Some(ref v) => { - let constructor_args = - if let Some(ref constructor_args_path) = self.constructor_args_path { - read_constructor_args_file(constructor_args_path.to_path_buf())? - } else { - self.constructor_args.clone() - }; - self.parse_constructor_args(v, &constructor_args)? - } - None => vec![], + let params = if let Some(constructor) = &abi.constructor { + let constructor_args = + self.constructor_args_path.clone().map(read_constructor_args_file).transpose()?; + self.parse_constructor_args( + constructor, + constructor_args.as_deref().unwrap_or(&self.constructor_args), + )? + } else { + vec![] }; + let provider = utils::get_provider(&config)?; + // respect chain, if set explicitly via cmd args let chain_id = if let Some(chain_id) = self.chain_id() { chain_id From 4012adefd376bd618d1348398c1da07224d2dace Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Wed, 30 Oct 2024 10:16:02 +0100 Subject: [PATCH 17/35] fix: allow_hyphen_values for constructor args (#9225) * fix: unescape ints * use allow_hyp --- crates/forge/bin/cmd/create.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/crates/forge/bin/cmd/create.rs b/crates/forge/bin/cmd/create.rs index 23fb0922ec35..e9f6cac745e1 100644 --- a/crates/forge/bin/cmd/create.rs +++ b/crates/forge/bin/cmd/create.rs @@ -45,6 +45,7 @@ pub struct CreateArgs { num_args(1..), conflicts_with = "constructor_args_path", value_name = "ARGS", + allow_hyphen_values = true, )] constructor_args: Vec, @@ -633,6 +634,7 @@ impl From for ContractDeploymentError { #[cfg(test)] mod tests { use super::*; + use alloy_primitives::I256; #[test] fn can_parse_create() { @@ -688,4 +690,17 @@ mod tests { let constructor: Constructor = serde_json::from_str(r#"{"type":"constructor","inputs":[{"name":"_points","type":"tuple[]","internalType":"struct Point[]","components":[{"name":"x","type":"uint256","internalType":"uint256"},{"name":"y","type":"uint256","internalType":"uint256"}]}],"stateMutability":"nonpayable"}"#).unwrap(); let _params = args.parse_constructor_args(&constructor, &args.constructor_args).unwrap(); } + + #[test] + fn test_parse_int_constructor_args() { + let args: CreateArgs = CreateArgs::parse_from([ + "foundry-cli", + "src/Domains.sol:Domains", + "--constructor-args", + "-5", + ]); + let constructor: Constructor = serde_json::from_str(r#"{"type":"constructor","inputs":[{"name":"_name","type":"int256","internalType":"int256"}],"stateMutability":"nonpayable"}"#).unwrap(); + let params = args.parse_constructor_args(&constructor, &args.constructor_args).unwrap(); + assert_eq!(params, vec![DynSolValue::Int(I256::unchecked_from(-5), 256)]); + } } From ec2fd7d1ab7412c54b742a24336de05505bf2ff2 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Wed, 30 Oct 2024 11:10:51 +0100 Subject: [PATCH 18/35] chore(meta): update SECURITY.md (#9230) --- SECURITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index 5260d529f5a4..bea27ad1140c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,4 +2,4 @@ ## Reporting a Vulnerability -Contact georgios at paradigm.xyz. +Contact [security@ithaca.xyz](mailto:security@ithaca.xyz). From 748af798223bd24e95394795109a0e683b42690c Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Wed, 30 Oct 2024 11:29:58 +0100 Subject: [PATCH 19/35] fix(`--gas-report`): add back signatures, even if empty, avoid nesting multiple selectors (#9229) * add back signatures, even if empty, flatten multiple selectors per feedback https://github.com/foundry-rs/foundry/pull/9216#issuecomment-2445386251 * avoid manually serializing `gas_info`, already implements serialize --- crates/forge/src/gas_report.rs | 37 +++------------- crates/forge/tests/cli/cmd.rs | 78 +++++++++++++++++----------------- 2 files changed, 43 insertions(+), 72 deletions(-) diff --git a/crates/forge/src/gas_report.rs b/crates/forge/src/gas_report.rs index 6c53bd9e6e75..ac2d0db00262 100644 --- a/crates/forge/src/gas_report.rs +++ b/crates/forge/src/gas_report.rs @@ -181,17 +181,6 @@ impl Display for GasReport { impl GasReport { fn format_json_output(&self) -> String { - #[inline] - fn format_gas_info(gas_info: &GasInfo) -> serde_json::Value { - json!({ - "calls": gas_info.calls, - "min": gas_info.min, - "mean": gas_info.mean, - "median": gas_info.median, - "max": gas_info.max, - }) - } - serde_json::to_string( &self .contracts @@ -205,27 +194,11 @@ impl GasReport { let functions = contract .functions .iter() - .map(|(fname, sigs)| { - // If there is only one signature, display the gas info directly. - let function_value = if sigs.len() == 1 { - format_gas_info(sigs.values().next().unwrap()) - } else { - // If there are multiple signatures, e.g. overloads like: - // - `foo(uint256)` - // - `foo(int256)` - // display the gas info as a map with the signature as the key. - let signatures = sigs - .iter() - .map(|(sig, gas_info)| { - let display_name = sig.replace(':', ""); - (display_name, format_gas_info(gas_info)) - }) - .collect::>(); - - json!(signatures) - }; - - (fname.to_string(), function_value) + .flat_map(|(_, sigs)| { + sigs.iter().map(|(sig, gas_info)| { + let display_name = sig.replace(':', ""); + (display_name, gas_info) + }) }) .collect::>(); diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 48b73ac626ec..f34d0e2dec5d 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -1601,7 +1601,7 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { "size": 255 }, "functions": { - "foo": { + "foo()": { "calls": 1, "min": 45387, "mean": 45387, @@ -1617,7 +1617,7 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { "size": 256 }, "functions": { - "baz": { + "baz()": { "calls": 1, "min": 260712, "mean": 260712, @@ -1633,7 +1633,7 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { "size": 255 }, "functions": { - "bar": { + "bar()": { "calls": 1, "min": 64984, "mean": 64984, @@ -1685,7 +1685,7 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { "size": 255 }, "functions": { - "foo": { + "foo()": { "calls": 1, "min": 45387, "mean": 45387, @@ -1701,7 +1701,7 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { "size": 256 }, "functions": { - "baz": { + "baz()": { "calls": 1, "min": 260712, "mean": 260712, @@ -1717,7 +1717,7 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { "size": 255 }, "functions": { - "bar": { + "bar()": { "calls": 1, "min": 64984, "mean": 64984, @@ -1769,7 +1769,7 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { "size": 255 }, "functions": { - "foo": { + "foo()": { "calls": 1, "min": 45387, "mean": 45387, @@ -1785,7 +1785,7 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { "size": 256 }, "functions": { - "baz": { + "baz()": { "calls": 1, "min": 260712, "mean": 260712, @@ -1801,7 +1801,7 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { "size": 255 }, "functions": { - "bar": { + "bar()": { "calls": 1, "min": 64984, "mean": 64984, @@ -1860,7 +1860,7 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { "size": 255 }, "functions": { - "foo": { + "foo()": { "calls": 1, "min": 45387, "mean": 45387, @@ -1876,7 +1876,7 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { "size": 256 }, "functions": { - "baz": { + "baz()": { "calls": 1, "min": 260712, "mean": 260712, @@ -1892,7 +1892,7 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { "size": 255 }, "functions": { - "bar": { + "bar()": { "calls": 1, "min": 64984, "mean": 64984, @@ -1935,7 +1935,7 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { "size": 255 }, "functions": { - "foo": { + "foo()": { "calls": 1, "min": 45387, "mean": 45387, @@ -1973,7 +1973,7 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { "size": 255 }, "functions": { - "bar": { + "bar()": { "calls": 1, "min": 64984, "mean": 64984, @@ -2014,7 +2014,7 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { "size": 256 }, "functions": { - "baz": { + "baz()": { "calls": 1, "min": 260712, "mean": 260712, @@ -2069,7 +2069,7 @@ forgetest!(gas_report_ignore_some_contracts, |prj, cmd| { "size": 256 }, "functions": { - "baz": { + "baz()": { "calls": 1, "min": 260712, "mean": 260712, @@ -2085,7 +2085,7 @@ forgetest!(gas_report_ignore_some_contracts, |prj, cmd| { "size": 255 }, "functions": { - "bar": { + "bar()": { "calls": 1, "min": 64984, "mean": 64984, @@ -2136,7 +2136,7 @@ forgetest!(gas_report_ignore_some_contracts, |prj, cmd| { "size": 255 }, "functions": { - "foo": { + "foo()": { "calls": 1, "min": 45387, "mean": 45387, @@ -2152,7 +2152,7 @@ forgetest!(gas_report_ignore_some_contracts, |prj, cmd| { "size": 256 }, "functions": { - "baz": { + "baz()": { "calls": 1, "min": 260712, "mean": 260712, @@ -2231,7 +2231,7 @@ warning: ContractThree is listed in both 'gas_reports' and 'gas_reports_ignore'. "size": 255 }, "functions": { - "foo": { + "foo()": { "calls": 1, "min": 45387, "mean": 45387, @@ -2247,7 +2247,7 @@ warning: ContractThree is listed in both 'gas_reports' and 'gas_reports_ignore'. "size": 256 }, "functions": { - "baz": { + "baz()": { "calls": 1, "min": 260712, "mean": 260712, @@ -2263,7 +2263,7 @@ warning: ContractThree is listed in both 'gas_reports' and 'gas_reports_ignore'. "size": 255 }, "functions": { - "bar": { + "bar()": { "calls": 1, "min": 64984, "mean": 64984, @@ -2283,7 +2283,7 @@ warning: ContractThree is listed in both 'gas_reports' and 'gas_reports_ignore'. "#]]); }); -forgetest!(gas_report_multiple_selectors, |prj, cmd| { +forgetest!(gas_report_flatten_multiple_selectors, |prj, cmd| { prj.insert_ds_test(); prj.add_source( "Counter.sol", @@ -2351,35 +2351,33 @@ contract CounterTest is DSTest { "size": 250 }, "functions": { - "a": { + "a()": { "calls": 1, "min": 2261, "mean": 2261, "median": 2261, "max": 2261 }, - "b": { + "b()": { "calls": 1, "min": 2305, "mean": 2305, "median": 2305, "max": 2305 }, - "setNumber": { - "setNumber(int256)": { - "calls": 2, - "min": 23648, - "mean": 33604, - "median": 33604, - "max": 43560 - }, - "setNumber(uint256)": { - "calls": 2, - "min": 23604, - "mean": 33560, - "median": 33560, - "max": 43516 - } + "setNumber(int256)": { + "calls": 2, + "min": 23648, + "mean": 33604, + "median": 33604, + "max": 43560 + }, + "setNumber(uint256)": { + "calls": 2, + "min": 23604, + "mean": 33560, + "median": 33560, + "max": 43516 } } } From 2bb446e9387b61d6fed1c157a7330b07c610b52e Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:02:56 +0530 Subject: [PATCH 20/35] feat(`cheatcodes`): access broadcast artifacts (#9107) * refac(`script`): extract script sequence and related types to new crate * replace MultiChainSequence in script crate * replace TransactionWithMetadata and AdditionalContract * replace ScriptSequence * replace all underlying ScriptSequence and related types * doc nits * add `ScriptTransactionBuilder` * remove `TxWithMetadata` * mv verify fns and use `ScriptSequence` directly * clippy * feat(`cheatcodes`): vm.getDeployment * cargo cheats * getBroadcast by txType * get all broadcast txs * nits * fix * feat: getBroadcasts by txType * nit * fix * mv `BroadcastReader` to script-sequence * fix: search all broadcast files and then apply filters * fix: ignore run-latest to avoid duplicating entries * nit * sort by descending block number * tests * feat(`CheatsConfig`): add `broadcast` dir path * feat: read multichain sequences * nit * minify json * use walkdir * fix * fix path * feat: getDeployment cheatcodes * feat: read broadcasts with multiple tx types * test: getDeployment * nit * fmt * fix * nit * cli test * nit * remove solidity test * nit --- Cargo.lock | 2 + crates/cheatcodes/Cargo.toml | 1 + crates/cheatcodes/assets/cheatcodes.json | 169 +++++++++++++++++++ crates/cheatcodes/spec/src/lib.rs | 2 + crates/cheatcodes/spec/src/vm.rs | 63 +++++++ crates/cheatcodes/src/config.rs | 4 + crates/cheatcodes/src/fs.rs | 169 +++++++++++++++++++ crates/forge/tests/cli/test_cmd.rs | 202 +++++++++++++++++++++++ crates/script-sequence/Cargo.toml | 1 + crates/script-sequence/src/lib.rs | 2 + crates/script-sequence/src/reader.rs | 179 ++++++++++++++++++++ testdata/cheats/Vm.sol | 8 + 12 files changed, 802 insertions(+) create mode 100644 crates/script-sequence/src/reader.rs diff --git a/Cargo.lock b/Cargo.lock index 014b458f9642..de6f11ea9b21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3514,6 +3514,7 @@ dependencies = [ "serde", "serde_json", "tracing", + "walkdir", ] [[package]] @@ -3613,6 +3614,7 @@ dependencies = [ "dialoguer", "ecdsa", "eyre", + "forge-script-sequence", "foundry-cheatcodes-spec", "foundry-common", "foundry-compilers", diff --git a/crates/cheatcodes/Cargo.toml b/crates/cheatcodes/Cargo.toml index adce79b211bd..00d73ec4d41a 100644 --- a/crates/cheatcodes/Cargo.toml +++ b/crates/cheatcodes/Cargo.toml @@ -29,6 +29,7 @@ foundry-config.workspace = true foundry-evm-core.workspace = true foundry-evm-traces.workspace = true foundry-wallets.workspace = true +forge-script-sequence.workspace = true alloy-dyn-abi.workspace = true alloy-json-abi.workspace = true diff --git a/crates/cheatcodes/assets/cheatcodes.json b/crates/cheatcodes/assets/cheatcodes.json index 4dbdd29b5da7..79761ae5a0ed 100644 --- a/crates/cheatcodes/assets/cheatcodes.json +++ b/crates/cheatcodes/assets/cheatcodes.json @@ -125,6 +125,24 @@ "description": "Unknown `forge` execution context." } ] + }, + { + "name": "BroadcastTxType", + "description": "The transaction type (`txType`) of the broadcast.", + "variants": [ + { + "name": "Call", + "description": "Represents a CALL broadcast tx." + }, + { + "name": "Create", + "description": "Represents a CREATE broadcast tx." + }, + { + "name": "Create2", + "description": "Represents a CREATE2 broadcast tx." + } + ] } ], "structs": [ @@ -524,6 +542,37 @@ "description": "The contract address where the opcode is running" } ] + }, + { + "name": "BroadcastTxSummary", + "description": "Represents a transaction's broadcast details.", + "fields": [ + { + "name": "txHash", + "ty": "bytes32", + "description": "The hash of the transaction that was broadcasted" + }, + { + "name": "txType", + "ty": "BroadcastTxType", + "description": "Represent the type of transaction among CALL, CREATE, CREATE2" + }, + { + "name": "contractAddress", + "ty": "address", + "description": "The address of the contract that was called or created.\n This is address of the contract that is created if the txType is CREATE or CREATE2." + }, + { + "name": "blockNumber", + "ty": "uint64", + "description": "The block number the transaction landed in." + }, + { + "name": "success", + "ty": "bool", + "description": "Status of the transaction, retrieved from the transaction receipt." + } + ] } ], "cheatcodes": [ @@ -5251,6 +5300,66 @@ "status": "stable", "safety": "safe" }, + { + "func": { + "id": "getBroadcast", + "description": "Returns the most recent broadcast for the given contract on `chainId` matching `txType`.\nFor example:\nThe most recent deployment can be fetched by passing `txType` as `CREATE` or `CREATE2`.\nThe most recent call can be fetched by passing `txType` as `CALL`.", + "declaration": "function getBroadcast(string memory contractName, uint64 chainId, BroadcastTxType txType) external returns (BroadcastTxSummary memory);", + "visibility": "external", + "mutability": "", + "signature": "getBroadcast(string,uint64,uint8)", + "selector": "0x3dc90cb3", + "selectorBytes": [ + 61, + 201, + 12, + 179 + ] + }, + "group": "filesystem", + "status": "stable", + "safety": "safe" + }, + { + "func": { + "id": "getBroadcasts_0", + "description": "Returns all broadcasts for the given contract on `chainId` with the specified `txType`.\nSorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber.", + "declaration": "function getBroadcasts(string memory contractName, uint64 chainId, BroadcastTxType txType) external returns (BroadcastTxSummary[] memory);", + "visibility": "external", + "mutability": "", + "signature": "getBroadcasts(string,uint64,uint8)", + "selector": "0xf7afe919", + "selectorBytes": [ + 247, + 175, + 233, + 25 + ] + }, + "group": "filesystem", + "status": "stable", + "safety": "safe" + }, + { + "func": { + "id": "getBroadcasts_1", + "description": "Returns all broadcasts for the given contract on `chainId`.\nSorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber.", + "declaration": "function getBroadcasts(string memory contractName, uint64 chainId) external returns (BroadcastTxSummary[] memory);", + "visibility": "external", + "mutability": "", + "signature": "getBroadcasts(string,uint64)", + "selector": "0xf2fa4a26", + "selectorBytes": [ + 242, + 250, + 74, + 38 + ] + }, + "group": "filesystem", + "status": "stable", + "safety": "safe" + }, { "func": { "id": "getCode", @@ -5291,6 +5400,66 @@ "status": "stable", "safety": "safe" }, + { + "func": { + "id": "getDeployment_0", + "description": "Returns the most recent deployment for the current `chainId`.", + "declaration": "function getDeployment(string memory contractName) external returns (address deployedAddress);", + "visibility": "external", + "mutability": "", + "signature": "getDeployment(string)", + "selector": "0xa8091d97", + "selectorBytes": [ + 168, + 9, + 29, + 151 + ] + }, + "group": "filesystem", + "status": "stable", + "safety": "safe" + }, + { + "func": { + "id": "getDeployment_1", + "description": "Returns the most recent deployment for the given contract on `chainId`", + "declaration": "function getDeployment(string memory contractName, uint64 chainId) external returns (address deployedAddress);", + "visibility": "external", + "mutability": "", + "signature": "getDeployment(string,uint64)", + "selector": "0x0debd5d6", + "selectorBytes": [ + 13, + 235, + 213, + 214 + ] + }, + "group": "filesystem", + "status": "stable", + "safety": "safe" + }, + { + "func": { + "id": "getDeployments", + "description": "Returns all deployments for the given contract on `chainId`\nSorted in descending order of deployment time i.e descending order of BroadcastTxSummary.blockNumber.\nThe most recent deployment is the first element, and the oldest is the last.", + "declaration": "function getDeployments(string memory contractName, uint64 chainId) external returns (address[] memory deployedAddresses);", + "visibility": "external", + "mutability": "", + "signature": "getDeployments(string,uint64)", + "selector": "0x74e133dd", + "selectorBytes": [ + 116, + 225, + 51, + 221 + ] + }, + "group": "filesystem", + "status": "stable", + "safety": "safe" + }, { "func": { "id": "getFoundryVersion", diff --git a/crates/cheatcodes/spec/src/lib.rs b/crates/cheatcodes/spec/src/lib.rs index 662853e9e811..eae2ae0ee9c2 100644 --- a/crates/cheatcodes/spec/src/lib.rs +++ b/crates/cheatcodes/spec/src/lib.rs @@ -86,11 +86,13 @@ impl Cheatcodes<'static> { Vm::StorageAccess::STRUCT.clone(), Vm::Gas::STRUCT.clone(), Vm::DebugStep::STRUCT.clone(), + Vm::BroadcastTxSummary::STRUCT.clone(), ]), enums: Cow::Owned(vec![ Vm::CallerMode::ENUM.clone(), Vm::AccountAccessKind::ENUM.clone(), Vm::ForgeContext::ENUM.clone(), + Vm::BroadcastTxType::ENUM.clone(), ]), errors: Vm::VM_ERRORS.iter().copied().cloned().collect(), events: Cow::Borrowed(&[]), diff --git a/crates/cheatcodes/spec/src/vm.rs b/crates/cheatcodes/spec/src/vm.rs index 21d41b373e01..ce0bc08b0577 100644 --- a/crates/cheatcodes/spec/src/vm.rs +++ b/crates/cheatcodes/spec/src/vm.rs @@ -283,6 +283,31 @@ interface Vm { address contractAddr; } + /// The transaction type (`txType`) of the broadcast. + enum BroadcastTxType { + /// Represents a CALL broadcast tx. + Call, + /// Represents a CREATE broadcast tx. + Create, + /// Represents a CREATE2 broadcast tx. + Create2 + } + + /// Represents a transaction's broadcast details. + struct BroadcastTxSummary { + /// The hash of the transaction that was broadcasted + bytes32 txHash; + /// Represent the type of transaction among CALL, CREATE, CREATE2 + BroadcastTxType txType; + /// The address of the contract that was called or created. + /// This is address of the contract that is created if the txType is CREATE or CREATE2. + address contractAddress; + /// The block number the transaction landed in. + uint64 blockNumber; + /// Status of the transaction, retrieved from the transaction receipt. + bool success; + } + // ======== EVM ======== /// Gets the address for a given private key. @@ -1670,6 +1695,44 @@ interface Vm { #[cheatcode(group = Filesystem)] function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode); + /// Returns the most recent broadcast for the given contract on `chainId` matching `txType`. + /// + /// For example: + /// + /// The most recent deployment can be fetched by passing `txType` as `CREATE` or `CREATE2`. + /// + /// The most recent call can be fetched by passing `txType` as `CALL`. + #[cheatcode(group = Filesystem)] + function getBroadcast(string memory contractName, uint64 chainId, BroadcastTxType txType) external returns (BroadcastTxSummary memory); + + /// Returns all broadcasts for the given contract on `chainId` with the specified `txType`. + /// + /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. + #[cheatcode(group = Filesystem)] + function getBroadcasts(string memory contractName, uint64 chainId, BroadcastTxType txType) external returns (BroadcastTxSummary[] memory); + + /// Returns all broadcasts for the given contract on `chainId`. + /// + /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. + #[cheatcode(group = Filesystem)] + function getBroadcasts(string memory contractName, uint64 chainId) external returns (BroadcastTxSummary[] memory); + + /// Returns the most recent deployment for the current `chainId`. + #[cheatcode(group = Filesystem)] + function getDeployment(string memory contractName) external returns (address deployedAddress); + + /// Returns the most recent deployment for the given contract on `chainId` + #[cheatcode(group = Filesystem)] + function getDeployment(string memory contractName, uint64 chainId) external returns (address deployedAddress); + + /// Returns all deployments for the given contract on `chainId` + /// + /// Sorted in descending order of deployment time i.e descending order of BroadcastTxSummary.blockNumber. + /// + /// The most recent deployment is the first element, and the oldest is the last. + #[cheatcode(group = Filesystem)] + function getDeployments(string memory contractName, uint64 chainId) external returns (address[] memory deployedAddresses); + // -------- Foreign Function Interface -------- /// Performs a foreign function call via the terminal. diff --git a/crates/cheatcodes/src/config.rs b/crates/cheatcodes/src/config.rs index cfd6e9452df6..fa1ec6039cde 100644 --- a/crates/cheatcodes/src/config.rs +++ b/crates/cheatcodes/src/config.rs @@ -37,6 +37,8 @@ pub struct CheatsConfig { pub fs_permissions: FsPermissions, /// Project root pub root: PathBuf, + /// Absolute Path to broadcast dir i.e project_root/broadcast + pub broadcast: PathBuf, /// Paths (directories) where file reading/writing is allowed pub allowed_paths: Vec, /// How the evm was configured by the user @@ -87,6 +89,7 @@ impl CheatsConfig { paths: config.project_paths(), fs_permissions: config.fs_permissions.clone().joined(config.root.as_ref()), root: config.root.0.clone(), + broadcast: config.root.0.clone().join(&config.broadcast), allowed_paths, evm_opts, labels: config.labels.clone(), @@ -216,6 +219,7 @@ impl Default for CheatsConfig { paths: ProjectPathsConfig::builder().build_with_root("./"), fs_permissions: Default::default(), root: Default::default(), + broadcast: Default::default(), allowed_paths: vec![], evm_opts: Default::default(), labels: Default::default(), diff --git a/crates/cheatcodes/src/fs.rs b/crates/cheatcodes/src/fs.rs index c8c512b6f15e..04af101eb753 100644 --- a/crates/cheatcodes/src/fs.rs +++ b/crates/cheatcodes/src/fs.rs @@ -5,11 +5,15 @@ use crate::{Cheatcode, Cheatcodes, CheatcodesExecutor, CheatsCtxt, Result, Vm::* use alloy_dyn_abi::DynSolType; use alloy_json_abi::ContractObject; use alloy_primitives::{hex, map::Entry, Bytes, U256}; +use alloy_provider::network::ReceiptResponse; +use alloy_rpc_types::AnyTransactionReceipt; use alloy_sol_types::SolValue; 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_inspectors::tracing::types::CallKind; use semver::Version; use std::{ io::{BufRead, BufReader, Write}, @@ -626,6 +630,171 @@ fn prompt( } } +impl Cheatcode for getBroadcastCall { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { contractName, chainId, txType } = self; + + let latest_broadcast = latest_broadcast( + contractName, + *chainId, + &state.config.broadcast, + vec![map_broadcast_tx_type(*txType)], + )?; + + Ok(latest_broadcast.abi_encode()) + } +} + +impl Cheatcode for getBroadcasts_0Call { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { contractName, chainId, txType } = self; + + let reader = BroadcastReader::new(contractName.clone(), *chainId, &state.config.broadcast)? + .with_tx_type(map_broadcast_tx_type(*txType)); + + let broadcasts = reader.read()?; + + let summaries = broadcasts + .into_iter() + .flat_map(|broadcast| { + let results = reader.into_tx_receipts(broadcast); + parse_broadcast_results(results) + }) + .collect::>(); + + Ok(summaries.abi_encode()) + } +} + +impl Cheatcode for getBroadcasts_1Call { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { contractName, chainId } = self; + + let reader = BroadcastReader::new(contractName.clone(), *chainId, &state.config.broadcast)?; + + let broadcasts = reader.read()?; + + let summaries = broadcasts + .into_iter() + .flat_map(|broadcast| { + let results = reader.into_tx_receipts(broadcast); + parse_broadcast_results(results) + }) + .collect::>(); + + Ok(summaries.abi_encode()) + } +} + +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 latest_broadcast = latest_broadcast( + contractName, + chain_id, + &ccx.state.config.broadcast, + vec![CallKind::Create, CallKind::Create2], + )?; + + Ok(latest_broadcast.contractAddress.abi_encode()) + } +} + +impl Cheatcode for getDeployment_1Call { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { contractName, chainId } = self; + + let latest_broadcast = latest_broadcast( + contractName, + *chainId, + &state.config.broadcast, + vec![CallKind::Create, CallKind::Create2], + )?; + + Ok(latest_broadcast.contractAddress.abi_encode()) + } +} + +impl Cheatcode for getDeploymentsCall { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { contractName, chainId } = self; + + let reader = BroadcastReader::new(contractName.clone(), *chainId, &state.config.broadcast)? + .with_tx_type(CallKind::Create) + .with_tx_type(CallKind::Create2); + + let broadcasts = reader.read()?; + + let summaries = broadcasts + .into_iter() + .flat_map(|broadcast| { + let results = reader.into_tx_receipts(broadcast); + parse_broadcast_results(results) + }) + .collect::>(); + + let deployed_addresses = + summaries.into_iter().map(|summary| summary.contractAddress).collect::>(); + + Ok(deployed_addresses.abi_encode()) + } +} + +fn map_broadcast_tx_type(tx_type: BroadcastTxType) -> CallKind { + match tx_type { + BroadcastTxType::Call => CallKind::Call, + BroadcastTxType::Create => CallKind::Create, + BroadcastTxType::Create2 => CallKind::Create2, + _ => unreachable!("invalid tx type"), + } +} + +fn parse_broadcast_results( + results: Vec<(TransactionWithMetadata, AnyTransactionReceipt)>, +) -> Vec { + results + .into_iter() + .map(|(tx, receipt)| BroadcastTxSummary { + txHash: receipt.transaction_hash, + blockNumber: receipt.block_number.unwrap_or_default(), + txType: match tx.opcode { + CallKind::Call => BroadcastTxType::Call, + CallKind::Create => BroadcastTxType::Create, + CallKind::Create2 => BroadcastTxType::Create2, + _ => unreachable!("invalid tx type"), + }, + contractAddress: tx.contract_address.unwrap_or_default(), + success: receipt.status(), + }) + .collect() +} + +fn latest_broadcast( + contract_name: &String, + chain_id: u64, + broadcast_path: &Path, + filters: Vec, +) -> Result { + let mut reader = BroadcastReader::new(contract_name.clone(), chain_id, broadcast_path)?; + + for filter in filters { + reader = reader.with_tx_type(filter); + } + + let broadcast = reader.read_latest()?; + + let results = reader.into_tx_receipts(broadcast); + + let summaries = parse_broadcast_results(results); + + summaries + .first() + .ok_or_else(|| fmt_err!("no deployment found for {contract_name} on chain {chain_id}")) + .cloned() +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index d76a6124f7bd..8ce502a652b9 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -1,6 +1,7 @@ //! Contains various tests for `forge test`. use alloy_primitives::U256; +use anvil::{spawn, NodeConfig}; use foundry_config::{Config, FuzzConfig}; use foundry_test_utils::{ rpc, str, @@ -2390,3 +2391,204 @@ contract Dummy { assert!(dump_path.exists()); }); + +forgetest_async!(can_get_broadcast_txs, |prj, cmd| { + foundry_test_utils::util::initialize(prj.root()); + + let (_api, handle) = spawn(NodeConfig::test().silent()).await; + + prj.insert_vm(); + prj.insert_ds_test(); + prj.insert_console(); + + prj.add_source( + "Counter.sol", + r#" + contract Counter { + uint256 public number; + + function setNumber(uint256 newNumber) public { + number = newNumber; + } + + function increment() public { + number++; + } +} + "#, + ) + .unwrap(); + + prj.add_script( + "DeployCounter", + r#" + import "forge-std/Script.sol"; + import "src/Counter.sol"; + + contract DeployCounter is Script { + function run() public { + vm.startBroadcast(); + + Counter counter = new Counter(); + + counter.increment(); + + counter.setNumber(10); + + vm.stopBroadcast(); + } + } + "#, + ) + .unwrap(); + + prj.add_script( + "DeployCounterWithCreate2", + r#" + import "forge-std/Script.sol"; + import "src/Counter.sol"; + + contract DeployCounterWithCreate2 is Script { + function run() public { + vm.startBroadcast(); + + bytes32 salt = bytes32(uint256(1337)); + Counter counter = new Counter{salt: salt}(); + + counter.increment(); + + counter.setNumber(20); + + vm.stopBroadcast(); + } + } + "#, + ) + .unwrap(); + + let test = r#" + import {Vm} from "../src/Vm.sol"; + import {DSTest} from "../src/test.sol"; + import {console} from "../src/console.sol"; + + contract GetBroadcastTest is DSTest { + + Vm constant vm = Vm(HEVM_ADDRESS); + + function test_getLatestBroacast() external { + // Gets the latest create + Vm.BroadcastTxSummary memory broadcast = vm.getBroadcast( + "Counter", + 31337, + Vm.BroadcastTxType.Create + ); + + console.log("latest create"); + console.log(broadcast.blockNumber); + + assertEq(broadcast.blockNumber, 1); + + // Gets the latest create2 + Vm.BroadcastTxSummary memory broadcast2 = vm.getBroadcast( + "Counter", + 31337, + Vm.BroadcastTxType.Create2 + ); + + console.log("latest create2"); + console.log(broadcast2.blockNumber); + assertEq(broadcast2.blockNumber, 4); + + // Gets the latest call + Vm.BroadcastTxSummary memory broadcast3 = vm.getBroadcast( + "Counter", + 31337, + Vm.BroadcastTxType.Call + ); + + console.log("latest call"); + assertEq(broadcast3.blockNumber, 6); + } + + function test_getBroadcasts() public { + // Gets all calls + Vm.BroadcastTxSummary[] memory broadcasts = vm.getBroadcasts( + "Counter", + 31337, + Vm.BroadcastTxType.Call + ); + + assertEq(broadcasts.length, 4); + } + + function test_getAllBroadcasts() public { + // Gets all broadcasts + Vm.BroadcastTxSummary[] memory broadcasts2 = vm.getBroadcasts( + "Counter", + 31337 + ); + + assertEq(broadcasts2.length, 6); + } + + function test_getLatestDeployment() public { + address deployedAddress = vm.getDeployment( + "Counter", + 31337 + ); + + assertEq(deployedAddress, address(0x030D07c16e2c0a77f74ab16f3C8F10ACeF89FF81)); + } + + function test_getDeployments() public { + address[] memory deployments = vm.getDeployments( + "Counter", + 31337 + ); + + assertEq(deployments.length, 2); + assertEq(deployments[0], address(0x030D07c16e2c0a77f74ab16f3C8F10ACeF89FF81)); // Create2 address - latest deployment + assertEq(deployments[1], address(0x5FbDB2315678afecb367f032d93F642f64180aa3)); // Create address - oldest deployment + } + +} + "#; + + prj.add_test("GetBroadcast", test).unwrap(); + + let sender = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; + + cmd.args([ + "script", + "DeployCounter", + "--rpc-url", + &handle.http_endpoint(), + "--sender", + sender, + "--unlocked", + "--broadcast", + "--slow", + ]) + .assert_success(); + + cmd.forge_fuse() + .args([ + "script", + "DeployCounterWithCreate2", + "--rpc-url", + &handle.http_endpoint(), + "--sender", + sender, + "--unlocked", + "--broadcast", + "--slow", + ]) + .assert_success(); + + let broadcast_path = prj.root().join("broadcast"); + + // Check if the broadcast folder exists + assert!(broadcast_path.exists() && broadcast_path.is_dir()); + + cmd.forge_fuse().args(["test", "--mc", "GetBroadcastTest", "-vvv"]).assert_success(); +}); diff --git a/crates/script-sequence/Cargo.toml b/crates/script-sequence/Cargo.toml index e128fe37b5ef..13326e684cac 100644 --- a/crates/script-sequence/Cargo.toml +++ b/crates/script-sequence/Cargo.toml @@ -22,6 +22,7 @@ serde.workspace = true eyre.workspace = true serde_json.workspace = true tracing.workspace = true +walkdir.workspace = true revm-inspectors.workspace = true diff --git a/crates/script-sequence/src/lib.rs b/crates/script-sequence/src/lib.rs index 11970e9478be..929f44a724b8 100644 --- a/crates/script-sequence/src/lib.rs +++ b/crates/script-sequence/src/lib.rs @@ -3,8 +3,10 @@ #[macro_use] extern crate foundry_common; +pub mod reader; pub mod sequence; pub mod transaction; +pub use reader::*; pub use sequence::*; pub use transaction::*; diff --git a/crates/script-sequence/src/reader.rs b/crates/script-sequence/src/reader.rs new file mode 100644 index 000000000000..c4627dec09ec --- /dev/null +++ b/crates/script-sequence/src/reader.rs @@ -0,0 +1,179 @@ +use crate::{ScriptSequence, TransactionWithMetadata}; +use alloy_rpc_types::AnyTransactionReceipt; +use eyre::{bail, Result}; +use foundry_common::fs; +use revm_inspectors::tracing::types::CallKind; +use std::path::{Component, Path, PathBuf}; + +/// This type reads broadcast files in the +/// `project_root/broadcast/{contract_name}.s.sol/{chain_id}/` directory. +/// +/// It consists methods that filter and search for transactions in the broadcast files that match a +/// `transactionType` if provided. +/// +/// Note: +/// +/// It only returns transactions for which there exists a corresponding receipt in the broadcast. +#[derive(Debug, Clone)] +pub struct BroadcastReader { + contract_name: String, + chain_id: u64, + tx_type: Vec, + broadcast_path: PathBuf, +} + +impl BroadcastReader { + /// Create a new `BroadcastReader` instance. + pub fn new(contract_name: String, chain_id: u64, broadcast_path: &Path) -> Result { + if !broadcast_path.exists() && !broadcast_path.is_dir() { + bail!("broadcast dir does not exist"); + } + + Ok(Self { + contract_name, + chain_id, + tx_type: Default::default(), + broadcast_path: broadcast_path.to_path_buf(), + }) + } + + /// Set the transaction type to filter by. + pub fn with_tx_type(mut self, tx_type: CallKind) -> Self { + self.tx_type.push(tx_type); + self + } + + /// Read all broadcast files in the broadcast directory. + /// + /// Example structure: + /// + /// project-root/broadcast/{script_name}.s.sol/{chain_id}/*.json + /// project-root/broadcast/multi/{multichain_script_name}.s.sol-{timestamp}/deploy.json + pub fn read(&self) -> eyre::Result> { + // 1. Recursively read all .json files in the broadcast directory + let mut broadcasts = vec![]; + for entry in walkdir::WalkDir::new(&self.broadcast_path).into_iter() { + let entry = entry?; + let path = entry.path(); + + if path.is_file() && path.extension().is_some_and(|ext| ext == "json") { + // Ignore -latest to avoid duplicating broadcast entries + if path.components().any(|c| c.as_os_str().to_string_lossy().contains("-latest")) { + continue; + } + + // Detect Multichain broadcasts using "multi" in the path + if path.components().any(|c| c == Component::Normal("multi".as_ref())) { + // Parse as MultiScriptSequence + + let broadcast = fs::read_json_file::(path)?; + let multichain_deployments = broadcast + .get("deployments") + .and_then(|deployments| { + serde_json::from_value::>(deployments.clone()).ok() + }) + .unwrap_or_default(); + + broadcasts.extend(multichain_deployments); + continue; + } + + let broadcast = fs::read_json_file::(path)?; + broadcasts.push(broadcast); + } + } + + let broadcasts = self.filter_and_sort(broadcasts); + + Ok(broadcasts) + } + + /// Attempts read the latest broadcast file in the broadcast directory. + /// + /// This may be the `run-latest.json` file or the broadcast file with the latest timestamp. + pub fn read_latest(&self) -> eyre::Result { + let broadcasts = self.read()?; + + // Find the broadcast with the latest timestamp + let target = broadcasts + .into_iter() + .max_by_key(|broadcast| broadcast.timestamp) + .ok_or_else(|| eyre::eyre!("No broadcasts found"))?; + + Ok(target) + } + + /// Applies the filters and sorts the broadcasts by descending timestamp. + pub fn filter_and_sort(&self, broadcasts: Vec) -> Vec { + // Apply the filters + let mut seqs = broadcasts + .into_iter() + .filter(|broadcast| { + if broadcast.chain != self.chain_id { + return false; + } + + broadcast.transactions.iter().any(move |tx| { + let name_filter = + tx.contract_name.clone().is_some_and(|cn| cn == self.contract_name); + + let type_filter = self.tx_type.is_empty() || + self.tx_type.iter().any(|kind| *kind == tx.opcode); + + name_filter && type_filter + }) + }) + .collect::>(); + + // Sort by descending timestamp + seqs.sort_by(|a, b| b.timestamp.cmp(&a.timestamp)); + + seqs + } + + /// Search for transactions in the broadcast that match the specified `contractName` and + /// `txType`. + /// + /// It cross-checks the transactions with their corresponding receipts in the broadcast and + /// returns the result. + /// + /// Transactions that don't have a corresponding receipt are ignored. + /// + /// Sorts the transactions by descending block number. + pub fn into_tx_receipts( + &self, + broadcast: ScriptSequence, + ) -> Vec<(TransactionWithMetadata, AnyTransactionReceipt)> { + let transactions = broadcast.transactions.clone(); + + let txs = transactions + .into_iter() + .filter(|tx| { + let name_filter = + tx.contract_name.clone().is_some_and(|cn| cn == self.contract_name); + + let type_filter = + self.tx_type.is_empty() || self.tx_type.iter().any(|kind| *kind == tx.opcode); + + name_filter && type_filter + }) + .collect::>(); + + let mut targets = Vec::new(); + for tx in txs.into_iter() { + let maybe_receipt = broadcast + .receipts + .iter() + .find(|receipt| tx.hash.is_some_and(|hash| hash == receipt.transaction_hash)); + + if let Some(receipt) = maybe_receipt { + targets.push((tx, receipt.clone())); + } + } + + // Sort by descending block number + targets.sort_by(|a, b| b.1.block_number.cmp(&a.1.block_number)); + + targets + } +} diff --git a/testdata/cheats/Vm.sol b/testdata/cheats/Vm.sol index 2d4030d30e1a..b33df8f2dc18 100644 --- a/testdata/cheats/Vm.sol +++ b/testdata/cheats/Vm.sol @@ -9,6 +9,7 @@ interface Vm { enum CallerMode { None, Broadcast, RecurrentBroadcast, Prank, RecurrentPrank } enum AccountAccessKind { Call, DelegateCall, CallCode, StaticCall, Create, SelfDestruct, Resume, Balance, Extcodesize, Extcodehash, Extcodecopy } enum ForgeContext { TestGroup, Test, Coverage, Snapshot, ScriptGroup, ScriptDryRun, ScriptBroadcast, ScriptResume, Unknown } + enum BroadcastTxType { Call, Create, Create2 } struct Log { bytes32[] topics; bytes data; address emitter; } struct Rpc { string key; string url; } struct EthGetLogs { address emitter; bytes32[] topics; bytes data; bytes32 blockHash; uint64 blockNumber; bytes32 transactionHash; uint64 transactionIndex; uint256 logIndex; bool removed; } @@ -21,6 +22,7 @@ interface Vm { 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; } struct DebugStep { uint256[] stack; bytes memoryInput; uint8 opcode; uint64 depth; bool isOutOfGas; address contractAddr; } + struct BroadcastTxSummary { bytes32 txHash; BroadcastTxType txType; address contractAddress; uint64 blockNumber; bool success; } function _expectCheatcodeRevert() external; function _expectCheatcodeRevert(bytes4 revertData) external; function _expectCheatcodeRevert(bytes calldata revertData) external; @@ -257,8 +259,14 @@ interface Vm { function getBlobhashes() external view returns (bytes32[] memory hashes); function getBlockNumber() external view returns (uint256 height); function getBlockTimestamp() external view returns (uint256 timestamp); + function getBroadcast(string memory contractName, uint64 chainId, BroadcastTxType txType) external returns (BroadcastTxSummary memory); + function getBroadcasts(string memory contractName, uint64 chainId, BroadcastTxType txType) external returns (BroadcastTxSummary[] memory); + function getBroadcasts(string memory contractName, uint64 chainId) external returns (BroadcastTxSummary[] memory); 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 memory contractName) external returns (address deployedAddress); + function getDeployment(string memory contractName, uint64 chainId) external returns (address deployedAddress); + function getDeployments(string memory contractName, uint64 chainId) external returns (address[] memory deployedAddresses); function getFoundryVersion() external view returns (string memory version); function getLabel(address account) external view returns (string memory currentLabel); function getMappingKeyAndParentOf(address target, bytes32 elementSlot) external returns (bool found, bytes32 key, bytes32 parent); From 45d5997134e9de548a99a46367023c1ea4625073 Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:10:18 +0530 Subject: [PATCH 21/35] fix(`anvil`): set `storage.best_number` correctly (#9215) * feat(`anvil`): persist accounts in `ForkedStorage` * load accounts * test * fix(`anvil`): override storage.best_number with fork_block_num if loading state on a fork url * Revert "load accounts" This reverts commit b650f56fe52f79be3eb7c8ab4d2ad1aaca08a32f. * Revert "feat(`anvil`): persist accounts in `ForkedStorage`" This reverts commit 456da156e07b1ede01c08c4f48ef36eed4094f17. * nit --------- Co-authored-by: grandizzy * nit --------- Co-authored-by: grandizzy --- crates/anvil/src/eth/backend/mem/mod.rs | 32 +++++---- crates/anvil/tests/it/state.rs | 94 ++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 14 deletions(-) diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 73adaa97f3fd..65ab8c32952b 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -907,19 +907,27 @@ impl Backend { // 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())); - let best_number = state.best_block_number.unwrap_or(block.number.to::()); - self.blockchain.storage.write().best_number = best_number; - - // Set the current best block hash; - let best_hash = - self.blockchain.storage.read().hash(best_number.into()).ok_or_else(|| { - BlockchainError::RpcError(RpcError::internal_error_with(format!( - "Best hash not found for best number {best_number}", - ))) - })?; - - self.blockchain.storage.write().best_hash = best_hash; + if let Some((number, hash)) = fork_num_and_hash { + // 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_hash = hash; + } else { + let best_number = state.best_block_number.unwrap_or(block.number.to::()); + self.blockchain.storage.write().best_number = best_number; + + // Set the current best block hash; + let best_hash = + self.blockchain.storage.read().hash(best_number.into()).ok_or_else(|| { + BlockchainError::RpcError(RpcError::internal_error_with(format!( + "Best hash not found for best number {best_number}", + ))) + })?; + + self.blockchain.storage.write().best_hash = best_hash; + } } if !self.db.write().await.load_state(state.clone())? { diff --git a/crates/anvil/tests/it/state.rs b/crates/anvil/tests/it/state.rs index cb8f3b9ebbca..f7736de2f403 100644 --- a/crates/anvil/tests/it/state.rs +++ b/crates/anvil/tests/it/state.rs @@ -1,10 +1,13 @@ //! general eth api tests use crate::abi::Greeter; -use alloy_primitives::{Bytes, Uint, U256}; +use alloy_network::{ReceiptResponse, TransactionBuilder}; +use alloy_primitives::{address, utils::Unit, Bytes, Uint, U256}; use alloy_provider::Provider; -use alloy_rpc_types::BlockId; +use alloy_rpc_types::{BlockId, TransactionRequest}; +use alloy_serde::WithOtherFields; use anvil::{spawn, NodeConfig}; +use foundry_test_utils::rpc::next_http_rpc_endpoint; #[tokio::test(flavor = "multi_thread")] async fn can_load_state() { @@ -155,3 +158,90 @@ async fn can_preserve_historical_states_between_dump_and_load() { assert_eq!(greeting_after_change, "World!"); } + +// +#[tokio::test(flavor = "multi_thread")] +async fn test_fork_load_state() { + let (api, handle) = spawn( + NodeConfig::test() + .with_eth_rpc_url(Some(next_http_rpc_endpoint())) + .with_fork_block_number(Some(21070682u64)), + ) + .await; + + let bob = address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); + let alice = address!("9276449EaC5b4f7Bc17cFC6700f7BeeB86F9bCd0"); + + let provider = handle.http_provider(); + + let init_nonce_bob = provider.get_transaction_count(bob).await.unwrap(); + + let init_balance_alice = provider.get_balance(alice).await.unwrap(); + + 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 receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap(); + + assert!(receipt.status()); + + let serialized_state = api.serialized_state(false).await.unwrap(); + + let state_dump_block = api.block_number().unwrap(); + + let (api, handle) = spawn( + NodeConfig::test() + .with_eth_rpc_url(Some(next_http_rpc_endpoint())) + .with_fork_block_number(Some(21070686u64)) // Forked chain has moved forward + .with_init_state(Some(serialized_state)), + ) + .await; + + // Ensure the initial block number is the fork_block_number and not the state_dump_block + let block_number = api.block_number().unwrap(); + assert_eq!(block_number, U256::from(21070686u64)); + assert_ne!(block_number, state_dump_block); + + let provider = handle.http_provider(); + + let restart_nonce_bob = provider.get_transaction_count(bob).await.unwrap(); + + let restart_balance_alice = provider.get_balance(alice).await.unwrap(); + + assert_eq!(init_nonce_bob + 1, restart_nonce_bob); + + assert_eq!(init_balance_alice + value, restart_balance_alice); + + // Send another tx to check if the state is preserved + + let tx = TransactionRequest::default().with_to(alice).with_value(value).with_from(bob); + let tx = WithOtherFields::new(tx); + + let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap(); + + assert!(receipt.status()); + + let nonce_bob = provider.get_transaction_count(bob).await.unwrap(); + + let balance_alice = provider.get_balance(alice).await.unwrap(); + + let tx = TransactionRequest::default() + .with_to(alice) + .with_value(value) + .with_from(bob) + .with_nonce(nonce_bob); + let tx = WithOtherFields::new(tx); + + let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap(); + + assert!(receipt.status()); + + let latest_nonce_bob = provider.get_transaction_count(bob).await.unwrap(); + + let latest_balance_alice = provider.get_balance(alice).await.unwrap(); + + assert_eq!(nonce_bob + 1, latest_nonce_bob); + + assert_eq!(balance_alice + value, latest_balance_alice); +} From c90ea4d67f6a2492caa5d218d6c077388e3ef932 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Wed, 30 Oct 2024 16:15:11 +0200 Subject: [PATCH 22/35] feat(`--gas-report`): add option to include tests (#9232) feat(`--gas-report`): add option to show gas for tests --- crates/config/src/lib.rs | 3 + crates/forge/bin/cmd/test/mod.rs | 1 + crates/forge/src/gas_report.rs | 7 ++- crates/forge/tests/cli/cmd.rs | 98 ++++++++++++++++++++++++++++++++ crates/forge/tests/cli/config.rs | 1 + 5 files changed, 108 insertions(+), 2 deletions(-) diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 2a75f3b23c72..916c77f9bd71 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -196,6 +196,8 @@ pub struct Config { pub gas_reports: Vec, /// list of contracts to ignore for gas reports pub gas_reports_ignore: Vec, + /// Whether to include gas reports for tests. + pub gas_reports_include_tests: bool, /// The Solc instance to use if any. /// /// This takes precedence over `auto_detect_solc`, if a version is set then this overrides @@ -2164,6 +2166,7 @@ impl Default for Config { evm_version: EvmVersion::Paris, gas_reports: vec!["*".to_string()], gas_reports_ignore: vec![], + gas_reports_include_tests: false, solc: None, vyper: Default::default(), auto_detect_solc: true, diff --git a/crates/forge/bin/cmd/test/mod.rs b/crates/forge/bin/cmd/test/mod.rs index fa20e26d8788..4c973217f4d7 100644 --- a/crates/forge/bin/cmd/test/mod.rs +++ b/crates/forge/bin/cmd/test/mod.rs @@ -583,6 +583,7 @@ impl TestArgs { GasReport::new( config.gas_reports.clone(), config.gas_reports_ignore.clone(), + config.gas_reports_include_tests, if self.json { GasReportKind::JSON } else { GasReportKind::Markdown }, ) }); diff --git a/crates/forge/src/gas_report.rs b/crates/forge/src/gas_report.rs index ac2d0db00262..ea8a49d373c2 100644 --- a/crates/forge/src/gas_report.rs +++ b/crates/forge/src/gas_report.rs @@ -36,6 +36,8 @@ pub struct GasReport { report_for: HashSet, /// Contracts to ignore when generating the report. ignore: HashSet, + /// Whether to include gas reports for tests. + include_tests: bool, /// All contracts that were analyzed grouped by their identifier /// ``test/Counter.t.sol:CounterTest pub contracts: BTreeMap, @@ -45,13 +47,14 @@ impl GasReport { pub fn new( report_for: impl IntoIterator, ignore: impl IntoIterator, + include_tests: bool, report_kind: GasReportKind, ) -> Self { let report_for = report_for.into_iter().collect::>(); let ignore = ignore.into_iter().collect::>(); let report_any = report_for.is_empty() || report_for.contains("*"); let report_type = report_kind; - Self { report_any, report_type, report_for, ignore, ..Default::default() } + Self { report_any, report_type, report_for, ignore, include_tests, ..Default::default() } } /// Whether the given contract should be reported. @@ -122,7 +125,7 @@ impl GasReport { } else if let Some(DecodedCallData { signature, .. }) = decoded().await.call_data { let name = signature.split('(').next().unwrap(); // ignore any test/setup functions - if !name.test_function_kind().is_known() { + if self.include_tests || !name.test_function_kind().is_known() { trace!(contract_name, signature, "adding gas info"); let gas_info = contract_info .functions diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index f34d0e2dec5d..f9e8997bd99c 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -2717,3 +2717,101 @@ interface Counter { "#]], ); }); + +// checks that `clean` also works with the "out" value set in Config +forgetest_init!(gas_report_include_tests, |prj, cmd| { + prj.write_config(Config { + gas_reports_include_tests: true, + fuzz: FuzzConfig { runs: 1, ..Default::default() }, + ..Default::default() + }); + + cmd.args(["test", "--mt", "test_Increment", "--gas-report"]).assert_success().stdout_eq(str![ + [r#" +... +| src/Counter.sol:Counter contract | | | | | | +|----------------------------------|-----------------|-------|--------|-------|---------| +| Deployment Cost | Deployment Size | | | | | +| 106715 | 277 | | | | | +| Function Name | min | avg | median | max | # calls | +| increment | 43404 | 43404 | 43404 | 43404 | 1 | +| number | 283 | 283 | 283 | 283 | 1 | +| setNumber | 23582 | 23582 | 23582 | 23582 | 1 | + + +| test/Counter.t.sol:CounterTest contract | | | | | | +|-----------------------------------------|-----------------|--------|--------|--------|---------| +| Deployment Cost | Deployment Size | | | | | +| 965418 | 4661 | | | | | +| Function Name | min | avg | median | max | # calls | +| setUp | 168064 | 168064 | 168064 | 168064 | 1 | +| test_Increment | 52367 | 52367 | 52367 | 52367 | 1 | +... + +"#] + ]); + + cmd.forge_fuse() + .args(["test", "--mt", "test_Increment", "--gas-report", "--json"]) + .assert_success() + .stdout_eq( + str![[r#" +[ + { + "contract": "src/Counter.sol:Counter", + "deployment": { + "gas": 106715, + "size": 277 + }, + "functions": { + "increment()": { + "calls": 1, + "min": 43404, + "mean": 43404, + "median": 43404, + "max": 43404 + }, + "number()": { + "calls": 1, + "min": 283, + "mean": 283, + "median": 283, + "max": 283 + }, + "setNumber(uint256)": { + "calls": 1, + "min": 23582, + "mean": 23582, + "median": 23582, + "max": 23582 + } + } + }, + { + "contract": "test/Counter.t.sol:CounterTest", + "deployment": { + "gas": 965418, + "size": 4661 + }, + "functions": { + "setUp()": { + "calls": 1, + "min": 168064, + "mean": 168064, + "median": 168064, + "max": 168064 + }, + "test_Increment()": { + "calls": 1, + "min": 52367, + "mean": 52367, + "median": 52367, + "max": 52367 + } + } + } +] +"#]] + .is_json(), + ); +}); diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index d7860381cb19..f6ec7c88eddf 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -43,6 +43,7 @@ forgetest!(can_extract_config_values, |prj, cmd| { evm_version: EvmVersion::Byzantium, gas_reports: vec!["Contract".to_string()], gas_reports_ignore: vec![], + gas_reports_include_tests: false, solc: Some(SolcReq::Local(PathBuf::from("custom-solc"))), auto_detect_solc: false, auto_detect_remappings: true, From 213d8174727023cf2881825e4b4f9417d726e1c8 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 31 Oct 2024 03:07:49 +0400 Subject: [PATCH 23/35] fix: remove steps after steps tracing cheatcodes are done (#9234) --- crates/cheatcodes/src/evm.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/cheatcodes/src/evm.rs b/crates/cheatcodes/src/evm.rs index acc349be15d3..723beb1cfc8a 100644 --- a/crates/cheatcodes/src/evm.rs +++ b/crates/cheatcodes/src/evm.rs @@ -761,9 +761,6 @@ impl Cheatcode for stopAndReturnDebugTraceRecordingCall { return Err(Error::from("nothing recorded")) }; - // Revert the tracer config to the one before recording - tracer.update_config(|_config| record_info.original_tracer_config); - // Use the trace nodes to flatten the call trace let root = tracer.traces(); let steps = flatten_call_trace(0, root, record_info.start_node_idx); @@ -771,6 +768,16 @@ impl Cheatcode for stopAndReturnDebugTraceRecordingCall { let debug_steps: Vec = steps.iter().map(|&step| convert_call_trace_to_debug_step(step)).collect(); + // Free up memory by clearing the steps if they are not recorded outside of cheatcode usage. + if !record_info.original_tracer_config.record_steps { + tracer.traces_mut().nodes_mut().iter_mut().for_each(|node| { + node.trace.steps = Vec::new(); + }); + } + + // Revert the tracer config to the one before recording + tracer.update_config(|_config| record_info.original_tracer_config); + // Clean up the recording info ccx.state.record_debug_steps_info = None; From 9d74675bae8bfbd83428ff1343cbe2ae206c3383 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 31 Oct 2024 03:42:59 +0400 Subject: [PATCH 24/35] fix: rename flag as_int -> as-int (#9235) * fix: rename flag as_int -> as-int * Update crates/cast/bin/args.rs Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> --------- Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> --- crates/cast/bin/args.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cast/bin/args.rs b/crates/cast/bin/args.rs index 7552c3bd5f03..988516c14065 100644 --- a/crates/cast/bin/args.rs +++ b/crates/cast/bin/args.rs @@ -320,7 +320,7 @@ pub enum CastSubcommand { value: Option, /// Decode the RLP data as int - #[arg(id = "int", long = "as_int", alias = "int")] + #[arg(long, alias = "int")] as_int: bool, }, From 736a3300234a0921b9d8adde6c0c4dd14053ec8a Mon Sep 17 00:00:00 2001 From: Delweng Date: Thu, 31 Oct 2024 17:22:10 +0800 Subject: [PATCH 25/35] feat(cast): add string-decode to decode string (#9237) * feat(cast): add error-decode to decode error string Signed-off-by: jsvisa * feat(cast): error-decode -> string-decode Signed-off-by: jsvisa * add test case for string-decode Signed-off-by: jsvisa * Apply suggestions from code review --------- Signed-off-by: jsvisa Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- crates/cast/bin/args.rs | 15 ++++++++++++++- crates/cast/bin/main.rs | 4 ++++ crates/cast/tests/cli/main.rs | 7 +++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/crates/cast/bin/args.rs b/crates/cast/bin/args.rs index 988516c14065..03ca46d23826 100644 --- a/crates/cast/bin/args.rs +++ b/crates/cast/bin/args.rs @@ -523,7 +523,7 @@ pub enum CastSubcommand { /// /// Similar to `abi-decode --input`, but function selector MUST be prefixed in `calldata` /// string - #[command(visible_aliases = &["--calldata-decode","cdd"])] + #[command(visible_aliases = &["--calldata-decode", "cdd"])] CalldataDecode { /// The function signature in the format `()()`. sig: String, @@ -536,6 +536,19 @@ pub enum CastSubcommand { json: bool, }, + /// Decode ABI-encoded string. + /// + /// Similar to `calldata-decode --input`, but the function argument is a `string` + #[command(visible_aliases = &["--string-decode", "sd"])] + StringDecode { + /// The ABI-encoded string. + data: String, + + /// Print the decoded string as JSON. + #[arg(long, short, help_heading = "Display options")] + json: bool, + }, + /// Decode ABI-encoded input or output data. /// /// Defaults to decoding output data. To decode input data pass --input. diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index a7cd013c8b2f..974b7eb86157 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -205,6 +205,10 @@ async fn main_args(args: CastArgs) -> Result<()> { CastSubcommand::CalldataEncode { sig, args } => { sh_println!("{}", SimpleCast::calldata_encode(sig, &args)?)?; } + CastSubcommand::StringDecode { data, json } => { + let tokens = SimpleCast::calldata_decode("Any(string)", &data, true)?; + print_tokens(&tokens, json) + } CastSubcommand::Interface(cmd) => cmd.run().await?, CastSubcommand::CreationCode(cmd) => cmd.run().await?, CastSubcommand::ConstructorArgs(cmd) => cmd.run().await?, diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 9ff8a6d49c6d..8a8d512f83c2 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -1417,6 +1417,13 @@ casttest!(parse_units, |_prj, cmd| { "#]]); }); +casttest!(string_decode, |_prj, cmd| { + cmd.args(["string-decode", "0x88c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000054753303235000000000000000000000000000000000000000000000000000000"]).assert_success().stdout_eq(str![[r#" +"GS025" + +"#]]); +}); + casttest!(format_units, |_prj, cmd| { cmd.args(["format-units", "1000000", "6"]).assert_success().stdout_eq(str![[r#" 1 From 17e0981a071fbd3b5a0a59affb4d638a28dfec89 Mon Sep 17 00:00:00 2001 From: Karrq Date: Thu, 31 Oct 2024 18:16:20 +0100 Subject: [PATCH 26/35] chore: avoid unnecessary `mut` (#9238) --- crates/script/src/simulate.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/script/src/simulate.rs b/crates/script/src/simulate.rs index 6eb11d7f9117..720b970af408 100644 --- a/crates/script/src/simulate.rs +++ b/crates/script/src/simulate.rs @@ -112,10 +112,10 @@ impl PreSimulationState { // Executes all transactions from the different forks concurrently. let futs = transactions .into_iter() - .map(|mut transaction| async { + .map(|transaction| async { let mut runner = runners.get(&transaction.rpc).expect("invalid rpc url").write(); - let tx = transaction.tx_mut(); + let tx = transaction.tx(); let to = if let Some(TxKind::Call(to)) = tx.to() { Some(to) } else { None }; let result = runner .simulate( From 6b0c27ed4ccfdb5a4805e9f53d487cca51c5e116 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Fri, 1 Nov 2024 11:05:10 +0200 Subject: [PATCH 27/35] fix(anvil): on anvil_mine jump to next timestamp before mine new block (#9241) * fix(anvil): on anvil_mine jump to next timestamp before mine new block * Fix unrelated clippy, simplify test --- crates/anvil/src/eth/api.rs | 4 ++-- crates/anvil/tests/it/anvil_api.rs | 18 ++++++++++++++++++ crates/cast/src/lib.rs | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 20ac92234f27..81990d75558b 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -1697,12 +1697,12 @@ impl EthApi { // mine all the blocks for _ in 0..blocks.to::() { - self.mine_one().await; - // 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.mine_one().await; } Ok(()) diff --git a/crates/anvil/tests/it/anvil_api.rs b/crates/anvil/tests/it/anvil_api.rs index da5372c7edb3..ce78d72ca59a 100644 --- a/crates/anvil/tests/it/anvil_api.rs +++ b/crates/anvil/tests/it/anvil_api.rs @@ -1009,3 +1009,21 @@ async fn test_mine_blks_with_same_timestamp() { // timestamps should be equal assert_eq!(blks, vec![init_timestamp; 4]); } + +// +#[tokio::test(flavor = "multi_thread")] +async fn test_mine_first_block_with_interval() { + let (api, _) = spawn(NodeConfig::test()).await; + + let init_block = api.block_by_number(0.into()).await.unwrap().unwrap(); + let init_timestamp = init_block.header.timestamp; + + // Mine 2 blocks with interval of 60. + let _ = api.anvil_mine(Some(U256::from(2)), Some(U256::from(60))).await; + + let first_block = api.block_by_number(1.into()).await.unwrap().unwrap(); + assert_eq!(first_block.header.timestamp, init_timestamp + 60); + + let second_block = api.block_by_number(2.into()).await.unwrap().unwrap(); + assert_eq!(second_block.header.timestamp, init_timestamp + 120); +} diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 97624c12ab64..bfa33c6e93f8 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -128,7 +128,7 @@ where /// # Ok(()) /// # } /// ``` - pub async fn call<'a>( + pub async fn call( &self, req: &WithOtherFields, func: Option<&Function>, From 95114622e832ca93a95004c5846c85e5ba81ba62 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 11:09:11 +0000 Subject: [PATCH 28/35] fix(`deps`): update `alloy-chains` to fix Celo explorer API URL (#9242) chore(deps): weekly `cargo update` Locking 32 packages to latest compatible versions Updating alloy-chains v0.1.42 -> v0.1.45 Updating alloy-dyn-abi v0.8.9 -> v0.8.10 Updating alloy-json-abi v0.8.9 -> v0.8.10 Updating alloy-primitives v0.8.9 -> v0.8.10 Updating alloy-sol-macro v0.8.9 -> v0.8.10 Updating alloy-sol-macro-expander v0.8.9 -> v0.8.10 Updating alloy-sol-macro-input v0.8.9 -> v0.8.10 Updating alloy-sol-type-parser v0.8.9 -> v0.8.10 Updating alloy-sol-types v0.8.9 -> v0.8.10 Updating anyhow v1.0.91 -> v1.0.92 Updating aws-sdk-kms v1.48.0 -> v1.49.0 Updating aws-sdk-sso v1.47.0 -> v1.48.0 Updating aws-sdk-ssooidc v1.48.0 -> v1.49.0 Updating aws-sdk-sts v1.47.0 -> v1.48.0 Updating clap_complete v4.5.35 -> v4.5.36 Updating divan v0.1.14 -> v0.1.15 Updating divan-macros v0.1.14 -> v0.1.15 Updating hyper-util v0.1.9 -> v0.1.10 Updating libm v0.2.9 -> v0.2.11 Updating op-alloy-consensus v0.5.1 -> v0.5.2 Updating op-alloy-rpc-types v0.5.1 -> v0.5.2 Updating quinn-udp v0.5.5 -> v0.5.6 Updating reqwest v0.12.8 -> v0.12.9 Updating rustix v0.38.37 -> v0.38.38 Updating rustls v0.23.15 -> v0.23.16 Updating serde v1.0.213 -> v1.0.214 Updating serde_derive v1.0.213 -> v1.0.214 Updating snapbox v0.6.18 -> v0.6.19 Updating syn v2.0.85 -> v2.0.86 Updating syn-solidity v0.8.9 -> v0.8.10 Updating thiserror v1.0.65 -> v1.0.66 Updating thiserror-impl v1.0.65 -> v1.0.66 note: pass `--verbose` to see 14 unchanged dependencies behind latest Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- Cargo.lock | 261 +++++++++++++++++++++++++++-------------------------- 1 file changed, 131 insertions(+), 130 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index de6f11ea9b21..c4a78fba0fd7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,9 +74,9 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alloy-chains" -version = "0.1.42" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca4a1469a3e572e9ba362920ff145f5d0a00a3e71a64ddcb4a3659cf64c76a7" +checksum = "4feb7c662fd0be3d0c926a456be4ac44e9cf8e05cbd91df6db7f7140b861016a" dependencies = [ "alloy-primitives", "num_enum", @@ -123,9 +123,9 @@ dependencies = [ [[package]] name = "alloy-dyn-abi" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5647fce5a168f9630f935bf7821c4207b1755184edaeba783cb4e11d35058484" +checksum = "f5228b189b18b85761340dc9eaac0141148a8503657b36f9bc3a869413d987ca" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -201,9 +201,9 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b5671117c38b1c2306891f97ad3828d85487087f54ebe2c7591a055ea5bcea7" +checksum = "31a0f0d51db8a1a30a4d98a9f90e090a94c8f44cb4d9eafc7e03aa6d00aae984" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -261,9 +261,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71738eb20c42c5fb149571e76536a0f309d142f3957c28791662b96baf77a3d" +checksum = "8edae627382349b56cd6a7a2106f4fd69b243a9233e560c55c2e03cabb7e1d3c" dependencies = [ "alloy-rlp", "arbitrary", @@ -371,7 +371,7 @@ checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -611,23 +611,23 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0900b83f4ee1f45c640ceee596afbc118051921b9438fdb5a3175c1a7e05f8b" +checksum = "841eabaa4710f719fddbc24c95d386eae313f07e6da4babc25830ee37945be0c" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] name = "alloy-sol-macro-expander" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41b1e78dde06b5e12e6702fa8c1d30621bf07728ba75b801fb801c9c6a0ba10" +checksum = "6672337f19d837b9f7073c45853aeb528ed9f7dd6a4154ce683e9e5cb7794014" dependencies = [ "alloy-json-abi", "alloy-sol-macro-input", @@ -637,16 +637,16 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", "syn-solidity", "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91dc311a561a306664393407b88d3e53ae58581624128afd8a15faa5de3627dc" +checksum = "0dff37dd20bfb118b777c96eda83b2067f4226d2644c5cfa00187b3bc01770ba" dependencies = [ "alloy-json-abi", "const-hex", @@ -655,15 +655,15 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.85", + "syn 2.0.86", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45d1fbee9e698f3ba176b6e7a145f4aefe6d2b746b611e8bb246fe11a0e9f6c4" +checksum = "5b853d42292dbb159671a3edae3b2750277ff130f32b726fe07dc2b17aa6f2b5" dependencies = [ "serde", "winnow", @@ -671,9 +671,9 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "086f41bc6ebcd8cb15f38ba20e47be38dd03692149681ce8061c35d960dbf850" +checksum = "aa828bb1b9a6dc52208fbb18084fb9ce2c30facc2bfda6a5d922349b4990354f" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -748,7 +748,7 @@ dependencies = [ "alloy-transport", "futures", "http 1.1.0", - "rustls 0.23.15", + "rustls 0.23.16", "serde_json", "tokio", "tokio-tungstenite", @@ -972,9 +972,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.91" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" +checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" [[package]] name = "arbitrary" @@ -1164,7 +1164,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -1186,7 +1186,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -1197,7 +1197,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -1250,7 +1250,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -1328,9 +1328,9 @@ dependencies = [ [[package]] name = "aws-sdk-kms" -version = "1.48.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2afbd208dabc6785946d4ef2444eb1f54fe0aaf0f62f2a4f9a9e9c303aeff0be" +checksum = "1f4c89f1d2e0df99ccd21f98598c1e587ad78bd87ae22a74aba392b5566bb038" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1350,9 +1350,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.47.0" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8776850becacbd3a82a4737a9375ddb5c6832a51379f24443a98e61513f852c" +checksum = "ded855583fa1d22e88fe39fd6062b062376e50a8211989e07cf5e38d52eb3453" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1372,9 +1372,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.48.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0007b5b8004547133319b6c4e87193eee2a0bcb3e4c18c75d09febe9dab7b383" +checksum = "9177ea1192e6601ae16c7273385690d88a7ed386a00b74a6bc894d12103cd933" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1394,9 +1394,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.47.0" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fffaa356e7f1c725908b75136d53207fa714e348f365671df14e95a60530ad3" +checksum = "823ef553cf36713c97453e2ddff1eb8f62be7f4523544e2a5db64caf80100f0a" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1782,7 +1782,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -2137,9 +2137,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.35" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07a13ab5b8cb13dbe35e68b83f6c12f9293b2f601797b71bc9f23befdb329feb" +checksum = "86bc73de94bc81e52f3bebec71bc4463e9748f7a59166663e32044669577b0e2" dependencies = [ "clap", ] @@ -2163,7 +2163,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -2581,7 +2581,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -2592,7 +2592,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -2665,7 +2665,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -2686,7 +2686,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -2696,7 +2696,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -2717,7 +2717,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", "unicode-xid", ] @@ -2825,14 +2825,14 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] name = "divan" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d567df2c9c2870a43f3f2bd65aaeb18dbce1c18f217c3e564b4fbaeb3ee56c" +checksum = "6e05d17bd4ff1c1e7998ed4623d2efd91f72f1e24141ac33aac9377974270e1f" dependencies = [ "cfg-if", "clap", @@ -2844,13 +2844,13 @@ dependencies = [ [[package]] name = "divan-macros" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27540baf49be0d484d8f0130d7d8da3011c32a44d4fc873368154f1510e574a2" +checksum = "1b4464d46ce68bfc7cb76389248c7c254def7baca8bece0693b02b83842c4c88" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -2977,7 +2977,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -3112,7 +3112,7 @@ dependencies = [ "regex", "serde", "serde_json", - "syn 2.0.85", + "syn 2.0.86", "toml 0.8.19", "walkdir", ] @@ -3140,7 +3140,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn 2.0.85", + "syn 2.0.86", "tempfile", "thiserror", "tiny-keccak", @@ -3530,7 +3530,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -4103,7 +4103,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -4262,7 +4262,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -4791,7 +4791,7 @@ dependencies = [ "markup5ever", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -4955,7 +4955,7 @@ dependencies = [ "http 1.1.0", "hyper 1.5.0", "hyper-util", - "rustls 0.23.15", + "rustls 0.23.16", "rustls-native-certs 0.8.0", "rustls-pki-types", "tokio", @@ -4995,9 +4995,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", @@ -5224,7 +5224,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b23a0c8dfe501baac4adf6ebbfa6eddf8f0c07f56b058cc1288017e32397846c" dependencies = [ "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -5477,9 +5477,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bda4c6077b0b08da2c48b172195795498381a7c8988c9e6212a6c55c5b9bd70" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libredox" @@ -5688,7 +5688,7 @@ checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -5779,7 +5779,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -6038,7 +6038,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -6086,9 +6086,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "op-alloy-consensus" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba7c98055fd048073738df0cc6d6537e992a0d8828f39d99a469e870db126dbd" +checksum = "f26c3b35b7b3e36d15e0563eebffe13c1d9ca16b7aaffcb6a64354633547e16b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6102,9 +6102,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919e9b69212d61f3c8932bfb717c7ad458ea3fc52072b3433d99994f8223d555" +checksum = "94bae9bf91b620e1e2c2291562e5998bc1247bd8ada011773e1997b31a95de99" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6177,7 +6177,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -6340,7 +6340,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -6399,7 +6399,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -6483,7 +6483,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -6541,7 +6541,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -6632,7 +6632,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -6710,7 +6710,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -6730,7 +6730,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", "version_check", "yansi", ] @@ -6794,7 +6794,7 @@ checksum = "6ff7ff745a347b87471d859a377a9a404361e7efc2a971d73424a6d183c0fc77" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -6817,7 +6817,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -6926,7 +6926,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.15", + "rustls 0.23.16", "socket2", "thiserror", "tokio", @@ -6943,7 +6943,7 @@ dependencies = [ "rand", "ring", "rustc-hash", - "rustls 0.23.15", + "rustls 0.23.16", "slab", "thiserror", "tinyvec", @@ -6952,10 +6952,11 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" +checksum = "e346e016eacfff12233c243718197ca12f148c84e1e84268a896699b41c71780" dependencies = [ + "cfg_aliases 0.2.1", "libc", "once_cell", "socket2", @@ -7147,9 +7148,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.8" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "async-compression", "base64 0.22.1", @@ -7174,7 +7175,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.15", + "rustls 0.23.16", "rustls-native-certs 0.8.0", "rustls-pemfile 2.2.0", "rustls-pki-types", @@ -7448,9 +7449,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" dependencies = [ "bitflags 2.6.0", "errno", @@ -7473,9 +7474,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.15" +version = "0.23.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" dependencies = [ "log", "once_cell", @@ -7651,7 +7652,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -7693,7 +7694,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -7851,22 +7852,22 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.213" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.213" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -7877,7 +7878,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -7921,7 +7922,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -7967,7 +7968,7 @@ checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -8146,9 +8147,9 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "snapbox" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba434818a8a9b1b106404288d6bd75a94348aae8fc9a518b211b609a36a54bc" +checksum = "881f1849454828a68363dd288b7a0a071e55e2a4356d2c38b567db18a9be0d9f" dependencies = [ "anstream", "anstyle", @@ -8329,7 +8330,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -8397,9 +8398,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.85" +version = "2.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +checksum = "e89275301d38033efb81a6e60e3497e734dfcc62571f2854bf4b16690398824c" dependencies = [ "proc-macro2", "quote", @@ -8408,14 +8409,14 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5e0c2ea8db64b2898b62ea2fbd60204ca95e0b2c6bdf53ff768bbe916fbe4d" +checksum = "16320d4a2021ba1a32470b3759676114a918885e9800e68ad60f2c67969fba62" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -8516,22 +8517,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.65" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.65" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -8656,7 +8657,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -8685,7 +8686,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.15", + "rustls 0.23.16", "rustls-pki-types", "tokio", ] @@ -8722,7 +8723,7 @@ checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", - "rustls 0.23.15", + "rustls 0.23.16", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -8931,7 +8932,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -9047,7 +9048,7 @@ dependencies = [ "httparse", "log", "rand", - "rustls 0.23.15", + "rustls 0.23.16", "rustls-pki-types", "sha1", "thiserror", @@ -9334,7 +9335,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", "wasm-bindgen-shared", ] @@ -9368,7 +9369,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -9599,7 +9600,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -9610,7 +9611,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -9621,7 +9622,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -9632,7 +9633,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -9898,7 +9899,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] @@ -9918,7 +9919,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.86", ] [[package]] From 7587eb53a996ff289de2c8fdb4a49c93e90d5f9b Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Fri, 1 Nov 2024 15:11:14 +0100 Subject: [PATCH 29/35] fix: reset shell colors based on the input style (#9243) --- crates/common/src/io/shell.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/crates/common/src/io/shell.rs b/crates/common/src/io/shell.rs index a132b343d11e..e13f1399969d 100644 --- a/crates/common/src/io/shell.rs +++ b/crates/common/src/io/shell.rs @@ -411,22 +411,16 @@ impl ShellOut { /// Write a styled fragment fn write_stdout(&mut self, fragment: impl fmt::Display, style: &Style) -> Result<()> { - let style = style.render(); - let reset = anstyle::Reset.render(); - let mut buffer = Vec::new(); - write!(buffer, "{style}{fragment}{reset}")?; + write!(buffer, "{style}{fragment}{style:#}")?; self.stdout().write_all(&buffer)?; Ok(()) } /// Write a styled fragment fn write_stderr(&mut self, fragment: impl fmt::Display, style: &Style) -> Result<()> { - let style = style.render(); - let reset = anstyle::Reset.render(); - let mut buffer = Vec::new(); - write!(buffer, "{style}{fragment}{reset}")?; + write!(buffer, "{style}{fragment}{style:#}")?; self.stderr().write_all(&buffer)?; Ok(()) } @@ -456,19 +450,17 @@ impl ShellOut { style: &Style, justified: bool, ) -> Result> { - let style = style.render(); - let bold = (anstyle::Style::new() | anstyle::Effects::BOLD).render(); - let reset = anstyle::Reset.render(); + let bold = anstyle::Style::new().bold(); let mut buffer = Vec::new(); if justified { - write!(&mut buffer, "{style}{status:>12}{reset}")?; + write!(buffer, "{style}{status:>12}{style:#}")?; } else { - write!(&mut buffer, "{style}{status}{reset}{bold}:{reset}")?; + write!(buffer, "{style}{status}{style:#}{bold}:{bold:#}")?; } match message { Some(message) => { - writeln!(&mut buffer, " {message}")?; + writeln!(buffer, " {message}")?; } None => write!(buffer, " ")?, } From ea11082555e15f899a8bb9102890f3c2f7713cb8 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:30:37 +0100 Subject: [PATCH 30/35] fix: avoid deadlock in nested shell calls (#9245) * fix: avoid deadlock in nested shell calls * cleanup --- crates/common/src/io/macros.rs | 19 ++++++++++++++++--- crates/common/src/io/shell.rs | 11 +++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/crates/common/src/io/macros.rs b/crates/common/src/io/macros.rs index fe1e72dfecc9..10e7cca4a2e3 100644 --- a/crates/common/src/io/macros.rs +++ b/crates/common/src/io/macros.rs @@ -132,15 +132,23 @@ macro_rules! sh_eprintln { #[macro_export] macro_rules! __sh_dispatch { ($f:ident $fmt:literal $($args:tt)*) => { - $crate::Shell::$f(&mut *$crate::Shell::get(), ::core::format_args!($fmt $($args)*)) + $crate::__sh_dispatch!(@impl $f &mut *$crate::Shell::get(), $fmt $($args)*) }; ($f:ident $shell:expr, $($args:tt)*) => { - $crate::Shell::$f($shell, ::core::format_args!($($args)*)) + $crate::__sh_dispatch!(@impl $f $shell, $($args)*) }; ($f:ident $($args:tt)*) => { - $crate::Shell::$f(&mut *$crate::Shell::get(), ::core::format_args!($($args)*)) + $crate::__sh_dispatch!(@impl $f &mut *$crate::Shell::get(), $($args)*) + }; + + // Ensure that the global shell lock is held for as little time as possible. + // Also avoids deadlocks in case of nested calls. + (@impl $f:ident $shell:expr, $($args:tt)*) => { + match ::core::format_args!($($args)*) { + fmt => $crate::Shell::$f($shell, fmt), + } }; } @@ -168,6 +176,11 @@ mod tests { sh_eprintln!("eprintln")?; sh_eprintln!("eprintln {}", "arg")?; + sh_println!("{:?}", { + sh_println!("hi")?; + "nested" + })?; + Ok(()) } diff --git a/crates/common/src/io/shell.rs b/crates/common/src/io/shell.rs index e13f1399969d..ee217fa728e8 100644 --- a/crates/common/src/io/shell.rs +++ b/crates/common/src/io/shell.rs @@ -186,9 +186,9 @@ impl Shell { } } - /// Get a static reference to the global shell. + /// Acquire a lock to the global shell. /// - /// Initializes the global shell with the default values if it has not been set yet. + /// Initializes it with the default values if it has not been set yet. pub fn get() -> impl DerefMut + 'static { GLOBAL_SHELL.get_or_init(Default::default).lock().unwrap_or_else(PoisonError::into_inner) } @@ -200,10 +200,9 @@ impl Shell { /// Panics if the global shell has already been set. #[track_caller] pub fn set(self) { - if GLOBAL_SHELL.get().is_some() { - panic!("attempted to set global shell twice"); - } - GLOBAL_SHELL.get_or_init(|| Mutex::new(self)); + GLOBAL_SHELL + .set(Mutex::new(self)) + .unwrap_or_else(|_| panic!("attempted to set global shell twice")) } /// Sets whether the next print should clear the current line and returns the previous value. From 56639cd1772dac628728d2441887e5ccc287ebe9 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Fri, 1 Nov 2024 18:29:36 +0100 Subject: [PATCH 31/35] anvil: Correctly set HF fields for Genesis block (#9248) Some fields were missing for some HF, leading to an invalid Genesis block hash. --- crates/anvil/src/eth/backend/mem/mod.rs | 4 +++- crates/anvil/src/eth/backend/mem/storage.rs | 21 ++++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 65ab8c32952b..c7ff9422a6e4 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -230,8 +230,10 @@ impl Backend { trace!(target: "backend", "using forked blockchain at {}", fork.block_number()); Blockchain::forked(fork.block_number(), fork.block_hash(), fork.total_difficulty()) } else { + let env = env.read(); Blockchain::new( - &env.read(), + &env, + env.handler_cfg.spec_id, fees.is_eip1559().then(|| fees.base_fee()), genesis.timestamp, ) diff --git a/crates/anvil/src/eth/backend/mem/storage.rs b/crates/anvil/src/eth/backend/mem/storage.rs index 2105666a4e91..d5a72fccbbb6 100644 --- a/crates/anvil/src/eth/backend/mem/storage.rs +++ b/crates/anvil/src/eth/backend/mem/storage.rs @@ -10,6 +10,8 @@ use crate::eth::{ error::BlockchainError, pool::transactions::PoolTransaction, }; +use alloy_consensus::constants::EMPTY_WITHDRAWALS; +use alloy_eips::eip7685::EMPTY_REQUESTS_HASH; use alloy_primitives::{ map::{B256HashMap, HashMap}, Bytes, B256, U256, U64, @@ -38,6 +40,7 @@ use foundry_evm::{ }, }; use parking_lot::RwLock; +use revm::primitives::SpecId; use std::{collections::VecDeque, fmt, sync::Arc, time::Duration}; // use yansi::Paint; @@ -262,7 +265,11 @@ pub struct BlockchainStorage { impl BlockchainStorage { /// Creates a new storage with a genesis block - pub fn new(env: &Env, base_fee: Option, timestamp: u64) -> Self { + pub fn new(env: &Env, spec_id: SpecId, base_fee: Option, timestamp: u64) -> Self { + let is_shanghai = spec_id >= SpecId::SHANGHAI; + let is_cancun = spec_id >= SpecId::CANCUN; + let is_prague = spec_id >= SpecId::PRAGUE; + // create a dummy genesis block let partial_header = PartialHeader { timestamp, @@ -272,6 +279,10 @@ impl BlockchainStorage { 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(), + + parent_beacon_block_root: is_cancun.then_some(Default::default()), + withdrawals_root: is_shanghai.then_some(EMPTY_WITHDRAWALS), + requests_hash: is_prague.then_some(EMPTY_REQUESTS_HASH), ..Default::default() }; let block = Block::new::(partial_header, vec![]); @@ -423,8 +434,12 @@ pub struct Blockchain { impl Blockchain { /// Creates a new storage with a genesis block - pub fn new(env: &Env, base_fee: Option, timestamp: u64) -> Self { - Self { storage: Arc::new(RwLock::new(BlockchainStorage::new(env, base_fee, timestamp))) } + pub fn new(env: &Env, spec_id: SpecId, base_fee: Option, timestamp: u64) -> Self { + Self { + storage: Arc::new(RwLock::new(BlockchainStorage::new( + env, spec_id, base_fee, timestamp, + ))), + } } pub fn forked(block_number: u64, block_hash: B256, total_difficulty: U256) -> Self { From 97be9b9a2e128633b17589cd58bfde4b4d544e23 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Sat, 2 Nov 2024 10:33:19 +0100 Subject: [PATCH 32/35] perf: cap default poll interval (#9250) --- crates/common/src/provider/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/common/src/provider/mod.rs b/crates/common/src/provider/mod.rs index fe7fd4ccc9d9..4fb9e29aec0c 100644 --- a/crates/common/src/provider/mod.rs +++ b/crates/common/src/provider/mod.rs @@ -270,6 +270,9 @@ impl ProviderBuilder { client.set_poll_interval( chain .average_blocktime_hint() + // we cap the poll interval because if not provided, chain would default to + // mainnet + .map(|hint| hint.min(DEFAULT_UNKNOWN_CHAIN_BLOCK_TIME)) .unwrap_or(DEFAULT_UNKNOWN_CHAIN_BLOCK_TIME) .mul_f32(POLL_INTERVAL_BLOCK_TIME_SCALE_FACTOR), ); From d402afd2db0e4546d33a7f94d3a226cce6ff2c76 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Sun, 3 Nov 2024 00:45:57 +0400 Subject: [PATCH 33/35] fix: better error handling when waiting for receipt (#9253) * fix: better error handling when waiting for receipt * fmt --- crates/script/src/receipts.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/crates/script/src/receipts.rs b/crates/script/src/receipts.rs index 02ee75fa672f..af80734c59fe 100644 --- a/crates/script/src/receipts.rs +++ b/crates/script/src/receipts.rs @@ -1,6 +1,6 @@ use alloy_chains::Chain; use alloy_primitives::{utils::format_units, TxHash, U256}; -use alloy_provider::{PendingTransactionBuilder, Provider}; +use alloy_provider::{PendingTransactionBuilder, PendingTransactionError, Provider, WatchTxError}; use alloy_rpc_types::AnyTransactionReceipt; use eyre::Result; use foundry_common::provider::RetryProvider; @@ -40,12 +40,16 @@ pub async fn check_tx_status( } loop { - if let Ok(receipt) = PendingTransactionBuilder::new(provider.clone(), hash) + match PendingTransactionBuilder::new(provider.clone(), hash) .with_timeout(Some(Duration::from_secs(timeout))) .get_receipt() .await { - return Ok(receipt.into()) + Ok(receipt) => return Ok(receipt.into()), + // do nothing on timeout, we will check whether tx is dropped below + Err(PendingTransactionError::TxWatcher(WatchTxError::Timeout)) => {} + // treat other errors as fatal + Err(e) => return Err(e.into()), } if provider.get_transaction_by_hash(hash).await?.is_some() { From 8660e5b941fe7f4d67e246cfd3dafea330fb53b1 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Sun, 3 Nov 2024 01:49:32 +0400 Subject: [PATCH 34/35] fix: use `Debug` when formatting errors (#9251) * fix: use Debug when formatting errors * sh_err * rm newline in handler --- crates/anvil/src/anvil.rs | 2 +- crates/cast/bin/main.rs | 2 +- crates/chisel/bin/main.rs | 2 +- crates/cli/src/handler.rs | 1 - crates/forge/bin/main.rs | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/anvil/src/anvil.rs b/crates/anvil/src/anvil.rs index 9d4a0cf7ba20..5e2a42f59ef0 100644 --- a/crates/anvil/src/anvil.rs +++ b/crates/anvil/src/anvil.rs @@ -39,7 +39,7 @@ pub enum AnvilSubcommand { fn main() { if let Err(err) = run() { - let _ = foundry_common::Shell::get().error(&err); + let _ = foundry_common::sh_err!("{err:?}"); std::process::exit(1); } } diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index 974b7eb86157..f7d66ef9d0d0 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -39,7 +39,7 @@ static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; fn main() { if let Err(err) = run() { - let _ = foundry_common::Shell::get().error(&err); + let _ = foundry_common::sh_err!("{err:?}"); std::process::exit(1); } } diff --git a/crates/chisel/bin/main.rs b/crates/chisel/bin/main.rs index 17697688bb3e..dca99d4a594d 100644 --- a/crates/chisel/bin/main.rs +++ b/crates/chisel/bin/main.rs @@ -108,7 +108,7 @@ pub enum ChiselSubcommand { fn main() { if let Err(err) = run() { - let _ = foundry_common::Shell::get().error(&err); + let _ = foundry_common::sh_err!("{err:?}"); std::process::exit(1); } } diff --git a/crates/cli/src/handler.rs b/crates/cli/src/handler.rs index 4f69c2ca445c..b2fbb49d4ea8 100644 --- a/crates/cli/src/handler.rs +++ b/crates/cli/src/handler.rs @@ -15,7 +15,6 @@ impl EyreHandler for Handler { if f.alternate() { return core::fmt::Debug::fmt(error, f) } - writeln!(f)?; write!(f, "{}", error.red())?; if let Some(cause) = error.source() { diff --git a/crates/forge/bin/main.rs b/crates/forge/bin/main.rs index a78218e94e0a..c713a703ee7b 100644 --- a/crates/forge/bin/main.rs +++ b/crates/forge/bin/main.rs @@ -22,7 +22,7 @@ static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; fn main() { if let Err(err) = run() { - let _ = foundry_common::Shell::get().error(&err); + let _ = foundry_common::sh_err!("{err:?}"); std::process::exit(1); } } From d2ed15d517a3af56fced592aa4a21df0293710c5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 03:47:27 +0000 Subject: [PATCH 35/35] chore(deps): weekly `cargo update` (#9254) Locking 5 packages to latest compatible versions Updating alloy-chains v0.1.45 -> v0.1.46 Updating anstyle v1.0.9 -> v1.0.10 Updating cc v1.1.31 -> v1.1.34 Updating jiff v0.1.13 -> v0.1.14 Updating syn v2.0.86 -> v2.0.87 note: pass `--verbose` to see 14 unchanged dependencies behind latest Co-authored-by: mattsse <19890894+mattsse@users.noreply.github.com> --- Cargo.lock | 136 ++++++++++++++++++++++++++--------------------------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c4a78fba0fd7..73a15ac8ce2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,9 +74,9 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alloy-chains" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4feb7c662fd0be3d0c926a456be4ac44e9cf8e05cbd91df6db7f7140b861016a" +checksum = "836cf02383d9ebb35502d379bcd1ae803155094077eaab9c29131d888cd5fa3e" dependencies = [ "alloy-primitives", "num_enum", @@ -371,7 +371,7 @@ checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -620,7 +620,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -637,7 +637,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", "syn-solidity", "tiny-keccak", ] @@ -655,7 +655,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.86", + "syn 2.0.87", "syn-solidity", ] @@ -816,9 +816,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" @@ -1164,7 +1164,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -1186,7 +1186,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -1197,7 +1197,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -1250,7 +1250,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -1782,7 +1782,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -1998,9 +1998,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.31" +version = "1.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +checksum = "67b9470d453346108f93a59222a9a1a5724db32d0a4727b7ab7ace4b4d822dc9" dependencies = [ "shlex", ] @@ -2163,7 +2163,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -2581,7 +2581,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -2592,7 +2592,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -2665,7 +2665,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -2686,7 +2686,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -2696,7 +2696,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -2717,7 +2717,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", "unicode-xid", ] @@ -2825,7 +2825,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -2850,7 +2850,7 @@ checksum = "1b4464d46ce68bfc7cb76389248c7c254def7baca8bece0693b02b83842c4c88" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -2977,7 +2977,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -3112,7 +3112,7 @@ dependencies = [ "regex", "serde", "serde_json", - "syn 2.0.86", + "syn 2.0.87", "toml 0.8.19", "walkdir", ] @@ -3140,7 +3140,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn 2.0.86", + "syn 2.0.87", "tempfile", "thiserror", "tiny-keccak", @@ -3530,7 +3530,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -4103,7 +4103,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -4262,7 +4262,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -4791,7 +4791,7 @@ dependencies = [ "markup5ever", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -5224,7 +5224,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b23a0c8dfe501baac4adf6ebbfa6eddf8f0c07f56b058cc1288017e32397846c" dependencies = [ "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -5309,9 +5309,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jiff" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a45489186a6123c128fdf6016183fcfab7113e1820eb813127e036e287233fb" +checksum = "b9d9d414fc817d3e3d62b2598616733f76c4cc74fbac96069674739b881295c8" dependencies = [ "jiff-tzdb-platform", "windows-sys 0.59.0", @@ -5688,7 +5688,7 @@ checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -5779,7 +5779,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -6038,7 +6038,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -6177,7 +6177,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -6340,7 +6340,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -6399,7 +6399,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -6483,7 +6483,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -6541,7 +6541,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -6632,7 +6632,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -6710,7 +6710,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -6730,7 +6730,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", "version_check", "yansi", ] @@ -6794,7 +6794,7 @@ checksum = "6ff7ff745a347b87471d859a377a9a404361e7efc2a971d73424a6d183c0fc77" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -6817,7 +6817,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -7652,7 +7652,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -7694,7 +7694,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -7867,7 +7867,7 @@ checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -7878,7 +7878,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -7922,7 +7922,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -7968,7 +7968,7 @@ checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -8330,7 +8330,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -8398,9 +8398,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.86" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89275301d38033efb81a6e60e3497e734dfcc62571f2854bf4b16690398824c" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -8416,7 +8416,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -8532,7 +8532,7 @@ checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -8657,7 +8657,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -8932,7 +8932,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -9335,7 +9335,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", "wasm-bindgen-shared", ] @@ -9369,7 +9369,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -9600,7 +9600,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -9611,7 +9611,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -9622,7 +9622,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -9633,7 +9633,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -9899,7 +9899,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -9919,7 +9919,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]]