Skip to content
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
90 changes: 90 additions & 0 deletions lib/dvf/parse.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashSet;
use std::env::VarError;
use std::fmt;
use std::fs::File;
Expand Down Expand Up @@ -671,4 +672,93 @@ impl CompleteDVF {
fn get_version(&self) -> &Version {
&self.version
}

pub fn critical_fields_equal(&self, other: &Self, ignore_chain_id: bool) -> bool {
let mut json1 = serde_json::to_value(self).expect("Serialization failed");
let mut json2 = serde_json::to_value(other).expect("Serialization failed");

// Keys to always ignore
let mut ignored_keys = vec!["id", "deployment_tx", "unvalidated_metadata"];

if ignore_chain_id {
ignored_keys.extend(&["chain_id"]);
}

for key in ignored_keys {
json1.as_object_mut().unwrap().remove(key);
json2.as_object_mut().unwrap().remove(key);
}

let has_diff = diff_json(&json1, &json2, "dvf".to_string());

!has_diff
}
}

// Returns true when there is a difference
fn diff_json(v1: &Value, v2: &Value, path: String) -> bool {
let mut has_diff = false;

match (v1, v2) {
(Value::Object(map1), Value::Object(map2)) => {
// Compare the keys of both objects
let keys1: HashSet<_> = map1.keys().collect();
let keys2: HashSet<_> = map2.keys().collect();

// Find keys that are in one object but not the other
let diff_keys1 = keys1.difference(&keys2);
let diff_keys2 = keys2.difference(&keys1);

for key in diff_keys1 {
println!(
"Different key at {}: key present in first but not second: {}",
path, key
);
has_diff = true;
}
for key in diff_keys2 {
println!(
"Different key at {}: key present in second but not first: {}",
path, key
);
has_diff = true;
}

// Recursively compare the values associated with each key
for key in keys1.intersection(&keys2) {
if diff_json(&map1[*key], &map2[*key], format!("{}/{}", path, key)) {
has_diff = true;
}
}
}
(Value::Array(arr1), Value::Array(arr2)) => {
// Compare the lengths of both arrays
if arr1.len() != arr2.len() {
println!(
"Different array lengths at {}: {} != {}",
path,
arr1.len(),
arr2.len()
);
has_diff = true;
}

// Compare each element in the array
for (i, (e1, e2)) in arr1.iter().zip(arr2.iter()).enumerate() {
if diff_json(e1, e2, format!("{}/{}", path, i)) {
has_diff = true;
}
}
}
_ => {
// If values are different, print the difference and return true
if v1 != v2 {
println!("Difference at {}: {} != {}", path, v1, v2);
has_diff = true;
}
}
}

// Return true if any difference is found, else false
has_diff
}
10 changes: 4 additions & 6 deletions lib/web3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -747,13 +747,11 @@ pub fn get_deployment(
Box::new(move || {
let config = unsafe { &*config_ptr };
let address = unsafe { &*address_ptr };
debug!("No deployment tx found in etherscan or blockscout, searching traces. ");
let current_block_num = get_eth_block_number(config)?;
let start_block_num = if current_block_num > 10 {
get_deployment_block_from_binary_search(config, address, current_block_num)?
} else {
1
};
let start_block_num =
get_deployment_block_from_binary_search(config, address, current_block_num)
.map_or(1, |v| v);
debug!("No deployment tx found in etherscan or blockscout, searching traces from {start_block_num}.");
match get_deployment_from_parity_trace(
config,
address,
Expand Down
20 changes: 20 additions & 0 deletions tests/Contracts/script/Waste1Block.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
pragma solidity ^0.8.12;

import "forge-std/Script.sol";
import "../src/BytesMapping.sol";

contract S is Script {
uint256 x;
uint256 y;

function run() external {
uint256 anvilSecondKey = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d;
//uint256 ganacheDefaultKey = 0x0cc0c2de7e8c30525b4ca3b9e0b9703fb29569060d403261055481df7014f7fa;
vm.startBroadcast(anvilSecondKey);
address payable recipient = payable(0x1234567890AbcdEF1234567890aBcdef12345678);

// Send exactly 1 wei
(bool success,) = recipient.call{value: 1 wei}("");
vm.stopBroadcast();
}
}
2 changes: 1 addition & 1 deletion tests/expected_dvfs/AllValueTypes_operators_Anvil.dvf.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"contract_name": "AllValueTypes",
"address": "0x5fbdb2315678afecb367f032d93f642f64180aa3",
"chain_id": 31337,
"deployment_block_num": 1,
"deployment_block_num": 2,
"init_block_num": 4,
"deployment_tx": "0x4c0eda23fa858c9ec88a7004c80c78a606561025d2d8b2c85f825957cab8fc9b",
"codehash": "0xc5f9a009f6b4fe853fa6d949876dedd2594d797a7aa57fcf9c58031f7911dfe5",
Expand Down
4 changes: 2 additions & 2 deletions tests/expected_dvfs/Lib.dvf.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"version": "0.9.1",
"id": "0xdb26661b8d95e1e02f9331fc20ac3e28635fa9895083c1366c7918a59963312d",
"id": "0x721fa24eea7458a12242c6cc73ac0f2c511b3c04da155445f2fd60e9632168a9",
"contract_name": "Lib",
"address": "0x8627e5da250bd67817177c77ed8432e8528d2bc9",
"chain_id": 31337,
"deployment_block_num": 1,
"deployment_block_num": 2,
"init_block_num": 4,
"deployment_tx": "0xc46bb378f0ae75fbf0c0c65d9536df3854c9147ebb0d8adec1cd65355cfe36bc",
"codehash": "0xacdec87e06ce0e6478a315ee1ceccbd69f4b0e9bb3ee92c4ea70b8a757818512",
Expand Down
131 changes: 44 additions & 87 deletions tests/test_end_to_end.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ mod tests {
use std::fs::metadata;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::{self, Write};
use std::io::{BufRead, BufReader};
use std::io::Write;
use std::panic;
use std::path::Path;
use std::process::{Child, Command as SimpleCommand, Stdio};
Expand Down Expand Up @@ -93,6 +92,22 @@ mod tests {
println!("Waiting for anvil config: {:?}", e);
sleep(Duration::from_millis(100));
}
// Waste one block to be consistent with geth
// forge script script/WasteBlock.s.sol --rpc-url "http://127.0.0.1:8546" --broadcast --slow
let mut forge_cmd = Command::new("forge");
forge_cmd.current_dir("tests/Contracts");
forge_cmd
.args(&[
"script",
"script/Waste1Block.s.sol",
"--rpc-url",
&anvil.endpoint(),
"--broadcast",
"--slow",
])
.assert()
.success();

LocalClient::Anvil(anvil)
}
_ => {
Expand Down Expand Up @@ -215,48 +230,26 @@ mod tests {
}
}

fn assert_eq_files<P: AsRef<Path>>(path1: P, path2: P, l: LocalClientType) -> io::Result<()> {
let file1 = File::open(path1)?;
let file2 = File::open(path2)?;

let reader1 = BufReader::new(&file1);
let reader2 = BufReader::new(&file2);

for (line_number, (line1, line2)) in reader1.lines().zip(reader2.lines()).enumerate() {
let line1 = line1?;
let line2 = line2?;

// Code hashes and deployment txs can be different

if !line1.contains("\"codehash\"") && !line1.contains("\"deployment_tx\"") {
// Chain ID is different for geth
if LocalClientType::Geth == l
&& !(line1.contains("\"chain_id\":")
|| line1.contains("\"deployment_block_num\":"))
{
// don't compare codehash to avoid metadata mis-matches
assert_eq!(
line1,
line2,
"Line {}: \nFile1: {}\nFile2: {}",
line_number + 1,
line1,
line2
);
}
}
}

let reader1 = BufReader::new(file1);
let reader2 = BufReader::new(file2);
#[test]
#[should_panic]
fn test_file_diff() {
let p1 = &Path::new("tests/expected_dvfs/Deploy_0_b1.dvf.json");
let p2 = &Path::new("tests/expected_dvfs/Deploy_0_updated.dvf.json");
assert_eq_files(p1, p2);
}

assert_eq!(
reader1.lines().count(),
reader2.lines().count(),
"Differently many lines."
fn assert_eq_files<P: AsRef<Path>>(path1: P, path2: P) {
let dvf1 =
CompleteDVF::from_path(path1.as_ref()).expect("File1 cannot be parsed into a DVF");
let dvf2 =
CompleteDVF::from_path(path2.as_ref()).expect("File2 cannot be parsed into a DVF");

assert!(
dvf1.critical_fields_equal(&dvf2, true),
"DVF {:?} does not match DVF {:?}",
path1.as_ref(),
path2.as_ref()
);

Ok(())
}

#[test]
Expand Down Expand Up @@ -397,12 +390,7 @@ mod tests {
// Uncomment to regenerate expected files
// std::fs::copy(outfile.path(), Path::new(&testcase.expected)).unwrap();

assert_eq_files(
&outfile.path(),
&Path::new(&testcase.expected),
client_type.clone(),
)
.unwrap();
assert_eq_files(&outfile.path(), &Path::new(&testcase.expected));

// Sign
let mut dvf_cmd = Command::cargo_bin("dv").unwrap();
Expand Down Expand Up @@ -452,12 +440,7 @@ mod tests {
// Uncomment to regenerate expected files
// std::fs::copy(Path::new(&updated_path), Path::new(&testcase.updated)).unwrap();

assert_eq_files(
&Path::new(&updated_path),
&Path::new(&testcase.updated),
client_type.clone(),
)
.unwrap();
assert_eq_files(&Path::new(&updated_path), &Path::new(&testcase.updated));

// Sign
let mut dvf_cmd = Command::cargo_bin("dv").unwrap();
Expand Down Expand Up @@ -562,9 +545,7 @@ mod tests {
assert_eq_files(
&factory_outfile.path(),
&Path::new("tests/expected_dvfs/PullPayment.dvf.json"),
client_type.clone(),
)
.unwrap();
);

// Sign
let mut dvf_cmd = Command::cargo_bin("dv").unwrap();
Expand Down Expand Up @@ -662,9 +643,7 @@ mod tests {
assert_eq_files(
&outfile.path(),
&Path::new("tests/expected_dvfs/MyToken.dvf.json"),
client_type.clone(),
)
.unwrap();
);

// Sign
let mut dvf_cmd = Command::cargo_bin("dv").unwrap();
Expand Down Expand Up @@ -724,9 +703,7 @@ mod tests {
assert_eq_files(
&proxy_outfile.path(),
&Path::new("tests/expected_dvfs/TransparentUpgradeableProxy.dvf.json"),
client_type.clone(),
)
.unwrap();
);

let mut dvf_cmd = Command::cargo_bin("dv").unwrap();
dvf_cmd
Expand Down Expand Up @@ -897,12 +874,7 @@ mod tests {
// Uncomment to regenerate expected files
// std::fs::copy(outfile.path(), Path::new(&testcase.expected)).unwrap();

assert_eq_files(
&outfile.path(),
&Path::new(&testcase.expected),
client_type.clone(),
)
.unwrap();
assert_eq_files(&outfile.path(), &Path::new(&testcase.expected));

// Sign
let mut dvf_cmd = Command::cargo_bin("dv").unwrap();
Expand Down Expand Up @@ -1170,12 +1142,7 @@ mod tests {
// Uncomment to regenerate expected files
// std::fs::copy(child_outfile.path(), Path::new(new_fname)).unwrap();

assert_eq_files(
&child_outfile.path(),
&Path::new(new_fname),
client_type.clone(),
)
.unwrap();
assert_eq_files(&child_outfile.path(), &Path::new(new_fname));

// Sign
let mut dvf_cmd = Command::cargo_bin("dv").unwrap();
Expand Down Expand Up @@ -1287,12 +1254,7 @@ mod tests {
// Uncomment to regenerate expected files
// std::fs::copy(factory_outfile.path(), Path::new(dvf_path)).unwrap();

assert_eq_files(
&factory_outfile.path(),
&Path::new(dvf_path),
client_type.clone(),
)
.unwrap();
assert_eq_files(&factory_outfile.path(), &Path::new(dvf_path));

// Sign
let mut dvf_cmd = Command::cargo_bin("dv").unwrap();
Expand Down Expand Up @@ -1595,12 +1557,7 @@ mod tests {
// Uncomment to regenerate expected files
// std::fs::copy(outfile.path(), Path::new(&testcase.expected)).unwrap();

assert_eq_files(
&outfile.path(),
&Path::new(&testcase.expected),
client_type.clone(),
)
.unwrap();
assert_eq_files(&outfile.path(), &Path::new(&testcase.expected));

drop(local_client); // this will kill the instance
}
Expand Down
Loading