Skip to content

fix(forge): do not use bytecode metadata in fuzz dict #10402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ chrono = { version = "0.4", default-features = false, features = [
"std",
] }
axum = "0.7"
ciborium = "0.2"
color-eyre = "0.6"
comfy-table = "7"
dirs = "6"
Expand Down
1 change: 1 addition & 0 deletions crates/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ path-slash.workspace = true
anstream.workspace = true
anstyle.workspace = true
terminal_size.workspace = true
ciborium.workspace = true

[build-dependencies]
chrono.workspace = true
Expand Down
17 changes: 17 additions & 0 deletions crates/common/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,20 @@ pub fn erc7201(id: &str) -> B256 {
let x = U256::from_be_bytes(keccak256(id).0) - U256::from(1);
keccak256(x.to_be_bytes::<32>()) & B256::from(!U256::from(0xff))
}

/// Utility function to ignore metadata hash of the given bytecode.
/// This assumes that the metadata is at the end of the bytecode.
pub fn ignore_metadata_hash(bytecode: &[u8]) -> &[u8] {
// Get the last two bytes of the bytecode to find the length of CBOR metadata.
let Some((rest, metadata_len_bytes)) = bytecode.split_last_chunk() else { return bytecode };
let metadata_len = u16::from_be_bytes(*metadata_len_bytes) as usize;
if metadata_len > rest.len() {
return bytecode;
}
let (rest, metadata) = rest.split_at(rest.len() - metadata_len);
if ciborium::from_reader::<ciborium::Value, _>(metadata).is_ok() {
rest
} else {
bytecode
}
}
3 changes: 2 additions & 1 deletion crates/evm/fuzz/src/strategies/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use alloy_primitives::{
map::{AddressIndexSet, B256IndexSet, HashMap},
Address, Bytes, Log, B256, U256,
};
use foundry_common::ignore_metadata_hash;
use foundry_config::FuzzDictionaryConfig;
use foundry_evm_core::utils::StateChangeset;
use parking_lot::{lock_api::RwLockReadGuard, RawRwLock, RwLock};
Expand Down Expand Up @@ -248,7 +249,7 @@ impl FuzzDictionary {
// Insert push bytes
if let Some(code) = &account_info.code {
self.insert_address(*address);
self.collect_push_bytes(code.bytes_slice());
self.collect_push_bytes(ignore_metadata_hash(code.original_byte_slice()));
}
}
}
Expand Down
18 changes: 9 additions & 9 deletions crates/forge/tests/it/invariant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1114,9 +1114,9 @@ Encountered 1 failing test in test/InvariantSequenceLenTest.t.sol:InvariantSeque
[FAIL: invariant increment failure]
[Sequence] (original: 4, shrunk: 4)
sender=0x00000000000000000000000000000000000018dE addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[1931387396117645594923 [1.931e21]]
sender=0x00000000000000000000000000000000000009d5 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[]
sender=0x0000000000000000000000000000000000000105 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[]
sender=0x00000000000000000000000000000000000009B2 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[996881781832960761274744263729582347 [9.968e35]]
sender=0x0000000000000000000000000000000000000C37 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[]
sender=0x0000000000000000000000000000000000000106 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[]
sender=0x0000000000000000000000000000000000001684 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[996881781832960761274744263729582347 [9.968e35]]
invariant_increment() (runs: 0, calls: 0, reverts: 0)

Encountered a total of 1 failing tests, 0 tests succeeded
Expand All @@ -1138,11 +1138,11 @@ Encountered 1 failing test in test/InvariantSequenceLenTest.t.sol:InvariantSeque
[Sequence] (original: 4, shrunk: 4)
vm.prank(0x00000000000000000000000000000000000018dE);
Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).setNumber(1931387396117645594923);
vm.prank(0x00000000000000000000000000000000000009d5);
vm.prank(0x0000000000000000000000000000000000000C37);
Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).increment();
vm.prank(0x0000000000000000000000000000000000000105);
vm.prank(0x0000000000000000000000000000000000000106);
Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).increment();
vm.prank(0x00000000000000000000000000000000000009B2);
vm.prank(0x0000000000000000000000000000000000001684);
Counter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).setNumber(996881781832960761274744263729582347);
invariant_increment() (runs: 0, calls: 0, reverts: 0)

Expand All @@ -1163,9 +1163,9 @@ Encountered 1 failing test in test/InvariantSequenceLenTest.t.sol:InvariantSeque
[FAIL: invariant_increment replay failure]
[Sequence] (original: 4, shrunk: 4)
sender=0x00000000000000000000000000000000000018dE addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[1931387396117645594923 [1.931e21]]
sender=0x00000000000000000000000000000000000009d5 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[]
sender=0x0000000000000000000000000000000000000105 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[]
sender=0x00000000000000000000000000000000000009B2 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[996881781832960761274744263729582347 [9.968e35]]
sender=0x0000000000000000000000000000000000000C37 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[]
sender=0x0000000000000000000000000000000000000106 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[]
sender=0x0000000000000000000000000000000000001684 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[996881781832960761274744263729582347 [9.968e35]]
invariant_increment() (runs: 1, calls: 1, reverts: 1)

Encountered a total of 1 failing tests, 0 tests succeeded
Expand Down
2 changes: 0 additions & 2 deletions crates/verify/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ regex = { workspace = true, default-features = false }
yansi.workspace = true
itertools.workspace = true

ciborium = "0.2"

[dev-dependencies]
tokio = { workspace = true, features = ["macros"] }
foundry-test-utils.workspace = true
Expand Down
21 changes: 4 additions & 17 deletions crates/verify/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ use foundry_block_explorers::{
contract::{ContractCreationData, ContractMetadata, Metadata},
errors::EtherscanError,
};
use foundry_common::{abi::encode_args, compile::ProjectCompiler, provider::RetryProvider, shell};
use foundry_common::{
abi::encode_args, compile::ProjectCompiler, ignore_metadata_hash, provider::RetryProvider,
shell,
};
use foundry_compilers::artifacts::{BytecodeHash, CompactContractBytecode, EvmVersion};
use foundry_config::Config;
use foundry_evm::{
Expand Down Expand Up @@ -204,22 +207,6 @@ fn try_extract_and_compare_bytecode(mut local_bytecode: &[u8], mut bytecode: &[u
local_bytecode == bytecode
}

/// This assumes that the metadata is at the end of the bytecode.
fn ignore_metadata_hash(bytecode: &[u8]) -> &[u8] {
// Get the last two bytes of the bytecode to find the length of CBOR metadata.
let Some((rest, metadata_len_bytes)) = bytecode.split_last_chunk() else { return bytecode };
let metadata_len = u16::from_be_bytes(*metadata_len_bytes) as usize;
if metadata_len > rest.len() {
return bytecode;
}
let (rest, metadata) = rest.split_at(rest.len() - metadata_len);
if ciborium::from_reader::<ciborium::Value, _>(metadata).is_ok() {
rest
} else {
bytecode
}
}

fn find_mismatch_in_settings(
etherscan_settings: &Metadata,
local_settings: &Config,
Expand Down